Merge "atrace: read package names from multiple sysprops" into nyc-dev
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 413b362..c31f655 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -295,20 +295,12 @@
     transport_unref(t);
 }
 
-static void kick_transport_locked(atransport* t) {
-    CHECK(t != nullptr);
-    if (!t->kicked) {
-        t->kicked = true;
-        t->kick(t);
-    }
-}
-
 void kick_transport(atransport* t) {
     adb_mutex_lock(&transport_lock);
     // As kick_transport() can be called from threads without guarantee that t is valid,
     // check if the transport is in transport_list first.
     if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
-        kick_transport_locked(t);
+        t->Kick();
     }
     adb_mutex_unlock(&transport_lock);
 }
@@ -621,7 +613,6 @@
     t->ref_count--;
     if (t->ref_count == 0) {
         D("transport: %s unref (kicking and closing)", t->serial);
-        kick_transport_locked(t);
         t->close(t);
         remove_transport(t);
     } else {
@@ -748,6 +739,14 @@
     return result;
 }
 
+void atransport::Kick() {
+    if (!kicked_) {
+        kicked_ = true;
+        CHECK(kick_func_ != nullptr);
+        kick_func_(this);
+    }
+}
+
 const std::string atransport::connection_state_name() const {
     switch (connection_state) {
         case kCsOffline: return "offline";
@@ -926,10 +925,7 @@
 void close_usb_devices() {
     adb_mutex_lock(&transport_lock);
     for (const auto& t : transport_list) {
-        if (!t->kicked) {
-            t->kicked = 1;
-            t->kick(t);
-        }
+        t->Kick();
     }
     adb_mutex_unlock(&transport_lock);
 }
@@ -1000,7 +996,7 @@
             // the read_transport thread will notify the main thread to make this transport
             // offline. Then the main thread will notify the write_transport thread to exit.
             // Finally, this transport will be closed and freed in the main thread.
-            kick_transport_locked(t);
+            t->Kick();
         }
     }
     adb_mutex_unlock(&transport_lock);
diff --git a/adb/transport.h b/adb/transport.h
index 5857249..35d7b50 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -60,7 +60,13 @@
     int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
     int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
     void (*close)(atransport* t) = nullptr;
-    void (*kick)(atransport* t) = nullptr;
+    void SetKickFunction(void (*kick_func)(atransport*)) {
+        kick_func_ = kick_func;
+    }
+    bool IsKicked() {
+        return kicked_;
+    }
+    void Kick();
 
     int fd = -1;
     int transport_socket = -1;
@@ -82,7 +88,6 @@
     char* device = nullptr;
     char* devpath = nullptr;
     int adb_port = -1;  // Use for emulators (local transport)
-    bool kicked = false;
 
     void* key = nullptr;
     unsigned char token[TOKEN_SIZE] = {};
@@ -123,6 +128,9 @@
     bool MatchesTarget(const std::string& target) const;
 
 private:
+    bool kicked_ = false;
+    void (*kick_func_)(atransport*) = nullptr;
+
     // A set of features transmitted in the banner with the initial connection.
     // This is stored in the banner as 'features=feature0,feature1,etc'.
     FeatureSet features_;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index f6c9df4..4121f47 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -388,7 +388,7 @@
 {
     int  fail = 0;
 
-    t->kick = remote_kick;
+    t->SetKickFunction(remote_kick);
     t->close = remote_close;
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 2028ecc..a6db07a 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -20,47 +20,6 @@
 
 #include "adb.h"
 
-class TestTransport : public atransport {
-public:
-    bool operator==(const atransport& rhs) const {
-        EXPECT_EQ(read_from_remote, rhs.read_from_remote);
-        EXPECT_EQ(write_to_remote, rhs.write_to_remote);
-        EXPECT_EQ(close, rhs.close);
-        EXPECT_EQ(kick, rhs.kick);
-
-        EXPECT_EQ(fd, rhs.fd);
-        EXPECT_EQ(transport_socket, rhs.transport_socket);
-
-        EXPECT_EQ(
-            0, memcmp(&transport_fde, &rhs.transport_fde, sizeof(fdevent)));
-
-        EXPECT_EQ(ref_count, rhs.ref_count);
-        EXPECT_EQ(sync_token, rhs.sync_token);
-        EXPECT_EQ(connection_state, rhs.connection_state);
-        EXPECT_EQ(online, rhs.online);
-        EXPECT_EQ(type, rhs.type);
-
-        EXPECT_EQ(usb, rhs.usb);
-        EXPECT_EQ(sfd, rhs.sfd);
-
-        EXPECT_EQ(serial, rhs.serial);
-        EXPECT_EQ(product, rhs.product);
-        EXPECT_EQ(model, rhs.model);
-        EXPECT_EQ(device, rhs.device);
-        EXPECT_EQ(devpath, rhs.devpath);
-        EXPECT_EQ(adb_port, rhs.adb_port);
-        EXPECT_EQ(kicked, rhs.kicked);
-
-        EXPECT_EQ(key, rhs.key);
-        EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
-        EXPECT_EQ(failed_auth_attempts, rhs.failed_auth_attempts);
-
-        EXPECT_EQ(features(), rhs.features());
-
-        return true;
-    }
-};
-
 class TransportSetup {
 public:
   TransportSetup() {
@@ -83,35 +42,19 @@
 static TransportSetup g_TransportSetup;
 
 TEST(transport, kick_transport) {
-  TestTransport t;
-
+  atransport t;
+  static size_t kick_count;
+  kick_count = 0;
   // Mutate some member so we can test that the function is run.
-  t.kick = [](atransport* trans) { trans->fd = 42; };
-
-  TestTransport expected;
-  expected.kick = t.kick;
-  expected.fd = 42;
-  expected.kicked = 1;
-
-  kick_transport(&t);
-  ASSERT_EQ(42, t.fd);
-  ASSERT_EQ(1, t.kicked);
-  ASSERT_EQ(expected, t);
-}
-
-TEST(transport, kick_transport_already_kicked) {
-  // Ensure that the transport is not modified if the transport has already been
-  // kicked.
-  TestTransport t;
-  t.kicked = 1;
-  t.kick = [](atransport*) { FAIL() << "Kick should not have been called"; };
-
-  TestTransport expected;
-  expected.kicked = 1;
-  expected.kick = t.kick;
-
-  kick_transport(&t);
-  ASSERT_EQ(expected, t);
+  t.SetKickFunction([](atransport* trans) { kick_count++; });
+  ASSERT_FALSE(t.IsKicked());
+  t.Kick();
+  ASSERT_TRUE(t.IsKicked());
+  ASSERT_EQ(1u, kick_count);
+  // A transport can only be kicked once.
+  t.Kick();
+  ASSERT_TRUE(t.IsKicked());
+  ASSERT_EQ(1u, kick_count);
 }
 
 static void DisconnectFunc(void* arg, atransport*) {
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 263f9e7..d05d928 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -84,7 +84,7 @@
 {
     D("transport: usb");
     t->close = remote_close;
-    t->kick = remote_kick;
+    t->SetKickFunction(remote_kick);
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
     t->sync_token = 1;
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c863ed2..0ba6b4b 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -31,6 +31,9 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <atomic>
+
+#include <android-base/logging.h>
 
 #include "adb.h"
 #include "transport.h"
@@ -49,14 +52,19 @@
 #define cpu_to_le16(x)  htole16(x)
 #define cpu_to_le32(x)  htole32(x)
 
+static int dummy_fd = -1;
+
 struct usb_handle
 {
     adb_cond_t notify;
     adb_mutex_t lock;
+    bool open_new_connection;
+    std::atomic<bool> kicked;
 
     int (*write)(usb_handle *h, const void *data, int len);
     int (*read)(usb_handle *h, void *data, int len);
     void (*kick)(usb_handle *h);
+    void (*close)(usb_handle *h);
 
     // Legacy f_adb
     int fd;
@@ -241,8 +249,10 @@
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
-        while (usb->fd != -1)
+        while (!usb->open_new_connection) {
             adb_cond_wait(&usb->notify, &usb->lock);
+        }
+        usb->open_new_connection = false;
         adb_mutex_unlock(&usb->lock);
 
         D("[ usb_thread - opening device ]");
@@ -281,6 +291,10 @@
             h->fd, n, errno, strerror(errno));
         return -1;
     }
+    if (h->kicked) {
+        D("usb_adb_write finished due to kicked");
+        return -1;
+    }
     D("[ done fd=%d ]", h->fd);
     return 0;
 }
@@ -299,6 +313,10 @@
                 h->fd, n, errno, strerror(errno));
             return -1;
         }
+        if (h->kicked) {
+            D("usb_adb_read finished due to kicked");
+            return -1;
+        }
         len -= n;
         data = ((char*)data) + n;
     }
