Merge changes I8f33830f,Icd2b891b,I8736ff5c,Iae6e342a

* changes:
  libunwindstack: add method to iterate across registers.
  libbacktrace: expose BacktraceMap's unwindstack::Memory.
  libunwindstack: expose UnwindStackMap::GetFunctionName.
  libbacktrace: expose libunwindstack Unwind routine.
diff --git a/adb/adb.h b/adb/adb.h
index a4d233e..3651413 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -67,9 +67,8 @@
     uint32_t magic;       /* command ^ 0xffffffff             */
 };
 
-struct apacket
-{
-    apacket *next;
+struct apacket {
+    apacket* next;
 
     size_t len;
     char* ptr;
@@ -85,13 +84,11 @@
 ** this should be used to cleanup objects that depend on the
 ** transport (e.g. remote sockets, listeners, etc...)
 */
-struct  adisconnect
-{
-    void        (*func)(void*  opaque, atransport*  t);
-    void*         opaque;
+struct adisconnect {
+    void (*func)(void* opaque, atransport* t);
+    void* opaque;
 };
 
-
 // A transport object models the connection to a remote device or emulator there
 // is one transport per connected device/emulator. A "local transport" connects
 // through TCP (for the emulator), while a "usb transport" through USB (for real
@@ -121,15 +118,14 @@
     kCsUnauthorized,
 };
 
-
-void print_packet(const char *label, apacket *p);
+void print_packet(const char* label, apacket* p);
 
 // These use the system (v)fprintf, not the adb prefixed ones defined in sysdeps.h, so they
 // shouldn't be tagged with ADB_FORMAT_ARCHETYPE.
 void fatal(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
 void fatal_errno(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
 
-void handle_packet(apacket *p, atransport *t);
+void handle_packet(apacket* p, atransport* t);
 
 int launch_server(const std::string& socket_spec);
 int adb_server_main(int is_daemon, const std::string& socket_spec, int ack_reply_fd);
@@ -138,7 +134,7 @@
 #if ADB_HOST
 int get_available_local_transport_index();
 #endif
-int  init_socket_transport(atransport *t, int s, int port, int local);
+int init_socket_transport(atransport* t, int s, int port, int local);
 void init_usb_transport(atransport* t, usb_handle* usb);
 
 std::string getEmulatorSerialString(int console_port);
@@ -153,77 +149,78 @@
 #endif
 
 #if !ADB_HOST
-int       init_jdwp(void);
-asocket*  create_jdwp_service_socket();
-asocket*  create_jdwp_tracker_service_socket();
-int       create_jdwp_connection_fd(int  jdwp_pid);
+int init_jdwp(void);
+asocket* create_jdwp_service_socket();
+asocket* create_jdwp_tracker_service_socket();
+int create_jdwp_connection_fd(int jdwp_pid);
 #endif
 
 int handle_forward_request(const char* service, TransportType type, const char* serial,
                            TransportId transport_id, int reply_fd);
 
 #if !ADB_HOST
-void framebuffer_service(int fd, void *cookie);
+void framebuffer_service(int fd, void* cookie);
 void set_verity_enabled_state_service(int fd, void* cookie);
 #endif
 
 /* packet allocator */
-apacket *get_apacket(void);
-void put_apacket(apacket *p);
+apacket* get_apacket(void);
+void put_apacket(apacket* p);
 
 // Define it if you want to dump packets.
 #define DEBUG_PACKETS 0
 
 #if !DEBUG_PACKETS
-#define print_packet(tag,p) do {} while (0)
+#define print_packet(tag, p) \
+    do {                     \
+    } while (0)
 #endif
 
 #if ADB_HOST_ON_TARGET
 /* adb and adbd are coexisting on the target, so use 5038 for adb
  * to avoid conflicting with adbd's usage of 5037
  */
-#  define DEFAULT_ADB_PORT 5038
+#define DEFAULT_ADB_PORT 5038
 #else
-#  define DEFAULT_ADB_PORT 5037
+#define DEFAULT_ADB_PORT 5037
 #endif
 
 #define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
 
-#define ADB_CLASS              0xff
-#define ADB_SUBCLASS           0x42
-#define ADB_PROTOCOL           0x1
-
+#define ADB_CLASS 0xff
+#define ADB_SUBCLASS 0x42
+#define ADB_PROTOCOL 0x1
 
 void local_init(int port);
 bool local_connect(int port);
-int  local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
+int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
-ConnectionState connection_state(atransport *t);
+ConnectionState connection_state(atransport* t);
 
 extern const char* adb_device_banner;
 
 #if !ADB_HOST
 extern int SHELL_EXIT_NOTIFY_FD;
-#endif // !ADB_HOST
+#endif  // !ADB_HOST
 
-#define CHUNK_SIZE (64*1024)
+#define CHUNK_SIZE (64 * 1024)
 
 #if !ADB_HOST
-#define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
-#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
+#define USB_FFS_ADB_PATH "/dev/usb-ffs/adb/"
+#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH #x
 
-#define USB_FFS_ADB_EP0   USB_FFS_ADB_EP(ep0)
-#define USB_FFS_ADB_OUT   USB_FFS_ADB_EP(ep1)
-#define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)
+#define USB_FFS_ADB_EP0 USB_FFS_ADB_EP(ep0)
+#define USB_FFS_ADB_OUT USB_FFS_ADB_EP(ep1)
+#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
 #endif
 
 int handle_host_request(const char* service, TransportType type, const char* serial,
                         TransportId transport_id, int reply_fd, asocket* s);
 
-void handle_online(atransport *t);
-void handle_offline(atransport *t);
+void handle_online(atransport* t);
+void handle_offline(atransport* t);
 
-void send_connect(atransport *t);
+void send_connect(atransport* t);
 
 void parse_banner(const std::string&, atransport* t);
 
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 30cb29b..a142384 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -172,7 +172,7 @@
     auto pred = [](const std::unique_ptr<alistener>& listener) {
         return listener->local_name == "*smartsocket*";
     };
-    listener_list.erase(std::remove_if(listener_list.begin(), listener_list.end(), pred));
+    listener_list.remove_if(pred);
 }
 
 InstallStatus install_listener(const std::string& local_name, const char* connect_to,
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index a7df0ed..1f376a4 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -253,7 +253,7 @@
                             continue;
                         }
                             /* aproto 01 needs 0 termination */
-                        if (interface->bInterfaceProtocol == 0x01) {
+                        if (interface->bInterfaceProtocol == ADB_PROTOCOL) {
                             max_packet_size = ep1->wMaxPacketSize;
                             zero_mask = ep1->wMaxPacketSize - 1;
                         }
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 4e1480f..2e999ee 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -174,7 +174,7 @@
         kr = (*iface)->GetInterfaceClass(iface, &if_class);
         kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
         kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
-        if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+        if (!is_adb_interface(if_class, subclass, protocol)) {
             // Ignore non-ADB devices.
             LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
                        << ", " << subclass << ", " << protocol;
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 1620e6e..61981b1 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -18,8 +18,10 @@
 
 #include "sysdeps.h"
 
+// clang-format off
 #include <winsock2.h>  // winsock.h *must* be included before windows.h.
 #include <windows.h>
+// clang-format on
 #include <usb100.h>
 #include <winerror.h>
 
@@ -47,29 +49,29 @@
   ability to break a thread out of pipe IO.
 */
 struct usb_handle {
-  /// Previous entry in the list of opened usb handles
-  usb_handle *prev;
+    /// Previous entry in the list of opened usb handles
+    usb_handle* prev;
 
-  /// Next entry in the list of opened usb handles
-  usb_handle *next;
+    /// Next entry in the list of opened usb handles
+    usb_handle* next;
 
-  /// Handle to USB interface
-  ADBAPIHANDLE  adb_interface;
+    /// Handle to USB interface
+    ADBAPIHANDLE adb_interface;
 
-  /// Handle to USB read pipe (endpoint)
-  ADBAPIHANDLE  adb_read_pipe;
+    /// Handle to USB read pipe (endpoint)
+    ADBAPIHANDLE adb_read_pipe;
 
-  /// Handle to USB write pipe (endpoint)
-  ADBAPIHANDLE  adb_write_pipe;
+    /// Handle to USB write pipe (endpoint)
+    ADBAPIHANDLE adb_write_pipe;
 
-  /// Interface name
-  wchar_t*      interface_name;
+    /// Interface name
+    wchar_t* interface_name;
 
-  /// Maximum packet size.
-  unsigned max_packet_size;
+    /// Maximum packet size.
+    unsigned max_packet_size;
 
-  /// Mask for determining when to use zero length packets
-  unsigned zero_mask;
+    /// Mask for determining when to use zero length packets
+    unsigned zero_mask;
 };
 
 /// Class ID assigned to the device by androidusb.sys
@@ -77,8 +79,7 @@
 
 /// List of opened usb handles
 static usb_handle handle_list = {
-  .prev = &handle_list,
-  .next = &handle_list,
+    .prev = &handle_list, .next = &handle_list,
 };
 
 /// Locker for the list of opened usb handles
@@ -118,7 +119,7 @@
 int usb_write(usb_handle* handle, const void* data, int len);
 
 /// Reads data using the opened usb handle
-int usb_read(usb_handle *handle, void* data, int len);
+int usb_read(usb_handle* handle, void* data, int len);
 
 /// Cleans up opened usb handle
 void usb_cleanup_handle(usb_handle* handle);
@@ -130,401 +131,374 @@
 int usb_close(usb_handle* handle);
 
 int known_device_locked(const wchar_t* dev_name) {
-  usb_handle* usb;
+    usb_handle* usb;
 
-  if (NULL != dev_name) {
-    // Iterate through the list looking for the name match.
-    for(usb = handle_list.next; usb != &handle_list; usb = usb->next) {
-      // In Windows names are not case sensetive!
-      if((NULL != usb->interface_name) &&
-         (0 == wcsicmp(usb->interface_name, dev_name))) {
-        return 1;
-      }
+    if (NULL != dev_name) {
+        // Iterate through the list looking for the name match.
+        for (usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+            // In Windows names are not case sensetive!
+            if ((NULL != usb->interface_name) && (0 == wcsicmp(usb->interface_name, dev_name))) {
+                return 1;
+            }
+        }
     }
-  }
 
-  return 0;
+    return 0;
 }
 
 int known_device(const wchar_t* dev_name) {
-  int ret = 0;
+    int ret = 0;
 
-  if (NULL != dev_name) {
-    std::lock_guard<std::mutex> lock(usb_lock);
-    ret = known_device_locked(dev_name);
-  }
+    if (NULL != dev_name) {
+        std::lock_guard<std::mutex> lock(usb_lock);
+        ret = known_device_locked(dev_name);
+    }
 
-  return ret;
+    return ret;
 }
 
 int register_new_device(usb_handle* handle) {
-  if (NULL == handle)
-    return 0;
+    if (NULL == handle) return 0;
 
-  std::lock_guard<std::mutex> lock(usb_lock);
+    std::lock_guard<std::mutex> lock(usb_lock);
 
-  // Check if device is already in the list
-  if (known_device_locked(handle->interface_name)) {
-    return 0;
-  }
+    // Check if device is already in the list
+    if (known_device_locked(handle->interface_name)) {
+        return 0;
+    }
 
-  // Not in the list. Add this handle to the list.
-  handle->next = &handle_list;
-  handle->prev = handle_list.prev;
-  handle->prev->next = handle;
-  handle->next->prev = handle;
+    // Not in the list. Add this handle to the list.
+    handle->next = &handle_list;
+    handle->prev = handle_list.prev;
+    handle->prev->next = handle;
+    handle->next->prev = handle;
 
-  return 1;
+    return 1;
 }
 
 void device_poll_thread() {
-  adb_thread_setname("Device Poll");
-  D("Created device thread");
+    adb_thread_setname("Device Poll");
+    D("Created device thread");
 
-  while (true) {
-    find_devices();
-    std::this_thread::sleep_for(1s);
-  }
+    while (true) {
+        find_devices();
+        std::this_thread::sleep_for(1s);
+    }
 }
 
-static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
-                                           LPARAM lParam) {
-  switch (uMsg) {
-  case WM_POWERBROADCAST:
-    switch (wParam) {
-    case PBT_APMRESUMEAUTOMATIC:
-      // Resuming from sleep or hibernation, so kick all existing USB devices
-      // and then allow the device_poll_thread to redetect USB devices from
-      // scratch. If we don't do this, existing USB devices will never respond
-      // to us because they'll be waiting for the connect/auth handshake.
-      D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, "
-        "so kicking all USB devices\n");
-      kick_devices();
-      return TRUE;
+static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+    switch (uMsg) {
+        case WM_POWERBROADCAST:
+            switch (wParam) {
+                case PBT_APMRESUMEAUTOMATIC:
+                    // Resuming from sleep or hibernation, so kick all existing USB devices
+                    // and then allow the device_poll_thread to redetect USB devices from
+                    // scratch. If we don't do this, existing USB devices will never respond
+                    // to us because they'll be waiting for the connect/auth handshake.
+                    D("Received (WM_POWERBROADCAST, PBT_APMRESUMEAUTOMATIC) notification, "
+                      "so kicking all USB devices\n");
+                    kick_devices();
+                    return TRUE;
+            }
     }
-  }
-  return DefWindowProcW(hwnd, uMsg, wParam, lParam);
+    return DefWindowProcW(hwnd, uMsg, wParam, lParam);
 }
 
 static void _power_notification_thread() {
-  // This uses a thread with its own window message pump to get power
-  // notifications. If adb runs from a non-interactive service account, this
-  // might not work (not sure). If that happens to not work, we could use
-  // heavyweight WMI APIs to get power notifications. But for the common case
-  // of a developer's interactive session, a window message pump is more
-  // appropriate.
-  D("Created power notification thread");
-  adb_thread_setname("Power Notifier");
+    // This uses a thread with its own window message pump to get power
+    // notifications. If adb runs from a non-interactive service account, this
+    // might not work (not sure). If that happens to not work, we could use
+    // heavyweight WMI APIs to get power notifications. But for the common case
+    // of a developer's interactive session, a window message pump is more
+    // appropriate.
+    D("Created power notification thread");
+    adb_thread_setname("Power Notifier");
 
-  // Window class names are process specific.
-  static const WCHAR kPowerNotificationWindowClassName[] =
-    L"PowerNotificationWindow";
+    // Window class names are process specific.
+    static const WCHAR kPowerNotificationWindowClassName[] = L"PowerNotificationWindow";
 
-  // Get the HINSTANCE corresponding to the module that _power_window_proc
-  // is in (the main module).
-  const HINSTANCE instance = GetModuleHandleW(NULL);
-  if (!instance) {
-    // This is such a common API call that this should never fail.
-    fatal("GetModuleHandleW failed: %s",
-          android::base::SystemErrorCodeToString(GetLastError()).c_str());
-  }
+    // Get the HINSTANCE corresponding to the module that _power_window_proc
+    // is in (the main module).
+    const HINSTANCE instance = GetModuleHandleW(NULL);
+    if (!instance) {
+        // This is such a common API call that this should never fail.
+        fatal("GetModuleHandleW failed: %s",
+              android::base::SystemErrorCodeToString(GetLastError()).c_str());
+    }
 
-  WNDCLASSEXW wndclass;
-  memset(&wndclass, 0, sizeof(wndclass));
-  wndclass.cbSize = sizeof(wndclass);
-  wndclass.lpfnWndProc = _power_window_proc;
-  wndclass.hInstance = instance;
-  wndclass.lpszClassName = kPowerNotificationWindowClassName;
-  if (!RegisterClassExW(&wndclass)) {
-    fatal("RegisterClassExW failed: %s",
-          android::base::SystemErrorCodeToString(GetLastError()).c_str());
-  }
+    WNDCLASSEXW wndclass;
+    memset(&wndclass, 0, sizeof(wndclass));
+    wndclass.cbSize = sizeof(wndclass);
+    wndclass.lpfnWndProc = _power_window_proc;
+    wndclass.hInstance = instance;
+    wndclass.lpszClassName = kPowerNotificationWindowClassName;
+    if (!RegisterClassExW(&wndclass)) {
+        fatal("RegisterClassExW failed: %s",
+              android::base::SystemErrorCodeToString(GetLastError()).c_str());
+    }
 
-  if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
-                       L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0,
-                       NULL, NULL, instance, NULL)) {
-    fatal("CreateWindowExW failed: %s",
-          android::base::SystemErrorCodeToString(GetLastError()).c_str());
-  }
+    if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
+                         L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, NULL, NULL,
+                         instance, NULL)) {
+        fatal("CreateWindowExW failed: %s",
+              android::base::SystemErrorCodeToString(GetLastError()).c_str());
+    }
 
-  MSG msg;
-  while (GetMessageW(&msg, NULL, 0, 0)) {
-    TranslateMessage(&msg);
-    DispatchMessageW(&msg);
-  }
+    MSG msg;
+    while (GetMessageW(&msg, NULL, 0, 0)) {
+        TranslateMessage(&msg);
+        DispatchMessageW(&msg);
+    }
 
-  // GetMessageW() will return false if a quit message is posted. We don't
-  // do that, but it might be possible for that to occur when logging off or
-  // shutting down. Not a big deal since the whole process will be going away
-  // soon anyway.
-  D("Power notification thread exiting");
+    // GetMessageW() will return false if a quit message is posted. We don't
+    // do that, but it might be possible for that to occur when logging off or
+    // shutting down. Not a big deal since the whole process will be going away
+    // soon anyway.
+    D("Power notification thread exiting");
 }
 
 void usb_init() {
-  std::thread(device_poll_thread).detach();
-  std::thread(_power_notification_thread).detach();
+    std::thread(device_poll_thread).detach();
+    std::thread(_power_notification_thread).detach();
 }
 
 void usb_cleanup() {}
 
 usb_handle* do_usb_open(const wchar_t* interface_name) {
-  unsigned long name_len = 0;
+    unsigned long name_len = 0;
 
-  // Allocate our handle
-  usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
-  if (NULL == ret) {
-    D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle),
-      strerror(errno));
-    goto fail;
-  }
+    // Allocate our handle
+    usb_handle* ret = (usb_handle*)calloc(1, sizeof(usb_handle));
+    if (NULL == ret) {
+        D("Could not allocate %u bytes for usb_handle: %s", sizeof(usb_handle), strerror(errno));
+        goto fail;
+    }
 
