Merge changes from topic 'adb_perf'

* changes:
  adb: Add bMaxBurst to superspeed descriptors
  adb: Set max socket sizes to larger values.
  adb: Pre allocate kernel memory
diff --git a/base/Android.bp b/base/Android.bp
index b9a6e0b..a7600f3 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -37,6 +37,9 @@
     cppflags: libbase_cppflags,
     export_include_dirs: ["include"],
     shared_libs: ["liblog"],
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
     target: {
         android: {
             srcs: [
@@ -86,6 +89,9 @@
         "strings_test.cpp",
         "test_main.cpp",
     ],
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
     target: {
         android: {
             srcs: ["properties_test.cpp"],
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4d7082a..e275fa2 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -58,6 +58,9 @@
 // tell you whether or not your call succeeded. A `false` return value definitely means failure.
 bool SetProperty(const std::string& key, const std::string& value);
 
+// Waits for the system property `key` to have the value `expected_value`, .
+void WaitForProperty(const std::string& key, const std::string& expected_value);
+
 } // namespace base
 } // namespace android
 
diff --git a/base/properties.cpp b/base/properties.cpp
index 37daf9a..0f0f638 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+
 #include "android-base/properties.h"
 
 #include <sys/system_properties.h>
+#include <sys/_system_properties.h>
 
 #include <string>
 
@@ -78,5 +81,43 @@
   return (__system_property_set(key.c_str(), value.c_str()) == 0);
 }
 
+struct WaitForPropertyData {
+  bool done;
+  const std::string* expected_value;
+  unsigned last_read_serial;
+};
+
+static void WaitForPropertyCallback(void* data_ptr, const char*, const char* value, unsigned serial) {
+  WaitForPropertyData* data = reinterpret_cast<WaitForPropertyData*>(data_ptr);
+  if (*data->expected_value == value) {
+    data->done = true;
+  } else {
+    data->last_read_serial = serial;
+  }
+}
+
+void WaitForProperty(const std::string& key, const std::string& expected_value) {
+  // Find the property's prop_info*.
+  const prop_info* pi;
+  unsigned global_serial = 0;
+  while ((pi = __system_property_find(key.c_str())) == nullptr) {
+    // The property doesn't even exist yet.
+    // Wait for a global change and then look again.
+    global_serial = __system_property_wait_any(global_serial);
+  }
+
+  WaitForPropertyData data;
+  data.expected_value = &expected_value;
+  data.done = false;
+  while (true) {
+    // Check whether the property has the value we're looking for?
+    __system_property_read_callback(pi, WaitForPropertyCallback, &data);
+    if (data.done) return;
+
+    // It didn't so wait for it to change before checking again.
+    __system_property_wait(pi, data.last_read_serial);
+  }
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index da89ec5..d8186be 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -18,7 +18,12 @@
 
 #include <gtest/gtest.h>
 
+#include <atomic>
+#include <chrono>
 #include <string>
+#include <thread>
+
+using namespace std::chrono_literals;
 
 TEST(properties, smoke) {
   android::base::SetProperty("debug.libbase.property_test", "hello");
@@ -119,3 +124,18 @@
 TEST(properties, GetUintProperty_uint16_t) { CheckGetUintProperty<uint16_t>(); }
 TEST(properties, GetUintProperty_uint32_t) { CheckGetUintProperty<uint32_t>(); }
 TEST(properties, GetUintProperty_uint64_t) { CheckGetUintProperty<uint64_t>(); }
+
+TEST(properties, WaitForProperty) {
+  std::atomic<bool> flag{false};
+  std::thread thread([&]() {
+    std::this_thread::sleep_for(100ms);
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+    while (!flag) std::this_thread::yield();
+    android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+  });
+
+  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a");
+  flag = true;
+  android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b");
+  thread.join();
+}
diff --git a/base/strings.cpp b/base/strings.cpp
index 46fe939..bfdaf12 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -36,11 +36,12 @@
 
   size_t base = 0;
   size_t found;
-  do {
+  while (true) {
     found = s.find_first_of(delimiters, base);
     result.push_back(s.substr(base, found - base));
+    if (found == s.npos) break;
     base = found + 1;
-  } while (found != s.npos);
+  }
 
   return result;
 }
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 7a65a00..7ed5b2b 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -251,3 +251,7 @@
   ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "bar"));
   ASSERT_FALSE(android::base::EqualsIgnoreCase("foo", "fool"));
 }
+
+TEST(strings, ubsan_28729303) {
+  android::base::Split("/dev/null", ":");
+}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 3b3d698..636477d 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -57,7 +57,13 @@
 
 static std::string GetSystemTempDir() {
 #if defined(__ANDROID__)
-  return "/data/local/tmp";
+  const char* tmpdir = "/data/local/tmp";
+  if (access(tmpdir, R_OK | W_OK | X_OK) == 0) {
+    return tmpdir;
+  }
+  // Tests running in app context can't access /data/local/tmp,
+  // so try current directory if /data/local/tmp is not accessible.
+  return ".";
 #elif defined(_WIN32)
   char tmp_dir[MAX_PATH];
   DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index d98a9d7..f744ad1 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -16,7 +16,6 @@
 
 bootstat_lib_src_files = [
     "boot_event_record_store.cpp",
-    "histogram_logger.cpp",
     "uptime_parser.cpp",
 ]
 
@@ -27,15 +26,12 @@
         "-Wall",
         "-Wextra",
         "-Werror",
-
-        // 524291 corresponds to sysui_histogram, from
-        // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
-        "-DHISTOGRAM_LOG_TAG=524291",
     ],
     shared_libs: [
         "libbase",
         "libcutils",
         "liblog",
+        "libmetricslogger",
     ],
     whole_static_libs: ["libgtest_prod"],
     // Clang is required because of C++14
diff --git a/bootstat/boot_event_record_store.cpp b/bootstat/boot_event_record_store.cpp
index f902af3..2648594 100644
--- a/bootstat/boot_event_record_store.cpp
+++ b/bootstat/boot_event_record_store.cpp
@@ -26,7 +26,6 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
-#include "histogram_logger.h"
 #include "uptime_parser.h"
 
 namespace {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index c85667e..a7354a7 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -35,9 +35,9 @@
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <cutils/properties.h>
+#include <metricslogger/metrics_logger.h>
 
 #include "boot_event_record_store.h"
-#include "histogram_logger.h"
 #include "uptime_parser.h"
 
 namespace {
@@ -49,7 +49,7 @@
 
   auto events = boot_event_store.GetAllBootEvents();
   for (auto i = events.cbegin(); i != events.cend(); ++i) {
-    bootstat::LogHistogram(i->first, i->second);
+    android::metricslogger::LogHistogram(i->first, i->second);
   }
 }
 
@@ -317,18 +317,18 @@
 
   if (current_time_utc < 0) {
     // UMA does not display negative values in buckets, so convert to positive.
-    bootstat::LogHistogram(
+    android::metricslogger::LogHistogram(
         "factory_reset_current_time_failure", std::abs(current_time_utc));
 
-    // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
     boot_event_store.AddBootEventWithValue(
         "factory_reset_current_time_failure", std::abs(current_time_utc));
     return;
   } else {
-    bootstat::LogHistogram("factory_reset_current_time", current_time_utc);
+    android::metricslogger::LogHistogram("factory_reset_current_time", current_time_utc);
 
-    // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+    // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
     // is losing records somehow.
     boot_event_store.AddBootEventWithValue(
         "factory_reset_current_time", current_time_utc);
@@ -347,9 +347,9 @@
   // Calculate and record the difference in time between now and the
   // factory_reset time.
   time_t factory_reset_utc = record.second;
-  bootstat::LogHistogram("factory_reset_record_value", factory_reset_utc);
+  android::metricslogger::LogHistogram("factory_reset_record_value", factory_reset_utc);
 
-  // Logging via BootEventRecordStore to see if using bootstat::LogHistogram
+  // Logging via BootEventRecordStore to see if using android::metricslogger::LogHistogram
   // is losing records somehow.
   boot_event_store.AddBootEventWithValue(
       "factory_reset_record_value", factory_reset_utc);
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 002e940..e22d6a9 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -407,3 +407,35 @@
   });
   AssertDeath(SIGUSR1);
 }
+
+TEST(crash_dump, zombie) {
+  pid_t forkpid = fork();
+
+  int pipefd[2];
+  ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
+
+  pid_t rc;
+  int status;
+
+  if (forkpid == 0) {
+    errno = 0;
+    rc = waitpid(-1, &status, WNOHANG | __WALL | __WNOTHREAD);
+    if (rc != -1 || errno != ECHILD) {
+      errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+    }
+
+    raise(DEBUGGER_SIGNAL);
+
+    errno = 0;
+    rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+    if (rc != -1 || errno != ECHILD) {
+      errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
+    }
+    _exit(0);
+  } else {
+    rc = waitpid(forkpid, &status, 0);
+    ASSERT_EQ(forkpid, rc);
+    ASSERT_TRUE(WIFEXITED(status));
+    ASSERT_EQ(0, WEXITSTATUS(status));
+  }
+}
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 38a7be3..353f642 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -249,7 +249,7 @@
 
     // Don't leave a zombie child.
     int status;