@@ -306,14 +324,23 @@
     return 0;
 }
 
-static void usb_adb_kick(usb_handle *h)
-{
+static void usb_adb_kick(usb_handle *h) {
     D("usb_kick");
-    adb_mutex_lock(&h->lock);
-    unix_close(h->fd);
-    h->fd = -1;
+    // Other threads may be calling usb_adb_read/usb_adb_write at the same time.
+    // If we close h->fd, the file descriptor will be reused to open other files,
+    // and the read/write thread may operate on the wrong file. So instead
+    // we set the kicked flag and reopen h->fd to a dummy file here. After read/write
+    // threads finish, we close h->fd in usb_adb_close().
+    h->kicked = true;
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->fd));
+}
 
-    // notify usb_adb_open_thread that we are disconnected
+static void usb_adb_close(usb_handle *h) {
+    h->kicked = false;
+    adb_close(h->fd);
+    // Notify usb_adb_open_thread to open a new connection.
+    adb_mutex_lock(&h->lock);
+    h->open_new_connection = true;
     adb_cond_signal(&h->notify);
     adb_mutex_unlock(&h->lock);
 }
@@ -326,8 +353,11 @@
     h->write = usb_adb_write;
     h->read = usb_adb_read;
     h->kick = usb_adb_kick;
+    h->close = usb_adb_close;
+    h->kicked = false;
     h->fd = -1;
 
+    h->open_new_connection = true;
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
@@ -350,7 +380,7 @@
 }
 
 
-static void init_functionfs(struct usb_handle *h)
+static bool init_functionfs(struct usb_handle *h)
 {
     ssize_t ret;
     struct desc_v1 v1_descriptor;
@@ -413,7 +443,7 @@
         goto err;
     }
 
-    return;
+    return true;
 
 err:
     if (h->bulk_in > 0) {
@@ -428,7 +458,7 @@
         adb_close(h->control);
         h->control = -1;
     }
-    return;
+    return false;
 }
 
 static void usb_ffs_open_thread(void* x) {
@@ -439,16 +469,16 @@
     while (true) {
         // wait until the USB device needs opening
         adb_mutex_lock(&usb->lock);
-        while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
+        while (!usb->open_new_connection) {
             adb_cond_wait(&usb->notify, &usb->lock);
+        }
+        usb->open_new_connection = false;
         adb_mutex_unlock(&usb->lock);
 
         while (true) {
-            init_functionfs(usb);
-
-            if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
+            if (init_functionfs(usb)) {
                 break;
-
+            }
             adb_sleep_ms(1000);
         }
         property_set("sys.usb.ffs.ready", "1");
@@ -513,16 +543,22 @@
         D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno);
     }
 
-    adb_mutex_lock(&h->lock);
-
     // don't close ep0 here, since we may not need to reinitialize it with
     // the same descriptors again. if however ep1/ep2 fail to re-open in
     // init_functionfs, only then would we close and open ep0 again.
+    // Ditto the comment in usb_adb_kick.
+    h->kicked = true;
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_out));
+    TEMP_FAILURE_RETRY(dup2(dummy_fd, h->bulk_in));
+}
+
+static void usb_ffs_close(usb_handle *h) {
+    h->kicked = false;
     adb_close(h->bulk_out);
     adb_close(h->bulk_in);
-    h->bulk_out = h->bulk_in = -1;
-
-    // notify usb_ffs_open_thread that we are disconnected
+    // Notify usb_adb_open_thread to open a new connection.
+    adb_mutex_lock(&h->lock);
+    h->open_new_connection = true;
     adb_cond_signal(&h->notify);
     adb_mutex_unlock(&h->lock);
 }