-  // Set linkers back to the handle
-  ret->next = ret;
-  ret->prev = ret;
+    // Set linkers back to the handle
+    ret->next = ret;
+    ret->prev = ret;
 
-  // Create interface.
-  ret->adb_interface = AdbCreateInterfaceByName(interface_name);
-  if (NULL == ret->adb_interface) {
-    D("AdbCreateInterfaceByName failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    goto fail;
-  }
+    // Create interface.
+    ret->adb_interface = AdbCreateInterfaceByName(interface_name);
+    if (NULL == ret->adb_interface) {
+        D("AdbCreateInterfaceByName failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        goto fail;
+    }
 
-  // Open read pipe (endpoint)
-  ret->adb_read_pipe =
-    AdbOpenDefaultBulkReadEndpoint(ret->adb_interface,
-                                   AdbOpenAccessTypeReadWrite,
-                                   AdbOpenSharingModeReadWrite);
-  if (NULL == ret->adb_read_pipe) {
-    D("AdbOpenDefaultBulkReadEndpoint failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    goto fail;
-  }
+    // Open read pipe (endpoint)
+    ret->adb_read_pipe = AdbOpenDefaultBulkReadEndpoint(
+        ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
+    if (NULL == ret->adb_read_pipe) {
+        D("AdbOpenDefaultBulkReadEndpoint failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        goto fail;
+    }
 
-  // Open write pipe (endpoint)
-  ret->adb_write_pipe =
-    AdbOpenDefaultBulkWriteEndpoint(ret->adb_interface,
-                                    AdbOpenAccessTypeReadWrite,
-                                    AdbOpenSharingModeReadWrite);
-  if (NULL == ret->adb_write_pipe) {
-    D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    goto fail;
-  }
+    // Open write pipe (endpoint)
+    ret->adb_write_pipe = AdbOpenDefaultBulkWriteEndpoint(
+        ret->adb_interface, AdbOpenAccessTypeReadWrite, AdbOpenSharingModeReadWrite);
+    if (NULL == ret->adb_write_pipe) {
+        D("AdbOpenDefaultBulkWriteEndpoint failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        goto fail;
+    }
 
-  // Save interface name
-  // First get expected name length
-  AdbGetInterfaceName(ret->adb_interface,
-                      NULL,
-                      &name_len,
-                      false);
-  if (0 == name_len) {
-    D("AdbGetInterfaceName returned name length of zero: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    goto fail;
-  }
+    // Save interface name
+    // First get expected name length
+    AdbGetInterfaceName(ret->adb_interface, NULL, &name_len, false);
+    if (0 == name_len) {
+        D("AdbGetInterfaceName returned name length of zero: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        goto fail;
+    }
 
-  ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
-  if (NULL == ret->interface_name) {
-    D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
-    goto fail;
-  }
+    ret->interface_name = (wchar_t*)malloc(name_len * sizeof(ret->interface_name[0]));
+    if (NULL == ret->interface_name) {
+        D("Could not allocate %lu characters for interface_name: %s", name_len, strerror(errno));
+        goto fail;
+    }
 
-  // Now save the name
-  if (!AdbGetInterfaceName(ret->adb_interface,
-                           ret->interface_name,
-                           &name_len,
-                           false)) {
-    D("AdbGetInterfaceName failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    goto fail;
-  }
+    // Now save the name
+    if (!AdbGetInterfaceName(ret->adb_interface, ret->interface_name, &name_len, false)) {
+        D("AdbGetInterfaceName failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        goto fail;
+    }
 
-  // We're done at this point
-  return ret;
+    // We're done at this point
+    return ret;
 
 fail:
-  if (NULL != ret) {
-    usb_cleanup_handle(ret);
-    free(ret);
-  }
+    if (NULL != ret) {
+        usb_cleanup_handle(ret);
+        free(ret);
+    }
 
-  return NULL;
+    return NULL;
 }
 
 int usb_write(usb_handle* handle, const void* data, int len) {
-  unsigned long time_out = 5000;
-  unsigned long written = 0;
-  int err = 0;
+    unsigned long time_out = 5000;
+    unsigned long written = 0;
+    int err = 0;
 
-  D("usb_write %d", len);
-  if (NULL == handle) {
-    D("usb_write was passed NULL handle");
-    err = EINVAL;
-    goto fail;
-  }
-
-  // Perform write
-  if (!AdbWriteEndpointSync(handle->adb_write_pipe,
-                            (void*)data,
-                            (unsigned long)len,
-                            &written,
-                            time_out)) {
-    D("AdbWriteEndpointSync failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    err = EIO;
-    goto fail;
-  }
-
-  // Make sure that we've written what we were asked to write
-  D("usb_write got: %ld, expected: %d", written, len);
-  if (written != (unsigned long)len) {
-    // If this occurs, this code should be changed to repeatedly call
-    // AdbWriteEndpointSync() until all bytes are written.
-    D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld",
-      len, written);
-    err = EIO;
-    goto fail;
-  }
-
-  if (handle->zero_mask && (len & handle->zero_mask) == 0) {
-    // Send a zero length packet
-    if (!AdbWriteEndpointSync(handle->adb_write_pipe,
-                              (void*)data,
-                              0,
-                              &written,
-                              time_out)) {
-      D("AdbWriteEndpointSync of zero length packet failed: %s",
-        android::base::SystemErrorCodeToString(GetLastError()).c_str());
-      err = EIO;
-      goto fail;
+    D("usb_write %d", len);
+    if (NULL == handle) {
+        D("usb_write was passed NULL handle");
+        err = EINVAL;
+        goto fail;
     }
-  }
 
-  return 0;
+    // Perform write
+    if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, (unsigned long)len, &written,
+                              time_out)) {
+        D("AdbWriteEndpointSync failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        err = EIO;
+        goto fail;
+    }
+
+    // Make sure that we've written what we were asked to write
+    D("usb_write got: %ld, expected: %d", written, len);
+    if (written != (unsigned long)len) {
+        // If this occurs, this code should be changed to repeatedly call
+        // AdbWriteEndpointSync() until all bytes are written.
+        D("AdbWriteEndpointSync was supposed to write %d, but only wrote %ld", len, written);
+        err = EIO;
+        goto fail;
+    }
+
+    if (handle->zero_mask && (len & handle->zero_mask) == 0) {
+        // Send a zero length packet
+        if (!AdbWriteEndpointSync(handle->adb_write_pipe, (void*)data, 0, &written, time_out)) {
+            D("AdbWriteEndpointSync of zero length packet failed: %s",
+              android::base::SystemErrorCodeToString(GetLastError()).c_str());
+            err = EIO;
+            goto fail;
+        }
+    }
+
+    return 0;
 
 fail:
-  // Any failure should cause us to kick the device instead of leaving it a
-  // zombie state with potential to hang.
-  if (NULL != handle) {
-    D("Kicking device due to error in usb_write");
-    usb_kick(handle);
-  }
+    // Any failure should cause us to kick the device instead of leaving it a
+    // zombie state with potential to hang.
+    if (NULL != handle) {
+        D("Kicking device due to error in usb_write");
+        usb_kick(handle);
+    }
 
-  D("usb_write failed");
-  errno = err;
-  return -1;
+    D("usb_write failed");
+    errno = err;
+    return -1;
 }
 
-int usb_read(usb_handle *handle, void* data, int len) {
-  unsigned long time_out = 0;
-  unsigned long read = 0;
-  int err = 0;
-  int orig_len = len;
+int usb_read(usb_handle* handle, void* data, int len) {
+    unsigned long time_out = 0;
+    unsigned long read = 0;
+    int err = 0;
+    int orig_len = len;
 
-  D("usb_read %d", len);
-  if (NULL == handle) {
-    D("usb_read was passed NULL handle");
-    err = EINVAL;
-    goto fail;
-  }
-
-  while (len == orig_len) {
-    if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) {
-      D("AdbReadEndpointSync failed: %s",
-        android::base::SystemErrorCodeToString(GetLastError()).c_str());
-      err = EIO;
-      goto fail;
+    D("usb_read %d", len);
+    if (NULL == handle) {
+        D("usb_read was passed NULL handle");
+        err = EINVAL;
+        goto fail;
     }
-    D("usb_read got: %ld, expected: %d", read, len);
 
-    data = (char*)data + read;
-    len -= read;
-  }
+    while (len == orig_len) {
+        if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) {
+            D("AdbReadEndpointSync failed: %s",
+              android::base::SystemErrorCodeToString(GetLastError()).c_str());
+            err = EIO;
+            goto fail;
+        }
+        D("usb_read got: %ld, expected: %d", read, len);
 
-  return orig_len - len;
+        data = (char*)data + read;
+        len -= read;
+    }
+
+    return orig_len - len;
 
 fail:
-  // Any failure should cause us to kick the device instead of leaving it a
-  // zombie state with potential to hang.
-  if (NULL != handle) {
-    D("Kicking device due to error in usb_read");
-    usb_kick(handle);
-  }
+    // Any failure should cause us to kick the device instead of leaving it a
+    // zombie state with potential to hang.
+    if (NULL != handle) {
+        D("Kicking device due to error in usb_read");
+        usb_kick(handle);
+    }
 
-  D("usb_read failed");
-  errno = err;
-  return -1;
+    D("usb_read failed");
+    errno = err;
+    return -1;
 }
 
 // Wrapper around AdbCloseHandle() that logs diagnostics.
 static void _adb_close_handle(ADBAPIHANDLE adb_handle) {
-  if (!AdbCloseHandle(adb_handle)) {
-    D("AdbCloseHandle(%p) failed: %s", adb_handle,
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-  }
+    if (!AdbCloseHandle(adb_handle)) {
+        D("AdbCloseHandle(%p) failed: %s", adb_handle,
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+    }
 }
 
 void usb_cleanup_handle(usb_handle* handle) {
-  D("usb_cleanup_handle");
-  if (NULL != handle) {
-    if (NULL != handle->interface_name)
-      free(handle->interface_name);
-    // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
-    // wait until the pipe no longer uses the interface. Then we can
-    // AdbCloseHandle() the interface.
-    if (NULL != handle->adb_write_pipe)
-      _adb_close_handle(handle->adb_write_pipe);
-    if (NULL != handle->adb_read_pipe)
-      _adb_close_handle(handle->adb_read_pipe);
-    if (NULL != handle->adb_interface)
-      _adb_close_handle(handle->adb_interface);
+    D("usb_cleanup_handle");
+    if (NULL != handle) {
+        if (NULL != handle->interface_name) free(handle->interface_name);
+        // AdbCloseHandle(pipe) will break any threads out of pending IO calls and
+        // wait until the pipe no longer uses the interface. Then we can
+        // AdbCloseHandle() the interface.
+        if (NULL != handle->adb_write_pipe) _adb_close_handle(handle->adb_write_pipe);
+        if (NULL != handle->adb_read_pipe) _adb_close_handle(handle->adb_read_pipe);
+        if (NULL != handle->adb_interface) _adb_close_handle(handle->adb_interface);
 
-    handle->interface_name = NULL;
-    handle->adb_write_pipe = NULL;
-    handle->adb_read_pipe = NULL;
-    handle->adb_interface = NULL;
-  }
+        handle->interface_name = NULL;
+        handle->adb_write_pipe = NULL;
+        handle->adb_read_pipe = NULL;
+        handle->adb_interface = NULL;
+    }
 }
 
 static void usb_kick_locked(usb_handle* handle) {
-  // The reason the lock must be acquired before calling this function is in
-  // case multiple threads are trying to kick the same device at the same time.
-  usb_cleanup_handle(handle);
+    // The reason the lock must be acquired before calling this function is in
+    // case multiple threads are trying to kick the same device at the same time.
+    usb_cleanup_handle(handle);
 }
 
 void usb_kick(usb_handle* handle) {
-  D("usb_kick");
-  if (NULL != handle) {
-    std::lock_guard<std::mutex> lock(usb_lock);
-    usb_kick_locked(handle);
-  } else {
-    errno = EINVAL;
-  }
+    D("usb_kick");
+    if (NULL != handle) {
+        std::lock_guard<std::mutex> lock(usb_lock);
+        usb_kick_locked(handle);
+    } else {
+        errno = EINVAL;
+    }
 }
 
 int usb_close(usb_handle* handle) {
-  D("usb_close");
+    D("usb_close");
 
-  if (NULL != handle) {
-    // Remove handle from the list
-    {
-      std::lock_guard<std::mutex> lock(usb_lock);
+    if (NULL != handle) {
+        // Remove handle from the list
+        {
+            std::lock_guard<std::mutex> lock(usb_lock);
 
-      if ((handle->next != handle) && (handle->prev != handle)) {
-        handle->next->prev = handle->prev;
-        handle->prev->next = handle->next;
-        handle->prev = handle;
-        handle->next = handle;
-      }
+            if ((handle->next != handle) && (handle->prev != handle)) {
+                handle->next->prev = handle->prev;
+                handle->prev->next = handle->next;
+                handle->prev = handle;
+                handle->next = handle;
+            }
+        }
+
+        // Cleanup handle
+        usb_cleanup_handle(handle);
+        free(handle);
     }
 
-    // Cleanup handle
-    usb_cleanup_handle(handle);
-    free(handle);
-  }
-
-  return 0;
+    return 0;
 }
 
 size_t usb_get_max_packet_size(usb_handle* handle) {
@@ -532,131 +506,124 @@
 }
 
 int recognized_device(usb_handle* handle) {
-  if (NULL == handle)
-    return 0;
+    if (NULL == handle) return 0;
 
-  // Check vendor and product id first
-  USB_DEVICE_DESCRIPTOR device_desc;
+    // Check vendor and product id first
+    USB_DEVICE_DESCRIPTOR device_desc;
 
-  if (!AdbGetUsbDeviceDescriptor(handle->adb_interface,
-                                 &device_desc)) {
-    D("AdbGetUsbDeviceDescriptor failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    return 0;
-  }
+    if (!AdbGetUsbDeviceDescriptor(handle->adb_interface, &device_desc)) {
+        D("AdbGetUsbDeviceDescriptor failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        return 0;
+    }
 
-  // Then check interface properties
-  USB_INTERFACE_DESCRIPTOR interf_desc;
+    // Then check interface properties
+    USB_INTERFACE_DESCRIPTOR interf_desc;
 
-  if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface,
-                                    &interf_desc)) {
-    D("AdbGetUsbInterfaceDescriptor failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    return 0;
-  }
+    if (!AdbGetUsbInterfaceDescriptor(handle->adb_interface, &interf_desc)) {
+        D("AdbGetUsbInterfaceDescriptor failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        return 0;
+    }
 
-  // Must have two endpoints
-  if (2 != interf_desc.bNumEndpoints) {
-    return 0;
-  }
+    // Must have two endpoints
+    if (2 != interf_desc.bNumEndpoints) {
+        return 0;
+    }
 
-  if (is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
-                       interf_desc.bInterfaceProtocol)) {
-    if (interf_desc.bInterfaceProtocol == 0x01) {
-      AdbEndpointInformation endpoint_info;
-      // assuming zero is a valid bulk endpoint ID
-      if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
+    if (!is_adb_interface(interf_desc.bInterfaceClass, interf_desc.bInterfaceSubClass,
+                          interf_desc.bInterfaceProtocol)) {
+        return 0;
+    }
+
+    AdbEndpointInformation endpoint_info;
+    // assuming zero is a valid bulk endpoint ID
+    if (AdbGetEndpointInformation(handle->adb_interface, 0, &endpoint_info)) {
         handle->max_packet_size = endpoint_info.max_packet_size;
         handle->zero_mask = endpoint_info.max_packet_size - 1;
         D("device zero_mask: 0x%x", handle->zero_mask);
-      } else {
+    } else {
         D("AdbGetEndpointInformation failed: %s",
           android::base::SystemErrorCodeToString(GetLastError()).c_str());
-      }
     }
 
     return 1;
-  }
-
-  return 0;
 }
 
 void find_devices() {
-  usb_handle* handle = NULL;
-  char entry_buffer[2048];
-  AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
-  unsigned long entry_buffer_size = sizeof(entry_buffer);
+    usb_handle* handle = NULL;
+    char entry_buffer[2048];
+    AdbInterfaceInfo* next_interface = (AdbInterfaceInfo*)(&entry_buffer[0]);
+    unsigned long entry_buffer_size = sizeof(entry_buffer);
 
-  // Enumerate all present and active interfaces.
-  ADBAPIHANDLE enum_handle =
-    AdbEnumInterfaces(usb_class_id, true, true, true);
+    // Enumerate all present and active interfaces.
+    ADBAPIHANDLE enum_handle = AdbEnumInterfaces(usb_class_id, true, true, true);
 
-  if (NULL == enum_handle) {
-    D("AdbEnumInterfaces failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-    return;
-  }
-
-  while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
-    // Lets see if we already have this device in the list
-    if (!known_device(next_interface->device_name)) {
-      // This seems to be a new device. Open it!
-      handle = do_usb_open(next_interface->device_name);
-      if (NULL != handle) {
-        // Lets see if this interface (device) belongs to us
-        if (recognized_device(handle)) {
-          D("adding a new device %ls", next_interface->device_name);
-
-          // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug in
-          // adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString, bytes_written) where the
-          // last parameter should be (str_len * sizeof(wchar_t)). The bug reads 2 bytes past the
-          // end of a stack buffer in the best case, and in the unlikely case of a long serial
-          // number, it will read 2 bytes past the end of a heap allocation. This doesn't affect the
-          // resulting string, but we should avoid the bad reads in the first place.
-          char serial_number[512];
-          unsigned long serial_number_len = sizeof(serial_number);
-          if (AdbGetSerialNumber(handle->adb_interface,
-                                serial_number,
-                                &serial_number_len,
-                                true)) {
-            // Lets make sure that we don't duplicate this device
-            if (register_new_device(handle)) {
-              register_usb_transport(handle, serial_number, NULL, 1);
-            } else {
-              D("register_new_device failed for %ls", next_interface->device_name);
-              usb_cleanup_handle(handle);
-              free(handle);
-            }
-          } else {
-            D("cannot get serial number: %s",
-              android::base::SystemErrorCodeToString(GetLastError()).c_str());
-            usb_cleanup_handle(handle);
-            free(handle);
-          }
-        } else {
-          usb_cleanup_handle(handle);
-          free(handle);
-        }
-      }
+    if (NULL == enum_handle) {
+        D("AdbEnumInterfaces failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+        return;
     }
 
-    entry_buffer_size = sizeof(entry_buffer);
-  }
+    while (AdbNextInterface(enum_handle, next_interface, &entry_buffer_size)) {
+        // Lets see if we already have this device in the list
+        if (!known_device(next_interface->device_name)) {
+            // This seems to be a new device. Open it!
+            handle = do_usb_open(next_interface->device_name);
+            if (NULL != handle) {
+                // Lets see if this interface (device) belongs to us
+                if (recognized_device(handle)) {
+                    D("adding a new device %ls", next_interface->device_name);
 
-  if (GetLastError() != ERROR_NO_MORE_ITEMS) {
-    // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration.
-    D("AdbNextInterface failed: %s",
-      android::base::SystemErrorCodeToString(GetLastError()).c_str());
-  }
+                    // We don't request a wchar_t string from AdbGetSerialNumber() because of a bug
+                    // in adb_winusb_interface.cpp:CopyMemory(buffer, ser_num->bString,
+                    // bytes_written) where the last parameter should be (str_len *
+                    // sizeof(wchar_t)). The bug reads 2 bytes past the end of a stack buffer in the
+                    // best case, and in the unlikely case of a long serial number, it will read 2
+                    // bytes past the end of a heap allocation. This doesn't affect the resulting
+                    // string, but we should avoid the bad reads in the first place.
+                    char serial_number[512];
+                    unsigned long serial_number_len = sizeof(serial_number);
+                    if (AdbGetSerialNumber(handle->adb_interface, serial_number, &serial_number_len,
+                                           true)) {
+                        // Lets make sure that we don't duplicate this device
+                        if (register_new_device(handle)) {
+                            register_usb_transport(handle, serial_number, NULL, 1);
+                        } else {
+                            D("register_new_device failed for %ls", next_interface->device_name);
+                            usb_cleanup_handle(handle);
+                            free(handle);
+                        }
+                    } else {
+                        D("cannot get serial number: %s",
+                          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+                        usb_cleanup_handle(handle);
+                        free(handle);
+                    }
+                } else {
+                    usb_cleanup_handle(handle);
+                    free(handle);
+                }
+            }
+        }
 
-  _adb_close_handle(enum_handle);
+        entry_buffer_size = sizeof(entry_buffer);
+    }
+
+    if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+        // Only ERROR_NO_MORE_ITEMS is expected at the end of enumeration.
+        D("AdbNextInterface failed: %s",
+          android::base::SystemErrorCodeToString(GetLastError()).c_str());
+    }
+
+    _adb_close_handle(enum_handle);
 }
 
 static void kick_devices() {
-  // Need to acquire lock to safely walk the list which might be modified
-  // by another thread.
-  std::lock_guard<std::mutex> lock(usb_lock);
-  for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
-    usb_kick_locked(usb);
-  }
+    // Need to acquire lock to safely walk the list which might be modified
+    // by another thread.
+    std::lock_guard<std::mutex> lock(usb_lock);
+    for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
+        usb_kick_locked(usb);
+    }
 }
diff --git a/base/logging.cpp b/base/logging.cpp
index 6357b4b..75078e5 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -80,7 +80,9 @@
 #if defined(__BIONIC__)
   return gettid();
 #elif defined(__APPLE__)
-  return syscall(SYS_thread_selfid);
+  uint64_t tid;
+  pthread_threadid_np(NULL, &tid);
+  return tid;
 #elif defined(__linux__)
   return syscall(__NR_gettid);
 #elif defined(_WIN32)
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 8916c59..2270133 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -212,6 +212,17 @@
     {"hard,hw_reset", 72},
     {"shutdown,suspend", 73},    // Suspend to RAM
     {"shutdown,hibernate", 74},  // Suspend to DISK
+    {"power_on_key", 75},
+    {"reboot_by_key", 76},
+    {"wdt_by_pass_pwk", 77},
+    {"reboot_longkey", 78},
+    {"powerkey", 79},
+    {"usb", 80},
+    {"wdt", 81},
+    {"tool_by_pass_pwk", 82},
+    {"2sec_reboot", 83},
+    {"reboot,by_key", 84},
+    {"reboot,longkey", 85},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/init/Android.bp b/init/Android.bp
index e906771..8c4f005 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -89,6 +89,7 @@
     whole_static_libs: ["libcap"],
     static_libs: [
         "libbase",
+        "libhidl-gen-utils",
         "libselinux",
         "liblog",
         "libprocessgroup",
@@ -136,6 +137,7 @@
         "libfs_mgr",
         "libfec",
         "libfec_rs",
+        "libhidl-gen-utils",
         "libsquashfs_utils",
         "liblogwrap",
         "libext4_utils",
@@ -185,6 +187,7 @@
     ],
     static_libs: [
         "libinit",
+        "libhidl-gen-utils",
         "libselinux",
         "libcrypto",
         "libprotobuf-cpp-lite",
diff --git a/init/Android.mk b/init/Android.mk
index dd0f1bf..44300f6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -64,6 +64,7 @@
     libfs_mgr \
     libfec \
     libfec_rs \
+    libhidl-gen-utils \
     libsquashfs_utils \
     liblogwrap \
     libext4_utils \
diff --git a/init/init.cpp b/init/init.cpp
index 51a98a2..571da7c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -202,24 +202,90 @@
     return next_process_restart_time;
 }
 
+static Result<Success> DoControlStart(Service* service) {
+    return service->Start();
+}
+
+static Result<Success> DoControlStop(Service* service) {
+    service->Stop();
+    return Success();
+}
+
+static Result<Success> DoControlRestart(Service* service) {
+    service->Restart();
+    return Success();
+}
+
+enum class ControlTarget {
+    SERVICE,    // function gets called for the named service
+    INTERFACE,  // action gets called for every service that holds this interface
+};
+
+struct ControlMessageFunction {
+    ControlTarget target;
+    std::function<Result<Success>(Service*)> action;
+};
+
+static const std::map<std::string, ControlMessageFunction>& get_control_message_map() {
+    // clang-format off
+    static const std::map<std::string, ControlMessageFunction> control_message_functions = {
+        {"start",             {ControlTarget::SERVICE,   DoControlStart}},
+        {"stop",              {ControlTarget::SERVICE,   DoControlStop}},
+        {"restart",           {ControlTarget::SERVICE,   DoControlRestart}},
+        {"interface_start",   {ControlTarget::INTERFACE, DoControlStart}},
+        {"interface_stop",    {ControlTarget::INTERFACE, DoControlStop}},
+        {"interface_restart", {ControlTarget::INTERFACE, DoControlRestart}},
+    };
+    // clang-format on
+
+    return control_message_functions;
+}
+
 void handle_control_message(const std::string& msg, const std::string& name) {
-    Service* svc = ServiceList::GetInstance().FindService(name);
-    if (svc == nullptr) {
-        LOG(ERROR) << "no such service '" << name << "'";
+    const auto& map = get_control_message_map();
+    const auto it = map.find(msg);
+
+    if (it == map.end()) {
+        LOG(ERROR) << "Unknown control msg '" << msg << "'";
         return;
     }
 
-    if (msg == "start") {
-        if (auto result = svc->Start(); !result) {
-            LOG(ERROR) << "Could not ctl.start service '" << name << "': " << result.error();
+    const ControlMessageFunction& function = it->second;
+
+    if (function.target == ControlTarget::SERVICE) {
+        Service* svc = ServiceList::GetInstance().FindService(name);
+        if (svc == nullptr) {
+            LOG(ERROR) << "No such service '" << name << "' for ctl." << msg;
+            return;
         }
-    } else if (msg == "stop") {
-        svc->Stop();
-    } else if (msg == "restart") {
-        svc->Restart();
-    } else {
-        LOG(ERROR) << "unknown control msg '" << msg << "'";
+        if (auto result = function.action(svc); !result) {
+            LOG(ERROR) << "Could not ctl." << msg << " for service " << name << ": "
+                       << result.error();
+        }
+
+        return;
     }
+
+    if (function.target == ControlTarget::INTERFACE) {
+        for (const auto& svc : ServiceList::GetInstance()) {
+            if (svc->interfaces().count(name) == 0) {
+                continue;
+            }
+
+            if (auto result = function.action(svc.get()); !result) {
+                LOG(ERROR) << "Could not handle ctl." << msg << " for service " << svc->name()
+                           << " with interface " << name << ": " << result.error();
+            }
+
+            return;
+        }
+
+        LOG(ERROR) << "Could not find service hosting interface " << name;
+        return;
+    }
+
+    LOG(ERROR) << "Invalid function target from static map key '" << msg
+               << "': " << static_cast<std::underlying_type<ControlTarget>::type>(function.target);
 }
 
 static Result<Success> wait_for_coldboot_done_action(const BuiltinArguments& args) {
diff --git a/init/reboot.cpp b/init/reboot.cpp
index b17dbaf..21086dc 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -280,16 +280,16 @@
         }
         bool unmount_done = true;
         if (emulated_devices.size() > 0) {
-            unmount_done = std::all_of(emulated_devices.begin(), emulated_devices.end(),
-                                       [](auto& entry) { return entry.Umount(false); });
+            for (auto& entry : emulated_devices) {
+                if (!entry.Umount(false)) unmount_done = false;
+            }
             if (unmount_done) {
                 sync();
             }
         }
-        unmount_done =
-            std::all_of(block_devices.begin(), block_devices.end(),
-                        [&timeout](auto& entry) { return entry.Umount(timeout == 0ms); }) &&
-            unmount_done;
+        for (auto& entry : block_devices) {
+            if (!entry.Umount(timeout == 0ms)) unmount_done = false;
+        }
         if (unmount_done) {
             return UMOUNT_STAT_SUCCESS;
         }
diff --git a/init/service.cpp b/init/service.cpp
index b339bc0..765b61e 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -37,6 +37,7 @@
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <hidl-util/FQName.h>
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
 #include <system/thread_defs.h>
@@ -418,6 +419,37 @@
     return Success();
 }
 
+Result<Success> Service::ParseInterface(const std::vector<std::string>& args) {
+    const std::string& interface_name = args[1];
+    const std::string& instance_name = args[2];
+
+    const FQName fq_name = FQName(interface_name);
+    if (!fq_name.isValid()) {
+        return Error() << "Invalid fully-qualified name for interface '" << interface_name << "'";
+    }
+
+    if (!fq_name.isFullyQualified()) {
+        return Error() << "Interface name not fully-qualified '" << interface_name << "'";
+    }
+
+    if (fq_name.isValidValueName()) {
+        return Error() << "Interface name must not be a value name '" << interface_name << "'";
+    }
+
+    const std::string fullname = interface_name + "/" + instance_name;
+
+    for (const auto& svc : ServiceList::GetInstance()) {
+        if (svc->interfaces().count(fullname) > 0) {
+            return Error() << "Interface '" << fullname << "' redefined in " << name()
+                           << " but is already defined by " << svc->name();
+        }
+    }
+
+    interfaces_.insert(fullname);
+
+    return Success();
+}
+
 Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
     if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
         return Error() << "priority value must be range 0 - 7";
@@ -619,6 +651,7 @@
         {"critical",    {0,     0,    &Service::ParseCritical}},
         {"disabled",    {0,     0,    &Service::ParseDisabled}},
         {"group",       {1,     NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
+        {"interface",   {2,     2,    &Service::ParseInterface}},
         {"ioprio",      {2,     2,    &Service::ParseIoprio}},
         {"priority",    {1,     1,    &Service::ParsePriority}},
         {"keycodes",    {1,     kMax, &Service::ParseKeycodes}},
diff --git a/init/service.h b/init/service.h
index 89dd780..593f782 100644
--- a/init/service.h
+++ b/init/service.h
@@ -108,6 +108,7 @@
     void set_keychord_id(int keychord_id) { keychord_id_ = keychord_id; }
     IoSchedClass ioprio_class() const { return ioprio_class_; }
     int ioprio_pri() const { return ioprio_pri_; }
+    const std::set<std::string>& interfaces() const { return interfaces_; }
     int priority() const { return priority_; }
     int oom_score_adjust() const { return oom_score_adjust_; }
     bool process_cgroup_empty() const { return process_cgroup_empty_; }
@@ -132,6 +133,7 @@
     Result<Success> ParseDisabled(const std::vector<std::string>& args);
     Result<Success> ParseGroup(const std::vector<std::string>& args);
     Result<Success> ParsePriority(const std::vector<std::string>& args);
+    Result<Success> ParseInterface(const std::vector<std::string>& args);
     Result<Success> ParseIoprio(const std::vector<std::string>& args);
     Result<Success> ParseKeycodes(const std::vector<std::string>& args);
     Result<Success> ParseOneshot(const std::vector<std::string>& args);
@@ -181,6 +183,8 @@
 
     std::vector<std::string> writepid_files_;
 
+    std::set<std::string> interfaces_;  // e.g. some.package.foo@1.0::IBaz/instance-name
+
     // keycodes for triggering this service via /dev/keychord
     std::vector<int> keycodes_;
     int keychord_id_;
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 927953d..84feeee 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -28,6 +28,7 @@
 #include <selinux/android.h>
 
 #include "action.h"
+#include "selinux.h"
 #include "system/core/init/subcontext.pb.h"
 #include "util.h"
 
@@ -165,6 +166,7 @@
     auto context = std::string(argv[2]);
     auto init_fd = std::atoi(argv[3]);
 
+    SelabelInitialize();
     auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
     subcontext_process.MainLoop();
     return 0;
diff --git a/init/subcontext.h b/init/subcontext.h
index e920034..eadabee 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -35,7 +35,7 @@
 class Subcontext {
   public:
     Subcontext(std::string path_prefix, std::string context)
-        : path_prefix_(std::move(path_prefix)), context_(std::move(context)) {
+        : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
         Fork();
     }
 
@@ -55,21 +55,6 @@
     android::base::unique_fd socket_;
 };
 
-// For testing, to kill the subcontext after the test has completed.
-class SubcontextKiller {
-  public:
-    SubcontextKiller(const Subcontext& subcontext) : subcontext_(subcontext) {}
-    ~SubcontextKiller() {
-        if (subcontext_.pid() > 0) {
-            kill(subcontext_.pid(), SIGTERM);
-            kill(subcontext_.pid(), SIGKILL);
-        }
-    }
-
-  private:
-    const Subcontext& subcontext_;
-};
-
 int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map);
 std::vector<Subcontext>* InitializeSubcontexts();
 bool SubcontextChildReap(pid_t pid);
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index a62b959..6307993 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -17,6 +17,7 @@
 #include "subcontext.h"
 
 #include <benchmark/benchmark.h>
+#include <selinux/selinux.h>
 
 #include "test_function_map.h"
 
@@ -24,12 +25,27 @@
 namespace init {
 
 static void BenchmarkSuccess(benchmark::State& state) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
+    if (getuid() != 0) {
+        state.SkipWithError("Skipping benchmark, must be run as root.");
+        return;
+    }
+    char* context;
+    if (getcon(&context) != 0) {
+        state.SkipWithError("getcon() failed");
+        return;
+    }
+
+    auto subcontext = Subcontext("path", context);
+    free(context);
 
     while (state.KeepRunning()) {
         subcontext.Execute(std::vector<std::string>{"return_success"});
     }
+
+    if (subcontext.pid() > 0) {
+        kill(subcontext.pid(), SIGTERM);
+        kill(subcontext.pid(), SIGKILL);
+    }
 }
 
 BENCHMARK(BenchmarkSuccess);
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 60b45b9..ca45266 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -23,6 +23,7 @@
 #include <android-base/properties.h>
 #include <android-base/strings.h>
 #include <gtest/gtest.h>
+#include <selinux/selinux.h>
 
 #include "builtin_arguments.h"
 #include "test_function_map.h"
@@ -38,88 +39,108 @@
 namespace android {
 namespace init {
 
+// I would use test fixtures, but I cannot skip the test if not root with them, so instead we have
+// this test runner.
+template <typename F>
+void RunTest(F&& test_function) {
+    if (getuid() != 0) {
+        GTEST_LOG_(INFO) << "Skipping test, must be run as root.";
+        return;
+    }
+
+    char* context;
+    ASSERT_EQ(0, getcon(&context));
+    auto context_string = std::string(context);
+    free(context);
+
+    auto subcontext = Subcontext("dummy_path", context_string);
+    ASSERT_NE(0, subcontext.pid());
+
+    test_function(subcontext, context_string);
+
+    if (subcontext.pid() > 0) {
+        kill(subcontext.pid(), SIGTERM);
+        kill(subcontext.pid(), SIGKILL);
+    }
+}
+
 TEST(subcontext, CheckDifferentPid) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
+    RunTest([](auto& subcontext, auto& context_string) {
+        auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
+        ASSERT_FALSE(result);
 
-    auto result = subcontext.Execute(std::vector<std::string>{"return_pids_as_error"});
-    ASSERT_FALSE(result);
-
-    auto pids = Split(result.error_string(), " ");
-    ASSERT_EQ(2U, pids.size());
-    auto our_pid = std::to_string(getpid());
-    EXPECT_NE(our_pid, pids[0]);
-    EXPECT_EQ(our_pid, pids[1]);
+        auto pids = Split(result.error_string(), " ");
+        ASSERT_EQ(2U, pids.size());
+        auto our_pid = std::to_string(getpid());
+        EXPECT_NE(our_pid, pids[0]);
+        EXPECT_EQ(our_pid, pids[1]);
+    });
 }
 
 TEST(subcontext, SetProp) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
+    RunTest([](auto& subcontext, auto& context_string) {
+        SetProperty("init.test.subcontext", "fail");
+        WaitForProperty("init.test.subcontext", "fail");
 
-    SetProperty("init.test.subcontext", "fail");
-    WaitForProperty("init.test.subcontext", "fail");
-
-    auto args = std::vector<std::string>{
-        "setprop",
-        "init.test.subcontext",
-        "success",
-    };
-    auto result = subcontext.Execute(args);
-    ASSERT_TRUE(result) << result.error();
-
-    EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
-}
-
-TEST(subcontext, MultipleCommands) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
-
-    auto first_pid = subcontext.pid();
-
-    auto expected_words = std::vector<std::string>{
-        "this",
-        "is",
-        "a",
-        "test",
-    };
-
-    for (const auto& word : expected_words) {
         auto args = std::vector<std::string>{
-            "add_word",
-            word,
+            "setprop",
+            "init.test.subcontext",
+            "success",
         };
         auto result = subcontext.Execute(args);
         ASSERT_TRUE(result) << result.error();
-    }
 
-    auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
-    ASSERT_FALSE(result);
-    EXPECT_EQ(Join(expected_words, " "), result.error_string());
-    EXPECT_EQ(first_pid, subcontext.pid());
+        EXPECT_TRUE(WaitForProperty("init.test.subcontext", "success", 10s));
+    });
+}
+
+TEST(subcontext, MultipleCommands) {
+    RunTest([](auto& subcontext, auto& context_string) {
+        auto first_pid = subcontext.pid();
+
+        auto expected_words = std::vector<std::string>{
+            "this",
+            "is",
+            "a",
+            "test",
+        };
+
+        for (const auto& word : expected_words) {
+            auto args = std::vector<std::string>{
+                "add_word",
+                word,
+            };
+            auto result = subcontext.Execute(args);
+            ASSERT_TRUE(result) << result.error();
+        }
+
+        auto result = subcontext.Execute(std::vector<std::string>{"return_words_as_error"});
+        ASSERT_FALSE(result);
+        EXPECT_EQ(Join(expected_words, " "), result.error_string());
+        EXPECT_EQ(first_pid, subcontext.pid());
+    });
 }
 
 TEST(subcontext, RecoverAfterAbort) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
+    RunTest([](auto& subcontext, auto& context_string) {
+        auto first_pid = subcontext.pid();
 
-    auto first_pid = subcontext.pid();
+        auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
+        ASSERT_FALSE(result);
 
-    auto result = subcontext.Execute(std::vector<std::string>{"cause_log_fatal"});
-    ASSERT_FALSE(result);
-
-    auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
-    ASSERT_FALSE(result2);
-    EXPECT_EQ("Sane error!", result2.error_string());
-    EXPECT_NE(subcontext.pid(), first_pid);
+        auto result2 = subcontext.Execute(std::vector<std::string>{"generate_sane_error"});
+        ASSERT_FALSE(result2);
+        EXPECT_EQ("Sane error!", result2.error_string());
+        EXPECT_NE(subcontext.pid(), first_pid);
+    });
 }
 
 TEST(subcontext, ContextString) {
-    auto subcontext = Subcontext("path", kVendorContext);
-    auto subcontext_killer = SubcontextKiller(subcontext);
-
-    auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
-    ASSERT_FALSE(result);
-    ASSERT_EQ(kVendorContext, result.error_string());
+    RunTest([](auto& subcontext, auto& context_string) {
+        auto result = subcontext.Execute(std::vector<std::string>{"return_context_as_error"});
+        ASSERT_FALSE(result);
+        ASSERT_EQ(context_string, result.error_string());
+    });
 }
 
 TestFunctionMap BuildTestFunctionMap() {
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 81f5e32..afe518c 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <assert.h>
 #include <inttypes.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -30,9 +31,10 @@
 #include <demangle.h>
 
 #include "BacktraceLog.h"
-#include "thread_utils.h"
 #include "UnwindCurrent.h"
 #include "UnwindPtrace.h"
+#include "UnwindStack.h"
+#include "thread_utils.h"
 
 using android::base::StringPrintf;
 
@@ -140,6 +142,34 @@
   }
 }
 
+Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
+  if (pid == BACKTRACE_CURRENT_PROCESS) {
+    pid = getpid();
+    if (tid == BACKTRACE_CURRENT_THREAD) {
+      tid = gettid();
+    }
+  } else if (tid == BACKTRACE_CURRENT_THREAD) {
+    tid = pid;
+  }
+
+  if (map == nullptr) {
+// This would cause the wrong type of map object to be created, so disallow.
+#if defined(__ANDROID__)
+    __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
+              "Backtrace::CreateNew() must be called with a real map pointer.");
+#else
+    BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
+    abort();
+#endif
+  }
+
+  if (pid == getpid()) {
+    return new UnwindStackCurrent(pid, tid, map);
+  } else {
+    return new UnwindStackPtrace(pid, tid, map);
+  }
+}
+
 std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
   switch (error) {
   case BACKTRACE_UNWIND_NO_ERROR:
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index dcd3d09..4c0c1a8 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -15,7 +15,6 @@
  */
 
 #define _GNU_SOURCE 1
-#include <assert.h>
 #include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
@@ -71,7 +70,7 @@
     back_frame->pc = frame->pc;
     back_frame->sp = frame->sp;
 
-    back_frame->func_name = frame->function_name;
+    back_frame->func_name = demangle(frame->function_name.c_str());
     back_frame->func_offset = frame->function_offset;
 
     back_frame->map.name = frame->map_name;
@@ -127,31 +126,3 @@
   error_ = BACKTRACE_UNWIND_NO_ERROR;
   return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames);
 }
-
-Backtrace* Backtrace::CreateNew(pid_t pid, pid_t tid, BacktraceMap* map) {
-  if (pid == BACKTRACE_CURRENT_PROCESS) {
-    pid = getpid();
-    if (tid == BACKTRACE_CURRENT_THREAD) {
-      tid = gettid();
-    }
-  } else if (tid == BACKTRACE_CURRENT_THREAD) {
-    tid = pid;
-  }
-
-  if (map == nullptr) {
-// This would cause the wrong type of map object to be created, so disallow.
-#if defined(__ANDROID__)
-    __assert2(__FILE__, __LINE__, __PRETTY_FUNCTION__,
-              "Backtrace::CreateNew() must be called with a real map pointer.");
-#else
-    BACK_LOGE("Backtrace::CreateNew() must be called with a real map pointer.");
-    abort();
-#endif
-  }
-
-  if (pid == getpid()) {
-    return new UnwindStackCurrent(pid, tid, map);
-  } else {
-    return new UnwindStackPtrace(pid, tid, map);
-  }
-}
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 036f8c5..4bae39e 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -35,7 +35,9 @@
 #ifndef __ANDROID__
 pid_t gettid() {
 #if defined(__APPLE__)
-  return syscall(SYS_thread_selfid);
+  uint64_t tid;
+  pthread_threadid_np(NULL, &tid);
+  return tid;
 #elif defined(__linux__)
   return syscall(__NR_gettid);
 #elif defined(_WIN32)
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index dc6591d..edf7ac2 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -35,7 +35,8 @@
 
 namespace unwindstack {
 
-bool Elf::Init() {
+bool Elf::Init(bool init_gnu_debugdata) {
+  load_bias_ = 0;
   if (!memory_) {
     return false;
   }
@@ -45,9 +46,14 @@
     return false;
   }
 
-  valid_ = interface_->Init();
+  valid_ = interface_->Init(&load_bias_);
   if (valid_) {
     interface_->InitHeaders();
+    if (init_gnu_debugdata) {
+      InitGnuDebugdata();
+    } else {
+      gnu_debugdata_interface_.reset(nullptr);
+    }
   } else {
     interface_.reset(nullptr);
   }
@@ -67,7 +73,11 @@
   if (gnu == nullptr) {
     return;
   }
-  if (gnu->Init()) {
+
+  // Ignore the load_bias from the compressed section, the correct load bias
+  // is in the uncompressed data.
+  uint64_t load_bias;
+  if (gnu->Init(&load_bias)) {
     gnu->InitHeaders();
   } else {
     // Free all of the memory associated with the gnu_debugdata section.
@@ -81,38 +91,39 @@
 }
 
 uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
-  uint64_t load_bias = 0;
-  if (valid()) {
-    load_bias = interface_->load_bias();
-  }
-
-  return pc - map_info->start + load_bias + map_info->elf_offset;
+  return pc - map_info->start + load_bias_ + map_info->elf_offset;
 }
 
 bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
-  return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
-                    (gnu_debugdata_interface_ &&
-                     gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
+  return valid_ && (interface_->GetFunctionName(addr, load_bias_, name, func_offset) ||
+                    (gnu_debugdata_interface_ && gnu_debugdata_interface_->GetFunctionName(
+                                                     addr, load_bias_, name, func_offset)));
 }
 
-bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
+// The relative pc is always relative to the start of the map from which it comes.
+bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
+               bool* finished) {
   if (!valid_) {
     return false;
   }
-  if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
+
+  // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
+  if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
     *finished = false;
     return true;
   }
+
+  // Adjust the load bias to get the real relative pc.
+  if (rel_pc < load_bias_) {
+    return false;
+  }
+  rel_pc -= load_bias_;
+
   return interface_->Step(rel_pc, regs, process_memory, finished) ||
          (gnu_debugdata_interface_ &&
           gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
 }
 
-uint64_t Elf::GetLoadBias() {
-  if (!valid_) return 0;
-  return interface_->load_bias();
-}
-
 bool Elf::IsValidElf(Memory* memory) {
   if (memory == nullptr) {
     return false;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 46a3f3f..20cc1b0 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -118,13 +118,13 @@
 }
 
 template <typename EhdrType, typename PhdrType, typename ShdrType>
-bool ElfInterface::ReadAllHeaders() {
+bool ElfInterface::ReadAllHeaders(uint64_t* load_bias) {
   EhdrType ehdr;
   if (!memory_->Read(0, &ehdr, sizeof(ehdr))) {
     return false;
   }
 
-  if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr)) {
+  if (!ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias)) {
     return false;
   }
 
@@ -137,7 +137,7 @@
 }
 
 template <typename EhdrType, typename PhdrType>
-bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr) {
+bool ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias) {
   uint64_t offset = ehdr.e_phoff;
   for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
     PhdrType phdr;
@@ -145,7 +145,7 @@
       return false;
     }
 
-    if (HandleType(offset, phdr.p_type)) {
+    if (HandleType(offset, phdr.p_type, *load_bias)) {
       continue;
     }
 
@@ -172,7 +172,7 @@
       pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
                                           static_cast<size_t>(phdr.p_memsz)};
       if (phdr.p_offset == 0) {
-        load_bias_ = phdr.p_vaddr;
+        *load_bias = phdr.p_vaddr;
       }
       break;
     }
@@ -334,14 +334,14 @@
 }
 
 template <typename SymType>
-bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
+bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
                                                uint64_t* func_offset) {
   if (symbols_.empty()) {
     return false;
   }
 
   for (const auto symbol : symbols_) {
-    if (symbol->GetName<SymType>(addr, load_bias_, memory_, name, func_offset)) {
+    if (symbol->GetName<SymType>(addr, load_bias, memory_, name, func_offset)) {
       return true;
     }
   }
@@ -349,12 +349,6 @@
 }
 
 bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
-  // Need to subtract off the load_bias to get the correct pc.
-  if (pc < load_bias_) {
-    return false;
-  }
-  pc -= load_bias_;
-
   // Try the eh_frame first.
   DwarfSection* eh_frame = eh_frame_.get();
   if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
@@ -389,11 +383,11 @@
 template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
 template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
 
-template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
-template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(uint64_t*);
+template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(uint64_t*);
 
-template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&);
-template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&);
+template bool ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, uint64_t*);
+template bool ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, uint64_t*);
 
 template bool ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
 template bool ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
@@ -401,9 +395,9 @@
 template bool ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(std::string*);
 template bool ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(std::string*);
 
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, uint64_t, std::string*,
                                                                    uint64_t*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
+template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, uint64_t, std::string*,
                                                                    uint64_t*);
 
 template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 17364d0..30a1532 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -31,12 +31,6 @@
     return false;
   }
 
-  // Need to subtract the load_bias from the pc.
-  if (pc < load_bias_) {
-    return false;
-  }
-  pc -= load_bias_;
-
   size_t first = 0;
   size_t last = total_entries_;
   while (first < last) {
@@ -81,7 +75,7 @@
 #define PT_ARM_EXIDX 0x70000001
 #endif
 
-bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type) {
+bool ElfInterfaceArm::HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) {
   if (type != PT_ARM_EXIDX) {
     return false;
   }
@@ -93,8 +87,7 @@
   if (!memory_->ReadField(offset, &phdr, &phdr.p_memsz, sizeof(phdr.p_memsz))) {
     return true;
   }
-  // The load_bias_ should always be set by this time.
-  start_offset_ = phdr.p_vaddr - load_bias_;
+  start_offset_ = phdr.p_vaddr - load_bias;
   total_entries_ = phdr.p_memsz / 8;
   return true;
 }
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
index bfe7704..eeb2e17 100644
--- a/libunwindstack/ElfInterfaceArm.h
+++ b/libunwindstack/ElfInterfaceArm.h
@@ -68,7 +68,7 @@
 
   bool FindEntry(uint32_t pc, uint64_t* entry_offset);
 
-  bool HandleType(uint64_t offset, uint32_t type) override;
+  bool HandleType(uint64_t offset, uint32_t type, uint64_t load_bias) override;
 
   bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
 
@@ -76,13 +76,9 @@
 
   uint64_t start_offset() { return start_offset_; }
 
-  void set_start_offset(uint64_t start_offset) { start_offset_ = start_offset; }
-
   size_t total_entries() { return total_entries_; }
 
-  void set_total_entries(size_t total_entries) { total_entries_ = total_entries; }
-
- private:
+ protected:
   uint64_t start_offset_ = 0;
   size_t total_entries_ = 0;
 
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 96f2cb4..140d05a 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -110,9 +110,8 @@
   }
 
   elf = new Elf(CreateMemory(process_memory));
-  if (elf->Init() && init_gnu_debugdata) {
-    elf->InitGnuDebugdata();
-  }
+  elf->Init(init_gnu_debugdata);
+
   // If the init fails, keep the elf around as an invalid object so we
   // don't try to reinit the object.
   return elf;
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index bf27d21..36b8e25 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -45,7 +45,7 @@
     return rel_pc;
   }
 
-  uint64_t load_bias = elf->interface()->load_bias();
+  uint64_t load_bias = elf->GetLoadBias();
   if (rel_pc < load_bias) {
     return rel_pc;
   }
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 15a8893..f1580a4 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -64,7 +64,19 @@
   }
 }
 