-    if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, __WCLONE)) == -1 && errno != ECHILD) {
+    if (TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0)) == -1) {
       __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s",
                         strerror(errno));
     } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 94b43e4..e957f6b 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -25,6 +25,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <cutils/properties.h>
 
 #include "fs_mgr.h"
@@ -77,8 +80,51 @@
     return 0;
 }
 
-// Gets slot_suffix from either the kernel cmdline / firmware or the
-// misc partition. Sets |out_suffix| on success and returns 0. Returns
+// finds slot_suffix in androidboot.slot_suffix kernel command line argument
+// or in the device tree node at /firmware/android/slot_suffix property
+static int get_active_slot_suffix_from_kernel(char *out_suffix,
+                                              size_t suffix_len)
+{
+    std::string cmdline;
+    if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+        for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+            std::vector<std::string> pieces = android::base::Split(entry, "=");
+            if (pieces.size() == 2) {
+                if (pieces[0] == "androidboot.slot_suffix") {
+                    strncpy(out_suffix, pieces[1].c_str(), suffix_len);
+                    return 0;
+                }
+            }
+        }
+    }
+
+    // if we can't find slot_suffix in cmdline, check the DT
+    static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
+    std::string file_name = android::base::StringPrintf("%s/compatible", android_dt_dir);
+    std::string dt_value;
+    if (android::base::ReadFileToString(file_name, &dt_value)) {
+        if (!dt_value.compare("android,firmware")) {
+            LERROR << "Error finding compatible android DT node";
+            return -1;
+        }
+
+        file_name = android::base::StringPrintf("%s/%s", android_dt_dir, "slot_suffix");
+        if (!android::base::ReadFileToString(file_name, &dt_value)) {
+            LERROR << "Error finding slot_suffix in device tree";
+            return -1;
+        }
+
+        // DT entries have a terminating '\0', so 'suffix_len' is safe.
+        strncpy(out_suffix, dt_value.c_str(), suffix_len);
+        return 0;
+    }
+
+    // slot_suffix missing in kernel cmdline or device tree
+    return -1;
+}
+
+// Gets slot_suffix from either the kernel cmdline / device tree / firmware
+// or the misc partition. Sets |out_suffix| on success and returns 0. Returns
 // -1 if slot_suffix could not be determined.
 static int get_active_slot_suffix(struct fstab *fstab, char *out_suffix,
                                   size_t suffix_len)
@@ -94,6 +140,15 @@
         return 0;
     }
 
+    // if the property is not set, we are either being invoked too early
+    // or the slot suffix in mentioned in the misc partition. If its
+    // "too early", try to find the slotsuffix ourselves in the kernel command
+    // line or the device tree
+    if (get_active_slot_suffix_from_kernel(out_suffix, suffix_len) == 0) {
+        LINFO << "Using slot suffix '" << out_suffix << "' from kernel";
+        return 0;
+    }
+
     // If we couldn't get the suffix from the kernel cmdline, try the
     // the misc partition.
     if (get_active_slot_suffix_from_misc(fstab, out_suffix, suffix_len) == 0) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index d959798..a9deed9 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -123,6 +123,7 @@
 int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
 int fs_mgr_is_notrim(struct fstab_rec *fstab);
 int fs_mgr_is_formattable(struct fstab_rec *fstab);
+int fs_mgr_is_slotselect(struct fstab_rec *fstab);
 int fs_mgr_is_nofail(struct fstab_rec *fstab);
 int fs_mgr_is_latemount(struct fstab_rec *fstab);
 int fs_mgr_is_quota(struct fstab_rec *fstab);
diff --git a/init/devices.cpp b/init/devices.cpp
index 6af237c..b3b808b 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -62,19 +62,7 @@
 
 extern struct selabel_handle *sehandle;
 
-static int device_fd = -1;
-
-struct uevent {
-    const char *action;
-    const char *path;
-    const char *subsystem;
-    const char *firmware;
-    const char *partition_name;
-    const char *device_name;
-    int partition_num;
-    int major;
-    int minor;
-};
+static android::base::unique_fd device_fd;
 
 struct perms_ {
     char *name;
@@ -249,11 +237,13 @@
 
     mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
 
-    if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
-        PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
-        return;
+    if (sehandle) {
+        if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
+            PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
+            return;
+        }
+        setfscreatecon(secontext);
     }
-    setfscreatecon(secontext);
 
     dev = makedev(major, minor);
     /* Temporarily change egid to avoid race condition setting the gid of the
@@ -264,7 +254,7 @@
     setegid(gid);
     /* 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 (mknod(path, mode, dev) && (errno == EEXIST) && secontext) {
 
         char* fcon = nullptr;
         int rc = lgetfilecon(path, &fcon);
@@ -285,8 +275,10 @@
     chown(path, uid, -1);
     setegid(AID_ROOT);
 
-    freecon(secontext);
-    setfscreatecon(NULL);
+    if (secontext) {
+        freecon(secontext);
+        setfscreatecon(NULL);
+    }
 }
 
 static void add_platform_device(const char *path)
@@ -349,6 +341,19 @@
     }
 }
 
+static void destroy_platform_devices() {
+    struct listnode* node;
+    struct listnode* n;
+    struct platform_node* bus;
+
+    list_for_each_safe(node, n, &platform_names) {
+        list_remove(node);
+        bus = node_to_item(node, struct platform_node, list);
+        free(bus->path);
+        free(bus);
+    }
+}
+
 /* Given a path that may start with a PCI device, populate the supplied buffer
  * with the PCI domain/bus number and the peripheral ID and return 0.
  * If it doesn't start with a PCI device, or there is some error, return -1 */
@@ -515,7 +520,7 @@
         return NULL;
     memset(links, 0, sizeof(char *) * 4);
 
-    LOG(INFO) << "found " << type << " device " << device;
+    LOG(VERBOSE) << "found " << type << " device " << device;
 
     snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
 
@@ -875,9 +880,15 @@
     }
 }
 
+static bool inline should_stop_coldboot(coldboot_action_t act)
+{
+    return (act == COLDBOOT_STOP || act == COLDBOOT_FINISH);
+}
+
 #define UEVENT_MSG_LEN  2048
 
-static inline void handle_device_fd_with(void (handle_uevent)(struct uevent*))
+static inline coldboot_action_t handle_device_fd_with(
+        std::function<coldboot_action_t(uevent* uevent)> handle_uevent)
 {
     char msg[UEVENT_MSG_LEN+2];
     int n;
@@ -890,14 +901,18 @@
 
         struct uevent uevent;
         parse_event(msg, &uevent);
-        handle_uevent(&uevent);
+        coldboot_action_t act = handle_uevent(&uevent);
+        if (should_stop_coldboot(act))
+            return act;
     }
+
+    return COLDBOOT_CONTINUE;
 }
 