@@ -537,10 +573,13 @@
     h->write = usb_ffs_write;
     h->read = usb_ffs_read;
     h->kick = usb_ffs_kick;
+    h->close = usb_ffs_close;
+    h->kicked = false;
     h->control = -1;
     h->bulk_out = -1;
     h->bulk_out = -1;
 
+    h->open_new_connection = true;
     adb_cond_init(&h->notify, 0);
     adb_mutex_init(&h->lock, 0);
 
@@ -552,6 +591,8 @@
 
 void usb_init()
 {
+    dummy_fd = adb_open("/dev/null", O_WRONLY);
+    CHECK_NE(dummy_fd, -1);
     if (access(USB_FFS_ADB_EP0, F_OK) == 0)
         usb_ffs_init();
     else
@@ -569,6 +610,7 @@
 }
 int usb_close(usb_handle *h)
 {
+    h->close(h);
     return 0;
 }
 
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 54d4c6c..ddde454 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,86 +29,96 @@
 #include <inttypes.h>
 #include <stdio.h>
 
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <vector>
+
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 
 #include "adb.h"
 #include "transport.h"
 
-#define  DBG   D
-
-// There's no strerror equivalent for the errors returned by IOKit.
-// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
-// Search the web for "IOReturn.h" to find a complete up to date list.
-
-static IONotificationPortRef    notificationPort = 0;
-static io_iterator_t            notificationIterator;
-
 struct usb_handle
 {
     UInt8 bulkIn;
     UInt8 bulkOut;
     IOUSBInterfaceInterface190** interface;
-    io_object_t usbNotification;
     unsigned int zero_mask;
+
+    // For garbage collecting disconnected devices.
+    bool mark;
+    std::string devpath;
+    std::atomic<bool> dead;
+
+    usb_handle() : bulkIn(0), bulkOut(0), interface(nullptr),
+        zero_mask(0), mark(false), dead(false) {
+    }
 };
 
-static CFRunLoopRef currentRunLoop = 0;
-static pthread_mutex_t start_lock;
-static pthread_cond_t start_cond;
+static std::atomic<bool> usb_inited_flag;
 
+static auto& g_usb_handles_mutex = *new std::mutex();
+static auto& g_usb_handles = *new std::vector<std::unique_ptr<usb_handle>>();
 