-void Unwinder::Unwind(std::set<std::string>* initial_map_names_to_skip) {
+static bool ShouldStop(const std::set<std::string>* map_suffixes_to_ignore, std::string& map_name) {
+  if (map_suffixes_to_ignore == nullptr) {
+    return false;
+  }
+  auto pos = map_name.find_last_of('.');
+  if (pos == std::string::npos) {
+    return false;
+  }
+  return map_suffixes_to_ignore->find(map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
+}
+
+void Unwinder::Unwind(const std::set<std::string>* initial_map_names_to_skip,
+                      const std::set<std::string>* map_suffixes_to_ignore) {
   frames_.clear();
 
   bool return_address_attempt = false;
@@ -77,6 +89,9 @@
     if (map_info == nullptr) {
       rel_pc = regs_->pc();
     } else {
+      if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
+        break;
+      }
       elf = map_info->GetElf(process_memory_, true);
       rel_pc = elf->GetRelPc(regs_->pc(), map_info);
     }
@@ -111,8 +126,7 @@
           in_device_map = true;
         } else {
           bool finished;
-          stepped =
-              elf->Step(rel_pc + map_info->elf_offset, regs_, process_memory_.get(), &finished);
+          stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
           if (stepped && finished) {
             break;
           }
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index f246beb..294d742 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -40,7 +40,7 @@
   Elf(Memory* memory) : memory_(memory) {}
   virtual ~Elf() = default;
 
-  bool Init();
+  bool Init(bool init_gnu_debugdata);
 
   void InitGnuDebugdata();
 
@@ -50,11 +50,12 @@
 
   uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
 
-  bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
+  bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
+            bool* finished);
 
   ElfInterface* CreateInterfaceFromMemory(Memory* memory);
 
-  uint64_t GetLoadBias();
+  uint64_t GetLoadBias() { return load_bias_; }
 
   bool valid() { return valid_; }
 
@@ -74,6 +75,7 @@
 
  protected:
   bool valid_ = false;
+  uint64_t load_bias_ = 0;
   std::unique_ptr<ElfInterface> interface_;
   std::unique_ptr<Memory> memory_;
   uint32_t machine_type_;
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 4fe966f..319623d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -51,13 +51,14 @@
   ElfInterface(Memory* memory) : memory_(memory) {}
   virtual ~ElfInterface();
 
-  virtual bool Init() = 0;
+  virtual bool Init(uint64_t* load_bias) = 0;
 
   virtual void InitHeaders() = 0;
 
   virtual bool GetSoname(std::string* name) = 0;
 
-  virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
+  virtual bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+                               uint64_t* offset) = 0;
 
   virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
 