-void handle_device_fd()
+coldboot_action_t handle_device_fd(coldboot_callback fn)
 {
-    handle_device_fd_with(
-        [](struct uevent *uevent) {
+    coldboot_action_t ret = handle_device_fd_with(
+        [&](uevent* uevent) -> coldboot_action_t {
             if (selinux_status_updated() > 0) {
                 struct selabel_handle *sehandle2;
                 sehandle2 = selinux_android_file_context_handle();
@@ -907,9 +922,21 @@
                 }
             }
 
-            handle_device_event(uevent);
-            handle_firmware_event(uevent);
+            // default is to always create the devices
+            coldboot_action_t act = COLDBOOT_CREATE;
+            if (fn) {
+                act = fn(uevent);
+            }
+
+            if (act == COLDBOOT_CREATE || act == COLDBOOT_STOP) {
+                handle_device_event(uevent);
+                handle_firmware_event(uevent);
+            }
+
+            return act;
         });
+
+    return ret;
 }
 
 /* Coldboot walks parts of the /sys tree and pokes the uevent files
@@ -921,21 +948,24 @@
 ** socket's buffer.
 */
 
-static void do_coldboot(DIR *d)
+static coldboot_action_t do_coldboot(DIR *d, coldboot_callback fn)
 {
     struct dirent *de;
     int dfd, fd;
+    coldboot_action_t act = COLDBOOT_CONTINUE;
 
     dfd = dirfd(d);
 
     fd = openat(dfd, "uevent", O_WRONLY);
-    if(fd >= 0) {
+    if (fd >= 0) {
         write(fd, "add\n", 4);
         close(fd);
-        handle_device_fd();
+        act = handle_device_fd(fn);
+        if (should_stop_coldboot(act))
+            return act;
     }
 
-    while((de = readdir(d))) {
+    while (!should_stop_coldboot(act) && (de = readdir(d))) {
         DIR *d2;
 
         if(de->d_type != DT_DIR || de->d_name[0] == '.')
@@ -949,85 +979,31 @@
         if(d2 == 0)
             close(fd);
         else {
-            do_coldboot(d2);
+            act = do_coldboot(d2, fn);
             closedir(d2);
         }
     }
+
+    // default is always to continue looking for uevents
+    return act;
 }
 
-static void coldboot(const char *path)
+static coldboot_action_t coldboot(const char *path, coldboot_callback fn)
 {
     std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
-    if(d) {
-        do_coldboot(d.get());
-    }
-}
-
-static void early_uevent_handler(struct uevent *uevent, const char *base, bool is_block)
-{
-    const char *name;
-    char devpath[DEVPATH_LEN];
-
-    if (is_block && strncmp(uevent->subsystem, "block", 5))
-        return;
-
-    name = parse_device_name(uevent, MAX_DEV_NAME);
-    if (!name) {
-        LOG(ERROR) << "Failed to parse dev name from uevent: " << uevent->action
-                   << " " << uevent->partition_name << " " << uevent->partition_num
-                   << " " << uevent->major << ":" << uevent->minor;
-        return;
+    if (d) {
+        return do_coldboot(d.get(), fn);
     }
 
-    snprintf(devpath, sizeof(devpath), "%s%s", base, name);
-    make_dir(base, 0755);
-
-    dev_t dev = makedev(uevent->major, uevent->minor);
-    mode_t mode = 0600 | (is_block ? S_IFBLK : S_IFCHR);
-    mknod(devpath, mode, dev);
+    return COLDBOOT_CONTINUE;
 }
 
-void early_create_dev(const std::string& syspath, early_device_type dev_type)
-{
-    android::base::unique_fd dfd(open(syspath.c_str(), O_RDONLY));
-    if (dfd < 0) {
-        LOG(ERROR) << "Failed to open " << syspath;
-        return;
-    }
-
-    android::base::unique_fd fd(openat(dfd, "uevent", O_WRONLY));
-    if (fd < 0) {
-        LOG(ERROR) << "Failed to open " << syspath << "/uevent";
-        return;
-    }
-
-    fcntl(device_fd, F_SETFL, O_NONBLOCK);
-
-    write(fd, "add\n", 4);
-    handle_device_fd_with(dev_type == EARLY_BLOCK_DEV ?
-        [](struct uevent *uevent) {
-            early_uevent_handler(uevent, "/dev/block/", true);
-        } :
-        [](struct uevent *uevent) {
-            early_uevent_handler(uevent, "/dev/", false);
-        });
-}
-
-int early_device_socket_open() {
-    device_fd = uevent_open_socket(256*1024, true);
-    return device_fd < 0;
-}
-
-void early_device_socket_close() {
-    close(device_fd);
-}
-
-void device_init() {
+void device_init(const char* path, coldboot_callback fn) {
     sehandle = selinux_android_file_context_handle();
     selinux_status_open(true);
 
     /* is 256K enough? udev uses 16MB! */
-    device_fd = uevent_open_socket(256*1024, true);
+    device_fd.reset(uevent_open_socket(256*1024, true));
     if (device_fd == -1) {
         return;
     }
@@ -1039,13 +1015,33 @@
     }
 
     Timer t;
-    coldboot("/sys/class");
-    coldboot("/sys/block");
-    coldboot("/sys/devices");
-    close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+    coldboot_action_t act;
+    if (!path) {
+        act = coldboot("/sys/class", fn);
+        if (!should_stop_coldboot(act)) {
+            act = coldboot("/sys/block", fn);
+            if (!should_stop_coldboot(act)) {
+                act = coldboot("/sys/devices", fn);
+            }
+        }
+    } else {
+        act = coldboot(path, fn);
+    }
+
+    // If we have a callback, then do as it says. If no, then the default is
+    // to always create COLDBOOT_DONE file.
+    if (!fn || (act == COLDBOOT_FINISH)) {
+        close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
+    }
+
     LOG(INFO) << "Coldboot took " << t;
 }
 
+void device_close() {
+    destroy_platform_devices();
+    device_fd.reset();
+}
+
 int get_device_fd() {
     return device_fd;
 }
diff --git a/init/devices.h b/init/devices.h
index 8e9ab7d..26a064b 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -17,16 +17,37 @@
 #ifndef _INIT_DEVICES_H
 #define _INIT_DEVICES_H
 
+#include <functional>
 #include <sys/stat.h>
 
-extern void handle_device_fd();
-extern void device_init(void);
+enum coldboot_action_t {
+    // coldboot continues without creating the device for the uevent
+    COLDBOOT_CONTINUE = 0,
+    // coldboot continues after creating the device for the uevent
+    COLDBOOT_CREATE,
+    // coldboot stops after creating the device for uevent but doesn't
+    // create the COLDBOOT_DONE file
+    COLDBOOT_STOP,
+    // same as COLDBOOT_STOP, but creates the COLDBOOT_DONE file
+    COLDBOOT_FINISH
+};
 
-enum early_device_type { EARLY_BLOCK_DEV, EARLY_CHAR_DEV };
+struct uevent {
+    const char* action;
+    const char* path;
+    const char* subsystem;
+    const char* firmware;
+    const char* partition_name;
+    const char* device_name;
+    int partition_num;
+    int major;
+    int minor;
+};
 
-extern int early_device_socket_open();
-extern void early_device_socket_close();
-extern void early_create_dev(const std::string& syspath, early_device_type dev_type);
+typedef std::function<coldboot_action_t(struct uevent* uevent)> coldboot_callback;
+extern coldboot_action_t handle_device_fd(coldboot_callback fn = nullptr);
+extern void device_init(const char* path = nullptr, coldboot_callback fn = nullptr);
+extern void device_close();
 
 extern int add_dev_perms(const char *name, const char *attr,
                          mode_t perm, unsigned int uid,
diff --git a/init/init.cpp b/init/init.cpp
index 43f601f..9c1e23b 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -495,28 +495,48 @@
     }
 }
 
-static void process_kernel_dt() {
-    static const char android_dir[] = "/proc/device-tree/firmware/android";
+static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";
 
-    std::string file_name = StringPrintf("%s/compatible", android_dir);
+static bool is_dt_compatible() {
+    std::string dt_value;
+    std::string file_name = StringPrintf("%s/compatible", android_dt_dir);
 
-    std::string dt_file;
-    android::base::ReadFileToString(file_name, &dt_file);
-    if (!dt_file.compare("android,firmware")) {
+    android::base::ReadFileToString(file_name, &dt_value);
+    if (!dt_value.compare("android,firmware")) {
         LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
-        return;
+        return false;
     }
 
-    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
+    return true;
+}
+
+static bool is_dt_fstab_compatible() {
+    std::string dt_value;
+    std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");
+
+    android::base::ReadFileToString(file_name, &dt_value);
+    if (!dt_value.compare("android,fstab")) {
+        LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
+        return false;
+    }
+
+    return true;
+}
+
+static void process_kernel_dt() {
+    if (!is_dt_compatible()) return;
+
+    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
     if (!dir) return;
 
+    std::string dt_file;
     struct dirent *dp;
     while ((dp = readdir(dir.get())) != NULL) {
         if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
             continue;
         }
 
-        file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
+        std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);
 
         android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -643,102 +663,208 @@
     }
 }
 
-/* Returns a new path consisting of base_path and the file name in reference_path. */
-static std::string get_path(const std::string& base_path, const std::string& reference_path) {
-    std::string::size_type pos = reference_path.rfind('/');
-    if (pos == std::string::npos) {
-        return base_path + '/' + reference_path;
-    } else {
-        return base_path + reference_path.substr(pos);
+static std::string import_dt_fstab() {
+    std::string fstab;
+    if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+        return fstab;
     }
-}
 
-/* Imports the fstab info from cmdline. */
-static std::string import_cmdline_fstab() {
-    std::string prefix, fstab, fstab_full;
+    std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
+    std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
+    if (!fstabdir) return fstab;
 
-    import_kernel_cmdline(false,
-        [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
-            if (key == "android.early.prefix") {
-                prefix = value;
-            } else if (key == "android.early.fstab") {
-                fstab = value;
-            }
-        });
-    if (!fstab.empty()) {
-        // Convert "mmcblk0p09+/odm+ext4+ro+verify" to "mmcblk0p09 /odm ext4 ro verify"
-        std::replace(fstab.begin(), fstab.end(), '+', ' ');
-        for (const auto& entry : android::base::Split(fstab, "\n")) {
-            fstab_full += prefix + entry + '\n';
+    dirent* dp;
+    while ((dp = readdir(fstabdir.get())) != NULL) {
+        // skip over name and compatible
+        if (dp->d_type != DT_DIR) {
+            continue;
         }
+
+        // skip if its not 'vendor', 'odm' or 'system'
+        if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
+            strcmp(dp->d_name, "vendor")) {
+            continue;
+        }
+
+        // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
+        std::vector<std::string> fstab_entry;
+        std::string file_name;
+        std::string value;
+        file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        // trim the terminating '\0' out
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+        fstab_entry.push_back(StringPrintf("/%s", dp->d_name));
+
+        file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+        if (!android::base::ReadFileToString(file_name, &value)) {
+            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
+            fstab.clear();
+            break;
+        }
+        value.resize(value.size() - 1);
+        fstab_entry.push_back(value);
+
+        fstab += android::base::Join(fstab_entry, " ");
+        fstab += '\n';
     }
-    return fstab_full;
+
+    return fstab;
 }
 
-/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
-static void early_mount() {
-    std::string fstab_string = import_cmdline_fstab();
-    if (fstab_string.empty()) {
-        LOG(INFO) << "Failed to load vendor fstab from kernel cmdline";
-        return;
+/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
+static bool early_mount() {
+    std::string fstab = import_dt_fstab();
+    if (fstab.empty()) {
+        LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
+        return true;
     }
-    FILE *fstab_file = fmemopen((void *)fstab_string.c_str(), fstab_string.length(), "r");
+
+    std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
+        fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
     if (!fstab_file) {
-        PLOG(ERROR) << "Failed to open fstab string as FILE";
-        return;
-    }
-    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_file(fstab_file), fs_mgr_free_fstab);
-    fclose(fstab_file);
-    if (!fstab) {
-        LOG(ERROR) << "Failed to parse fstab string: " << fstab_string;
-        return;
-    }
-    LOG(INFO) << "Loaded vendor fstab from cmdline";
-
-    if (early_device_socket_open()) {
-        LOG(ERROR) << "Failed to open device uevent socket";
-        return;
+        PLOG(ERROR) << "Early mount failed to open fstab file in memory";
+        return false;
     }
 
-    /* Create /dev/device-mapper for dm-verity */
-    early_create_dev("/sys/devices/virtual/misc/device-mapper", EARLY_CHAR_DEV);
+    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
+        fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
+    if (!tab) {
+        LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
+        return false;
+    }
 
-    for (int i = 0; i < fstab->num_entries; ++i) {
-        struct fstab_rec *rec = &fstab->recs[i];
-        std::string mount_point = rec->mount_point;
-        std::string syspath = rec->blk_device;
+    // find out fstab records for odm, system and vendor
+    fstab_rec* odm_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/odm");
+    fstab_rec* system_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/system");
+    fstab_rec* vendor_rec = fs_mgr_get_entry_for_mount_point(tab.get(), "/vendor");
+    if (!odm_rec && !system_rec && !vendor_rec) {
+        // nothing to early mount
+        return true;
+    }
 
-        if (mount_point != "/vendor" && mount_point != "/odm")
-            continue;
+    // assume A/B device if we find 'slotselect' in any fstab entry
+    bool is_ab = ((odm_rec && fs_mgr_is_slotselect(odm_rec)) ||
+                  (system_rec && fs_mgr_is_slotselect(system_rec)) ||
+                  (vendor_rec && fs_mgr_is_slotselect(vendor_rec)));
+    bool found_odm = !odm_rec;
+    bool found_system = !system_rec;
+    bool found_vendor = !vendor_rec;
+    int count_odm = 0, count_vendor = 0, count_system = 0;
 
-        /* Create mount target under /dev/block/ from sysfs via uevent */
-        LOG(INFO) << "Mounting " << mount_point << " from " << syspath << "...";
-        char *devpath = strdup(get_path("/dev/block", syspath).c_str());
-        if (!devpath) {
-            PLOG(ERROR) << "Failed to strdup dev path in early mount " << syspath;
-            continue;
-        }
-        rec->blk_device = devpath;
-        early_create_dev(syspath, EARLY_BLOCK_DEV);
-
-        int rc = fs_mgr_early_setup_verity(rec);
-        if (rc == FS_MGR_EARLY_SETUP_VERITY_SUCCESS) {
-            /* Mount target is changed to /dev/block/dm-<n>; initiate its creation from sysfs counterpart */
-            early_create_dev(get_path("/sys/devices/virtual/block", rec->blk_device), EARLY_BLOCK_DEV);
-        } else if (rc == FS_MGR_EARLY_SETUP_VERITY_FAIL) {
-            LOG(ERROR) << "Failed to set up dm-verity on " << rec->blk_device;
-            continue;
-        } else { /* FS_MGR_EARLY_SETUP_VERITY_NO_VERITY */
-            LOG(INFO) << "dm-verity disabled on debuggable device; mount directly on " << rec->blk_device;
+    // create the devices we need..
+    device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
+        if (!strncmp(uevent->subsystem, "firmware", 8)) {
+            return COLDBOOT_CONTINUE;
         }
 
-        mkdir(mount_point.c_str(), 0755);
-        rc = mount(rec->blk_device, mount_point.c_str(), rec->fs_type, rec->flags, rec->fs_options);
-        if (rc) {
-            PLOG(ERROR) << "Failed to mount on " << rec->blk_device;
+        // we need platform devices to create symlinks
+        if (!strncmp(uevent->subsystem, "platform", 8)) {
+            return COLDBOOT_CREATE;
         }
+
+        // Ignore everything that is not a block device
+        if (strncmp(uevent->subsystem, "block", 5)) {
+            return COLDBOOT_CONTINUE;
+        }
+
+        coldboot_action_t ret;
+        bool create_this_node = false;
+        if (uevent->partition_name) {
+            // prefix match partition names so we create device nodes for
+            // A/B-ed partitions
+            if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
+                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+                // wait twice for A/B-ed partitions
+                count_odm++;
+                if (!is_ab) {
+                    found_odm = true;
+                } else if (count_odm == 2) {
+                    found_odm = true;
+                }
+
+                create_this_node = true;
+            } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
+                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+
+                count_system++;
+                if (!is_ab) {
+                    found_system = true;
+                } else if (count_system == 2) {
+                    found_system = true;
+                }
+
+                create_this_node = true;
+            } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
+                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
+                count_vendor++;
+                if (!is_ab) {
+                    found_vendor = true;
+                } else if (count_vendor == 2) {
+                    found_vendor = true;
+                }
+
+                create_this_node = true;
+            }
+        }
+
+        // if we found all other partitions already, create this
+        // node and stop coldboot. If this is a prefix matched
+        // partition, create device node and continue. For everything
+        // else skip the device node
+        if (found_odm && found_system && found_vendor) {
+            ret = COLDBOOT_STOP;
+        } else if (create_this_node) {
+            ret = COLDBOOT_CREATE;
+        } else {
+            ret = COLDBOOT_CONTINUE;
+        }
+
+        return ret;
+    });
+
+    // TODO: add support to mount partitions w/ verity
+
+    int ret = 0;
+    if (odm_rec &&
+        (ret = fs_mgr_do_mount(tab.get(), odm_rec->mount_point, odm_rec->blk_device, NULL))) {
+        PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting odm";
+        return false;
     }
-    early_device_socket_close();
+
+    if (vendor_rec &&
+        (ret = fs_mgr_do_mount(tab.get(), vendor_rec->mount_point, vendor_rec->blk_device, NULL))) {
+        PLOG(ERROR) << "early_mount: fs_mgr_do_mount returned error for mounting vendor";
+        return false;
+    }
+
+    device_close();
+
+    return true;
 }
 
 int main(int argc, char** argv) {
@@ -787,8 +913,10 @@
     LOG(INFO) << "init " << (is_first_stage ? "first" : "second") << " stage started!";
 
     if (is_first_stage) {
-        // Mount devices defined in android.early.* kernel commandline
-        early_mount();
+        if (!early_mount()) {
+            LOG(ERROR) << "Failed to mount required partitions early ...";
+            panic();
+        }
 
         // Set up SELinux, loading the SELinux policy.
         selinux_initialize(true);
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 5e54328..0a2f5a3 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -21,6 +21,7 @@
 #include <dwarf.h>
 }
 
+#include <pthread.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -30,6 +31,7 @@
 #include <unistd.h>
 
 #include <memory>
+#include <mutex>
 #include <string>
 #include <vector>
 
@@ -90,9 +92,6 @@
       has_debug_frame(false), has_gnu_debugdata(false) { }
 };
 
-static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>& g_debug_frames =
-    *new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
-
 void Space::Clear() {
   start = 0;
   end = 0;
@@ -282,39 +281,14 @@
 
   // vaddr in the elf file.
   uint64_t ip_vaddr = ip - map.start + debug_frame->min_vaddr;
-  if (debug_frame->has_arm_exidx) {
-    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
-    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
-      // Use binary search to find the correct function.
-      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
-                                 static_cast<uint32_t>(ip_vaddr));
-      if (it != func_vaddrs.begin()) {
-        --it;
-        // Found the exidx entry.
-        size_t index = it - func_vaddrs.begin();
 
-        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
-        proc_info->unwind_info = reinterpret_cast<void*>(
-            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
-                                   debug_frame->arm_exidx.exidx_vaddr +
-                                   debug_frame->min_vaddr));
-
-        // Prepare arm_exidx space and arm_extab space.
-        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
-        arm_exidx_space_.end = arm_exidx_space_.start +
-            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
-        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
-            debug_frame->arm_exidx.exidx_data.data());
-
-        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
-        arm_extab_space_.end = arm_extab_space_.start +
-            debug_frame->arm_exidx.extab_data.size();
-        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
-        return true;
-      }
-    }
-  }
-
+  // The unwind info can come from .ARM.exidx or .eh_frame, or .debug_frame/.gnu_debugdata.
+  // First check .eh_frame/.debug_frame, then check .ARM.exidx. Because .eh_frame/.debug_frame has
+  // function range for each entry, by matching ip address with the function range, we know exactly
+  // whether the ip address hits an entry. But .ARM.exidx doesn't have function range for each
+  // entry, it thinks that an ip address hits an entry when (entry.addr <= ip < next_entry.addr).
+  // To prevent ip addresses hit in .eh_frame/.debug_frame being regarded as addresses hit in
+  // .ARM.exidx, we need to check .eh_frame/.debug_frame first.
   if (debug_frame->has_eh_frame) {
     if (ip_vaddr >= debug_frame->eh_frame.min_func_vaddr &&
         ip_vaddr < debug_frame->text_end_vaddr) {
@@ -323,7 +297,6 @@
       eh_frame_hdr_space_.end =
           eh_frame_hdr_space_.start + debug_frame->eh_frame.hdr_data.size();
       eh_frame_hdr_space_.data = debug_frame->eh_frame.hdr_data.data();
-
       eh_frame_space_.start = ip - ip_vaddr + debug_frame->eh_frame.vaddr;
       eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.data.size();
       eh_frame_space_.data = debug_frame->eh_frame.data.data();
@@ -345,7 +318,6 @@
       }
     }
   }