-static void AndroidInterfaceAdded(void *refCon, io_iterator_t iterator);
-static void AndroidInterfaceNotify(void *refCon, io_iterator_t iterator,
-                                   natural_t messageType,
-                                   void *messageArgument);
-static usb_handle* CheckInterface(IOUSBInterfaceInterface190 **iface,
-                                  UInt16 vendor, UInt16 product);
-
-static int
-InitUSB()
-{
-    CFMutableDictionaryRef  matchingDict;
-    CFRunLoopSourceRef      runLoopSource;
-
-    //* To set up asynchronous notifications, create a notification port and
-    //* add its run loop event source to the program's run loop
-    notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
-    runLoopSource = IONotificationPortGetRunLoopSource(notificationPort);
-    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
-
-    //* Create our matching dictionary to find the Android device's
-    //* adb interface
-    //* IOServiceAddMatchingNotification consumes the reference, so we do
-    //* not need to release this
-    matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
-
-    if (!matchingDict) {
-        LOG(ERROR) << "Couldn't create USB matching dictionary.";
-        return -1;
+static bool IsKnownDevice(const std::string& devpath) {
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    for (auto& usb : g_usb_handles) {
+        if (usb->devpath == devpath) {
+            // Set mark flag to indicate this device is still alive.
+            usb->mark = true;
+            return true;
+        }
     }
+    return false;
+}
 
-    //* We have to get notifications for all potential candidates and test them
-    //* at connection time because the matching rules don't allow for a
-    //* USB interface class of 0xff for class+subclass+protocol matches
-    //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html
-    IOServiceAddMatchingNotification(
-            notificationPort,
-            kIOFirstMatchNotification,
-            matchingDict,
-            AndroidInterfaceAdded,
-            NULL,
-            &notificationIterator);
+static void usb_kick_locked(usb_handle* handle);
 
-    //* Iterate over set of matching interfaces to access already-present
-    //* devices and to arm the notification
-    AndroidInterfaceAdded(NULL, notificationIterator);
+static void KickDisconnectedDevices() {
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    for (auto& usb : g_usb_handles) {
+        if (!usb->mark) {
+            usb_kick_locked(usb.get());
+        } else {
+            usb->mark = false;
+        }
+    }
+}
 
-    return 0;
+static void AddDevice(std::unique_ptr<usb_handle> handle) {
+    handle->mark = true;
+    std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+    g_usb_handles.push_back(std::move(handle));
+}
+
+static void AndroidInterfaceAdded(io_iterator_t iterator);
+static std::unique_ptr<usb_handle> CheckInterface(IOUSBInterfaceInterface190 **iface,
+                                                  UInt16 vendor, UInt16 product);
+
+static bool FindUSBDevices() {
+    // Create the matching dictionary to find the Android device's adb interface.
+    CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
+    if (!matchingDict) {
+        LOG(ERROR) << "couldn't create USB matching dictionary";
+        return false;
+    }
+    // Create an iterator for all I/O Registry objects that match the dictionary.
+    io_iterator_t iter = 0;
+    kern_return_t kr = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter);
+    if (kr != KERN_SUCCESS) {
+        LOG(ERROR) << "failed to get matching services";
+        return false;
+    }
+    // Iterate over all matching objects.
+    AndroidInterfaceAdded(iter);
+    IOObjectRelease(iter);
+    return true;
 }
 
 static void
-AndroidInterfaceAdded(void *refCon, io_iterator_t iterator)
+AndroidInterfaceAdded(io_iterator_t iterator)
 {
     kern_return_t            kr;
     io_service_t             usbDevice;
@@ -124,8 +134,7 @@
     UInt16                   product;
     UInt8                    serialIndex;
     char                     serial[256];
-    char                     devpathBuf[64];
-    char                     *devpath = NULL;
+    std::string devpath;
 
     while ((usbInterface = IOIteratorNext(iterator))) {
         //* Create an intermediate interface plugin
@@ -199,9 +208,11 @@
         kr = (*dev)->GetDeviceVendor(dev, &vendor);
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->GetLocationID(dev, &locationId);
-        if (kr == 0) {
-            snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
-            devpath = devpathBuf;
+        if (kr == KERN_SUCCESS) {
+            devpath = android::base::StringPrintf("usb:%" PRIu32 "X", locationId);
+            if (IsKnownDevice(devpath)) {
+                continue;
+            }
         }
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
@@ -256,49 +267,29 @@
 
         (*dev)->Release(dev);
 
-        LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+        VLOG(USB) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
                         vendor, product, serial);
-
-        usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
-                                            vendor, product);
-        if (handle == NULL) {
-            LOG(ERROR) << "Could not find device interface";
+        if (devpath.empty()) {
+            devpath = serial;
+        }
+        if (IsKnownDevice(devpath)) {
+            (*iface)->USBInterfaceClose(iface);
             (*iface)->Release(iface);
             continue;
         }
 
-        LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
-        register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
-
-        // Register for an interest notification of this device being removed.
-        // Pass the reference to our private data as the refCon for the
-        // notification.
-        kr = IOServiceAddInterestNotification(notificationPort,
-                usbInterface,
-                kIOGeneralInterest,
-                AndroidInterfaceNotify,
-                handle,
-                &handle->usbNotification);
-
-        if (kIOReturnSuccess != kr) {
-            LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
+        std::unique_ptr<usb_handle> handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
+                                                            vendor, product);
+        if (handle == nullptr) {
+            LOG(ERROR) << "Could not find device interface";
+            (*iface)->Release(iface);
+            continue;
         }
-    }
-}
-
-static void
-AndroidInterfaceNotify(void *refCon, io_service_t service, natural_t messageType, void *messageArgument)
-{
-    usb_handle *handle = (usb_handle *)refCon;
-
-    if (messageType == kIOMessageServiceIsTerminated) {
-        if (!handle) {
-            LOG(ERROR) << "NULL handle";
-            return;
-        }
-        LOG(DEBUG) << "AndroidInterfaceNotify";
-        IOObjectRelease(handle->usbNotification);
-        usb_kick(handle);
+        handle->devpath = devpath;
+        usb_handle* handle_p = handle.get();
+        VLOG(USB) << "Add usb device " << serial;
+        AddDevice(std::move(handle));
+        register_usb_transport(handle_p, serial, devpath.c_str(), 1);
     }
 }
 
@@ -316,10 +307,10 @@
 
 //* TODO: simplify this further since we only register to get ADB interface
 //* subclass+protocol events
-static usb_handle*
+static std::unique_ptr<usb_handle>
 CheckInterface(IOUSBInterfaceInterface190 **interface, UInt16 vendor, UInt16 product)
 {
-    usb_handle* handle;
+    std::unique_ptr<usb_handle> handle;
     IOReturn kr;
     UInt8 interfaceNumEndpoints, interfaceClass, interfaceSubClass, interfaceProtocol;
     UInt8 endpoint;
@@ -353,8 +344,10 @@
         goto err_bad_adb_interface;
     }
 
-    handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
-    if (handle == nullptr) goto err_bad_adb_interface;
+    handle.reset(new usb_handle);
+    if (handle == nullptr) {
+        goto err_bad_adb_interface;
+    }
 
     //* Iterate over the endpoints for this interface and find the first
     //* bulk in/out pipes available.  These will be our read/write pipes.
@@ -392,39 +385,37 @@
     return handle;
 
 err_get_pipe_props:
-    free(handle);
 err_bad_adb_interface:
 err_get_interface_class:
 err_get_num_ep:
     (*interface)->USBInterfaceClose(interface);
-    return NULL;
+    return nullptr;
 }
 