@@ -66,8 +67,6 @@
   Memory* memory() { return memory_; }
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; }
-  uint64_t load_bias() { return load_bias_; }
-  void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
 
   uint64_t dynamic_offset() { return dynamic_offset_; }
   uint64_t dynamic_size() { return dynamic_size_; }
@@ -86,10 +85,10 @@
   void InitHeadersWithTemplate();
 
   template <typename EhdrType, typename PhdrType, typename ShdrType>
-  bool ReadAllHeaders();
+  bool ReadAllHeaders(uint64_t* load_bias);
 
   template <typename EhdrType, typename PhdrType>
-  bool ReadProgramHeaders(const EhdrType& ehdr);
+  bool ReadProgramHeaders(const EhdrType& ehdr, uint64_t* load_bias);
 
   template <typename EhdrType, typename ShdrType>
   bool ReadSectionHeaders(const EhdrType& ehdr);
@@ -98,16 +97,16 @@
   bool GetSonameWithTemplate(std::string* soname);
 
   template <typename SymType>
-  bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
+  bool GetFunctionNameWithTemplate(uint64_t addr, uint64_t load_bias, std::string* name,
+                                   uint64_t* func_offset);
 
-  virtual bool HandleType(uint64_t, uint32_t) { return false; }
+  virtual bool HandleType(uint64_t, uint32_t, uint64_t) { return false; }
 
   template <typename EhdrType>
   static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
 
   Memory* memory_;
   std::unordered_map<uint64_t, LoadInfo> pt_loads_;