-
   if (debug_frame->has_debug_frame || debug_frame->has_gnu_debugdata) {
     unw_dyn_info_t di;
     unw_word_t segbase = map.start - map.offset;
@@ -359,6 +331,40 @@
       }
     }
   }
+
+  if (debug_frame->has_arm_exidx) {
+    auto& func_vaddrs = debug_frame->arm_exidx.func_vaddr_array;
+    if (ip_vaddr >= func_vaddrs[0] && ip_vaddr < debug_frame->text_end_vaddr) {
+      // Use binary search to find the correct function.
+      auto it = std::upper_bound(func_vaddrs.begin(), func_vaddrs.end(),
+                                 static_cast<uint32_t>(ip_vaddr));
+      if (it != func_vaddrs.begin()) {
+        --it;
+        // Found the exidx entry.
+        size_t index = it - func_vaddrs.begin();
+        proc_info->start_ip = *it;
+        proc_info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+        proc_info->unwind_info = reinterpret_cast<void*>(
+            static_cast<uintptr_t>(index * sizeof(ArmIdxEntry) +
+                                   debug_frame->arm_exidx.exidx_vaddr +
+                                   debug_frame->min_vaddr));
+        eh_frame_hdr_space_.Clear();
+        eh_frame_space_.Clear();
+        // Prepare arm_exidx space and arm_extab space.
+        arm_exidx_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.exidx_vaddr;
+        arm_exidx_space_.end = arm_exidx_space_.start +
+            debug_frame->arm_exidx.exidx_data.size() * sizeof(ArmIdxEntry);
+        arm_exidx_space_.data = reinterpret_cast<const uint8_t*>(
+            debug_frame->arm_exidx.exidx_data.data());
+
+        arm_extab_space_.start = debug_frame->min_vaddr + debug_frame->arm_exidx.extab_vaddr;
+        arm_extab_space_.end = arm_extab_space_.start +
+            debug_frame->arm_exidx.extab_data.size();
+        arm_extab_space_.data = debug_frame->arm_exidx.extab_data.data();
+        return true;
+      }
+    }
+  }
   return false;
 }
 