+std::mutex& operate_device_lock = *new std::mutex();
+
 static void RunLoopThread(void* unused) {
     adb_thread_setname("RunLoop");
-    InitUSB();
 
-    currentRunLoop = CFRunLoopGetCurrent();
-
-    // Signal the parent that we are running
-    adb_mutex_lock(&start_lock);
-    adb_cond_signal(&start_cond);
-    adb_mutex_unlock(&start_lock);
-
-    CFRunLoopRun();
-    currentRunLoop = 0;
-
-    IOObjectRelease(notificationIterator);
-    IONotificationPortDestroy(notificationPort);
-
-    LOG(DEBUG) << "RunLoopThread done";
+    VLOG(USB) << "RunLoopThread started";
+    while (true) {
+        {
+            std::lock_guard<std::mutex> lock_guard(operate_device_lock);
+            FindUSBDevices();
+            KickDisconnectedDevices();
+        }
+        // Signal the parent that we are running
+        usb_inited_flag = true;
+        adb_sleep_ms(1000);
+    }
+    VLOG(USB) << "RunLoopThread done";
 }
 
 static void usb_cleanup() {
-    LOG(DEBUG) << "usb_cleanup";
+    VLOG(USB) << "usb_cleanup";
+    // Wait until usb operations in RunLoopThread finish, and prevent further operations.
+    operate_device_lock.lock();
     close_usb_devices();
-    if (currentRunLoop)
-        CFRunLoopStop(currentRunLoop);
 }
 
 void usb_init() {
@@ -432,20 +423,16 @@
     if (!initialized) {
         atexit(usb_cleanup);
 
-        adb_mutex_init(&start_lock, NULL);
-        adb_cond_init(&start_cond, NULL);
+        usb_inited_flag = false;
 
         if (!adb_thread_create(RunLoopThread, nullptr)) {
             fatal_errno("cannot create RunLoop thread");
         }
 
         // Wait for initialization to finish
-        adb_mutex_lock(&start_lock);
-        adb_cond_wait(&start_cond, &start_lock);
-        adb_mutex_unlock(&start_lock);
-
-        adb_mutex_destroy(&start_lock);
-        adb_cond_destroy(&start_cond);
+        while (!usb_inited_flag) {
+            adb_sleep_ms(100);
+        }
 
         initialized = true;
     }
@@ -458,7 +445,7 @@
     if (!len)
         return 0;
 
-    if (!handle)
+    if (!handle || handle->dead)
         return -1;
 
     if (NULL == handle->interface) {
@@ -499,7 +486,7 @@
         return 0;
     }
 
-    if (!handle) {
+    if (!handle || handle->dead) {
         return -1;
     }
 
@@ -532,20 +519,33 @@
 
 int usb_close(usb_handle *handle)
 {
+    std::lock_guard<std::mutex> lock(g_usb_handles_mutex);
+    for (auto it = g_usb_handles.begin(); it != g_usb_handles.end(); ++it) {
+        if ((*it).get() == handle) {
+            g_usb_handles.erase(it);
+            break;
+        }
+    }
     return 0;
 }
 
-void usb_kick(usb_handle *handle)
+static void usb_kick_locked(usb_handle *handle)
 {
     LOG(INFO) << "Kicking handle";
     /* release the interface */
     if (!handle)
         return;
 
-    if (handle->interface)
+    if (!handle->dead)
     {
+        handle->dead = true;
         (*handle->interface)->USBInterfaceClose(handle->interface);
         (*handle->interface)->Release(handle->interface);
-        handle->interface = 0;
     }
 }
+
+void usb_kick(usb_handle *handle) {
+    // Use the lock to avoid multiple thread kicking the device at the same time.
+    std::lock_guard<std::mutex> lock_guard(g_usb_handles_mutex);
+    usb_kick_locked(handle);
+}
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 12f507a..7f0e5bb 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -25,9 +25,11 @@
 #include <sys/poll.h>
 #include <sys/prctl.h>
 #include <sys/ptrace.h>
+#include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/un.h>
 #include <time.h>
 
 #include <set>
@@ -36,6 +38,7 @@
 
 #include <log/logger.h>
 
+#include <android-base/unique_fd.h>
 #include <cutils/debugger.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
@@ -248,6 +251,43 @@
   return 0;
 }
 
+static int activity_manager_connect() {
+  android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));
+  if (amfd.get() < -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (socket failed: %s)", strerror(errno));
+    return -1;
+  }
+
+  struct sockaddr_un address;
+  memset(&address, 0, sizeof(address));
+  address.sun_family = AF_UNIX;
+  // The path used here must match the value defined in NativeCrashListener.java.
+  strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
+  if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address),
+                                 sizeof(address))) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (connect failed: %s)", strerror(errno));
+    return -1;
+  }
+
+  struct timeval tv;
+  memset(&tv, 0, sizeof(tv));
+  tv.tv_sec = 1;  // tight leash
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
+          strerror(errno));
+    return -1;
+  }
+
+  tv.tv_sec = 3;  // 3 seconds on handshake read
+  if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+    ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
+          strerror(errno));
+    return -1;
+  }
+
+  return amfd.release();
+}
+
 static bool should_attach_gdb(const debugger_request_t& request) {
   if (request.action == DEBUGGER_ACTION_CRASH) {
     return property_get_bool("debug.debuggerd.wait_for_gdb", false);
@@ -375,7 +415,7 @@
 
 static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
                          BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
-                         int* crash_signal) {
+                         int* crash_signal, int amfd) {
   if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
     ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
     return false;
@@ -393,7 +433,7 @@
         if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
           ALOGV("debuggerd: stopped -- dumping to tombstone");
           engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                            request.original_si_code, request.abort_msg_address);
+                            request.original_si_code, request.abort_msg_address, amfd);
         } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
           ALOGV("debuggerd: stopped -- dumping to fd");
           dump_backtrace(fd, -1, backtrace_map, request.pid, request.tid, siblings);
@@ -420,7 +460,7 @@
         ALOGV("stopped -- fatal signal\n");
         *crash_signal = signal;
         engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
-                          request.original_si_code, request.abort_msg_address);
+                          request.original_si_code, request.abort_msg_address, amfd);
         break;
 
       default:
@@ -506,6 +546,12 @@
   // Generate the backtrace map before dropping privileges.
   std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
 
+  int amfd = -1;
+  if (request.action == DEBUGGER_ACTION_CRASH) {
+    // Connect to the activity manager before dropping privileges.
+    amfd = activity_manager_connect();
+  }
+
   bool succeeded = false;
 
   // Now that we've done everything that requires privileges, we can drop them.
@@ -515,7 +561,8 @@
   }
 
   int crash_signal = SIGKILL;
-  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings, &crash_signal);
+  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
+                           &crash_signal, amfd);
   if (succeeded) {
     if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
       if (!tombstone_path.empty()) {
@@ -559,6 +606,8 @@
     uninit_getevent();
   }
 
+  close(amfd);
+
   exit(!succeeded);
 }
 
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 7cf2ffc..d802c8c 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -28,9 +28,7 @@
 #include <string.h>
 #include <time.h>
 #include <sys/ptrace.h>
-#include <sys/socket.h>
 #include <sys/stat.h>
-#include <sys/un.h>
 
 #include <memory>
 #include <string>
@@ -59,9 +57,6 @@
 #define TOMBSTONE_DIR   "/data/tombstones"
 #define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
 