-  uint64_t load_bias_ = 0;
 
   // Stored elf data.
   uint64_t dynamic_offset_ = 0;
@@ -136,8 +135,8 @@
   ElfInterface32(Memory* memory) : ElfInterface(memory) {}
   virtual ~ElfInterface32() = default;
 
-  bool Init() override {
-    return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>();
+  bool Init(uint64_t* load_bias) override {
+    return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
   }
 
   void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
@@ -146,8 +145,9 @@
     return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname);
   }
 
-  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
-    return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
+  bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+                       uint64_t* func_offset) override {
+    return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, load_bias, name, func_offset);
   }
 
   static void GetMaxSize(Memory* memory, uint64_t* size) {
@@ -160,8 +160,8 @@
   ElfInterface64(Memory* memory) : ElfInterface(memory) {}
   virtual ~ElfInterface64() = default;
 
-  bool Init() override {
-    return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>();
+  bool Init(uint64_t* load_bias) override {
+    return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
   }
 
   void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
@@ -170,8 +170,9 @@
     return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname);
   }
 
-  bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
-    return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
+  bool GetFunctionName(uint64_t addr, uint64_t load_bias, std::string* name,
+                       uint64_t* func_offset) override {
+    return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, load_bias, name, func_offset);
   }
 
   static void GetMaxSize(Memory* memory, uint64_t* size) {
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index 71703b4..ca5933d 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -60,7 +60,8 @@
   }
   ~Unwinder() = default;
 