@@ -549,18 +555,31 @@
   return "";
 }
 
+static std::mutex g_lock;
+static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>* g_debug_frames = nullptr;
+
 static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
 
 DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
   if (cache_file_) {
-    auto it = g_debug_frames.find(filename);
-    if (it != g_debug_frames.end()) {
-      return it->second.get();
+    std::lock_guard<std::mutex> lock(g_lock);
+    if (g_debug_frames != nullptr) {
+      auto it = g_debug_frames->find(filename);
+      if (it != g_debug_frames->end()) {
+        return it->second.get();
+      }
     }
   }
   DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
   if (cache_file_) {
-      g_debug_frames.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+    std::lock_guard<std::mutex> lock(g_lock);
+    if (g_debug_frames == nullptr) {
+      g_debug_frames = new std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>>;
+    }
+    auto pair = g_debug_frames->emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
+    if (!pair.second) {
+      debug_frame = pair.first->second.get();
+    }
   }
   return debug_frame;
 }
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 49fcb29..465b3f9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -220,25 +220,7 @@
 #endif
 }
 
-static void BacktraceOfflineTest(const std::string& testlib_name) {
-  const std::string arch = GetArch();
-  if (arch.empty()) {
-    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
-    return;
-  }
-  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
-  std::string testdata;
-  ASSERT_TRUE(android::base::ReadFileToString(offline_testdata_path, &testdata));
-
-  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
-  struct stat st;
-  if (stat(testlib_path.c_str(), &st) == -1) {
-    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
-    return;
-  }
-
-  // Parse offline_testdata.
-  std::vector<std::string> lines = android::base::Split(testdata, "\n");
+struct OfflineTestData {
   int pid;
   int tid;
   std::vector<backtrace_map_t> maps;
@@ -246,63 +228,93 @@
   backtrace_stackinfo_t stack_info;
   std::vector<uint8_t> stack;
   std::vector<FunctionSymbol> symbols;
+};
+
+bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) {
+  std::string s;
+  if (!android::base::ReadFileToString(offline_testdata_path, &s)) {
+    return false;
+  }
+  // Parse offline_testdata.
+  std::vector<std::string> lines = android::base::Split(s, "\n");
+  memset(&testdata->unw_context, 0, sizeof(testdata->unw_context));
   for (const auto& line : lines) {
     if (android::base::StartsWith(line, "pid:")) {
-      sscanf(line.c_str(), "pid: %d tid: %d", &pid, &tid);
+      sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid);
     } else if (android::base::StartsWith(line, "map:")) {
-      maps.resize(maps.size() + 1);
+      testdata->maps.resize(testdata->maps.size() + 1);
+      backtrace_map_t& map = testdata->maps.back();
       int pos;
       sscanf(line.c_str(),
              "map: start: %" SCNxPTR " end: %" SCNxPTR " offset: %" SCNxPTR
              " load_base: %" SCNxPTR " flags: %d name: %n",
-             &maps.back().start, &maps.back().end, &maps.back().offset,
-             &maps.back().load_base, &maps.back().flags, &pos);
-      maps.back().name = android::base::Trim(line.substr(pos));
+             &map.start, &map.end, &map.offset, &map.load_base, &map.flags, &pos);
+      map.name = android::base::Trim(line.substr(pos));
     } else if (android::base::StartsWith(line, "registers:")) {
       size_t size;
       int pos;
       sscanf(line.c_str(), "registers: %zu %n", &size, &pos);
-      ASSERT_EQ(sizeof(unw_context), size);
-      HexStringToRawData(&line[pos], &unw_context, size);
+      if (sizeof(testdata->unw_context) != size) {
+        return false;
+      }
+      HexStringToRawData(&line[pos], &testdata->unw_context, size);
     } else if (android::base::StartsWith(line, "stack:")) {
       size_t size;
       int pos;
       sscanf(line.c_str(),
              "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n",
-             &stack_info.start, &stack_info.end, &size, &pos);
-      stack.resize(size);
-      HexStringToRawData(&line[pos], &stack[0], size);
-      stack_info.data = stack.data();
+             &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos);
+      testdata->stack.resize(size);
+      HexStringToRawData(&line[pos], &testdata->stack[0], size);
+      testdata->stack_info.data = testdata->stack.data();
     } else if (android::base::StartsWith(line, "function:")) {
-      symbols.resize(symbols.size() + 1);
+      testdata->symbols.resize(testdata->symbols.size() + 1);
+      FunctionSymbol& symbol = testdata->symbols.back();
       int pos;
       sscanf(line.c_str(),
              "function: start: %" SCNxPTR " end: %" SCNxPTR " name: %n",
-             &symbols.back().start, &symbols.back().end,
-             &pos);
-      symbols.back().name = line.substr(pos);
+             &symbol.start, &symbol.end, &pos);
+      symbol.name = line.substr(pos);
     }
   }