-// Must match the path defined in NativeCrashListener.java
-#define NCRASH_SOCKET_PATH "/data/system/ndebugsocket"
-
 static bool signal_has_si_addr(int sig) {
   switch (sig) {
     case SIGBUS:
@@ -711,39 +706,9 @@
   return fd;
 }
 
-static int activity_manager_connect() {
-  int amfd = socket(PF_UNIX, SOCK_STREAM, 0);
-  if (amfd >= 0) {
-    struct sockaddr_un address;
-    int err;
-
-    memset(&address, 0, sizeof(address));
-    address.sun_family = AF_UNIX;
-    strncpy(address.sun_path, NCRASH_SOCKET_PATH, sizeof(address.sun_path));
-    err = TEMP_FAILURE_RETRY(connect(
-        amfd, reinterpret_cast<struct sockaddr*>(&address), sizeof(address)));
-    if (!err) {
-      struct timeval tv;
-      memset(&tv, 0, sizeof(tv));
-      tv.tv_sec = 1;  // tight leash
-      err = setsockopt(amfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-      if (!err) {
-        tv.tv_sec = 3;  // 3 seconds on handshake read
-        err = setsockopt(amfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-      }
-    }
-    if (err) {
-      close(amfd);
-      amfd = -1;
-    }
-  }
-
-  return amfd;
-}
-
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address) {
+                       uintptr_t abort_msg_address, int amfd) {
   log_t log;
   log.current_tid = tid;
   log.crashed_tid = tid;
@@ -756,10 +721,6 @@
   log.tfd = tombstone_fd;
   // Preserve amfd since it can be modified through the calls below without
   // being closed.
-  int amfd = activity_manager_connect();
   log.amfd = amfd;
   dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
-
-  // This file descriptor can be -1, any error is ignored.
-  close(amfd);
 }
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 2b8b8be..7f3eebe 100644
--- a/debuggerd/tombstone.h
+++ b/debuggerd/tombstone.h
@@ -34,6 +34,6 @@
 /* Creates a tombstone file and writes the crash dump to it. */
 void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
                        const std::set<pid_t>& siblings, int signal, int original_si_code,
-                       uintptr_t abort_msg_address);
+                       uintptr_t abort_msg_address, int amfd);
 
 #endif // _DEBUGGERD_TOMBSTONE_H
diff --git a/gatekeeperd/gatekeeperd.rc b/gatekeeperd/gatekeeperd.rc
index 3f1b92d..8b126d5 100644
--- a/gatekeeperd/gatekeeperd.rc
+++ b/gatekeeperd/gatekeeperd.rc
@@ -1,3 +1,4 @@
 service gatekeeperd /system/bin/gatekeeperd /data/misc/gatekeeper
     class late_start
     user system
+    writepid /dev/cpuset/system-background/tasks
diff --git a/init/devices.cpp b/init/devices.cpp
index 39cd706..cffc561 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -242,7 +242,11 @@
 
     mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
-    selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
+    if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+        ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
+                path, strerror(errno));
+        return;
+    }
     setfscreatecon(secontext);
 
     dev = makedev(major, minor);
@@ -252,14 +256,19 @@
      * racy. Fixing the gid race at least fixed the issue with system_server
      * opening dynamic input devices under the AID_INPUT gid. */
     setegid(gid);
-    mknod(path, mode, dev);
+    /* If the node already exists update its SELinux label to handle cases when
+     * it was created with the wrong context during coldboot procedure. */
+    if (mknod(path, mode, dev) && (errno == EEXIST)) {
+        if (lsetfilecon(path, secontext)) {
+            ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
+                    secontext, path, strerror(errno));
+        }
+    }
     chown(path, uid, -1);
     setegid(AID_ROOT);
 
-    if (secontext) {
-        freecon(secontext);
-        setfscreatecon(NULL);
-    }
+    freecon(secontext);
+    setfscreatecon(NULL);
 }
 
 static void add_platform_device(const char *path)
diff --git a/liblog/event_tag_map.c b/liblog/event_tag_map.c
index 64d872a..3cb04cf 100644
--- a/liblog/event_tag_map.c
+++ b/liblog/event_tag_map.c
@@ -73,7 +73,7 @@
     if (newTagMap == NULL)
         return NULL;
 
-    fd = open(fileName, O_RDONLY);
+    fd = open(fileName, O_RDONLY | O_CLOEXEC);
     if (fd < 0) {
         fprintf(stderr, "%s: unable to open map '%s': %s\n",
             OUT_TAG, fileName, strerror(errno));
diff --git a/liblog/logd_reader.c b/liblog/logd_reader.c
index d844104..b894349 100644
--- a/liblog/logd_reader.c
+++ b/liblog/logd_reader.c
@@ -85,7 +85,7 @@
     .clear = logdClear,
     .getSize = logdGetSize,
     .setSize = logdSetSize,
-    .getReadableSize = logdGetSize,
+    .getReadableSize = logdGetReadableSize,
     .getPrune = logdGetPrune,
     .setPrune = logdSetPrune,
     .getStats = logdGetStats,
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 9b60d4a..c8457f4 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1042,7 +1042,7 @@
          * Anything in the Android Logger before the dmesg logging span will
          * be highly suspect regarding the monotonic time calculations.
          */
-        FILE *p = popen("/system/bin/dmesg", "r");
+        FILE *p = popen("/system/bin/dmesg", "re");
         if (p) {
             char *line = NULL;
             size_t len = 0;
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 5695e8a..f5e91c8 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -151,13 +151,13 @@
     memset(log_msg, 0, sizeof(*log_msg));
 
     if (transp->context.fd <= 0) {
-        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+        int fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
 
         if (fd < 0) {
             return -errno;
         }
         if (fd == 0) { /* Argggg */
-            fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY);
+            fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
             close(0);
             if (fd < 0) {
                 return -errno;
diff --git a/liblog/pmsg_writer.c b/liblog/pmsg_writer.c
index 9cd3c48..2ba31fa 100644
--- a/liblog/pmsg_writer.c
+++ b/liblog/pmsg_writer.c
@@ -54,7 +54,7 @@
 static int pmsgOpen()
 {
     if (pmsgLoggerWrite.context.fd < 0) {
-        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY));
+        pmsgLoggerWrite.context.fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
     }
 
     return pmsgLoggerWrite.context.fd;
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 19393ec..62366f2 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
+#include <errno.h>
 #include <inttypes.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include <map>
 #include <utility>
@@ -22,6 +25,7 @@
 #include "Allocator.h"
 #include "HeapWalker.h"
 #include "LeakFolding.h"
+#include "ScopedSignalHandler.h"
 #include "log.h"
 
 bool HeapWalker::Allocation(uintptr_t begin, uintptr_t end) {
@@ -37,18 +41,26 @@
     return true;
   } else {
     Range overlap = inserted.first->first;
-    ALOGE("range %p-%p overlaps with existing range %p-%p",
-        reinterpret_cast<void*>(begin),
-        reinterpret_cast<void*>(end),
-        reinterpret_cast<void*>(overlap.begin),
-        reinterpret_cast<void*>(overlap.end));
+    if (overlap != range) {
+      ALOGE("range %p-%p overlaps with existing range %p-%p",
+          reinterpret_cast<void*>(begin),
+          reinterpret_cast<void*>(end),
+          reinterpret_cast<void*>(overlap.begin),
+          reinterpret_cast<void*>(overlap.end));
+    }
     return false;
   }
 }
 
-bool HeapWalker::IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info) {
-  if (ptr >= valid_allocations_range_.begin && ptr < valid_allocations_range_.end) {
-    AllocationMap::iterator it = allocations_.find(Range{ptr, ptr + 1});
+bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
+  walking_ptr_ = word_ptr;
+  // This access may segfault if the process under test has done something strange,
+  // for example mprotect(PROT_NONE) on a native heap page.  If so, it will be
+  // caught and handled by mmaping a zero page over the faulting page.
+  uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+  walking_ptr_ = 0;
+  if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
+    AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
     if (it != allocations_.end()) {
       *range = it->first;
       *info = &it->second;
@@ -135,3 +147,30 @@
 
   return true;
 }
+
+static bool MapOverPage(void* addr) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  void *page = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) & ~(page_size-1));
+
+  void* ret = mmap(page, page_size, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0);
+  if (ret == MAP_FAILED) {
+    ALOGE("failed to map page at %p: %s", page, strerror(errno));
+    return false;
+  }
+
+  return true;
+}
+
+void HeapWalker::HandleSegFault(ScopedSignalHandler& handler, int signal, siginfo_t* si, void* /*uctx*/) {
+  uintptr_t addr = reinterpret_cast<uintptr_t>(si->si_addr);
+  if (addr != walking_ptr_) {
+    handler.reset();
+    return;
+  }
+  ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+  if (!MapOverPage(si->si_addr)) {
+    handler.reset();
+  }
+}
+
+ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 7b851c4..3c1b513 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -17,9 +17,12 @@
 #ifndef LIBMEMUNREACHABLE_HEAP_WALKER_H_
 #define LIBMEMUNREACHABLE_HEAP_WALKER_H_
 