-  void Unwind(std::set<std::string>* initial_map_names_to_skip = nullptr);
+  void Unwind(const std::set<std::string>* initial_map_names_to_skip = nullptr,
+              const std::set<std::string>* map_suffixes_to_ignore = nullptr);
 
   size_t NumFrames() { return frames_.size(); }
 
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
index 71f7f6b..b94a8a4 100644
--- a/libunwindstack/tests/ElfFake.cpp
+++ b/libunwindstack/tests/ElfFake.cpp
@@ -32,7 +32,7 @@
 std::deque<FunctionData> ElfInterfaceFake::functions_;
 std::deque<StepData> ElfInterfaceFake::steps_;
 
-bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
+bool ElfInterfaceFake::GetFunctionName(uint64_t, uint64_t, std::string* name, uint64_t* offset) {
   if (functions_.empty()) {
     return false;
   }
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index 4359bca..565b13f 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -27,6 +27,8 @@
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
 
+#include "ElfInterfaceArm.h"
+
 namespace unwindstack {
 
 struct StepData {
@@ -48,6 +50,10 @@
   ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
   virtual ~ElfFake() = default;
 
+  void FakeSetValid(bool valid) { valid_ = valid; }
+
+  void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
+
   void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
 };
 
@@ -56,15 +62,14 @@
   ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
   virtual ~ElfInterfaceFake() = default;
 
-  bool Init() override { return false; }
+  bool Init(uint64_t*) override { return false; }
   void InitHeaders() override {}
   bool GetSoname(std::string*) override { return false; }
 
-  bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
+  bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override;
 
   bool Step(uint64_t, Regs*, Memory*, bool*) override;
 
-  void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
 
   static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
   static void FakePushStepData(const StepData data) { steps_.push_back(data); }
@@ -79,6 +84,37 @@
   static std::deque<StepData> steps_;
 };
 
+class ElfInterface32Fake : public ElfInterface32 {
+ public:
+  ElfInterface32Fake(Memory* memory) : ElfInterface32(memory) {}
+  virtual ~ElfInterface32Fake() = default;
+
+  void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+  void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+  void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+  void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterface64Fake : public ElfInterface64 {
+ public:
+  ElfInterface64Fake(Memory* memory) : ElfInterface64(memory) {}
+  virtual ~ElfInterface64Fake() = default;
+
+  void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
+  void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
+  void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
+  void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
+};
+
+class ElfInterfaceArmFake : public ElfInterfaceArm {
+ public:
+  ElfInterfaceArmFake(Memory* memory) : ElfInterfaceArm(memory) {}
+  virtual ~ElfInterfaceArmFake() = default;
+
+  void FakeSetStartOffset(uint64_t offset) { start_offset_ = offset; }
+  void FakeSetTotalEntries(size_t entries) { total_entries_ = entries; }
+};
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 4df7e1c..feb24ce 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -25,6 +25,7 @@
 #include "ElfInterfaceArm.h"
 #include "Machine.h"
 
+#include "ElfFake.h"
 #include "MemoryFake.h"
 
 namespace unwindstack {
@@ -41,7 +42,7 @@
 };
 
 TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
   memory_.SetData32(0x1000, 0x230000);
 
   uint32_t value;
@@ -58,36 +59,36 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_start_zero) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0);
-  interface.set_total_entries(10);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0);
+  interface.FakeSetTotalEntries(10);
 
   uint64_t entry_offset;
   ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_no_entries) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x100);
-  interface.set_total_entries(0);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x100);
+  interface.FakeSetTotalEntries(0);
 
   uint64_t entry_offset;
   ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_no_valid_memory) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x100);
-  interface.set_total_entries(2);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x100);
+  interface.FakeSetTotalEntries(2);
 
   uint64_t entry_offset;
   ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(1);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(1);
   memory_.SetData32(0x1000, 0x6000);
 
   uint64_t entry_offset;
@@ -95,9 +96,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x8000);
-  interface.set_total_entries(1);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x8000);
+  interface.FakeSetTotalEntries(1);
   memory_.SetData32(0x8000, 0x7fffff00);
 
   uint64_t entry_offset;
@@ -106,9 +107,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(2);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(2);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1008, 0x7000);
 
@@ -117,11 +118,10 @@
   ASSERT_EQ(0x1000U, entry_offset);
 }
 
-
 TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(1);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(1);
   memory_.SetData32(0x1000, 0x6000);
 
   uint64_t entry_offset;
@@ -136,9 +136,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(2);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(2);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1008, 0x8000);
 
@@ -155,9 +155,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(4);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(4);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1008, 0x7000);
   memory_.SetData32(0x1010, 0x8000);
@@ -178,9 +178,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(5);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(5);
   memory_.SetData32(0x1000, 0x5000);
   memory_.SetData32(0x1008, 0x6000);
   memory_.SetData32(0x1010, 0x7000);
@@ -203,9 +203,9 @@
 }
 
 TEST_F(ElfInterfaceArmTest, iterate) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(5);
+  ElfInterfaceArmFake interface(&memory_);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(5);
   memory_.SetData32(0x1000, 0x5000);
   memory_.SetData32(0x1008, 0x6000);
   memory_.SetData32(0x1010, 0x7000);
@@ -242,56 +242,36 @@
   ASSERT_EQ(0xa020U, entries[4]);
 }
 
-TEST_F(ElfInterfaceArmTest, FindEntry_load_bias) {
-  ElfInterfaceArm interface(&memory_);
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(2);
-  memory_.SetData32(0x1000, 0x6000);
-  memory_.SetData32(0x1008, 0x8000);
-
-  uint64_t entry_offset;
-  interface.set_load_bias(0x2000);
-  ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
-  ASSERT_FALSE(interface.FindEntry(0x8000, &entry_offset));
-  ASSERT_FALSE(interface.FindEntry(0x8fff, &entry_offset));
-  ASSERT_TRUE(interface.FindEntry(0x9000, &entry_offset));
-  ASSERT_EQ(0x1000U, entry_offset);
-  ASSERT_TRUE(interface.FindEntry(0xb007, &entry_offset));
-  ASSERT_EQ(0x1000U, entry_offset);
-  ASSERT_TRUE(interface.FindEntry(0xb008, &entry_offset));
-  ASSERT_EQ(0x1008U, entry_offset);
-}
-
 TEST_F(ElfInterfaceArmTest, HandleType_not_arm_exidx) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME));
-  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_NULL, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOAD, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_DYNAMIC, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_INTERP, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_NOTE, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_SHLIB, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_PHDR, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_TLS, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOOS, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIOS, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_LOPROC, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_HIPROC, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_EH_FRAME, 0));
+  ASSERT_FALSE(interface.HandleType(0x1000, PT_GNU_STACK, 0));
 }
 
 TEST_F(ElfInterfaceArmTest, HandleType_arm_exidx) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
   Elf32_Phdr phdr;
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(100);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(100);
   phdr.p_vaddr = 0x2000;
   phdr.p_memsz = 0xa00;
 
   // Verify that if reads fail, we don't set the values but still get true.
-  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
   ASSERT_EQ(0x1000U, interface.start_offset());
   ASSERT_EQ(100U, interface.total_entries());
 
@@ -299,7 +279,7 @@
   memory_.SetData32(
       0x1000 + reinterpret_cast<uint64_t>(&phdr.p_vaddr) - reinterpret_cast<uint64_t>(&phdr),
       phdr.p_vaddr);
-  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
   ASSERT_EQ(0x1000U, interface.start_offset());
   ASSERT_EQ(100U, interface.total_entries());
 
@@ -307,27 +287,26 @@
   memory_.SetData32(
       0x1000 + reinterpret_cast<uint64_t>(&phdr.p_memsz) - reinterpret_cast<uint64_t>(&phdr),
       phdr.p_memsz);
-  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0));
   ASSERT_EQ(0x2000U, interface.start_offset());
   ASSERT_EQ(320U, interface.total_entries());
 
   // Non-zero load bias.
-  interface.set_load_bias(0x1000);
-  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001));
+  ASSERT_TRUE(interface.HandleType(0x1000, 0x70000001, 0x1000));
   ASSERT_EQ(0x1000U, interface.start_offset());
   ASSERT_EQ(320U, interface.total_entries());
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
   // FindEntry fails.
   bool finished;
   ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
 
   // ExtractEntry should fail.
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(2);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(2);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1008, 0x8000);
 
@@ -353,10 +332,10 @@
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(2);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(2);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1004, 0x808800b0);
   memory_.SetData32(0x1008, 0x8000);
@@ -379,10 +358,10 @@
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(1);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(1);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1004, 1);
 
@@ -401,10 +380,10 @@
 }
 
 TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
-  ElfInterfaceArm interface(&memory_);
+  ElfInterfaceArmFake interface(&memory_);
 
-  interface.set_start_offset(0x1000);
-  interface.set_total_entries(1);
+  interface.FakeSetStartOffset(0x1000);
+  interface.FakeSetTotalEntries(1);
   memory_.SetData32(0x1000, 0x6000);
   memory_.SetData32(0x1004, 0x808000b0);
 
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index acb7320..2752e99 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -25,6 +25,7 @@
 #include "DwarfEncoding.h"
 #include "ElfInterfaceArm.h"
 
+#include "ElfFake.h"
 #include "MemoryFake.h"
 
 #if !defined(PT_ARM_EXIDX)
@@ -134,7 +135,9 @@
   phdr.p_align = 0x1000;
   memory_.SetMemory(0x100, &phdr, sizeof(phdr));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0x2000U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(1U, pt_loads.size());
@@ -190,7 +193,9 @@
   phdr.p_align = 0x1002;
   memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0x2000U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(3U, pt_loads.size());
@@ -257,7 +262,9 @@
   phdr.p_align = 0x1002;
   memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0x2000U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(3U, pt_loads.size());
@@ -326,7 +333,9 @@
   phdr.p_align = 0x1002;
   memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(1U, pt_loads.size());
@@ -398,7 +407,9 @@
   memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
   phdr_offset += sizeof(phdr);
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0x2000U, load_bias);
 
   const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
   ASSERT_EQ(1U, pt_loads.size());
@@ -438,7 +449,9 @@
   memory_.SetData32(0x2000, 0x1000);
   memory_.SetData32(0x2008, 0x1000);
 
-  ASSERT_TRUE(elf_arm.Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf_arm.Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
 
   std::vector<uint32_t> entries;
   for (auto addr : elf_arm) {
@@ -493,7 +506,10 @@
 
   SetStringMemory(0x10010, "fake_soname.so");
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+
   std::string name;
   ASSERT_TRUE(elf->GetSoname(&name));
   ASSERT_STREQ("fake_soname.so", name.c_str());
@@ -549,7 +565,10 @@
 
   SetStringMemory(0x10010, "fake_soname.so");
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+
   std::string name;
   ASSERT_FALSE(elf->GetSoname(&name));
 }
@@ -603,7 +622,10 @@
 
   SetStringMemory(0x10010, "fake_soname.so");
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
+
   std::string name;
   ASSERT_FALSE(elf->GetSoname(&name));
 }
@@ -616,38 +638,14 @@
   SonameSize<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
 }
 