+  return true;
+}
+
+static void BacktraceOfflineTest(const std::string& testlib_name) {
+  const std::string arch = GetArch();
+  if (arch.empty()) {
+    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+    return;
+  }
+  const std::string testlib_path = "testdata/" + arch + "/" + testlib_name;
+  struct stat st;
+  if (stat(testlib_path.c_str(), &st) == -1) {
+    GTEST_LOG_(INFO) << "This test is skipped as " << testlib_path << " doesn't exist.";
+    return;
+  }
+
+  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata";
+  OfflineTestData testdata;
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
 
   // Fix path of libbacktrace_testlib.so.
-  for (auto& map : maps) {
+  for (auto& map : testdata.maps) {
     if (map.name.find("libbacktrace_test.so") != std::string::npos) {
       map.name = testlib_path;
     }
   }
 
   // Do offline backtrace.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid, maps));
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
   ASSERT_TRUE(map != nullptr);
 
   std::unique_ptr<Backtrace> backtrace(
-      Backtrace::CreateOffline(pid, tid, map.get(), stack_info));
+      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
   ASSERT_TRUE(backtrace != nullptr);
 
-  ucontext_t ucontext = GetUContextFromUnwContext(unw_context);
+  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
   ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
 
-
   // Collect pc values of the call stack frames.
   std::vector<uintptr_t> pc_values;
   for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
@@ -311,17 +323,20 @@
 
   size_t test_one_index = 0;
   for (size_t i = 0; i < pc_values.size(); ++i) {
-    if (FunctionNameForAddress(pc_values[i], symbols) == "test_level_one") {
+    if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") {
       test_one_index = i;
       break;
     }
   }
 
   ASSERT_GE(test_one_index, 3u);
-  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], symbols));
-  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], symbols));
-  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2], symbols));
-  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3], symbols));
+  ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols));
+  ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1],
+                                                     testdata.symbols));
+  ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2],
+                                                       testdata.symbols));
+  ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3],
+                                                      testdata.symbols));
 }
 
 TEST(libbacktrace, offline_eh_frame) {
@@ -339,3 +354,47 @@
 TEST(libbacktrace, offline_arm_exidx) {
   BacktraceOfflineTest("libbacktrace_test_arm_exidx.so");
 }
+
+// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx
+// overlap with each other, which appears in /system/lib/libart.so.
+TEST(libbacktrace, offline_unwind_mix_eh_frame_and_arm_exidx) {
+  const std::string arch = GetArch();
+  if (arch.empty() || arch != "arm") {
+    GTEST_LOG_(INFO) << "This test does nothing on current arch.";
+    return;
+  }
+  const std::string testlib_path = "testdata/" + arch + "/libart.so";
+  struct stat st;
+  ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path;
+
+  const std::string offline_testdata_path = "testdata/" + arch + "/offline_testdata_for_libart";
+  OfflineTestData testdata;
+  ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata));
+
+  // Fix path of /system/lib/libart.so.
+  for (auto& map : testdata.maps) {
+    if (map.name.find("libart.so") != std::string::npos) {
+      map.name = testlib_path;
+    }
+  }
+
+  // Do offline backtrace.
+  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(testdata.pid, testdata.maps));
+  ASSERT_TRUE(map != nullptr);
+
+  std::unique_ptr<Backtrace> backtrace(
+      Backtrace::CreateOffline(testdata.pid, testdata.tid, map.get(), testdata.stack_info));
+  ASSERT_TRUE(backtrace != nullptr);
+
+  ucontext_t ucontext = GetUContextFromUnwContext(testdata.unw_context);
+  ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+  // The last frame is outside of libart.so
+  ASSERT_EQ(testdata.symbols.size() + 1, backtrace->NumFrames());
+  for (size_t i = 0; i + 1 < backtrace->NumFrames(); ++i) {
+    uintptr_t vaddr_in_file = backtrace->GetFrame(i)->pc - testdata.maps[0].start +
+        testdata.maps[0].load_base;
+    std::string name = FunctionNameForAddress(vaddr_in_file, testdata.symbols);
+    ASSERT_EQ(name, testdata.symbols[i].name);
+  }
+}
diff --git a/libbacktrace/testdata/arm/libart.so b/libbacktrace/testdata/arm/libart.so
new file mode 100644
index 0000000..bed8e35
--- /dev/null
+++ b/libbacktrace/testdata/arm/libart.so
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
new file mode 100644
index 0000000..63f6a07
--- /dev/null
+++ b/libbacktrace/testdata/arm/offline_testdata_for_libart
@@ -0,0 +1,10 @@
+pid: 32232 tid: 32233
+registers: 64 000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e9
+map: start: e9380000 end: e9766000 offset: 0 load_base: b000 flags: 5 name: /system/lib/libart.so
+stack: start: ffd12dc0 end: ffd16000 size: 12864 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d8952431abed6fac33576fb438d1ff030000007800502400000000a0005024060000007893476f00908eec000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004489bd6f78005024d00c5024a0005024a431d1ff2c31d1ff9b99aa71a4d49c6f30d8952400000000e8d895244489bd6fa8e5bc6fc8b895240100000000000000b033d1ff56000000637171e900000000d00c5024c8b89524000000000100000000000000b033d1ff560000006431d1ffa431d1ff000000009fb671e9b033d1ff00000000a431d1ff6431d1ffc431d1ff000000000000000081b771e9b033d1ff00000000c431d1ff8431d1ff01000000020000002429000001000000dc501b002033d1ff0100000018f9736f0100000000908eec58d8952440f180e9a8ec01245b215ce8a4d49c6f00908eec0832d1ffb033d1ff040000008c908eeca832d1ffabc141e9b033d1ff5b215ce82832d1ffb033d1ff080000008c908eec000000000035d1ff0834d1ffa832d1ffa4d49c6f04000000cca312e800908eec6832d1ffb033d1ff0834d1ff6bc354e9b033d1ff5b215ce8cca312e800908eec8832d1ffb033d1ff0834d1ff6bc354e900908eeca4d49c6f44b8bfeb1833d1ff000000006832d1ffb033d1ff478054e9b033d1ff1b8054e90834d1ffa4d49c6f0000000000000000000000000000000008000000000000000834d1ff0000000000000000000000000000000000000000000000000000000058d895240000000000000000000000000000000000000000000000000000000058d89524b17e54e98c56af6f00000000a4d49c6f288944e800908eec00000000d032d1ff0000000000000000000000000000000000000000000000007e8ea6c358a58cec00f580e90834d1ffa4d49c6f58d8952400908eecb033d1ffe9100000da8844e8833c70e9e9100000b033d1ff0200000058d8952408b1796f0200000000908eecda8844e82c34d1ff00908eece9100000005d70e9070000007d1300006034d1ff98d170e9b033d1ff0834d1ff148844e800908eecb033d1ffa034d1ffa833d1ff0100000044b8bfeb41f252e9e91fdeeaa491deea000000004700000001000000d9c4ddea0000000000000000b834d1ff00b051ff0834d1ff00908eecf833d1ffa034d1ff148844e800000000020000004d4c53e900000000000000000000000000908eec44b8bfeb0834d1ff3835d1ff148844e85035d1ffbb936fe90000000044b8bfebb033d1ffda8844e8148844e8000000000d0000005a0000007d137d13d00c502400000000600480240400000070048024f80c5024170000000100000002000000000000000040000000000000d0018024d00c502400000000600480240000000070048024f80c5024000000000000000000000000000000000000000000000000d001802465906fe97b2e5ce8000000000300000000000000881388131a00000001000000000000004cdd76e9010000007b2e5ce8020000009835d1ff5835d1ffc435d1ff010000000000000000000000010000000000000000dd76e90834d1ff0d0000000100000000000000000000005035d1ff9036d1ff00000000a435d1ff7e8ea6c3080000000000000000000000000000000000000038cb7e7044b8bfeb7d2e5ce800000000c037d1ff5600000000908eec00000000cc35d1ff55af71e9e0285a6f040000000800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e00000018eb01243173d870040000007d2e5ce800000000c037d1ff5600000000000000cc35d1ff637171e90000000018eb012402000000010000007d2e5ce800000000c037d1ff560000004436d1ff000000000000000081b771e9c037d1ff000000004436d1ff0436d1ff00e68dec0800000001000000a437d1ff010000001c73d870000000000000000043000000339768e9040000006c36d1ff0e000000b436d1ff8cc97e706c36d1ff0e000000adf861e918eb01243173d870040000007b2e5ce844b8bfeb00908eeca836d1ffc037d1ff040000008c908eec7c37d1ffd5c141e9c037d1ff7b2e5ce80000000000908eecd036d1ff00000000b038d1ff183ad1ff0000000044b8bfeb1038d1ff7c37d1ff6c37d1ffc037d1ff7b2e5ce8000000007b2e5ce8610d67e9c037d1ff7b2e5ce8280477e99835456f960300009a35456f10aa5e6f9a35456f9835456f68b85e6f881e77e9b30a47e9e81382e94c95b4ec7100000000908eec9c908eec30528bec1038d1ff7b2e5ce800000000c78469e91038d1ff0aeb3b52208989ec150645e9010000001038d1ff6c37d1ff44b8bfeb6c37d1ff00000000d837d1ff1038d1ff7b2e5ce8000000006c38d1ff8f0b67e97b2e5ce818eb012400000000000000000838d1ff7b2e5ce802000000040000007c37d1ff18eb01249835456f00000000901e77e9180000000300000000908eec480000004800000043000000640477e97669747954687265070000001a00000060eb0124000000000000000000000000a500000044b8bfeb1038d1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce96c38d1ff18eb012400908eeceeac73e943000000640477e9000059008bc95ce900908eec30528bec409181e900908eec430000005900000000528bec409181e900004300710000000300000030528bec89c75ce944b8bfebe2050000103dd1ff03000000a3f6a7eb89c75ce96c38d1ff7e8ea6c389c75ce997f5a7eb710000000000000030528bec7e8ea6c3e83cd1ff2079002488beba6ff0ca726f5600000000908eec000000005439d1ff8b1db8aa803a89ec7e8ea6c3000000009173d870ec55af6f00000000010000004892796f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003801802488beba6ff0ca726f56000000000000005439d1ff9d3daa71cc55af6f7039d1ff0b0000006839d1ff7d2e5ce800000000483bd1ff637171e900000000207900240b00000058a58cec40f180e9010000007d2e5ce800000000483bd1ff56000000cc39d1ff000000000000000081b771e9483bd1ff00000000cc39d1ff8c39d1ff05000000050000000c000000040000000100000012000000958c00000100000074d73500483bd1ff01000000e880746f0100000000908eec903ad1ff40f180e97e02000000908eec2079002400000000383ad1ff7b2e5ce8cc55af6f00908eec303ad1ff483bd1ff040000008c908eec043bd1ffd5c141e9483bd1ff7b2e5ce840f180e900908eec583ad1ff00000000000000000000000000000000cc55af6f983bd1ff043bd1fff43ad1ff483bd1ff7b2e5ce8000000007b2e5ce8610d67e9483bd1ff7b2e5ce8280477e94892796f860100004e92796f00a088ec4e92796f4892796f18a688ec881e77e9b30a47e978e388ec4c95b4ec2100000000908eec9c908eec30528bec983bd1ff7b2e5ce800000000c78469e9983bd1ff06b005fdf0298aec150645e901000000983bd1fff43ad1ffcc55af6ff43ad1ff00000000603bd1ff983bd1ff7b2e5ce800000000f43bd1ff8f0b67e97b2e5ce8e00864e80000000000000000903bd1ff7b2e5ce80200000004000000043bd1ff207900249c908eec04000000583bd1ff603bd1ff4892796f04000000ac3bd1ff01000000901e77e917885ee9010000004d5cb1eb485cb1eb00908eec4892796f00000000000000000000000000004300cc55af6f983bd1ff00908eeceeac73e943000000640477e9901e77e9e6ac73e961705ce9f43bd1ff55000000ac3bd1ffeeac73e943000000640477e900005900e3225ce900908eec30528bec409181e900908eec430000005900000000528bec409181e9000043005500000078e388ec2100000009215ce901000000ce3fb8aae83cd1ff40420f00a3f6a7eb09215ce9f43bd1ff7e8ea6c309215ce9ed0ea8eb2100000075270000003289ec0000000030528becef665c74db0e42e911ac58e99daf58e9103dd1ff010000007e8ea6c31b000000385cd1ff385cd1ff02000000103dd1ff0300000087e26deae43cd1ff0200000001000000a31eb8aa020000007c3cd1ff18ac89ec1dac89ec0f000000fc94b4ec7c3cd1ff18ac89ec7e8ea6c3e83cd1ff884dd1ff741ab8aaa81ab8aa000000000700000004000000e43cd1ff3b19b8aa000000000000000000000000000000000000000000000000884dd1ff0000000001000000844dd1ff7e8ea6c3f065b4ec00fd0000205db8aa308789ec010000000000000004000000b8e78aec18ac89ec005db8aa2ceab2eb101082e935000000000000000800000001100000ba5bd1ff99000000b8e78aec205db8aa508789ec030000000000000004000000e2050000108789ec00000000d991aeece583aeec10d0acec10d0acec50d0acec6170705f70726f63657373333200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080a4ec00000000001000009dfe6feb00000000975673eb000000002516b8aa844dd1ff08000000a84dd1ff0000000000000000000000007c4dd1ff3b996feb00000000000000000000000000000000000000005015b8aad45cb8aadc5cb8aae85cb8aa804dd1ff0000000015b8aeec08000000ba5bd1ffd45bd1ffe05bd1ffee5bd1ff0f5cd1ff335cd1ff355cd1ff385cd1ff00000000535cd1ff6f5cd1ff825cd1ff9d5cd1ffbf5cd1ffd45cd1ffee5cd1ff015dd1ff1c5dd1ffe35ed1fffc5ed1ff465fd1ffc55fd1ff0000000010000000d6b0270006000000001000001100000064000000030000003400b8aa040000002000000005000000090000000700000000d0adec080000000000000009000000ec14b8aa0b000000752700000c000000752700000d000000752700000e000000752700001700000000000000190000007c4ed1ff1a0000001f0000001f000000de5fd1ff0f0000008c4ed1ff00000000000000000000000086da76325883c1a6b44d586d68c7843576386c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000636f6d2e6578616d706c652e7375646f67616d65000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f3d2f73797374656d2f62696e2f6170705f70726f63657373333200414e44524f49445f444154413d2f6461746100444f574e4c4f41445f43414348453d2f646174612f636163686500414e44524f49445f534f434b45545f7a79676f74655f7365636f6e646172793d3900414e44524f49445f524f4f543d2f73797374656d00415345435f4d4f554e54504f494e543d2f6d6e742f6173656300414e44524f49445f424f4f544c4f474f3d3100414e44524f49445f4153534554533d2f73797374656d2f61707000424f4f54434c415353504154483d2f73797374656d2f6672616d65776f726b2f636f72652d6f6a2e6a61723a2f73797374656d2f6672616d65776f726b2f636f72652d6c69626172742e6a61723a2f73797374656d2f6672616d65776f726b2f636f6e7363727970742e6a61723a2f73797374656d2f6672616d65776f726b2f6f6b687474702e6a61723a2f73797374656d2f6672616d65776f726b2f6c65676163792d746573742e6a61723a2f73797374656d2f6672616d65776f726b2f626f756e6379636173746c652e6a61723a2f73797374656d2f6672616d65776f726b2f6578742e6a61723a2f73797374656d2f6672616d65776f726b2f6672616d65776f726b2e6a61723a2f73797374656d2f6672616d65776f726b2f74656c6570686f6e792d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f766f69702d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f696d732d636f6d6d6f6e2e6a61723a2f73797374656d2f6672616d65776f726b2f6170616368652d786d6c2e6a61723a2f73797374656d2f6672616d65776f726b2f6f72672e6170616368652e687474702e6c65676163792e626f6f742e6a617200414e44524f49445f53544f524147453d2f73746f7261676500504154483d2f7362696e3a2f73797374656d2f7362696e3a2f73797374656d2f62696e3a2f73797374656d2f7862696e3a2f76656e646f722f62696e3a2f76656e646f722f7862696e0053595354454d534552564552434c415353504154483d2f73797374656d2f6672616d65776f726b2f73657276696365732e6a61723a2f73797374656d2f6672616d65776f726b2f65746865726e65742d736572766963652e6a61723a2f73797374656d2f6672616d65776f726b2f776966692d736572766963652e6a61720045585445524e414c5f53544f524147453d2f736463617264002f73797374656d2f62696e2f6170705f70726f636573733332000000000000000000
+function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
+function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
+function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
+function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
+function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
+function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
\ No newline at end of file
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index b701bba..7e27c3e 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -161,7 +161,7 @@
     /* Support wifi_hal_legacy administering a network interface. */
     { 00755, AID_WIFI,      AID_WIFI,      CAP_MASK_LONG(CAP_NET_ADMIN) |
                                            CAP_MASK_LONG(CAP_NET_RAW),
-                                              "system/bin/hw/android.hardware.wifi@1.0-service" },
+                                              "vendor/bin/hw/android.hardware.wifi@1.0-service" },
 
     /* Support Bluetooth legacy hal accessing /sys/class/rfkill */
     { 00700, AID_BLUETOOTH, AID_BLUETOOTH, CAP_MASK_LONG(CAP_NET_ADMIN),
diff --git a/libcutils/properties.cpp b/libcutils/properties.cpp
index 43ad574..d2645e6 100644
--- a/libcutils/properties.cpp
+++ b/libcutils/properties.cpp
@@ -129,7 +129,7 @@
     void* cookie;
 };
 