+#include <signal.h>
+
 #include "android-base/macros.h"
 
 #include "Allocator.h"
+#include "ScopedSignalHandler.h"
 #include "Tarjan.h"
 
 // A range [begin, end)
@@ -28,6 +31,12 @@
   uintptr_t end;
 
   size_t size() const { return end - begin; };
+  bool operator==(const Range& other) const {
+    return this->begin == other.begin && this->end == other.end;
+  }
+  bool operator!=(const Range& other) const {
+    return !(*this == other);
+  }
 };
 
 // Comparator for Ranges that returns equivalence for overlapping ranges
@@ -41,10 +50,17 @@
  public:
   HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
     allocations_(allocator), allocation_bytes_(0),
-	roots_(allocator), root_vals_(allocator) {
+	roots_(allocator), root_vals_(allocator),
+	segv_handler_(allocator), walking_ptr_(0) {
     valid_allocations_range_.end = 0;
     valid_allocations_range_.begin = ~valid_allocations_range_.end;
+
+    segv_handler_.install(SIGSEGV,
+        [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+          this->HandleSegFault(handler, signal, siginfo, uctx);
+      });
   }
+
   ~HeapWalker() {}
   bool Allocation(uintptr_t begin, uintptr_t end);
   void Root(uintptr_t begin, uintptr_t end);
@@ -70,7 +86,8 @@
  private:
 
   void RecurseRoot(const Range& root);
-  bool IsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  bool WordContainsAllocationPtr(uintptr_t ptr, Range* range, AllocationInfo** info);
+  void HandleSegFault(ScopedSignalHandler&, int, siginfo_t*, void*);
 
   DISALLOW_COPY_AND_ASSIGN(HeapWalker);
   Allocator<HeapWalker> allocator_;
@@ -81,6 +98,9 @@
 
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
+
+  ScopedSignalHandler segv_handler_;
+  uintptr_t walking_ptr_;
 };
 
 template<class F>
@@ -92,7 +112,7 @@
   for (uintptr_t i = begin; i < range.end; i += sizeof(uintptr_t)) {
     Range ref_range;
     AllocationInfo* ref_info;
-    if (IsAllocationPtr(*reinterpret_cast<uintptr_t*>(i), &ref_range, &ref_info)) {
+    if (WordContainsAllocationPtr(i, &ref_range, &ref_info)) {
       f(ref_range, ref_info);
     }
   }
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
new file mode 100644
index 0000000..e006d43
--- /dev/null
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+#define LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
+
+#include <errno.h>
+#include <signal.h>
+
+#include <functional>
+
+#include "android-base/macros.h"
+
+#include "log.h"
+
+class ScopedSignalHandler {
+ public:
+  using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
+
+  ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+  ~ScopedSignalHandler() {
+    reset();
+  }
+
+  template <class F>
+  void install(int signal, F&& f) {
+    LOG_ALWAYS_FATAL_IF(signal_ != -1, "ScopedSignalHandler already installed");
+
+    handler_ = SignalFn(std::allocator_arg, allocator_,
+        [=](int signal, siginfo_t* si, void* uctx) {
+          f(*this, signal, si, uctx);
+        });
+
+    struct sigaction act{};
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+      handler_(signal, si, uctx);
+    };
+    act.sa_flags = SA_SIGINFO;
+
+    int ret = sigaction(signal, &act, &old_act_);
+    if (ret < 0) {
+      LOG_ALWAYS_FATAL("failed to install segfault handler: %s", strerror(errno));
+    }
+
+    signal_ = signal;
+  }
+
+  void reset() {
+    if (signal_ != -1) {
+      int ret = sigaction(signal_, &old_act_, NULL);
+      if (ret < 0) {
+        ALOGE("failed to uninstall segfault handler");
+      }
+      handler_ = SignalFn{};
+      signal_ = -1;
+    }
+  }
+
+
+ private:
+  using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+  DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
+  Allocator<Fn> allocator_;
+  int signal_;
+  struct sigaction old_act_;
+  // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
+  // to be a static map of signals to handlers, but allocated with Allocator.
+  static SignalFn handler_;
+};
+
+#endif // LIBMEMUNREACHABLE_SCOPED_SIGNAL_HANDLER_H_
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index c3e1c4d..98e4aa1 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <sys/mman.h>
+#include <unistd.h>
+
 #include "HeapWalker.h"
 
 #include <gtest/gtest.h>