-class MockElfInterface32 : public ElfInterface32 {
- public:
-  MockElfInterface32(Memory* memory) : ElfInterface32(memory) {}
-  virtual ~MockElfInterface32() = default;
-
-  void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
-  void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
-  void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
-  void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
-class MockElfInterface64 : public ElfInterface64 {
- public:
-  MockElfInterface64(Memory* memory) : ElfInterface64(memory) {}
-  virtual ~MockElfInterface64() = default;
-
-  void TestSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
-  void TestSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
-
-  void TestSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
-  void TestSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
 template <typename ElfType>
 void ElfInterfaceTest::InitHeadersEhFrameTest() {
   ElfType elf(&memory_);
 
-  elf.TestSetEhFrameOffset(0x10000);
-  elf.TestSetEhFrameSize(0);
-  elf.TestSetDebugFrameOffset(0);
-  elf.TestSetDebugFrameSize(0);
+  elf.FakeSetEhFrameOffset(0x10000);
+  elf.FakeSetEhFrameSize(0);
+  elf.FakeSetDebugFrameOffset(0);
+  elf.FakeSetDebugFrameSize(0);
 
   memory_.SetMemory(0x10000,
                     std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata2, DW_EH_PE_udata2});
@@ -661,21 +659,21 @@
 }
 
 TEST_F(ElfInterfaceTest, init_headers_eh_frame32) {
-  InitHeadersEhFrameTest<MockElfInterface32>();
+  InitHeadersEhFrameTest<ElfInterface32Fake>();
 }
 
 TEST_F(ElfInterfaceTest, init_headers_eh_frame64) {
-  InitHeadersEhFrameTest<MockElfInterface64>();
+  InitHeadersEhFrameTest<ElfInterface64Fake>();
 }
 
 template <typename ElfType>
 void ElfInterfaceTest::InitHeadersDebugFrame() {
   ElfType elf(&memory_);
 
-  elf.TestSetEhFrameOffset(0);
-  elf.TestSetEhFrameSize(0);
-  elf.TestSetDebugFrameOffset(0x5000);
-  elf.TestSetDebugFrameSize(0x200);
+  elf.FakeSetEhFrameOffset(0);
+  elf.FakeSetEhFrameSize(0);
+  elf.FakeSetDebugFrameOffset(0x5000);
+  elf.FakeSetDebugFrameSize(0x200);
 
   memory_.SetData32(0x5000, 0xfc);
   memory_.SetData32(0x5004, 0xffffffff);
@@ -694,21 +692,21 @@
 }
 
 TEST_F(ElfInterfaceTest, init_headers_debug_frame32) {
-  InitHeadersDebugFrame<MockElfInterface32>();
+  InitHeadersDebugFrame<ElfInterface32Fake>();
 }
 
 TEST_F(ElfInterfaceTest, init_headers_debug_frame64) {
-  InitHeadersDebugFrame<MockElfInterface64>();
+  InitHeadersDebugFrame<ElfInterface64Fake>();
 }
 
 template <typename ElfType>
 void ElfInterfaceTest::InitHeadersEhFrameFail() {
   ElfType elf(&memory_);
 
-  elf.TestSetEhFrameOffset(0x1000);
-  elf.TestSetEhFrameSize(0x100);
-  elf.TestSetDebugFrameOffset(0);
-  elf.TestSetDebugFrameSize(0);
+  elf.FakeSetEhFrameOffset(0x1000);
+  elf.FakeSetEhFrameSize(0x100);
+  elf.FakeSetDebugFrameOffset(0);
+  elf.FakeSetDebugFrameSize(0);
 
   elf.InitHeaders();
 
@@ -719,21 +717,21 @@
 }
 
 TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
-  InitHeadersEhFrameFail<MockElfInterface32>();
+  InitHeadersEhFrameFail<ElfInterface32Fake>();
 }
 
 TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
-  InitHeadersEhFrameFail<MockElfInterface64>();
+  InitHeadersEhFrameFail<ElfInterface64Fake>();
 }
 
 template <typename ElfType>
 void ElfInterfaceTest::InitHeadersDebugFrameFail() {
   ElfType elf(&memory_);
 
-  elf.TestSetEhFrameOffset(0);
-  elf.TestSetEhFrameSize(0);
-  elf.TestSetDebugFrameOffset(0x1000);
-  elf.TestSetDebugFrameSize(0x100);
+  elf.FakeSetEhFrameOffset(0);
+  elf.FakeSetEhFrameSize(0);
+  elf.FakeSetDebugFrameOffset(0x1000);
+  elf.FakeSetDebugFrameSize(0x100);
 
   elf.InitHeaders();
 
@@ -744,11 +742,11 @@
 }
 
 TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
-  InitHeadersDebugFrameFail<MockElfInterface32>();
+  InitHeadersDebugFrameFail<ElfInterface32Fake>();
 }
 
 TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
-  InitHeadersDebugFrameFail<MockElfInterface64>();
+  InitHeadersDebugFrameFail<ElfInterface64Fake>();
 }
 
 template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
@@ -762,7 +760,9 @@
   ehdr.e_shentsize = sizeof(Shdr);
   memory_.SetMemory(0, &ehdr, sizeof(ehdr));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
 }
 
 TEST_F(ElfInterfaceTest, init_section_headers_malformed32) {
@@ -827,7 +827,9 @@
   InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
   InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
   EXPECT_EQ(0U, elf->debug_frame_offset());
   EXPECT_EQ(0U, elf->debug_frame_size());
   EXPECT_EQ(0U, elf->gnu_debugdata_offset());
@@ -836,10 +838,10 @@
   // Look in the first symbol table.
   std::string name;
   uint64_t name_offset;
-  ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
+  ASSERT_TRUE(elf->GetFunctionName(0x90010, 0, &name, &name_offset));
   EXPECT_EQ("function_one", name);
   EXPECT_EQ(16U, name_offset);
-  ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
+  ASSERT_TRUE(elf->GetFunctionName(0xd0020, 0, &name, &name_offset));
   EXPECT_EQ("function_two", name);
   EXPECT_EQ(32U, name_offset);
 }
@@ -911,7 +913,9 @@
   memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
   memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
 
-  ASSERT_TRUE(elf->Init());
+  uint64_t load_bias = 0;
+  ASSERT_TRUE(elf->Init(&load_bias));
+  EXPECT_EQ(0U, load_bias);
   EXPECT_EQ(0x6000U, elf->debug_frame_offset());
   EXPECT_EQ(0x500U, elf->debug_frame_size());
   EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 42a0246..4e48fa1 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -20,11 +20,13 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <unwindstack/Elf.h>
 #include <unwindstack/MapInfo.h>
 
+#include "ElfFake.h"
 #include "ElfTestUtils.h"
 #include "LogFake.h"
 #include "MemoryFake.h"
@@ -107,7 +109,7 @@
 TEST_F(ElfTest, invalid_memory) {
   Elf elf(memory_);
 
-  ASSERT_FALSE(elf.Init());
+  ASSERT_FALSE(elf.Init(false));
   ASSERT_FALSE(elf.valid());
 }
 
@@ -119,7 +121,7 @@
   // Corrupt the ELF signature.
   memory_->SetData32(0, 0x7f000000);
 
-  ASSERT_FALSE(elf.Init());
+  ASSERT_FALSE(elf.Init(false));
   ASSERT_FALSE(elf.valid());
   ASSERT_TRUE(elf.interface() == nullptr);
 
@@ -130,7 +132,7 @@
   ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
 
   bool finished;
-  ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
+  ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
 }
 
 TEST_F(ElfTest, elf32_invalid_machine) {
@@ -139,7 +141,7 @@
   InitElf32(EM_PPC);
 
   ResetLogs();
-  ASSERT_FALSE(elf.Init());
+  ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
   ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86: e_machine = 20\n\n",
@@ -152,7 +154,7 @@
   InitElf64(EM_PPC64);
 
   ResetLogs();
-  ASSERT_FALSE(elf.Init());
+  ASSERT_FALSE(elf.Init(false));
 
   ASSERT_EQ("", GetFakeLogBuf());
   ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64: e_machine = 21\n\n",
@@ -164,7 +166,7 @@
 
   InitElf32(EM_ARM);
 
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.valid());
   ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
   ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -176,7 +178,7 @@
 
   InitElf32(EM_386);
 
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.valid());
   ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
   ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -188,7 +190,7 @@
 
   InitElf64(EM_AARCH64);
 
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.valid());
   ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
   ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -200,7 +202,7 @@
 
   InitElf64(EM_X86_64);
 
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.valid());
   ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
   ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -214,7 +216,7 @@
                                                });
 
   Elf elf(memory_);
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.interface() != nullptr);
   ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
   EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
@@ -228,7 +230,7 @@
                                                });
 
   Elf elf(memory_);
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(false));
   ASSERT_TRUE(elf.interface() != nullptr);
   ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
   EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
@@ -242,14 +244,11 @@
                                                });
 
   Elf elf(memory_);
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(true));
   ASSERT_TRUE(elf.interface() != nullptr);
-  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
   EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
   EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
-
-  elf.InitGnuDebugdata();
-  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
 }
 
 TEST_F(ElfTest, gnu_debugdata_init64) {
@@ -259,42 +258,109 @@
                                                });
 
   Elf elf(memory_);
-  ASSERT_TRUE(elf.Init());
+  ASSERT_TRUE(elf.Init(true));
   ASSERT_TRUE(elf.interface() != nullptr);
-  ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
+  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
   EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
   EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
-
-  elf.InitGnuDebugdata();
-  ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
 }
 
-class MockElf : public Elf {
- public:
-  MockElf(Memory* memory) : Elf(memory) {}
-  virtual ~MockElf() = default;
-
-  void set_valid(bool valid) { valid_ = valid; }
-  void set_elf_interface(ElfInterface* interface) { interface_.reset(interface); }
-};
-
 TEST_F(ElfTest, rel_pc) {
-  MockElf elf(memory_);
+  ElfFake elf(memory_);
 
-  ElfInterface* interface = new ElfInterface32(memory_);
-  elf.set_elf_interface(interface);
+  ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+  elf.FakeSetInterface(interface);
 
-  elf.set_valid(true);
-  interface->set_load_bias(0);
+  elf.FakeSetValid(true);
+  elf.FakeSetLoadBias(0);
   MapInfo map_info{.start = 0x1000, .end = 0x2000};
 
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 
-  interface->set_load_bias(0x3000);
+  elf.FakeSetLoadBias(0x3000);
   ASSERT_EQ(0x3101U, elf.GetRelPc(0x1101, &map_info));
 
-  elf.set_valid(false);
+  elf.FakeSetValid(false);
+  elf.FakeSetLoadBias(0);
   ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
 }
 
+TEST_F(ElfTest, step_in_signal_map) {
+  ElfFake elf(memory_);
+
+  RegsArm regs;
+  regs[13] = 0x50000;
+  regs[15] = 0x8000;
+  regs.SetFromRaw();
+
+  ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
+  elf.FakeSetInterface(interface);
+
+  memory_->SetData32(0x3000, 0xdf0027ad);
+  MemoryFake process_memory;
+  process_memory.SetData32(0x50000, 0);
+  for (size_t i = 0; i < 16; i++) {
+    process_memory.SetData32(0x500a0 + i * sizeof(uint32_t), i);
+  }
+
+  elf.FakeSetValid(true);
+  elf.FakeSetLoadBias(0);
+  bool finished;
+  ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+  EXPECT_FALSE(finished);
+  EXPECT_EQ(15U, regs.pc());
+  EXPECT_EQ(13U, regs.sp());
+}
+
+class ElfInterfaceMock : public ElfInterface {
+ public:
+  ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
+  virtual ~ElfInterfaceMock() = default;
+
+  bool Init(uint64_t*) override { return false; }
+  void InitHeaders() override {}
+  bool GetSoname(std::string*) override { return false; }
+  bool GetFunctionName(uint64_t, uint64_t, std::string*, uint64_t*) override { return false; }
+  MOCK_METHOD4(Step, bool(uint64_t, Regs*, Memory*, bool*));
+};
+
+TEST_F(ElfTest, step_in_interface) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  elf.FakeSetLoadBias(0);
+
+  RegsArm regs;
+
+  ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+  elf.FakeSetInterface(interface);
+  MemoryFake process_memory;
+
+  bool finished;
+  EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished))
+      .WillOnce(::testing::Return(true));
+
+  ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+}
+
+TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
+  ElfFake elf(memory_);
+  elf.FakeSetValid(true);
+  elf.FakeSetLoadBias(0x4000);
+
+  RegsArm regs;
+
+  ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
+  elf.FakeSetInterface(interface);
+  MemoryFake process_memory;
+
+  // Invalid relative pc given load_bias.
+  bool finished;
+  ASSERT_FALSE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
+
+  EXPECT_CALL(*interface, Step(0x3300, &regs, &process_memory, &finished))
+      .WillOnce(::testing::Return(true));
+
+  ASSERT_TRUE(elf.Step(0x7300, 0x2000, &regs, &process_memory, &finished));
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
index 3b9f92b..2a02669 100644
--- a/libunwindstack/tests/RegsTest.cpp
+++ b/libunwindstack/tests/RegsTest.cpp
@@ -115,7 +115,7 @@
   RegsArm arm;
 
   // Check fence posts.
-  elf_interface_->FakeSetLoadBias(0);
+  elf_->FakeSetLoadBias(0);
   ASSERT_EQ(3U,  arm.GetAdjustedPc(0x5, elf_.get()));
   ASSERT_EQ(4U,  arm.GetAdjustedPc(0x4, elf_.get()));
   ASSERT_EQ(3U,  arm.GetAdjustedPc(0x3, elf_.get()));
@@ -123,7 +123,7 @@
   ASSERT_EQ(1U,  arm.GetAdjustedPc(0x1, elf_.get()));
   ASSERT_EQ(0U,  arm.GetAdjustedPc(0x0, elf_.get()));
 
-  elf_interface_->FakeSetLoadBias(0x100);
+  elf_->FakeSetLoadBias(0x100);
   ASSERT_EQ(0xffU,  arm.GetAdjustedPc(0xff, elf_.get()));
   ASSERT_EQ(0x103U,  arm.GetAdjustedPc(0x105, elf_.get()));
   ASSERT_EQ(0x104U,  arm.GetAdjustedPc(0x104, elf_.get()));
@@ -133,13 +133,13 @@
   ASSERT_EQ(0x100U,  arm.GetAdjustedPc(0x100, elf_.get()));
 
   // Check thumb instructions handling.
-  elf_interface_->FakeSetLoadBias(0);
+  elf_->FakeSetLoadBias(0);
   memory_->SetData32(0x2000, 0);
   ASSERT_EQ(0x2003U,  arm.GetAdjustedPc(0x2005, elf_.get()));
   memory_->SetData32(0x2000, 0xe000f000);
   ASSERT_EQ(0x2001U,  arm.GetAdjustedPc(0x2005, elf_.get()));
 
-  elf_interface_->FakeSetLoadBias(0x400);
+  elf_->FakeSetLoadBias(0x400);
   memory_->SetData32(0x2100, 0);
   ASSERT_EQ(0x2503U,  arm.GetAdjustedPc(0x2505, elf_.get()));
   memory_->SetData32(0x2100, 0xf111f111);
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 16640a1..8384473 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -96,6 +96,15 @@
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
 
+    info.name = "/fake/compressed.so";
+    info.start = 0x33000;
+    info.end = 0x34000;
+    info.flags = PROT_READ | PROT_WRITE;
+    elf = new ElfFake(nullptr);
+    info.elf = elf;
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    maps_.FakeAddMapInfo(info);
+
     info.name = "/fake/fake.apk";
     info.start = 0x43000;
     info.end = 0x44000;
@@ -105,6 +114,14 @@
     info.elf = elf;
     elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
     maps_.FakeAddMapInfo(info);