-static void trampoline(void* raw_data, const char* name, const char* value) {
+static void trampoline(void* raw_data, const char* name, const char* value, unsigned /*serial*/) {
     callback_data* data = reinterpret_cast<callback_data*>(raw_data);
     data->callback(name, value, data->cookie);
 }
diff --git a/libmetricslogger/Android.bp b/libmetricslogger/Android.bp
new file mode 100644
index 0000000..75eab66
--- /dev/null
+++ b/libmetricslogger/Android.bp
@@ -0,0 +1,64 @@
+// Copyright 2017 The Android Open Source Project
+
+metricslogger_lib_src_files = [
+    "metrics_logger.cpp",
+]
+
+cc_defaults {
+    name: "metricslogger_defaults",
+
+    clang: true,
+    host_supported: true,
+
+    export_include_dirs: ["include"],
+    local_include_dirs: ["include"],
+    shared_libs: ["liblog"],
+    whole_static_libs: ["libgtest_prod"],
+
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+
+        // 524291 corresponds to sysui_histogram, from
+        // frameworks/base/core/java/com/android/internal/logging/EventLogTags.logtags
+        "-DHISTOGRAM_LOG_TAG=524291",
+    ],
+}
+
+// metricslogger shared library
+// -----------------------------------------------------------------------------
+cc_library_shared {
+    name: "libmetricslogger",
+    srcs: metricslogger_lib_src_files,
+    defaults: ["metricslogger_defaults"],
+}
+
+// metricslogger shared library, debug
+// -----------------------------------------------------------------------------
+cc_library_shared {
+    name: "libmetricslogger_debug",
+    srcs: metricslogger_lib_src_files,
+    defaults: ["metricslogger_defaults"],
+
+    target: {
+        host: {
+            cflags: ["-UNDEBUG"],
+        },
+    },
+}
+
+// Native tests
+// -----------------------------------------------------------------------------
+cc_test {
+    name: "metricslogger_tests",
+    defaults: ["metricslogger_defaults"],
+    shared_libs: [
+        "libbase",
+        "libmetricslogger_debug",
+    ],
+    static_libs: ["libBionicGtestMain"],
+    srcs: [
+        "metrics_logger_test.cpp",
+    ],
+}
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h
similarity index 72%
rename from bootstat/histogram_logger.h
rename to libmetricslogger/include/metricslogger/metrics_logger.h
index 60c7776..d30e56c 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/include/metricslogger/metrics_logger.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -17,10 +17,12 @@
 #include <cstdint>
 #include <string>
 