@@ -172,3 +175,27 @@
   EXPECT_EQ(2*sizeof(uintptr_t), leaked_bytes);
   ASSERT_EQ(2U, leaked.size());
 }
+
+TEST_F(HeapWalkerTest, segv) {
+  const size_t page_size = sysconf(_SC_PAGE_SIZE);
+  void* buffer1 = mmap(NULL, page_size, PROT_NONE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+  ASSERT_NE(buffer1, nullptr);
+  void* buffer2;
+
+  buffer2 = &buffer1;
+
+  HeapWalker heap_walker(heap_);
+  heap_walker.Allocation(buffer_begin(buffer1), buffer_begin(buffer1)+page_size);
+  heap_walker.Root(buffer_begin(buffer2), buffer_end(buffer2));
+
+  ASSERT_EQ(true, heap_walker.DetectLeaks());
+
+  allocator::vector<Range> leaked(heap_);
+  size_t num_leaks = 0;
+  size_t leaked_bytes = 0;
+  ASSERT_EQ(true, heap_walker.Leaked(leaked, 100, &num_leaks, &leaked_bytes));
+
+  EXPECT_EQ(0U, num_leaks);
+  EXPECT_EQ(0U, leaked_bytes);
+  ASSERT_EQ(0U, leaked.size());
+}
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index f28a693..665b5b5 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -37,13 +37,9 @@
 namespace android {
 
 #if defined(__ANDROID__)
-static constexpr const char* kPublicNativeLibrariesSystemConfig = "/system/etc/public.libraries.txt";
+static constexpr const char* kPublicNativeLibrariesSystemConfigPathFromRoot = "/etc/public.libraries.txt";
 static constexpr const char* kPublicNativeLibrariesVendorConfig = "/vendor/etc/public.libraries.txt";
 
-static bool namespace_workaround_enabled(int32_t target_sdk_version) {
-  return target_sdk_version <= 23;
-}
-
 class LibraryNamespaces {
  public:
   LibraryNamespaces() : initialized_(false) { }
@@ -109,10 +105,14 @@
 
   void Initialize() {
     std::vector<std::string> sonames;
+    const char* android_root_env = getenv("ANDROID_ROOT");
+    std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
+    std::string public_native_libraries_system_config =
+            root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
 
-    LOG_ALWAYS_FATAL_IF(!ReadConfig(kPublicNativeLibrariesSystemConfig, &sonames),
+    LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
                         "Error reading public native library list from \"%s\": %s",
-                        kPublicNativeLibrariesSystemConfig, strerror(errno));
+                        public_native_libraries_system_config.c_str(), strerror(errno));
     // This file is optional, quietly ignore if the file does not exist.
     ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames);
 
@@ -156,18 +156,7 @@
   bool InitPublicNamespace(const char* library_path, int32_t target_sdk_version) {
     std::string publicNativeLibraries = public_libraries_;
 
-    // TODO (dimitry): This is a workaround for http://b/26436837
-    // will be removed before the release.
-    if (namespace_workaround_enabled(target_sdk_version)) {
-      // check if libart.so is loaded.
-      void* handle = dlopen("libart.so", RTLD_NOW | RTLD_NOLOAD);
-      if (handle != nullptr) {
-        publicNativeLibraries += ":libart.so";
-        dlclose(handle);
-      }
-    }
-    // END OF WORKAROUND
-
+    UNUSED(target_sdk_version);
     // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
@@ -187,10 +176,6 @@
 
 static std::mutex g_namespaces_mutex;
 static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
-
-static bool namespaces_enabled(uint32_t target_sdk_version) {
-  return target_sdk_version > 0;
-}
 #endif
 
 void InitializeNativeLoader() {
@@ -208,10 +193,7 @@
                                    jstring library_path,
                                    jstring permitted_path) {
 #if defined(__ANDROID__)
-  if (!namespaces_enabled(target_sdk_version)) {
-    return nullptr;
-  }
-
+  UNUSED(target_sdk_version);
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
   android_namespace_t* ns = g_namespaces->Create(env,
                                                  class_loader,
@@ -235,7 +217,8 @@
                         jobject class_loader,
                         jstring library_path) {
 #if defined(__ANDROID__)
-  if (!namespaces_enabled(target_sdk_version) || class_loader == nullptr) {
+  UNUSED(target_sdk_version);
+  if (class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 5c18f26..9480e4a 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -48,6 +48,9 @@
 
 #include <private/android_filesystem_config.h>
 
+/* FUSE_CANONICAL_PATH is not currently upstreamed */
+#define FUSE_CANONICAL_PATH 2016
+
 /* README
  *
  * What is this?
@@ -1471,6 +1474,35 @@
     return NO_STATUS;
 }
 
+static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
+        const struct fuse_in_header *hdr)
+{
+    struct node* node;
+    char path[PATH_MAX];
+    int len;
+
+    pthread_mutex_lock(&fuse->global->lock);
+    node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+            path, sizeof(path));
+    TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
+        node ? node->name : "?");
+    pthread_mutex_unlock(&fuse->global->lock);
+
+    if (!node) {
+        return -ENOENT;
+    }
+    if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+        return -EACCES;
+    }
+    len = strlen(path);
+    if (len + 1 > PATH_MAX)
+        len = PATH_MAX - 1;
+    path[PATH_MAX - 1] = 0;
+    fuse_reply(fuse, hdr->unique, path, len + 1);
+    return NO_STATUS;
+}
+
+
 static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
         const struct fuse_in_header *hdr, const void *data, size_t data_len)
 {
@@ -1586,6 +1618,10 @@
         return handle_init(fuse, handler, hdr, req);
     }
 
+    case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
+        return handle_canonical_path(fuse, handler, hdr);
+    }
+
     default: {
         TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
                 handler->token, hdr->opcode, hdr->unique, hdr->nodeid);