+
+    info.name = "/fake/fake.oat";
+    info.start = 0x53000;
+    info.end = 0x54000;
+    info.offset = 0;
+    info.flags = PROT_READ | PROT_WRITE;
+    info.elf = nullptr;
+    maps_.FakeAddMapInfo(info);
   }
 
   void SetUp() override {
@@ -345,7 +362,7 @@
   ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
 
   regs_.FakeSetPc(0x1000);
-  regs_.FakeSetSp(0x53000);
+  regs_.FakeSetSp(0x63000);
   ElfInterfaceFake::FakePushStepData(StepData(0x21002, 0x50020, false));
   ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
 
@@ -358,7 +375,7 @@
   EXPECT_EQ(0U, frame->num);
   EXPECT_EQ(0U, frame->rel_pc);
   EXPECT_EQ(0x1000U, frame->pc);
-  EXPECT_EQ(0x53000U, frame->sp);
+  EXPECT_EQ(0x63000U, frame->sp);
   EXPECT_EQ("Frame0", frame->function_name);
   EXPECT_EQ(0U, frame->function_offset);
   EXPECT_EQ("/system/fake/libc.so", frame->map_name);
@@ -540,6 +557,59 @@
   EXPECT_EQ(0, frame->map_flags);
 }
 
+// Verify that an unwind stops when a frame is in given suffix.
+TEST_F(UnwinderTest, map_ignore_suffixes) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
+
+  // Fake as if code called a nullptr function.
+  regs_.FakeSetPc(0x1000);
+  regs_.FakeSetSp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0x43402, 0x10010, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0x53502, 0x10020, false));
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, &maps_, &regs_, process_memory_);
+  std::set<std::string> suffixes{"oat"};
+  unwinder.Unwind(nullptr, &suffixes);
+
+  ASSERT_EQ(2U, unwinder.NumFrames());
+  // Make sure the elf was not initialized.
+  MapInfo* map_info = maps_.Find(0x53000);
+  ASSERT_TRUE(map_info != nullptr);
+  EXPECT_TRUE(map_info->elf == nullptr);
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0U, frame->rel_pc);
+  EXPECT_EQ(0x1000U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
+  EXPECT_EQ(0U, frame->map_offset);
+  EXPECT_EQ(0x1000U, frame->map_start);
+  EXPECT_EQ(0x8000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+
+  frame = &unwinder.frames()[1];
+  EXPECT_EQ(1U, frame->num);
+  EXPECT_EQ(0x400U, frame->rel_pc);
+  EXPECT_EQ(0x43400U, frame->pc);
+  EXPECT_EQ(0x10010U, frame->sp);
+  EXPECT_EQ("Frame1", frame->function_name);
+  EXPECT_EQ(1U, frame->function_offset);
+  EXPECT_EQ("/fake/fake.apk", frame->map_name);
+  EXPECT_EQ(0x1d000U, frame->map_offset);
+  EXPECT_EQ(0x43000U, frame->map_start);
+  EXPECT_EQ(0x44000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame_static) {
   FrameData frame;
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 66a9439..77f3bb2 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -53,7 +53,7 @@
       uint64_t func_offset;
       uint64_t pc = addr + load_bias;
       // This might be a thumb function, so set the low bit.
-      if (interface->GetFunctionName(pc | 1, &name, &func_offset) && !name.empty()) {
+      if (interface->GetFunctionName(pc | 1, load_bias, &name, &func_offset) && !name.empty()) {
         printf(" <%s>", name.c_str());
       }
       printf("\n");
@@ -92,8 +92,7 @@
     printf("\n  PC 0x%" PRIx64, fde->pc_start + load_bias);
     std::string name;
     uint64_t func_offset;
-    if (interface->GetFunctionName(fde->pc_start + load_bias, &name, &func_offset) &&
-        !name.empty()) {
+    if (interface->GetFunctionName(fde->pc_start, load_bias, &name, &func_offset) && !name.empty()) {
       printf(" <%s>", name.c_str());
     }
     printf("\n");
@@ -115,7 +114,7 @@
   }
 
   Elf elf(memory);
-  if (!elf.Init() || !elf.valid()) {
+  if (!elf.Init(true) || !elf.valid()) {
     printf("%s is not a valid elf file.\n", file);
     return 1;
   }
@@ -128,7 +127,7 @@
 
   if (interface->eh_frame() != nullptr) {
     printf("eh_frame information:\n");
-    DumpDwarfSection(interface, interface->eh_frame(), interface->load_bias());
+    DumpDwarfSection(interface, interface->eh_frame(), elf.GetLoadBias());
     printf("\n");
   } else {
     printf("\nno eh_frame information\n");
@@ -136,7 +135,7 @@
 
   if (interface->debug_frame() != nullptr) {
     printf("\ndebug_frame information:\n");
-    DumpDwarfSection(interface, interface->debug_frame(), interface->load_bias());
+    DumpDwarfSection(interface, interface->debug_frame(), elf.GetLoadBias());
     printf("\n");
   } else {
     printf("\nno debug_frame information\n");
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index dc9ae5a..697e4cd 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -66,7 +66,7 @@
   }
 
   unwindstack::Elf elf(memory);
-  if (!elf.Init() || !elf.valid()) {
+  if (!elf.Init(true) || !elf.valid()) {
     printf("%s is not a valid elf file.\n", argv[1]);
     return 1;
   }
@@ -90,7 +90,7 @@
   }
 
   std::string name;
-  uint64_t load_bias = elf.interface()->load_bias();
+  uint64_t load_bias = elf.GetLoadBias();
   if (argc == 3) {
     std::string cur_name;
     uint64_t func_offset;
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 3d56472..07981fc 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1831,11 +1831,10 @@
     }
     android::close_output(context);
     android::close_error(context);
+
     if (context->fds[1] >= 0) {
-        // NB: could be closed by the above fclose(s), ignore error.
-        int save_errno = errno;
+        // NB: this should be closed by close_output, but just in case...
         close(context->fds[1]);
-        errno = save_errno;
         context->fds[1] = -1;
     }
 
diff --git a/logcat/logcat_system.cpp b/logcat/logcat_system.cpp
index ea393bd..6dfd110 100644
--- a/logcat/logcat_system.cpp
+++ b/logcat/logcat_system.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <ctype.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
@@ -98,8 +99,12 @@
         return NULL;
     }
 
-    FILE* retval = fdopen(fd, "reb");
-    if (!retval) android_logcat_destroy(ctx);
+    int duped = dup(fd);
+    FILE* retval = fdopen(duped, "reb");
+    if (!retval) {
+        close(duped);
+        android_logcat_destroy(ctx);
+    }
     return retval;
 }
 
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e199ed4..fd46251 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -178,8 +178,62 @@
 # ld.config.txt
 include $(CLEAR_VARS)
 
+_enforce_vndk_at_runtime := false
+
+ifdef BOARD_VNDK_VERSION
+ifneq ($(BOARD_VNDK_RUNTIME_DISABLE),true)
+  _enforce_vndk_at_runtime := true
+endif
+endif
+
+ifeq ($(_enforce_vndk_at_runtime),true)
 LOCAL_MODULE := ld.config.txt
-ifeq ($(PRODUCT_FULL_TREBLE),true)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_MODULE_STEM := $(LOCAL_MODULE)
+include $(BUILD_SYSTEM)/base_rules.mk
+vndk_lib_md5 := $(word 1, $(shell echo $(LLNDK_LIBRARIES) $(VNDK_SAMEPROCESS_LIBRARIES) | $(MD5SUM)))
+vndk_lib_dep := $(intermediates)/$(vndk_lib_md5).dep
+$(vndk_lib_dep):
+	$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.dep && touch $@
+
+llndk_libraries := $(subst $(space),:,$(addsuffix .so,$(LLNDK_LIBRARIES)))
+
+vndk_sameprocess_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_SAMEPROCESS_LIBRARIES)))
+
+vndk_core_libraries := $(subst $(space),:,$(addsuffix .so,$(VNDK_CORE_LIBRARIES)))
+
+sanitizer_runtime_libraries := $(subst $(space),:,$(addsuffix .so,\
+$(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(UBSAN_RUNTIME_LIBRARY) \
+$(TSAN_RUNTIME_LIBRARY) \
+$(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
+$(2ND_UBSAN_RUNTIME_LIBRARY) \
+$(2ND_TSAN_RUNTIME_LIBRARY)))
+
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES := $(llndk_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(vndk_sameprocess_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_PRIVATE_LIBRARIES := $(llndk_private_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(vndk_core_libraries)
+$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/ld.config.txt.in $(vndk_lib_dep)
+	@echo "Generate: $< -> $@"
+	@mkdir -p $(dir $@)
+	$(hide) sed -e 's?%LLNDK_LIBRARIES%?$(PRIVATE_LLNDK_LIBRARIES)?g' $< >$@
+	$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $@
+	$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $@
+	$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@
+
+vndk_lib_md5 :=
+vndk_lib_dep :=
+llndk_libraries :=
+vndk_sameprocess_libraries :=
+vndk_core_libraries :=
+sanitizer_runtime_libraries :=
+else # if _enforce_vndk_at_runtime is not true
+
+LOCAL_MODULE := ld.config.txt
+ifeq ($(PRODUCT_FULL_TREBLE)|$(SANITIZE_TARGET),true|)
 LOCAL_SRC_FILES := etc/ld.config.txt
 else
 LOCAL_SRC_FILES := etc/ld.config.legacy.txt
@@ -188,3 +242,4 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
 LOCAL_MODULE_STEM := $(LOCAL_MODULE)
 include $(BUILD_PREBUILT)
+endif
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 436589e..ce354f2 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -7,6 +7,10 @@
 dir.system = /system/bin/
 dir.system = /system/xbin/
 dir.vendor = /vendor/bin/
+dir.test = /data/nativetest/
+dir.test = /data/nativetest64/
+dir.test = /data/benchmarktest/
+dir.test = /data/benchmarktest64/
 
 [system]
 additional.namespaces = sphal,vndk,rs
@@ -50,7 +54,7 @@
 namespace.sphal.isolated = true
 namespace.sphal.visible = true
 namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
-namespace.sphal.permitted.paths = /vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
 
 namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
 namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
@@ -105,9 +109,23 @@
 namespace.vndk.links = default
 namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so:libc.so:libz.so:libm.so:libdl.so:libstdc++.so:liblog.so:libnativewindow.so:libEGL.so:libsync.so:libvndksupport.so
 
-
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
 [vendor]
 namespace.default.isolated = false
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
+
+###############################################################################
+# Namespace config for tests. No VNDK restriction is enforced for these tests.
+###############################################################################
+[test]
+namespace.default.isolated = false
 namespace.default.search.paths = /vendor/${LIB}:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/system/${LIB}
 
 namespace.default.asan.search.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/system/${LIB}:/system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
new file mode 100644
index 0000000..e741a34
--- /dev/null
+++ b/rootdir/etc/ld.config.txt.in
@@ -0,0 +1,152 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolution path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
+###############################################################################
+namespace.default.isolated = true
+# TODO(b/63553457): remove /vendor/lib from the search path. For now, this is
+# required since the classloader namespace for vendor apks should have access
+# vendor libraries in the directory. These search paths are copied to the search
+# paths of the classloader namespace.
+namespace.default.search.paths = /system/${LIB}:/vendor/${LIB}
+# /vendor/app, /vendor/framework were added since libart should be able to dlopen
+# the odex files from the directory.
+namespace.default.permitted.paths = /system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/data:/mnt/expand
+
+namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.default.asan.permitted.paths = /data:/system/${LIB}/drm:/system/${LIB}/hw:/system/framework:/system/app:/system/priv-app:/vendor/app:/vendor/framework:/oem/app:/mnt/expand
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+namespace.sphal.search.paths = /vendor/${LIB}/egl:/vendor/${LIB}/hw:/vendor/${LIB}
+namespace.sphal.permitted.paths = /vendor/${LIB}:/system/${LIB}/vndk-sp/hw
+
+namespace.sphal.asan.search.paths = /data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.sphal.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+# WARNING: only NDK libs can be listed here.
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+namespace.rs.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/vendor/${LIB}
+namespace.rs.permitted.paths = /vendor/${LIB}:/data
+
+namespace.rs.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp:/data/asan/vendor/${LIB}:/vendor/${LIB}
+namespace.rs.asan.permitted.paths = /data/asan/vendor/${LIB}:/vendor/${LIB}:/data
+
+namespace.rs.links = default,vndk
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.search.paths = /vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.permitted.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl
+
+namespace.vndk.asan.search.paths = /data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.vndk.asan.permitted.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%:%SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+additional.namespaces = system
+
+###############################################################################
+# "default" namespace
+#
+# Vendor-side code runs in this namespace.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
+
+namespace.default.search.paths = /vendor/${LIB}/hw:/vendor/${LIB}/egl:/vendor/${LIB}:/vendor/${LIB}/vndk:/system/${LIB}/vndk:/vendor/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.permitted.paths = /vendor:/system/${LIB}/vndk:/system/${LIB}/vndk-sp
+
+namespace.default.asan.search.paths = /data/asan/vendor/${LIB}/hw:/vendor/${LIB}/hw:/data/asan/vendor/${LIB}/egl:/vendor/${LIB}/egl:/data/asan/vendor/${LIB}:/vendor/${LIB}:/data/asan/vendor/${LIB}/vndk:/vendor/${LIB}/vndk:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/vendor/${LIB}/vndk-sp:/vendor/${LIB}/vndk-sp:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+namespace.default.asan.permitted.paths = /data/asan/vendor:/vendor:/data/asan/system/${LIB}/vndk:/system/${LIB}/vndk:/data/asan/system/${LIB}/vndk-sp:/system/${LIB}/vndk-sp
+
+namespace.default.links = system
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%:libmedia.so:libandroid_runtime.so
+# libmedia.so must be removed after we have fix for lib-dplmedia.so (b/64427765)
+# libandroid_runtime.so must be removed after we have a fix for qseeproxydaemon (b/64820887)
+
+###############################################################################
+# "system" namespace
+#
+# This is for vendor process to use LL-NDK in system partition.
+###############################################################################
+namespace.system.isolated = false
+namespace.system.search.paths = /system/${LIB}
+namespace.system.permitted.paths = /system/${LIB}
+
+namespace.system.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB}
+namespace.system.asan.permitted.paths = /data/asan/system/${LIB}:/system/${LIB}
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
index 55a03bd..b8c2032 100644
--- a/trusty/keymaster/trusty_keymaster_device.cpp
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "TrustyKeymaster"
 
 #include <assert.h>
+#include <errno.h>
 #include <openssl/evp.h>
 #include <openssl/x509.h>
 #include <stddef.h>