-namespace bootstat {
+namespace android {
+namespace metricslogger {
 
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
+// Logs a Tron histogram metric named |event| containing |data| to the Tron log
+// buffer.
 void LogHistogram(const std::string& event, int32_t data);
 
-}  // namespace bootstat
\ No newline at end of file
+}  // namespace metricslogger
+}  // namespace android
diff --git a/bootstat/histogram_logger.cpp b/libmetricslogger/metrics_logger.cpp
similarity index 76%
rename from bootstat/histogram_logger.cpp
rename to libmetricslogger/metrics_logger.cpp
index 73f3295..f8e0174 100644
--- a/bootstat/histogram_logger.cpp
+++ b/libmetricslogger/metrics_logger.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016 The Android Open Source Project
+ * Copyright (C) 2017 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.
@@ -14,19 +14,19 @@
  * limitations under the License.
  */
 
-#include "histogram_logger.h"
+#include "metricslogger/metrics_logger.h"
 
 #include <cstdlib>
 
-#include <android-base/logging.h>
 #include <log/log_event_list.h>
 
-namespace bootstat {
+namespace android {
+namespace metricslogger {
 
 void LogHistogram(const std::string& event, int32_t data) {
-  LOG(INFO) << "Logging histogram: " << event << " " << data;
   android_log_event_list log(HISTOGRAM_LOG_TAG);
   log << event << data << LOG_ID_EVENTS;
 }
 
-}  // namespace bootstat
+}  // namespace metricslogger
+}  // namespace android
diff --git a/bootstat/histogram_logger.h b/libmetricslogger/metrics_logger_test.cpp
similarity index 70%
copy from bootstat/histogram_logger.h
copy to libmetricslogger/metrics_logger_test.cpp
index 60c7776..5a30ad7 100644
--- a/bootstat/histogram_logger.h
+++ b/libmetricslogger/metrics_logger_test.cpp
@@ -14,13 +14,11 @@
  * limitations under the License.
  */
 
-#include <cstdint>
-#include <string>
+#include "metricslogger/metrics_logger.h"
 
-namespace bootstat {
+#include <gtest/gtest.h>
 
-// Builds an EventLog buffer named |event| containing |data| and writes
-// the log into the Tron histogram logs.
-void LogHistogram(const std::string& event, int32_t data);
-
-}  // namespace bootstat
\ No newline at end of file
+TEST(MetricsLoggerTest, AddSingleBootEvent) {
+  android::metricslogger::LogHistogram("test_event", 42);
+  // TODO(jhawkins): Verify the EventLog is updated.
+}
diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h
index 02e7075..ac64f71 100644
--- a/libnativeloader/include/nativeloader/dlext_namespaces.h
+++ b/libnativeloader/include/nativeloader/dlext_namespaces.h
@@ -22,16 +22,15 @@
 __BEGIN_DECLS
 
 /*
- * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
- * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- * The libraries in this list should be loaded prior to this call.
+ * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
+ * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
  *
- * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * The library_search_path is the search path for anonymous namespace. The anonymous namespace
  * is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
  * for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
  */
-extern bool android_init_namespaces(const char* public_ns_sonames,
-                                    const char* anon_ns_library_path);
+extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+                                             const char* library_search_path);
 
 
 enum {
@@ -87,6 +86,26 @@
                                                             android_namespace_t* parent);
 
 /*
+ * Creates a link between namespaces. Every link has list of sonames of
+ * shared libraries. These are the libraries which are accessible from
+ * namespace 'from' but loaded within namespace 'to' context.
+ * When to namespace is nullptr this function establishes a link between
+ * 'from' namespace and the default namespace.
+ *
+ * The lookup order of the libraries in namespaces with links is following:
+ * 1. Look inside current namespace using 'this' namespace search path.
+ * 2. Look in linked namespaces
+ * 2.1. Perform soname check - if library soname is not in the list of shared
+ *      libraries sonames skip this link, otherwise
+ * 2.2. Search library using linked namespace search path. Note that this
+ *      step will not go deeper into linked namespaces for this library but
+ *      will do so for DT_NEEDED libraries.
+ */
+extern bool android_link_namespaces(android_namespace_t* from,
+                                    android_namespace_t* to,
+                                    const char* shared_libs_sonames);
+
+/*
  * Get the default library search path.
  * The path will be copied into buffer, which must have space for at least
  * buffer_size chars. Elements are separated with ':', and the path will always
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 2f23c2c..74f2f1d 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -165,6 +165,11 @@
         return false;
       }
 
+      if (!android_link_namespaces(ns, nullptr, public_libraries_.c_str())) {
+        *error_msg = dlerror();
+        return false;
+      }
+
       native_loader_ns = NativeLoaderNamespace(ns);
     } else {
       native_bridge_namespace_t* ns = NativeBridgeCreateNamespace("classloader-namespace",
@@ -310,8 +315,8 @@
     // code is one example) unknown to linker in which  case linker uses anonymous
     // namespace. The second argument specifies the search path for the anonymous
     // namespace which is the library_path of the classloader.
-    initialized_ = android_init_namespaces(public_libraries_.c_str(),
-                                           is_native_bridge ? nullptr : library_path);
+    initialized_ = android_init_anonymous_namespace(public_libraries_.c_str(),
+                                                    is_native_bridge ? nullptr : library_path);
     if (!initialized_) {
       *error_msg = dlerror();
       return false;
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index ed11164..80bb673 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -11,7 +11,7 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
 service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 66e7750..36bb443 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -11,7 +11,7 @@
     onrestart restart media
     onrestart restart netd
     onrestart restart wificond
-    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
+    writepid /dev/cpuset/foreground/tasks
 
 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
     class main