Merge changes If8747ba1,Id1943ebd

* changes:
  adb: improve network_connect error messages.
  adbd: fix TCP bind address.
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index 56b5cd8..9e1760d 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -25,6 +25,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -209,6 +210,22 @@
     return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
 }
 
+static bool is_mountpoint(const std::string& path, pid_t tid) {
+    const std::string mountinfo_path = "/proc/" + std::to_string(tid) + "/mountinfo";
+    std::string mountinfo;
+    if (!android::base::ReadFileToString(mountinfo_path, &mountinfo)) {
+        PLOG(ERROR) << "Failed to open " << mountinfo_path;
+        return false;
+    }
+    std::vector<std::string> lines = android::base::Split(mountinfo, "\n");
+    return std::find_if(lines.begin(), lines.end(), [&path](const auto& line) {
+               auto tokens = android::base::Split(line, " ");
+               // line format is ...
+               // mountid parentmountid major:minor sourcepath targetpath option ...
+               return tokens.size() >= 4 && tokens[4] == path;
+           }) != lines.end();
+}
+
 // Make sure that SendFail from adb_io.cpp isn't accidentally used in this file.
 #pragma GCC poison SendFail
 
@@ -415,6 +432,18 @@
     struct stat st;
     bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) ||
                      (S_ISLNK(st.st_mode) && !S_ISLNK(mode));
+
+    // If the path is a file that is a mount point, don't unlink it, but instead
+    // truncate to zero. If unlinked, existing mounts on the path is all
+    // unmounted
+    if (S_ISREG(st.st_mode) && is_mountpoint(path, getpid())) {
+        do_unlink = false;
+        if (truncate(path.c_str(), 0) == -1) {
+            SendSyncFail(s, "truncate to zero failed");
+            return false;
+        }
+    }
+
     if (do_unlink) {
         adb_unlink(path.c_str());
     }
@@ -546,7 +575,64 @@
     return true;
 }
 
+#if defined(__ANDROID__)
+class FileSyncPreparer {
+  public:
+    FileSyncPreparer() : saved_ns_fd_(-1), rooted_(getuid() == 0) {
+        const std::string namespace_path = "/proc/" + std::to_string(gettid()) + "/ns/mnt";
+        const int ns_fd = adb_open(namespace_path.c_str(), O_RDONLY | O_CLOEXEC);
+        if (ns_fd == -1) {
+            if (rooted_) PLOG(ERROR) << "Failed to save mount namespace";
+            return;
+        }
+        saved_ns_fd_.reset(ns_fd);
+
+        // Note: this is for the current thread only
+        if (unshare(CLONE_NEWNS) != 0) {
+            if (rooted_) PLOG(ERROR) << "Failed to clone mount namespace";
+            return;
+        }
+
+        // Set the propagation type of / to private so that unmount below is
+        // not propagated to other mount namespaces.
+        if (mount(nullptr, "/", nullptr, MS_PRIVATE | MS_REC, nullptr) == -1) {
+            if (rooted_) PLOG(ERROR) << "Could not change propagation type of / to MS_PRIVATE";
+            return;
+        }
+
+        // unmount /bionic which is bind-mount to itself by init. Under /bionic,
+        // there are other bind mounts for the bionic files. By unmounting this,
+        // we unmount them all thus revealing the raw file system that is the
+        // same as the local file system seen by the adb client.
+        if (umount2("/bionic", MNT_DETACH) == -1 && errno != ENOENT) {
+            if (rooted_) PLOG(ERROR) << "Could not unmount /bionic to reveal raw filesystem";
+            return;
+        }
+    }
+
+    ~FileSyncPreparer() {
+        if (saved_ns_fd_.get() != -1) {
+            // In fact, this is not strictly required because this thread for file
+            // sync service will be destroyed after the current transfer is all
+            // done. However, let's restore the ns in case the same thread is
+            // reused by multiple transfers in the future refactoring.
+            if (setns(saved_ns_fd_, CLONE_NEWNS) == -1) {
+                PLOG(ERROR) << "Failed to restore saved mount namespace";
+            }
+        }
+    }
+
+  private:
+    unique_fd saved_ns_fd_;
+    bool rooted_;
+};
+#endif
+
 void file_sync_service(unique_fd fd) {
+#if defined(__ANDROID__)
+    FileSyncPreparer preparer;
+#endif
+
     std::vector<char> buffer(SYNC_DATA_MAX);
 
     while (handle_sync_command(fd.get(), buffer)) {
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index b26c691..5e6d416 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -49,6 +49,8 @@
 #include "set_verity_enable_state_service.h"
 
 using android::base::Realpath;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::ReadDefaultFstab;
 
 // Returns the last device used to mount a directory in /proc/mounts.
 // This will find overlayfs entry where upperdir=lowerdir, to make sure
@@ -230,6 +232,23 @@
     android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
 }
 
+static void try_unmount_bionic(int fd) {
+    static constexpr const char* kBionic = "/bionic";
+    struct statfs buf;
+    if (statfs(kBionic, &buf) == -1) {
+        WriteFdFmt(fd, "statfs of the %s mount failed: %s.\n", kBionic, strerror(errno));
+        return;
+    }
+    if (buf.f_flags & ST_RDONLY) {
+        // /bionic is on a read-only partition; can happen for
+        // non-system-as-root-devices. Don' try to unmount.
+        return;
+    }
+    // Success/Fail of the actual remount will be reported by the function.
+    remount_partition(fd, kBionic);
+    return;
+}
+
 void remount_service(unique_fd fd, const std::string& cmd) {
     bool user_requested_reboot = cmd == "-R";
 
@@ -323,6 +342,8 @@
         return;
     }
 
+    try_unmount_bionic(fd.get());
+
     if (!success) {
         WriteFdExactly(fd.get(), "remount failed\n");
     } else {
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index f5c28c6..92851c0 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -211,8 +211,8 @@
         // Not using AVB - assume VB1.0.
 
         // read all fstab entries at once from all sources
-        Fstab fstab;
-        if (!ReadDefaultFstab(&fstab)) {
+        android::fs_mgr::Fstab fstab;
+        if (!android::fs_mgr::ReadDefaultFstab(&fstab)) {
             WriteFdExactly(fd.get(), "Failed to read fstab\n");
             suggest_run_adb_root(fd.get());
             return;
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index e096560..fa3738d 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -33,6 +33,8 @@
 #include <list>
 #include <mutex>
 #include <unordered_map>
+#include <utility>
+#include <variant>
 #include <vector>
 
 #include <android-base/chrono_utils.h>
@@ -121,13 +123,8 @@
                                        state.c_str());
 }
 
-void fdevent_install(fdevent* fde, int fd, fd_func func, void* arg) {
-    check_main_thread();
-    CHECK_GE(fd, 0);
-    memset(fde, 0, sizeof(fdevent));
-}
-
-fdevent* fdevent_create(int fd, fd_func func, void* arg) {
+template <typename F>
+static fdevent* fdevent_create_impl(int fd, F func, void* arg) {
     check_main_thread();
     CHECK_GE(fd, 0);
 
@@ -150,6 +147,14 @@
     return fde;
 }
 
+fdevent* fdevent_create(int fd, fd_func func, void* arg) {
+    return fdevent_create_impl(fd, func, arg);
+}
+
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg) {
+    return fdevent_create_impl(fd, func, arg);
+}
+
 unique_fd fdevent_release(fdevent* fde) {
     check_main_thread();
     if (!fde) {
@@ -290,13 +295,27 @@
     }
 }
 
+template <class T>
+struct always_false : std::false_type {};
+
 static void fdevent_call_fdfunc(fdevent* fde) {
     unsigned events = fde->events;
     fde->events = 0;
     CHECK(fde->state & FDE_PENDING);
     fde->state &= (~FDE_PENDING);
     D("fdevent_call_fdfunc %s", dump_fde(fde).c_str());
-    fde->func(fde->fd.get(), events, fde->arg);
+    std::visit(
+            [&](auto&& f) {
+                using F = std::decay_t<decltype(f)>;
+                if constexpr (std::is_same_v<fd_func, F>) {
+                    f(fde->fd.get(), events, fde->arg);
+                } else if constexpr (std::is_same_v<fd_func2, F>) {
+                    f(fde, events, fde->arg);
+                } else {
+                    static_assert(always_false<F>::value, "non-exhaustive visitor");
+                }
+            },
+            fde->func);
 }
 
 static void fdevent_run_flush() EXCLUDES(run_queue_mutex) {
diff --git a/adb/fdevent.h b/adb/fdevent.h
index df2339a..70e0a96 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -21,6 +21,7 @@
 #include <stdint.h>  /* for int64_t */
 
 #include <functional>
+#include <variant>
 
 #include "adb_unique_fd.h"
 
@@ -30,6 +31,7 @@
 #define FDE_ERROR             0x0004
 
 typedef void (*fd_func)(int fd, unsigned events, void *userdata);
+typedef void (*fd_func2)(struct fdevent* fde, unsigned events, void* userdata);
 
 struct fdevent {
     uint64_t id;
@@ -40,15 +42,14 @@
     uint16_t state = 0;
     uint16_t events = 0;
 
-    fd_func func = nullptr;
+    std::variant<fd_func, fd_func2> func;
     void* arg = nullptr;
 };
 
-/* Allocate and initialize a new fdevent object
- * Note: use FD_TIMER as 'fd' to create a fd-less object
- * (used to implement timers).
-*/
+// Allocate and initialize a new fdevent object
+// TODO: Switch these to unique_fd.
 fdevent *fdevent_create(int fd, fd_func func, void *arg);
+fdevent* fdevent_create(int fd, fd_func2 func, void* arg);
 
 // Deallocate an fdevent object that was created by fdevent_create.
 void fdevent_destroy(fdevent *fde);
@@ -56,16 +57,14 @@
 // fdevent_destroy, except releasing the file descriptor previously owned by the fdevent.
 unique_fd fdevent_release(fdevent* fde);
 
-/* Change which events should cause notifications
-*/
+// Change which events should cause notifications
 void fdevent_set(fdevent *fde, unsigned events);
 void fdevent_add(fdevent *fde, unsigned events);
 void fdevent_del(fdevent *fde, unsigned events);
 
 void fdevent_set_timeout(fdevent *fde, int64_t  timeout_ms);
 
-/* loop forever, handling events.
-*/
+// Loop forever, handling events.
 void fdevent_loop();
 
 void check_main_thread();
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index 816134f..a9746bb 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -30,10 +30,16 @@
 
 class FdHandler {
   public:
-    FdHandler(int read_fd, int write_fd) : read_fd_(read_fd), write_fd_(write_fd) {
-        read_fde_ = fdevent_create(read_fd_, FdEventCallback, this);
+    FdHandler(int read_fd, int write_fd, bool use_new_callback)
+        : read_fd_(read_fd), write_fd_(write_fd) {
+        if (use_new_callback) {
+            read_fde_ = fdevent_create(read_fd_, FdEventNewCallback, this);
+            write_fde_ = fdevent_create(write_fd_, FdEventNewCallback, this);
+        } else {
+            read_fde_ = fdevent_create(read_fd_, FdEventCallback, this);
+            write_fde_ = fdevent_create(write_fd_, FdEventCallback, this);
+        }
         fdevent_add(read_fde_, FDE_READ);
-        write_fde_ = fdevent_create(write_fd_, FdEventCallback, this);
     }
 
     ~FdHandler() {
@@ -64,6 +70,29 @@
         }
     }
 
+    static void FdEventNewCallback(fdevent* fde, unsigned events, void* userdata) {
+        int fd = fde->fd.get();
+        FdHandler* handler = reinterpret_cast<FdHandler*>(userdata);
+        ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events;
+        if (events & FDE_READ) {
+            ASSERT_EQ(fd, handler->read_fd_);
+            char c;
+            ASSERT_EQ(1, adb_read(fd, &c, 1));
+            handler->queue_.push(c);
+            fdevent_add(handler->write_fde_, FDE_WRITE);
+        }
+        if (events & FDE_WRITE) {
+            ASSERT_EQ(fd, handler->write_fd_);
+            ASSERT_FALSE(handler->queue_.empty());
+            char c = handler->queue_.front();
+            handler->queue_.pop();
+            ASSERT_EQ(1, adb_write(fd, &c, 1));
+            if (handler->queue_.empty()) {
+                fdevent_del(handler->write_fde_, FDE_WRITE);
+            }
+        }
+    }
+
   private:
     const int read_fd_;
     const int write_fd_;
@@ -84,56 +113,60 @@
 }
 
 TEST_F(FdeventTest, smoke) {
-    const size_t PIPE_COUNT = 10;
-    const size_t MESSAGE_LOOP_COUNT = 100;
-    const std::string MESSAGE = "fdevent_test";
-    int fd_pair1[2];
-    int fd_pair2[2];
-    ASSERT_EQ(0, adb_socketpair(fd_pair1));
-    ASSERT_EQ(0, adb_socketpair(fd_pair2));
-    ThreadArg thread_arg;
-    thread_arg.first_read_fd = fd_pair1[0];
-    thread_arg.last_write_fd = fd_pair2[1];
-    thread_arg.middle_pipe_count = PIPE_COUNT;
-    int writer = fd_pair1[1];
-    int reader = fd_pair2[0];
+    for (bool use_new_callback : {true, false}) {
+        fdevent_reset();
+        const size_t PIPE_COUNT = 10;
+        const size_t MESSAGE_LOOP_COUNT = 100;
+        const std::string MESSAGE = "fdevent_test";
+        int fd_pair1[2];
+        int fd_pair2[2];
+        ASSERT_EQ(0, adb_socketpair(fd_pair1));
+        ASSERT_EQ(0, adb_socketpair(fd_pair2));
+        ThreadArg thread_arg;
+        thread_arg.first_read_fd = fd_pair1[0];
+        thread_arg.last_write_fd = fd_pair2[1];
+        thread_arg.middle_pipe_count = PIPE_COUNT;
+        int writer = fd_pair1[1];
+        int reader = fd_pair2[0];
 
-    PrepareThread();
+        PrepareThread();
 
-    std::vector<std::unique_ptr<FdHandler>> fd_handlers;
-    fdevent_run_on_main_thread([&thread_arg, &fd_handlers]() {
-        std::vector<int> read_fds;
-        std::vector<int> write_fds;
+        std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+        fdevent_run_on_main_thread([&thread_arg, &fd_handlers, use_new_callback]() {
+            std::vector<int> read_fds;
+            std::vector<int> write_fds;
 
-        read_fds.push_back(thread_arg.first_read_fd);
-        for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
-            int fds[2];
-            ASSERT_EQ(0, adb_socketpair(fds));
-            read_fds.push_back(fds[0]);
-            write_fds.push_back(fds[1]);
+            read_fds.push_back(thread_arg.first_read_fd);
+            for (size_t i = 0; i < thread_arg.middle_pipe_count; ++i) {
+                int fds[2];
+                ASSERT_EQ(0, adb_socketpair(fds));
+                read_fds.push_back(fds[0]);
+                write_fds.push_back(fds[1]);
+            }
+            write_fds.push_back(thread_arg.last_write_fd);
+
+            for (size_t i = 0; i < read_fds.size(); ++i) {
+                fd_handlers.push_back(
+                        std::make_unique<FdHandler>(read_fds[i], write_fds[i], use_new_callback));
+            }
+        });
+        WaitForFdeventLoop();
+
+        for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
+            std::string read_buffer = MESSAGE;
+            std::string write_buffer(MESSAGE.size(), 'a');
+            ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
+            ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
+            ASSERT_EQ(read_buffer, write_buffer);
         }
-        write_fds.push_back(thread_arg.last_write_fd);
 
-        for (size_t i = 0; i < read_fds.size(); ++i) {
-            fd_handlers.push_back(std::make_unique<FdHandler>(read_fds[i], write_fds[i]));
-        }
-    });
-    WaitForFdeventLoop();
+        fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
+        WaitForFdeventLoop();
 
-    for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
-        std::string read_buffer = MESSAGE;
-        std::string write_buffer(MESSAGE.size(), 'a');
-        ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
-        ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
-        ASSERT_EQ(read_buffer, write_buffer);
+        TerminateThread();
+        ASSERT_EQ(0, adb_close(writer));
+        ASSERT_EQ(0, adb_close(reader));
     }
-
-    fdevent_run_on_main_thread([&fd_handlers]() { fd_handlers.clear(); });
-    WaitForFdeventLoop();
-
-    TerminateThread();
-    ASSERT_EQ(0, adb_close(writer));
-    ASSERT_EQ(0, adb_close(reader));
 }
 
 struct InvalidFdArg {
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 2c890b4..83213e9 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -17,10 +17,10 @@
 #pragma once
 
 #include <dirent.h>
+#include <errno.h>
 #include <fcntl.h>
 
 #if !defined(_WIN32)
-#include <dirent.h>
 #include <sys/socket.h>
 #endif
 
@@ -114,6 +114,8 @@
 
  private:
   void reset(int new_value, void* previous_tag) {
+    int previous_errno = errno;
+
     if (fd_ != -1) {
       close(fd_, this);
     }
@@ -122,6 +124,8 @@
     if (new_value != -1) {
       tag(new_value, previous_tag, this);
     }
+
+    errno = previous_errno;
   }
 
   int fd_ = -1;
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 10f52f4..4a53a33 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -114,7 +114,6 @@
         "libasync_safe",
         "libbase",
         "libdebuggerd",
-        "libbacktrace",
         "libunwindstack",
         "libdexfile",  // libunwindstack dependency
         "libdexfile_external",  // libunwindstack dependency
@@ -124,7 +123,6 @@
     ],
     target: {
         recovery: {
-            cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
             exclude_static_libs: [
                 "libartbase",
                 "libdexfile",
@@ -164,7 +162,6 @@
 
     srcs: [
         "libdebuggerd/backtrace.cpp",
-        "libdebuggerd/elf_utils.cpp",
         "libdebuggerd/open_files_list.cpp",
         "libdebuggerd/tombstone.cpp",
         "libdebuggerd/utility.cpp",
@@ -177,7 +174,6 @@
     include_dirs: ["bionic/libc"],
 
     static_libs: [
-        "libbacktrace",
         "libdexfile_external",  // libunwindstack dependency
         "libdexfile_support",  // libunwindstack dependency
         "libunwindstack",
@@ -223,7 +219,6 @@
     },
 
     shared_libs: [
-        "libbacktrace",
         "libbase",
         "libcutils",
         "libdebuggerd_client",
@@ -291,7 +286,6 @@
     ],
 
     shared_libs: [
-        "libbacktrace",
         "libbase",
         "liblog",
         "libprocinfo",
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d79d20b..82ba0a1 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,7 +48,12 @@
 #define ATRACE_TAG ATRACE_TAG_BIONIC
 #include <utils/Trace.h>
 
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 #include "libdebuggerd/backtrace.h"
 #include "libdebuggerd/tombstone.h"
@@ -63,8 +68,6 @@
 using android::base::unique_fd;
 using android::base::StringPrintf;
 
-using unwindstack::Regs;
-
 static bool pid_contains_tid(int pid_proc_fd, pid_t tid) {
   struct stat st;
   std::string task_path = StringPrintf("task/%d", tid);
@@ -287,7 +290,8 @@
     case 1:
       *abort_msg_address = crash_info->data.v1.abort_msg_address;
       *siginfo = crash_info->data.v1.siginfo;
-      regs->reset(Regs::CreateFromUcontext(Regs::CurrentArch(), &crash_info->data.v1.ucontext));
+      regs->reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(),
+                                                        &crash_info->data.v1.ucontext));
       break;
 
     default:
@@ -469,7 +473,7 @@
         info.siginfo = &siginfo;
         info.signo = info.siginfo->si_signo;
       } else {
-        info.registers.reset(Regs::RemoteGet(thread));
+        info.registers.reset(unwindstack::Regs::RemoteGet(thread));
         if (!info.registers) {
           PLOG(WARNING) << "failed to fetch registers for thread " << thread;
           ptrace(PTRACE_DETACH, thread, 0, 0);
@@ -562,30 +566,25 @@
   }
 
   // TODO: Use seccomp to lock ourselves down.
-  std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(vm_pid, false));
-  if (!map) {
-    LOG(FATAL) << "failed to create backtrace map";
-  }
-
-  std::shared_ptr<unwindstack::Memory> process_memory = map->GetProcessMemory();
-  if (!process_memory) {
-    LOG(FATAL) << "failed to get unwindstack::Memory handle";
+  unwindstack::UnwinderFromPid unwinder(256, vm_pid);
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+    LOG(FATAL) << "Failed to init unwinder object.";
   }
 
   std::string amfd_data;
   if (backtrace) {
     ATRACE_NAME("dump_backtrace");
-    dump_backtrace(std::move(g_output_fd), map.get(), thread_info, g_target_thread);
+    dump_backtrace(std::move(g_output_fd), &unwinder, thread_info, g_target_thread);
   } else {
     {
       ATRACE_NAME("fdsan table dump");
-      populate_fdsan_table(&open_files, process_memory, fdsan_table_address);
+      populate_fdsan_table(&open_files, unwinder.GetProcessMemory(), fdsan_table_address);
     }
 
     {
       ATRACE_NAME("engrave_tombstone");
-      engrave_tombstone(std::move(g_output_fd), map.get(), process_memory.get(), thread_info,
-                        g_target_thread, abort_msg_address, &open_files, &amfd_data);
+      engrave_tombstone(std::move(g_output_fd), &unwinder, thread_info, g_target_thread,
+                        abort_msg_address, &open_files, &amfd_data);
     }
   }
 
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 15c0265..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,9 +42,12 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
-#include <backtrace/BacktraceMap.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 #include "debuggerd/handler.h"
 #include "handler/fallback.h"
@@ -55,7 +58,6 @@
 #include "libdebuggerd/tombstone.h"
 
 using android::base::unique_fd;
-using unwindstack::Regs;
 
 extern "C" bool __linker_enable_fallback_allocator();
 extern "C" void __linker_disable_fallback_allocator();
@@ -73,17 +75,22 @@
   }
 
   {
-    std::unique_ptr<Regs> regs;
+    std::unique_ptr<unwindstack::Regs> regs;
 
     ThreadInfo thread;
     thread.pid = getpid();
     thread.tid = gettid();
     thread.thread_name = get_thread_name(gettid());
-    thread.registers.reset(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+    unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+    thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
 
     // TODO: Create this once and store it in a global?
-    std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
-    dump_backtrace_thread(output_fd, map.get(), thread);
+    unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
+    if (unwinder.Init(arch)) {
+      dump_backtrace_thread(output_fd, &unwinder, thread);
+    } else {
+      async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
+    }
   }
   __linker_disable_fallback_allocator();
 }
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f0a01f4..753ebcb 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -35,8 +35,8 @@
 #include <string>
 
 #include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
 #include <log/log.h>
+#include <unwindstack/Unwinder.h>
 
 #include "libdebuggerd/types.h"
 #include "libdebuggerd/utility.h"
@@ -59,25 +59,27 @@
   _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
 }
 
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread) {
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+                           const ThreadInfo& thread) {
   log_t log;
   log.tfd = output_fd;
   log.amfd_data = nullptr;
 
   _LOG(&log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", thread.thread_name.c_str(), thread.tid);
 
-  std::vector<backtrace_frame_data_t> frames;
-  if (!Backtrace::Unwind(thread.registers.get(), map, &frames, 0, nullptr)) {
+  unwinder->SetRegs(thread.registers.get());
+  unwinder->Unwind();
+  if (unwinder->NumFrames() == 0) {
     _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
     return;
   }
 
-  for (auto& frame : frames) {
-    _LOG(&log, logtype::BACKTRACE, "  %s\n", Backtrace::FormatFrameData(&frame).c_str());
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(&log, logtype::BACKTRACE, "  %s\n", unwinder->FormatFrame(i).c_str());
   }
 }
 
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                     const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread) {
   log_t log;
   log.tfd = output_fd.get();
@@ -91,10 +93,10 @@
 
   dump_process_header(&log, target->second.pid, target->second.process_name.c_str());
 
-  dump_backtrace_thread(output_fd.get(), map, target->second);
+  dump_backtrace_thread(output_fd.get(), unwinder, target->second);
   for (const auto& [tid, info] : thread_info) {
     if (tid != target_thread) {
-      dump_backtrace_thread(output_fd.get(), map, info);
+      dump_backtrace_thread(output_fd.get(), unwinder, info);
     }
   }
 
diff --git a/debuggerd/libdebuggerd/elf_utils.cpp b/debuggerd/libdebuggerd/elf_utils.cpp
deleted file mode 100644
index d7afc0b..0000000
--- a/debuggerd/libdebuggerd/elf_utils.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "DEBUG"
-
-#include "libdebuggerd/elf_utils.h"
-
-#include <elf.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <unwindstack/Memory.h>
-
-#define NOTE_ALIGN(size)  (((size) + 3) & ~3)
-
-template <typename HdrType, typename PhdrType, typename NhdrType>
-static bool get_build_id(unwindstack::Memory* memory, uintptr_t base_addr, uint8_t* e_ident,
-                         std::string* build_id) {
-  HdrType hdr;
-
-  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
-
-  // First read the rest of the header.
-  if (memory->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
-                   sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
-    return false;
-  }
-
-  for (size_t i = 0; i < hdr.e_phnum; i++) {
-    PhdrType phdr;
-    if (memory->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
-                     reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
-      return false;
-    }
-    // Looking for the .note.gnu.build-id note.
-    if (phdr.p_type == PT_NOTE) {
-      size_t hdr_size = phdr.p_filesz;
-      uintptr_t addr = base_addr + phdr.p_offset;
-      while (hdr_size >= sizeof(NhdrType)) {
-        NhdrType nhdr;
-        if (memory->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
-          return false;
-        }
-        addr += sizeof(nhdr);
-        if (nhdr.n_type == NT_GNU_BUILD_ID) {
-          // Skip the name (which is the owner and should be "GNU").
-          addr += NOTE_ALIGN(nhdr.n_namesz);
-          uint8_t build_id_data[160];
-          if (nhdr.n_descsz > sizeof(build_id_data)) {
-            ALOGE("Possible corrupted note, desc size value is too large: %u",
-                  nhdr.n_descsz);
-            return false;
-          }
-          if (memory->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
-            return false;
-          }
-
-          build_id->clear();
-          for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
-            *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
-          }
-
-          return true;
-        } else {
-          // Move past the extra note data.
-          hdr_size -= sizeof(nhdr);
-          size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
-          addr += skip_bytes;
-          if (hdr_size < skip_bytes) {
-            break;
-          }
-          hdr_size -= skip_bytes;
-        }
-      }
-    }
-  }
-  return false;
-}
-
-bool elf_get_build_id(unwindstack::Memory* memory, uintptr_t addr, std::string* build_id) {
-  // Read and verify the elf magic number first.
-  uint8_t e_ident[EI_NIDENT];
-  if (memory->Read(addr, e_ident, SELFMAG) != SELFMAG) {
-    return false;
-  }
-
-  if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
-    return false;
-  }
-
-  // Read the rest of EI_NIDENT.
-  if (memory->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
-    return false;
-  }
-
-  if (e_ident[EI_CLASS] == ELFCLASS32) {
-    return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(memory, addr, e_ident, build_id);
-  } else if (e_ident[EI_CLASS] == ELFCLASS64) {
-    return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(memory, addr, e_ident, build_id);
-  }
-
-  return false;
-}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
index 119e59b..c20d090 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/backtrace.h
@@ -28,15 +28,19 @@
 #include "types.h"
 #include "utility.h"
 
-class BacktraceMap;
+// Forward delcaration
+namespace unwindstack {
+class Unwinder;
+}
 
 // Dumps a backtrace using a format similar to what Dalvik uses so that the result
 // can be intermixed in a bug report.
-void dump_backtrace(android::base::unique_fd output_fd, BacktraceMap* map,
+void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                     const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread);
 
 void dump_backtrace_header(int output_fd);
-void dump_backtrace_thread(int output_fd, BacktraceMap* map, const ThreadInfo& thread);
+void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder,
+                           const ThreadInfo& thread);
 void dump_backtrace_footer(int output_fd);
 
 #endif // _DEBUGGERD_BACKTRACE_H
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
index be90d0f..7133f77 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h
@@ -29,7 +29,13 @@
 #include "open_files_list.h"
 #include "types.h"
 
-class BacktraceMap;
+// Forward declarations
+namespace unwindstack {
+class Unwinder;
+}
+
+// The maximum number of frames to save when unwinding.
+constexpr size_t kMaxFrames = 256;
 
 /* Create and open a tombstone file for writing.
  * Returns a writable file descriptor, or -1 with errno set appropriately.
@@ -38,16 +44,15 @@
 int open_tombstone(std::string* path);
 
 /* Creates a tombstone file and writes the crash dump to it. */
-void engrave_tombstone(int tombstone_fd, BacktraceMap* map, const OpenFilesList* open_files,
-                       pid_t pid, pid_t tid, const std::string& process_name,
-                       const std::map<pid_t, std::string>& threads, uint64_t abort_msg_address,
-                       std::string* amfd_data);
+void engrave_tombstone(int tombstone_fd, unwindstack::Unwinder* unwinder,
+                       const OpenFilesList* open_files, pid_t pid, pid_t tid,
+                       const std::string& process_name, const std::map<pid_t, std::string>& threads,
+                       uint64_t abort_msg_address, std::string* amfd_data);
 
 void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo,
                                 ucontext_t* ucontext);
 
-void engrave_tombstone(android::base::unique_fd output_fd, BacktraceMap* map,
-                       unwindstack::Memory* process_memory,
+void engrave_tombstone(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& thread_info, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data);
diff --git a/debuggerd/libdebuggerd/test/BacktraceMock.h b/debuggerd/libdebuggerd/test/BacktraceMock.h
deleted file mode 100644
index e7dbed7..0000000
--- a/debuggerd/libdebuggerd/test/BacktraceMock.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-#define _DEBUGGERD_TEST_BACKTRACE_MOCK_H
-
-#include <backtrace/BacktraceMap.h>
-
-class BacktraceMapMock : public BacktraceMap {
- public:
-  BacktraceMapMock() : BacktraceMap(0) {}
-  virtual ~BacktraceMapMock() {}
-
-  void AddMap(backtrace_map_t& map) {
-    maps_.push_back(map);
-  }
-};
-
-#endif //  _DEBUGGERD_TEST_BACKTRACE_MOCK_H
diff --git a/debuggerd/libdebuggerd/test/UnwinderMock.h b/debuggerd/libdebuggerd/test/UnwinderMock.h
new file mode 100644
index 0000000..023a578
--- /dev/null
+++ b/debuggerd/libdebuggerd/test/UnwinderMock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Unwinder.h>
+
+class UnwinderMock : public unwindstack::Unwinder {
+ public:
+  UnwinderMock() : Unwinder(128, new unwindstack::Maps, nullptr) {}
+  virtual ~UnwinderMock() { delete GetMaps(); }
+
+  void MockAddMap(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, std::string name,
+                  uint64_t load_bias) {
+    GetMaps()->Add(start, end, offset, flags, name, load_bias);
+  }
+
+  void MockSetBuildID(uint64_t offset, const std::string& build_id) {
+    unwindstack::MapInfo* map_info = GetMaps()->Find(offset);
+    if (map_info != nullptr) {
+      std::string* new_build_id = new std::string(build_id);
+      map_info->build_id = reinterpret_cast<uintptr_t>(new_build_id);
+    }
+  }
+};
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index d24c887..eed5bd3 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -26,26 +26,16 @@
 
 #include "libdebuggerd/utility.h"
 
-#include "BacktraceMock.h"
-#include "elf_fake.h"
+#include "UnwinderMock.h"
 #include "host_signal_fixup.h"
 #include "log_fake.h"
 
 #include "tombstone.cpp"
 
-void dump_registers(log_t*, pid_t) {
-}
-
-void dump_memory_and_code(log_t*, Backtrace*) {
-}
-
-void dump_backtrace_to_log(Backtrace*, log_t*, char const*) {
-}
-
 class TombstoneTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
-    map_mock_.reset(new BacktraceMapMock());
+    unwinder_mock_.reset(new UnwinderMock());
 
     char tmp_file[256];
     const char data_template[] = "/data/local/tmp/debuggerd_memory_testXXXXXX";
@@ -71,7 +61,6 @@
     log_.should_retrieve_logcat = false;
 
     resetLogs();
-    elf_set_fake_build_id("");
   }
 
   virtual void TearDown() {
@@ -80,24 +69,20 @@
     }
   }
 
-  std::unique_ptr<BacktraceMapMock> map_mock_;
+  std::unique_ptr<UnwinderMock> unwinder_mock_;
 
   log_t log_;
   std::string amfd_data_;
 };
 
 TEST_F(TombstoneTest, single_map) {
-  backtrace_map_t map;
 #if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
+  unwinder_mock_->MockAddMap(0x123456789abcd000UL, 0x123456789abdf000UL, 0, 0, "", 0);
 #else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
+  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, 0, "", 0);
 #endif
-  map_mock_->AddMap(map);
 
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -119,20 +104,25 @@
 }
 
 TEST_F(TombstoneTest, single_map_elf_build_id) {
-  backtrace_map_t map;
+  uint64_t build_id_offset;
 #if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
+  build_id_offset = 0x123456789abcd000UL;
+  unwinder_mock_->MockAddMap(build_id_offset, 0x123456789abdf000UL, 0, PROT_READ,
+                             "/system/lib/libfake.so", 0);
 #else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
+  build_id_offset = 0x1234000;
+  unwinder_mock_->MockAddMap(0x1234000, 0x1235000, 0, PROT_READ, "/system/lib/libfake.so", 0);
 #endif
-  map.flags = PROT_READ;
-  map.name = "/system/lib/libfake.so";
-  map_mock_->AddMap(map);
 
-  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  unwinder_mock_->MockSetBuildID(
+      build_id_offset,
+      std::string{static_cast<char>(0xab), static_cast<char>(0xcd), static_cast<char>(0xef),
+                  static_cast<char>(0x12), static_cast<char>(0x34), static_cast<char>(0x56),
+                  static_cast<char>(0x78), static_cast<char>(0x90), static_cast<char>(0xab),
+                  static_cast<char>(0xcd), static_cast<char>(0xef), static_cast<char>(0x12),
+                  static_cast<char>(0x34), static_cast<char>(0x56), static_cast<char>(0x78),
+                  static_cast<char>(0x90)});
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -153,83 +143,15 @@
   ASSERT_STREQ("", getFakeLogPrint().c_str());
 }
 
-// Even though build id is present, it should not be printed in either of
-// these cases.
-TEST_F(TombstoneTest, single_map_no_build_id) {
-  backtrace_map_t map;
-#if defined(__LP64__)
-  map.start = 0x123456789abcd000UL;
-  map.end = 0x123456789abdf000UL;
-#else
-  map.start = 0x1234000;
-  map.end = 0x1235000;
-#endif
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.name = "/system/lib/libfake.so";
-  map_mock_->AddMap(map);
-
-  elf_set_fake_build_id("abcdef1234567890abcdef1234567890");
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
-
-  std::string tombstone_contents;
-  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
-  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents));
-  const char* expected_dump = \
-"\nmemory map (2 entries):\n"
-#if defined(__LP64__)
-"    12345678'9abcd000-12345678'9abdefff -w-         0     12000\n"
-"    12345678'9abcd000-12345678'9abdefff -w-         0     12000  /system/lib/libfake.so\n";
-#else
-"    01234000-01234fff -w-         0      1000\n"
-"    01234000-01234fff -w-         0      1000  /system/lib/libfake.so\n";
-#endif
-  ASSERT_STREQ(expected_dump, tombstone_contents.c_str());
-
-  ASSERT_STREQ("", amfd_data_.c_str());
-
-  // Verify that the log buf is empty, and no error messages.
-  ASSERT_STREQ("", getFakeLogBuf().c_str());
-  ASSERT_STREQ("", getFakeLogPrint().c_str());
-}
-
 TEST_F(TombstoneTest, multiple_maps) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa234000, 0xa235000, 0, 0, "", 0);
+  unwinder_mock_->MockAddMap(0xa334000, 0xa335000, 0xf000, PROT_READ, "", 0);
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa234000;
-  map.end = 0xa235000;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa334000;
-  map.end = 0xa335000;
-  map.offset = 0xf000;
-  map.flags = PROT_READ;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -259,31 +181,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_before) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0x1000);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0x1000);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -311,31 +214,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_between) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa533000);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0xa533000);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -363,31 +247,12 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_in_map) {
-  backtrace_map_t map;
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
-
-  dump_all_maps(&log_, map_mock_.get(), nullptr, 0xa534040);
+  dump_all_maps(&log_, unwinder_mock_.get(), 0xa534040);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -413,36 +278,17 @@
 }
 
 TEST_F(TombstoneTest, multiple_maps_fault_address_after) {
-  backtrace_map_t map;
-
-  map.start = 0xa434000;
-  map.end = 0xa435000;
-  map.offset = 0x1000;
-  map.load_bias = 0xd000;
-  map.flags = PROT_WRITE;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa534000;
-  map.end = 0xa535000;
-  map.offset = 0x3000;
-  map.load_bias = 0x2000;
-  map.flags = PROT_EXEC;
-  map_mock_->AddMap(map);
-
-  map.start = 0xa634000;
-  map.end = 0xa635000;
-  map.offset = 0;
-  map.load_bias = 0;
-  map.flags = PROT_READ | PROT_WRITE | PROT_EXEC;
-  map.name = "/system/lib/fake.so";
-  map_mock_->AddMap(map);
+  unwinder_mock_->MockAddMap(0xa434000, 0xa435000, 0x1000, PROT_WRITE, "", 0xd000);
+  unwinder_mock_->MockAddMap(0xa534000, 0xa535000, 0x3000, PROT_EXEC, "", 0x2000);
+  unwinder_mock_->MockAddMap(0xa634000, 0xa635000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+                             "/system/lib/fake.so", 0);
 
 #if defined(__LP64__)
   uint64_t addr = 0x12345a534040UL;
 #else
   uint64_t addr = 0xf534040UL;
 #endif
-  dump_all_maps(&log_, map_mock_.get(), nullptr, addr);
+  dump_all_maps(&log_, unwinder_mock_.get(), addr);
 
   std::string tombstone_contents;
   ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
@@ -502,3 +348,467 @@
   dump_timestamp(&log_, 0);
   ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str());
 }
+
+class MemoryPattern : public unwindstack::Memory {
+ public:
+  MemoryPattern() = default;
+  virtual ~MemoryPattern() = default;
+
+  size_t Read(uint64_t, void* dst, size_t size) override {
+    uint8_t* data = reinterpret_cast<uint8_t*>(dst);
+    for (size_t i = 0; i < size; i++) {
+      data[i] = (i % 0xff);
+    }
+    return size;
+  }
+};
+
+TEST_F(TombstoneTest, dump_stack_single_frame) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "         0000000000002010  1716151413121110\n"
+      "         0000000000002018  1f1e1d1c1b1a1918\n"
+      "         0000000000002020  2726252423222120\n"
+      "         0000000000002028  2f2e2d2c2b2a2928\n"
+      "         0000000000002030  3736353433323130\n"
+      "         0000000000002038  3f3e3d3c3b3a3938\n"
+      "         0000000000002040  4746454443424140\n"
+      "         0000000000002048  4f4e4d4c4b4a4948\n"
+      "         0000000000002050  5756555453525150\n"
+      "         0000000000002058  5f5e5d5c5b5a5958\n"
+      "         0000000000002060  6766656463626160\n"
+      "         0000000000002068  6f6e6d6c6b6a6968\n"
+      "         0000000000002070  7776757473727170\n"
+      "         0000000000002078  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "         00002010  13121110\n"
+      "         00002014  17161514\n"
+      "         00002018  1b1a1918\n"
+      "         0000201c  1f1e1d1c\n"
+      "         00002020  23222120\n"
+      "         00002024  27262524\n"
+      "         00002028  2b2a2928\n"
+      "         0000202c  2f2e2d2c\n"
+      "         00002030  33323130\n"
+      "         00002034  37363534\n"
+      "         00002038  3b3a3938\n"
+      "         0000203c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_same_sp) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2000});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         ................  ................\n"
+      "    #01  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "         0000000000002010  1716151413121110\n"
+      "         0000000000002018  1f1e1d1c1b1a1918\n"
+      "         0000000000002020  2726252423222120\n"
+      "         0000000000002028  2f2e2d2c2b2a2928\n"
+      "         0000000000002030  3736353433323130\n"
+      "         0000000000002038  3f3e3d3c3b3a3938\n"
+      "         0000000000002040  4746454443424140\n"
+      "         0000000000002048  4f4e4d4c4b4a4948\n"
+      "         0000000000002050  5756555453525150\n"
+      "         0000000000002058  5f5e5d5c5b5a5958\n"
+      "         0000000000002060  6766656463626160\n"
+      "         0000000000002068  6f6e6d6c6b6a6968\n"
+      "         0000000000002070  7776757473727170\n"
+      "         0000000000002078  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         ........  ........\n"
+      "    #01  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "         00002010  13121110\n"
+      "         00002014  17161514\n"
+      "         00002018  1b1a1918\n"
+      "         0000201c  1f1e1d1c\n"
+      "         00002020  23222120\n"
+      "         00002024  27262524\n"
+      "         00002028  2b2a2928\n"
+      "         0000202c  2f2e2d2c\n"
+      "         00002030  33323130\n"
+      "         00002034  37363534\n"
+      "         00002038  3b3a3938\n"
+      "         0000203c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2100});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "    #01  0000000000002010  0706050403020100\n"
+      "         0000000000002018  0f0e0d0c0b0a0908\n"
+      "         0000000000002020  1716151413121110\n"
+      "         0000000000002028  1f1e1d1c1b1a1918\n"
+      "         0000000000002030  2726252423222120\n"
+      "         0000000000002038  2f2e2d2c2b2a2928\n"
+      "         0000000000002040  3736353433323130\n"
+      "         0000000000002048  3f3e3d3c3b3a3938\n"
+      "         0000000000002050  4746454443424140\n"
+      "         0000000000002058  4f4e4d4c4b4a4948\n"
+      "         0000000000002060  5756555453525150\n"
+      "         0000000000002068  5f5e5d5c5b5a5958\n"
+      "         0000000000002070  6766656463626160\n"
+      "         0000000000002078  6f6e6d6c6b6a6968\n"
+      "         0000000000002080  7776757473727170\n"
+      "         0000000000002088  7f7e7d7c7b7a7978\n"
+      "         ................  ................\n"
+      "    #02  0000000000002100  0706050403020100\n"
+      "         0000000000002108  0f0e0d0c0b0a0908\n"
+      "         0000000000002110  1716151413121110\n"
+      "         0000000000002118  1f1e1d1c1b1a1918\n"
+      "         0000000000002120  2726252423222120\n"
+      "         0000000000002128  2f2e2d2c2b2a2928\n"
+      "         0000000000002130  3736353433323130\n"
+      "         0000000000002138  3f3e3d3c3b3a3938\n"
+      "         0000000000002140  4746454443424140\n"
+      "         0000000000002148  4f4e4d4c4b4a4948\n"
+      "         0000000000002150  5756555453525150\n"
+      "         0000000000002158  5f5e5d5c5b5a5958\n"
+      "         0000000000002160  6766656463626160\n"
+      "         0000000000002168  6f6e6d6c6b6a6968\n"
+      "         0000000000002170  7776757473727170\n"
+      "         0000000000002178  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "    #01  00002010  03020100\n"
+      "         00002014  07060504\n"
+      "         00002018  0b0a0908\n"
+      "         0000201c  0f0e0d0c\n"
+      "         00002020  13121110\n"
+      "         00002024  17161514\n"
+      "         00002028  1b1a1918\n"
+      "         0000202c  1f1e1d1c\n"
+      "         00002030  23222120\n"
+      "         00002034  27262524\n"
+      "         00002038  2b2a2928\n"
+      "         0000203c  2f2e2d2c\n"
+      "         00002040  33323130\n"
+      "         00002044  37363534\n"
+      "         00002048  3b3a3938\n"
+      "         0000204c  3f3e3d3c\n"
+      "         ........  ........\n"
+      "    #02  00002100  03020100\n"
+      "         00002104  07060504\n"
+      "         00002108  0b0a0908\n"
+      "         0000210c  0f0e0d0c\n"
+      "         00002110  13121110\n"
+      "         00002114  17161514\n"
+      "         00002118  1b1a1918\n"
+      "         0000211c  1f1e1d1c\n"
+      "         00002120  23222120\n"
+      "         00002124  27262524\n"
+      "         00002128  2b2a2928\n"
+      "         0000212c  2f2e2d2c\n"
+      "         00002130  33323130\n"
+      "         00002134  37363534\n"
+      "         00002138  3b3a3938\n"
+      "         0000213c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
+
+TEST_F(TombstoneTest, dump_stack_multiple_frames_disjoint_frames) {
+  std::vector<unwindstack::FrameData> frames;
+  unwindstack::Maps maps;
+  MemoryPattern memory;
+
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1000, .pc = 0x301000, .sp = 0x2000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x2010});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1000});
+  frames.push_back(
+      unwindstack::FrameData{.num = 0, .rel_pc = 0x1400, .pc = 0x301400, .sp = 0x1030});
+  dump_stack(&log_, frames, &maps, &memory);
+
+  std::string contents;
+  ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
+  ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &contents));
+
+  std::string expected =
+#if defined(__LP64__)
+      "         0000000000001f80  0706050403020100\n"
+      "         0000000000001f88  0f0e0d0c0b0a0908\n"
+      "         0000000000001f90  1716151413121110\n"
+      "         0000000000001f98  1f1e1d1c1b1a1918\n"
+      "         0000000000001fa0  2726252423222120\n"
+      "         0000000000001fa8  2f2e2d2c2b2a2928\n"
+      "         0000000000001fb0  3736353433323130\n"
+      "         0000000000001fb8  3f3e3d3c3b3a3938\n"
+      "         0000000000001fc0  4746454443424140\n"
+      "         0000000000001fc8  4f4e4d4c4b4a4948\n"
+      "         0000000000001fd0  5756555453525150\n"
+      "         0000000000001fd8  5f5e5d5c5b5a5958\n"
+      "         0000000000001fe0  6766656463626160\n"
+      "         0000000000001fe8  6f6e6d6c6b6a6968\n"
+      "         0000000000001ff0  7776757473727170\n"
+      "         0000000000001ff8  7f7e7d7c7b7a7978\n"
+      "    #00  0000000000002000  0706050403020100\n"
+      "         0000000000002008  0f0e0d0c0b0a0908\n"
+      "    #01  0000000000002010  0706050403020100\n"
+      "         0000000000002018  0f0e0d0c0b0a0908\n"
+      "         0000000000002020  1716151413121110\n"
+      "         0000000000002028  1f1e1d1c1b1a1918\n"
+      "         0000000000002030  2726252423222120\n"
+      "         0000000000002038  2f2e2d2c2b2a2928\n"
+      "         0000000000002040  3736353433323130\n"
+      "         0000000000002048  3f3e3d3c3b3a3938\n"
+      "         0000000000002050  4746454443424140\n"
+      "         0000000000002058  4f4e4d4c4b4a4948\n"
+      "         0000000000002060  5756555453525150\n"
+      "         0000000000002068  5f5e5d5c5b5a5958\n"
+      "         0000000000002070  6766656463626160\n"
+      "         0000000000002078  6f6e6d6c6b6a6968\n"
+      "         0000000000002080  7776757473727170\n"
+      "         0000000000002088  7f7e7d7c7b7a7978\n"
+      "         ................  ................\n"
+      "    #02  0000000000001000  0706050403020100\n"
+      "         0000000000001008  0f0e0d0c0b0a0908\n"
+      "         0000000000001010  1716151413121110\n"
+      "         0000000000001018  1f1e1d1c1b1a1918\n"
+      "         0000000000001020  2726252423222120\n"
+      "         0000000000001028  2f2e2d2c2b2a2928\n"
+      "    #03  0000000000001030  0706050403020100\n"
+      "         0000000000001038  0f0e0d0c0b0a0908\n"
+      "         0000000000001040  1716151413121110\n"
+      "         0000000000001048  1f1e1d1c1b1a1918\n"
+      "         0000000000001050  2726252423222120\n"
+      "         0000000000001058  2f2e2d2c2b2a2928\n"
+      "         0000000000001060  3736353433323130\n"
+      "         0000000000001068  3f3e3d3c3b3a3938\n"
+      "         0000000000001070  4746454443424140\n"
+      "         0000000000001078  4f4e4d4c4b4a4948\n"
+      "         0000000000001080  5756555453525150\n"
+      "         0000000000001088  5f5e5d5c5b5a5958\n"
+      "         0000000000001090  6766656463626160\n"
+      "         0000000000001098  6f6e6d6c6b6a6968\n"
+      "         00000000000010a0  7776757473727170\n"
+      "         00000000000010a8  7f7e7d7c7b7a7978\n";
+#else
+      "         00001fc0  03020100\n"
+      "         00001fc4  07060504\n"
+      "         00001fc8  0b0a0908\n"
+      "         00001fcc  0f0e0d0c\n"
+      "         00001fd0  13121110\n"
+      "         00001fd4  17161514\n"
+      "         00001fd8  1b1a1918\n"
+      "         00001fdc  1f1e1d1c\n"
+      "         00001fe0  23222120\n"
+      "         00001fe4  27262524\n"
+      "         00001fe8  2b2a2928\n"
+      "         00001fec  2f2e2d2c\n"
+      "         00001ff0  33323130\n"
+      "         00001ff4  37363534\n"
+      "         00001ff8  3b3a3938\n"
+      "         00001ffc  3f3e3d3c\n"
+      "    #00  00002000  03020100\n"
+      "         00002004  07060504\n"
+      "         00002008  0b0a0908\n"
+      "         0000200c  0f0e0d0c\n"
+      "    #01  00002010  03020100\n"
+      "         00002014  07060504\n"
+      "         00002018  0b0a0908\n"
+      "         0000201c  0f0e0d0c\n"
+      "         00002020  13121110\n"
+      "         00002024  17161514\n"
+      "         00002028  1b1a1918\n"
+      "         0000202c  1f1e1d1c\n"
+      "         00002030  23222120\n"
+      "         00002034  27262524\n"
+      "         00002038  2b2a2928\n"
+      "         0000203c  2f2e2d2c\n"
+      "         00002040  33323130\n"
+      "         00002044  37363534\n"
+      "         00002048  3b3a3938\n"
+      "         0000204c  3f3e3d3c\n"
+      "         ........  ........\n"
+      "    #02  00001000  03020100\n"
+      "         00001004  07060504\n"
+      "         00001008  0b0a0908\n"
+      "         0000100c  0f0e0d0c\n"
+      "         00001010  13121110\n"
+      "         00001014  17161514\n"
+      "         00001018  1b1a1918\n"
+      "         0000101c  1f1e1d1c\n"
+      "         00001020  23222120\n"
+      "         00001024  27262524\n"
+      "         00001028  2b2a2928\n"
+      "         0000102c  2f2e2d2c\n"
+      "    #03  00001030  03020100\n"
+      "         00001034  07060504\n"
+      "         00001038  0b0a0908\n"
+      "         0000103c  0f0e0d0c\n"
+      "         00001040  13121110\n"
+      "         00001044  17161514\n"
+      "         00001048  1b1a1918\n"
+      "         0000104c  1f1e1d1c\n"
+      "         00001050  23222120\n"
+      "         00001054  27262524\n"
+      "         00001058  2b2a2928\n"
+      "         0000105c  2f2e2d2c\n"
+      "         00001060  33323130\n"
+      "         00001064  37363534\n"
+      "         00001068  3b3a3938\n"
+      "         0000106c  3f3e3d3c\n";
+#endif
+  EXPECT_EQ(expected, contents);
+}
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index b20014f..8798ad3 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -41,19 +41,20 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/log.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
 #include <log/log.h>
 #include <log/logprint.h>
 #include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/JitDebug.h>
+#include <unwindstack/Maps.h>
 #include <unwindstack/Memory.h>
 #include <unwindstack/Regs.h>
+#include <unwindstack/Unwinder.h>
 
 // Needed to get DEBUGGER_SIGNAL.
 #include "debuggerd/handler.h"
 
 #include "libdebuggerd/backtrace.h"
-#include "libdebuggerd/elf_utils.h"
 #include "libdebuggerd/open_files_list.h"
 #include "libdebuggerd/utility.h"
 
@@ -62,9 +63,6 @@
 using android::base::StringPrintf;
 using android::base::unique_fd;
 
-using unwindstack::Memory;
-using unwindstack::Regs;
-
 using namespace std::literals::string_literals;
 
 #define STACK_WORDS 16
@@ -87,7 +85,7 @@
   _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf);
 }
 
-static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, unwindstack::Maps* maps) {
   std::string cause;
   if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
     if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -104,12 +102,9 @@
       cause = "call to kuser_cmpxchg64";
     }
   } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
-    for (auto it = map->begin(); it != map->end(); ++it) {
-      const backtrace_map_t* entry = *it;
-      if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
-          si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
-        cause = "execute-only (no-read) memory access error; likely due to data in .text.";
-      }
+    unwindstack::MapInfo* map_info = maps->Find(reinterpret_cast<uint64_t>(si->si_addr));
+    if (map_info != nullptr && map_info->flags == PROT_EXEC) {
+      cause = "execute-only (no-read) memory access error; likely due to data in .text.";
     }
   } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
     cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
@@ -119,7 +114,8 @@
   if (!cause.empty()) _LOG(log, logtype::HEADER, "Cause: %s\n", cause.c_str());
 }
 
-static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, Memory* process_memory) {
+static void dump_signal_info(log_t* log, const ThreadInfo& thread_info,
+                             unwindstack::Memory* process_memory) {
   char addr_desc[64];  // ", fault addr 0x1234"
   if (signal_has_si_addr(thread_info.siginfo)) {
     void* addr = thread_info.siginfo->si_addr;
@@ -156,14 +152,14 @@
        thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
 }
 
-static void dump_stack_segment(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
+static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
                                uint64_t* sp, size_t words, int label) {
   // Read the data all at once.
   word_t stack_data[words];
 
   // TODO: Do we need to word align this for crashes caused by a misaligned sp?
   //       The process_vm_readv implementation of Memory should handle this appropriately?
-  size_t bytes_read = process_memory->Read(*sp, stack_data, sizeof(word_t) * words);
+  size_t bytes_read = memory->Read(*sp, stack_data, sizeof(word_t) * words);
   words = bytes_read / sizeof(word_t);
   std::string line;
   for (size_t i = 0; i < words; i++) {
@@ -176,17 +172,15 @@
     }
     line += StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, static_cast<uint64_t>(stack_data[i]));
 
-    backtrace_map_t map;
-    backtrace_map->FillIn(stack_data[i], &map);
-    std::string map_name{map.Name()};
-    if (BacktraceMap::IsValid(map) && !map_name.empty()) {
-      line += "  " + map_name;
-      uint64_t offset = 0;
-      std::string func_name = backtrace_map->GetFunctionName(stack_data[i], &offset);
-      if (!func_name.empty()) {
+    unwindstack::MapInfo* map_info = maps->Find(stack_data[i]);
+    if (map_info != nullptr && !map_info->name.empty()) {
+      line += "  " + map_info->name;
+      std::string func_name;
+      uint64_t func_offset = 0;
+      if (map_info->GetFunctionName(stack_data[i], &func_name, &func_offset)) {
         line += " (" + func_name;
-        if (offset) {
-          line += StringPrintf("+%" PRIu64, offset);
+        if (func_offset) {
+          line += StringPrintf("+%" PRIu64, func_offset);
         }
         line += ')';
       }
@@ -197,12 +191,11 @@
   }
 }
 
-static void dump_stack(log_t* log, BacktraceMap* backtrace_map, Memory* process_memory,
-                       std::vector<backtrace_frame_data_t>& frames) {
+static void dump_stack(log_t* log, const std::vector<unwindstack::FrameData>& frames,
+                       unwindstack::Maps* maps, unwindstack::Memory* memory) {
   size_t first = 0, last;
   for (size_t i = 0; i < frames.size(); i++) {
-    const backtrace_frame_data_t& frame = frames[i];
-    if (frame.sp) {
+    if (frames[i].sp) {
       if (!first) {
         first = i+1;
       }
@@ -217,29 +210,44 @@
 
   // Dump a few words before the first frame.
   uint64_t sp = frames[first].sp - STACK_WORDS * sizeof(word_t);
-  dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, -1);
+  dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, -1);
+
+#if defined(__LP64__)
+  static constexpr const char delimiter[] = "         ................  ................\n";
+#else
+  static constexpr const char delimiter[] = "         ........  ........\n";
+#endif
 
   // Dump a few words from all successive frames.
-  // Only log the first 3 frames, put the rest in the tombstone.
   for (size_t i = first; i <= last; i++) {
-    const backtrace_frame_data_t* frame = &frames[i];
+    auto* frame = &frames[i];
     if (sp != frame->sp) {
-      _LOG(log, logtype::STACK, "         ........  ........\n");
+      _LOG(log, logtype::STACK, delimiter);
       sp = frame->sp;
     }
-    if (i == last) {
-      dump_stack_segment(log, backtrace_map, process_memory, &sp, STACK_WORDS, i);
-      if (sp < frame->sp + frame->stack_size) {
-        _LOG(log, logtype::STACK, "         ........  ........\n");
-      }
-    } else {
-      size_t words = frame->stack_size / sizeof(word_t);
-      if (words == 0) {
-        words = 1;
-      } else if (words > STACK_WORDS) {
+    if (i != last) {
+      // Print stack data up to the stack from the next frame.
+      size_t words;
+      uint64_t next_sp = frames[i + 1].sp;
+      if (next_sp < sp) {
+        // The next frame is probably using a completely different stack,
+        // so dump the max from this stack.
         words = STACK_WORDS;
+      } else {
+        words = (next_sp - sp) / sizeof(word_t);
+        if (words == 0) {
+          // The sp is the same as the next frame, print at least
+          // one line for this frame.
+          words = 1;
+        } else if (words > STACK_WORDS) {
+          words = STACK_WORDS;
+        }
       }
-      dump_stack_segment(log, backtrace_map, process_memory, &sp, words, i);
+      dump_stack_segment(log, maps, memory, &sp, words, i);
+    } else {
+      // Print some number of words past the last stack frame since we
+      // don't know how large the stack is.
+      dump_stack_segment(log, maps, memory, &sp, STACK_WORDS, i);
     }
   }
 }
@@ -256,7 +264,7 @@
   return addr_str;
 }
 
-static void dump_abort_message(log_t* log, Memory* process_memory, uint64_t address) {
+static void dump_abort_message(log_t* log, unwindstack::Memory* process_memory, uint64_t address) {
   if (address == 0) {
     return;
   }
@@ -285,16 +293,16 @@
   _LOG(log, logtype::HEADER, "Abort message: '%s'\n", &msg[0]);
 }
 
-static void dump_all_maps(log_t* log, BacktraceMap* map, Memory* process_memory, uint64_t addr) {
+static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t addr) {
   bool print_fault_address_marker = addr;
 
-  ScopedBacktraceMapIteratorLock lock(map);
+  unwindstack::Maps* maps = unwinder->GetMaps();
   _LOG(log, logtype::MAPS,
        "\n"
        "memory map (%zu entr%s):",
-       map->size(), map->size() == 1 ? "y" : "ies");
+       maps->Total(), maps->Total() == 1 ? "y" : "ies");
   if (print_fault_address_marker) {
-    if (map->begin() != map->end() && addr < (*map->begin())->start) {
+    if (maps->Total() != 0 && addr < maps->Get(0)->start) {
       _LOG(log, logtype::MAPS, "\n--->Fault address falls at %s before any mapped regions\n",
            get_addr_string(addr).c_str());
       print_fault_address_marker = false;
@@ -305,51 +313,54 @@
     _LOG(log, logtype::MAPS, "\n");
   }
 
+  std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory();
+
   std::string line;
-  for (auto it = map->begin(); it != map->end(); ++it) {
-    const backtrace_map_t* entry = *it;
+  for (unwindstack::MapInfo* map_info : *maps) {
     line = "    ";
     if (print_fault_address_marker) {
-      if (addr < entry->start) {
+      if (addr < map_info->start) {
         _LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
              get_addr_string(addr).c_str());
         print_fault_address_marker = false;
-      } else if (addr >= entry->start && addr < entry->end) {
+      } else if (addr >= map_info->start && addr < map_info->end) {
         line = "--->";
         print_fault_address_marker = false;
       }
     }
-    line += get_addr_string(entry->start) + '-' + get_addr_string(entry->end - 1) + ' ';
-    if (entry->flags & PROT_READ) {
+    line += get_addr_string(map_info->start) + '-' + get_addr_string(map_info->end - 1) + ' ';
+    if (map_info->flags & PROT_READ) {
       line += 'r';
     } else {
       line += '-';
     }
-    if (entry->flags & PROT_WRITE) {
+    if (map_info->flags & PROT_WRITE) {
       line += 'w';
     } else {
       line += '-';
     }
-    if (entry->flags & PROT_EXEC) {
+    if (map_info->flags & PROT_EXEC) {
       line += 'x';
     } else {
       line += '-';
     }
-    line += StringPrintf("  %8" PRIx64 "  %8" PRIx64, entry->offset, entry->end - entry->start);
+    line += StringPrintf("  %8" PRIx64 "  %8" PRIx64, map_info->offset,
+                         map_info->end - map_info->start);
     bool space_needed = true;
-    if (entry->name.length() > 0) {
+    if (!map_info->name.empty()) {
       space_needed = false;
-      line += "  " + entry->name;
-      std::string build_id;
-      if ((entry->flags & PROT_READ) && elf_get_build_id(process_memory, entry->start, &build_id)) {
+      line += "  " + map_info->name;
+      std::string build_id = map_info->GetPrintableBuildID();
+      if (!build_id.empty()) {
         line += " (BuildId: " + build_id + ")";
       }
     }
-    if (entry->load_bias != 0) {
+    uint64_t load_bias = map_info->GetLoadBias(process_memory);
+    if (load_bias != 0) {
       if (space_needed) {
         line += ' ';
       }
-      line += StringPrintf(" (load bias 0x%" PRIx64 ")", entry->load_bias);
+      line += StringPrintf(" (load bias 0x%" PRIx64 ")", load_bias);
     }
     _LOG(log, logtype::MAPS, "%s\n", line.c_str());
   }
@@ -359,9 +370,9 @@
   }
 }
 
-void dump_backtrace(log_t* log, std::vector<backtrace_frame_data_t>& frames, const char* prefix) {
-  for (auto& frame : frames) {
-    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, Backtrace::FormatFrameData(&frame).c_str());
+void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) {
+  for (size_t i = 0; i < unwinder->NumFrames(); i++) {
+    _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str());
   }
 }
 
@@ -377,7 +388,7 @@
   _LOG(log, logtype::REGISTERS, "  %s\n", output.c_str());
 }
 
-void dump_registers(log_t* log, Regs* regs) {
+void dump_registers(log_t* log, unwindstack::Regs* regs) {
   // Split lr/sp/pc into their own special row.
   static constexpr size_t column_count = 4;
   std::vector<std::pair<std::string, uint64_t>> current_row;
@@ -416,23 +427,22 @@
   print_register_row(log, special_row);
 }
 
-void dump_memory_and_code(log_t* log, BacktraceMap* map, Memory* memory, Regs* regs) {
-  regs->IterateRegisters([log, map, memory](const char* reg_name, uint64_t reg_value) {
+void dump_memory_and_code(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory,
+                          unwindstack::Regs* regs) {
+  regs->IterateRegisters([log, maps, memory](const char* reg_name, uint64_t reg_value) {
     std::string label{"memory near "s + reg_name};
-    if (map) {
-      backtrace_map_t map_info;
-      map->FillIn(reg_value, &map_info);
-      std::string map_name{map_info.Name()};
-      if (!map_name.empty()) label += " (" + map_info.Name() + ")";
+    if (maps) {
+      unwindstack::MapInfo* map_info = maps->Find(reg_value);
+      if (map_info != nullptr && !map_info->name.empty()) {
+        label += " (" + map_info->name + ")";
+      }
     }
     dump_memory(log, memory, reg_value, label);
   });
 }
 
-static bool dump_thread(log_t* log, BacktraceMap* map, Memory* process_memory,
-                        const ThreadInfo& thread_info, uint64_t abort_msg_address,
-                        bool primary_thread) {
-  UNUSED(process_memory);
+static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const ThreadInfo& thread_info,
+                        uint64_t abort_msg_address, bool primary_thread) {
   log->current_tid = thread_info.tid;
   if (!primary_thread) {
     _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
@@ -440,41 +450,41 @@
   dump_thread_info(log, thread_info);
 
   if (thread_info.siginfo) {
-    dump_signal_info(log, thread_info, process_memory);
-    dump_probable_cause(log, thread_info.siginfo, map);
+    dump_signal_info(log, thread_info, unwinder->GetProcessMemory().get());
+    dump_probable_cause(log, thread_info.siginfo, unwinder->GetMaps());
   }
 
   if (primary_thread) {
-    dump_abort_message(log, process_memory, abort_msg_address);
+    dump_abort_message(log, unwinder->GetProcessMemory().get(), abort_msg_address);
   }
 
   dump_registers(log, thread_info.registers.get());
 
   // Unwind will mutate the registers, so make a copy first.
-  std::unique_ptr<Regs> regs_copy(thread_info.registers->Clone());
-  std::vector<backtrace_frame_data_t> frames;
-  if (!Backtrace::Unwind(regs_copy.get(), map, &frames, 0, nullptr)) {
+  std::unique_ptr<unwindstack::Regs> regs_copy(thread_info.registers->Clone());
+  unwinder->SetRegs(regs_copy.get());
+  unwinder->Unwind();
+  if (unwinder->NumFrames() == 0) {
     _LOG(log, logtype::THREAD, "Failed to unwind");
-    return false;
-  }
-
-  if (!frames.empty()) {
+  } else {
     _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
-    dump_backtrace(log, frames, "    ");
+    dump_backtrace(log, unwinder, "    ");
 
     _LOG(log, logtype::STACK, "\nstack:\n");
-    dump_stack(log, map, process_memory, frames);
+    dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get());
   }
 
   if (primary_thread) {
-    dump_memory_and_code(log, map, process_memory, thread_info.registers.get());
-    if (map) {
+    unwindstack::Maps* maps = unwinder->GetMaps();
+    dump_memory_and_code(log, maps, unwinder->GetProcessMemory().get(),
+                         thread_info.registers.get());
+    if (maps != nullptr) {
       uint64_t addr = 0;
       siginfo_t* si = thread_info.siginfo;
       if (signal_has_si_addr(si)) {
         addr = reinterpret_cast<uint64_t>(si->si_addr);
       }
-      dump_all_maps(log, map, process_memory, addr);
+      dump_all_maps(log, unwinder, addr);
     }
   }
 
@@ -625,7 +635,8 @@
   read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>");
   read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>");
 
-  std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
+  std::unique_ptr<unwindstack::Regs> regs(
+      unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
 
   std::map<pid_t, ThreadInfo> threads;
   threads[gettid()] = ThreadInfo{
@@ -637,18 +648,16 @@
       .siginfo = siginfo,
   };
 
-  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid(), false));
-  if (!backtrace_map) {
-    ALOGE("failed to create backtrace map");
-    _exit(1);
+  unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
+  if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+    LOG(FATAL) << "Failed to init unwinder object.";
   }
 
-  std::shared_ptr<Memory> process_memory = backtrace_map->GetProcessMemory();
-  engrave_tombstone(unique_fd(dup(tombstone_fd)), backtrace_map.get(), process_memory.get(),
-                    threads, tid, abort_msg_address, nullptr, nullptr);
+  engrave_tombstone(unique_fd(dup(tombstone_fd)), &unwinder, threads, tid, abort_msg_address,
+                    nullptr, nullptr);
 }
 
-void engrave_tombstone(unique_fd output_fd, BacktraceMap* map, Memory* process_memory,
+void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder,
                        const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread,
                        uint64_t abort_msg_address, OpenFilesList* open_files,
                        std::string* amfd_data) {
@@ -669,7 +678,7 @@
   if (it == threads.end()) {
     LOG(FATAL) << "failed to find target thread";
   }
-  dump_thread(&log, map, process_memory, it->second, abort_msg_address, true);
+  dump_thread(&log, unwinder, it->second, abort_msg_address, true);
 
   if (want_logs) {
     dump_logs(&log, it->second.pid, 50);
@@ -680,7 +689,7 @@
       continue;
     }
 
-    dump_thread(&log, map, process_memory, thread_info, 0, false);
+    dump_thread(&log, unwinder, thread_info, 0, false);
   }
 
   if (open_files) {
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index a2336bf..1b09f79 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -28,6 +28,7 @@
 #include <cutils/android_reboot.h>
 #include <ext4_utils/wipe.h>
 #include <fs_mgr.h>
+#include <fs_mgr/roots.h>
 #include <libgsi/libgsi.h>
 #include <liblp/builder.h>
 #include <liblp/liblp.h>
@@ -462,13 +463,56 @@
     return UpdateSuper(device, args[1], wipe);
 }
 
-bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
-    if (!android::gsi::IsGsiInstalled()) {
-        return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
+class AutoMountMetadata {
+  public:
+    AutoMountMetadata() {
+        Fstab proc_mounts;
+        if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
+            LOG(ERROR) << "Could not read /proc/mounts";
+            return;
+        }
+
+        auto iter = std::find_if(proc_mounts.begin(), proc_mounts.end(),
+                [](const auto& entry) { return entry.mount_point == "/metadata"; });
+        if (iter != proc_mounts.end()) {
+            mounted_ = true;
+            return;
+        }
+
+        if (!ReadDefaultFstab(&fstab_)) {
+            LOG(ERROR) << "Could not read default fstab";
+            return;
+        }
+        mounted_ = EnsurePathMounted(&fstab_, "/metadata");
+        should_unmount_ = true;
     }
+    ~AutoMountMetadata() {
+        if (mounted_ && should_unmount_) {
+            EnsurePathUnmounted(&fstab_, "/metadata");
+        }
+    }
+    explicit operator bool() const { return mounted_; }
+
+  private:
+    Fstab fstab_;
+    bool mounted_ = false;
+    bool should_unmount_ = false;
+};
+
+bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
     if (args.size() != 2) {
         return device->WriteFail("Invalid arguments");
     }
+
+    AutoMountMetadata mount_metadata;
+    if (!mount_metadata) {
+        return device->WriteFail("Could not find GSI install");
+    }
+
+    if (!android::gsi::IsGsiInstalled()) {
+        return device->WriteStatus(FastbootResult::FAIL, "No GSI is installed");
+    }
+
     if (args[1] == "wipe") {
         if (!android::gsi::UninstallGsi()) {
             return device->WriteStatus(FastbootResult::FAIL, strerror(errno));
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 17cab3a..4cdd8bc 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1948,11 +1948,10 @@
             std::string size = next_arg(&args);
             fb->ResizePartition(partition, size);
         } else if (command == "gsi") {
-            if (args.empty()) {
-                syntax_error("missing 'wipe' or 'disable' argument");
-            } else if (args.size() == 1 && args[0] == "wipe") {
+            std::string arg = next_arg(&args);
+            if (arg == "wipe") {
                 fb->RawCommand("gsi:wipe", "wiping GSI");
-            } else if (args.size() == 1 && args[0] == "disable") {
+            } else if (arg == "disable") {
                 fb->RawCommand("gsi:disable", "disabling GSI");
             } else {
                 syntax_error("expected 'wipe' or 'disable'");
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 943a071..e5caf3a 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -90,9 +90,9 @@
 using android::base::unique_fd;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
-using android::fs_mgr::AvbHandle;
-using android::fs_mgr::AvbHashtreeResult;
-using android::fs_mgr::AvbUniquePtr;
+
+// Realistically, this file should be part of the android::fs_mgr namespace;
+using namespace android::fs_mgr;
 
 using namespace std::literals;
 
@@ -1255,16 +1255,6 @@
     return ret;
 }
 
-int fs_mgr_do_mount_one(struct fstab_rec* rec) {
-    if (!rec) {
-        return FS_MGR_DOMNT_FAILED;
-    }
-
-    auto entry = FstabRecToFstabEntry(rec);
-
-    return fs_mgr_do_mount_one(entry);
-}
-
 // If tmp_mount_point is non-null, mount the filesystem there.  This is for the
 // tmp mount we do to check the user password
 // If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 1a0e7ab..1c6652a 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -37,6 +37,9 @@
 
 using android::base::unique_fd;
 
+// Realistically, this file should be part of the android::fs_mgr namespace;
+using namespace android::fs_mgr;
+
 static int get_dev_sz(const std::string& fs_blkdev, uint64_t* dev_sz) {
     unique_fd fd(TEMP_FAILURE_RETRY(open(fs_blkdev.c_str(), O_RDONLY | O_CLOEXEC)));
 
@@ -132,9 +135,3 @@
         return -EINVAL;
     }
 }
-
-int fs_mgr_do_format(struct fstab_rec* rec, bool crypt_footer) {
-    auto entry = FstabRecToFstabEntry(rec);
-
-    return fs_mgr_do_format(entry, crypt_footer);
-}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 146e82f..ee88e0d 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -41,14 +41,18 @@
 using android::base::Split;
 using android::base::StartsWith;
 
+namespace android {
+namespace fs_mgr {
+namespace {
+
 const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android");
 
-struct flag_list {
+struct FlagList {
     const char *name;
     uint64_t flag;
 };
 
-static struct flag_list mount_flags_list[] = {
+FlagList kMountFlagsList[] = {
         {"noatime", MS_NOATIME},
         {"noexec", MS_NOEXEC},
         {"nosuid", MS_NOSUID},
@@ -66,7 +70,7 @@
         {"defaults", 0},
 };
 
-static off64_t calculate_zram_size(int percentage) {
+off64_t CalculateZramSize(int percentage) {
     off64_t total;
 
     total  = sysconf(_SC_PHYS_PAGES);
@@ -78,16 +82,12 @@
     return total;
 }
 
-/* fills 'dt_value' with the underlying device tree value string without
- * the trailing '\0'. Returns true if 'dt_value' has a valid string, 'false'
- * otherwise.
- */
-static bool read_dt_file(const std::string& file_name, std::string* dt_value)
-{
+// Fills 'dt_value' with the underlying device tree value string without the trailing '\0'.
+// Returns true if 'dt_value' has a valid string, 'false' otherwise.
+bool ReadDtFile(const std::string& file_name, std::string* dt_value) {
     if (android::base::ReadFileToString(file_name, dt_value)) {
         if (!dt_value->empty()) {
-            // trim the trailing '\0' out, otherwise the comparison
-            // will produce false-negatives.
+            // Trim the trailing '\0' out, otherwise the comparison will produce false-negatives.
             dt_value->resize(dt_value->size() - 1);
             return true;
         }
@@ -96,19 +96,19 @@
     return false;
 }
 
-const static std::array<const char*, 3> kFileContentsEncryptionMode = {
+const std::array<const char*, 3> kFileContentsEncryptionMode = {
         "aes-256-xts",
         "adiantum",
         "ice",
 };
 
-const static std::array<const char*, 3> kFileNamesEncryptionMode = {
+const std::array<const char*, 3> kFileNamesEncryptionMode = {
         "aes-256-cts",
         "aes-256-heh",
         "adiantum",
 };
 
-static void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
+void ParseFileEncryption(const std::string& arg, FstabEntry* entry) {
     // The fileencryption flag is followed by an = and the mode of contents encryption, then
     // optionally a and the mode of filenames encryption (defaults to aes-256-cts).  Get it and
     // return it.
@@ -150,8 +150,8 @@
     }
 }
 
-static bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
-    for (const auto& [name, value] : mount_flags_list) {
+bool SetMountFlag(const std::string& flag, FstabEntry* entry) {
+    for (const auto& [name, value] : kMountFlagsList) {
         if (flag == name) {
             entry->flags |= value;
             return true;
@@ -160,7 +160,7 @@
     return false;
 }
 
-static void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
+void ParseMountFlags(const std::string& flags, FstabEntry* entry) {
     std::string fs_options;
     for (const auto& flag : Split(flags, ",")) {
         if (!SetMountFlag(flag, entry)) {
@@ -174,7 +174,7 @@
     entry->fs_options = std::move(fs_options);
 }
 
-static void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
+void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) {
     entry->fs_mgr_flags.val = 0U;
     for (const auto& flag : Split(flags, ",")) {
         std::string arg;
@@ -255,7 +255,7 @@
                 arg.pop_back();
                 int val;
                 if (ParseInt(arg, &val, 0, 100)) {
-                    entry->zram_size = calculate_zram_size(val);
+                    entry->zram_size = CalculateZramSize(val);
                 } else {
                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
                 }
@@ -346,7 +346,7 @@
     }
 }
 
-static std::string init_android_dt_dir() {
+std::string InitAndroidDtDir() {
     std::string android_dt_dir;
     // The platform may specify a custom Android DT path in kernel cmdline
     if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
@@ -356,30 +356,23 @@
     return android_dt_dir;
 }
 
-// FIXME: The same logic is duplicated in system/core/init/
-const std::string& get_android_dt_dir() {
-    // Set once and saves time for subsequent calls to this function
-    static const std::string kAndroidDtDir = init_android_dt_dir();
-    return kAndroidDtDir;
-}
-
-static bool is_dt_fstab_compatible() {
+bool IsDtFstabCompatible() {
     std::string dt_value;
     std::string file_name = get_android_dt_dir() + "/fstab/compatible";
 
-    if (read_dt_file(file_name, &dt_value) && dt_value == "android,fstab") {
+    if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
         // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
         std::string status_value;
         std::string status_file_name = get_android_dt_dir() + "/fstab/status";
-        return !read_dt_file(status_file_name, &status_value) || status_value == "ok" ||
+        return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
                status_value == "okay";
     }
 
     return false;
 }
 
-static std::string read_fstab_from_dt() {
-    if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
+std::string ReadFstabFromDt() {
+    if (!is_dt_compatible() || !IsDtFstabCompatible()) {
         return {};
     }
 
@@ -400,7 +393,7 @@
         std::string value;
         // skip a partition entry if the status property is present and not set to ok
         file_name = android::base::StringPrintf("%s/%s/status", fstabdir_name.c_str(), dp->d_name);
-        if (read_dt_file(file_name, &value)) {
+        if (ReadDtFile(file_name, &value)) {
             if (value != "okay" && value != "ok") {
                 LINFO << "dt_fstab: Skip disabled entry for partition " << dp->d_name;
                 continue;
@@ -408,7 +401,7 @@
         }
 
         file_name = android::base::StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
-        if (!read_dt_file(file_name, &value)) {
+        if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find device for partition " << dp->d_name;
             return {};
         }
@@ -417,7 +410,7 @@
         std::string mount_point;
         file_name =
             android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
-        if (read_dt_file(file_name, &value)) {
+        if (ReadDtFile(file_name, &value)) {
             LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
             mount_point = value;
         } else {
@@ -426,21 +419,21 @@
         fstab_entry.push_back(mount_point);
 
         file_name = android::base::StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
-        if (!read_dt_file(file_name, &value)) {
+        if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
             return {};
         }
         fstab_entry.push_back(value);
 
         file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
-        if (!read_dt_file(file_name, &value)) {
+        if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
             return {};
         }
         fstab_entry.push_back(value);
 
         file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
-        if (!read_dt_file(file_name, &value)) {
+        if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
             return {};
         }
@@ -460,19 +453,26 @@
     return fstab_result;
 }
 
-bool is_dt_compatible() {
-    std::string file_name = get_android_dt_dir() + "/compatible";
-    std::string dt_value;
-    if (read_dt_file(file_name, &dt_value)) {
-        if (dt_value == "android,firmware") {
-            return true;
+// Identify path to fstab file. Lookup is based on pattern fstab.<hardware>,
+// fstab.<hardware.platform> in folders /odm/etc, vendor/etc, or /.
+std::string GetFstabPath() {
+    for (const char* prop : {"hardware", "hardware.platform"}) {
+        std::string hw;
+
+        if (!fs_mgr_get_boot_config(prop, &hw)) continue;
+
+        for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
+            std::string fstab_path = prefix + hw;
+            if (access(fstab_path.c_str(), F_OK) == 0) {
+                return fstab_path;
+            }
         }
     }
 
-    return false;
+    return "";
 }
 
-static bool fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
+bool ReadFstabFile(FILE* fstab_file, bool proc_mounts, Fstab* fstab_out) {
     ssize_t len;
     size_t alloc_len = 0;
     char *line = NULL;
@@ -568,7 +568,7 @@
  *   /dev/block/pci/soc.0/f9824900.sdhci/by-name/vendor
  * it returns a set { "soc/1da4000.ufshc", "soc.0/f9824900.sdhci" }.
  */
-static std::set<std::string> extract_boot_devices(const Fstab& fstab) {
+std::set<std::string> ExtraBootDevices(const Fstab& fstab) {
     std::set<std::string> boot_devices;
 
     for (const auto& entry : fstab) {
@@ -601,13 +601,13 @@
     return boot_devices;
 }
 
-static void EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
+void EraseFstabEntry(Fstab* fstab, const std::string& mount_point) {
     auto iter = std::remove_if(fstab->begin(), fstab->end(),
                                [&](const auto& entry) { return entry.mount_point == mount_point; });
     fstab->erase(iter, fstab->end());
 }
 
-static void TransformFstabForGsi(Fstab* fstab) {
+void TransformFstabForGsi(Fstab* fstab) {
     EraseFstabEntry(fstab, "/system");
     EraseFstabEntry(fstab, "/data");
 
@@ -631,6 +631,8 @@
     fstab->emplace_back(userdata);
 }
 
+}  // namespace
+
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
     auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
     if (!fstab_file) {
@@ -640,7 +642,7 @@
 
     bool is_proc_mounts = path == "/proc/mounts";
 
-    if (!fs_mgr_read_fstab_file(fstab_file.get(), is_proc_mounts, fstab)) {
+    if (!ReadFstabFile(fstab_file.get(), is_proc_mounts, fstab)) {
         LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'";
         return false;
     }
@@ -651,18 +653,9 @@
     return true;
 }
 
-struct fstab* fs_mgr_read_fstab(const char* fstab_path) {
-    Fstab fstab;
-    if (!ReadFstabFromFile(fstab_path, &fstab)) {
-        return nullptr;
-    }
-
-    return FstabToLegacyFstab(fstab);
-}
-
 // Returns fstab entries parsed from the device tree if they exist
 bool ReadFstabFromDt(Fstab* fstab, bool log) {
-    std::string fstab_buf = read_fstab_from_dt();
+    std::string fstab_buf = ReadFstabFromDt();
     if (fstab_buf.empty()) {
         if (log) LINFO << __FUNCTION__ << "(): failed to read fstab from dt";
         return false;
@@ -676,7 +669,7 @@
         return false;
     }
 
-    if (!fs_mgr_read_fstab_file(fstab_file.get(), false, fstab)) {
+    if (!ReadFstabFile(fstab_file.get(), false, fstab)) {
         if (log) {
             LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:" << std::endl
                    << fstab_buf;
@@ -687,38 +680,6 @@
     return true;
 }
 
-struct fstab* fs_mgr_read_fstab_dt() {
-    Fstab fstab;
-    if (!ReadFstabFromDt(&fstab)) {
-        return nullptr;
-    }
-
-    return FstabToLegacyFstab(fstab);
-}
-
-/*
- * Identify path to fstab file. Lookup is based on pattern
- * fstab.<hardware>, fstab.<hardware.platform> in folders
-   /odm/etc, vendor/etc, or /.
- */
-static std::string get_fstab_path()
-{
-    for (const char* prop : {"hardware", "hardware.platform"}) {
-        std::string hw;
-
-        if (!fs_mgr_get_boot_config(prop, &hw)) continue;
-
-        for (const char* prefix : {"/odm/etc/fstab.", "/vendor/etc/fstab.", "/fstab."}) {
-            std::string fstab_path = prefix + hw;
-            if (access(fstab_path.c_str(), F_OK) == 0) {
-                return fstab_path;
-            }
-        }
-    }
-
-    return std::string();
-}
-
 // Loads the fstab file and combines with fstab entries passed in from device tree.
 bool ReadDefaultFstab(Fstab* fstab) {
     Fstab dt_fstab;
@@ -731,7 +692,7 @@
     if (access("/system/bin/recovery", F_OK) == 0) {
         default_fstab_path = "/etc/recovery.fstab";
     } else {  // normal boot
-        default_fstab_path = get_fstab_path();
+        default_fstab_path = GetFstabPath();
     }
 
     Fstab default_fstab;
@@ -748,6 +709,92 @@
     return !fstab->empty();
 }
 
+FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
+    if (fstab == nullptr) {
+        return nullptr;
+    }
+
+    for (auto& entry : *fstab) {
+        if (entry.mount_point == path) {
+            return &entry;
+        }
+    }
+
+    return nullptr;
+}
+
+std::set<std::string> GetBootDevices() {
+    // First check the kernel commandline, then try the device tree otherwise
+    std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
+    std::string value;
+    if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
+        ReadDtFile(dt_file_name, &value)) {
+        auto boot_devices = Split(value, ",");
+        return std::set<std::string>(boot_devices.begin(), boot_devices.end());
+    }
+
+    // Fallback to extract boot devices from fstab.
+    Fstab fstab;
+    if (!ReadDefaultFstab(&fstab)) {
+        return {};
+    }
+
+    return ExtraBootDevices(fstab);
+}
+
+FstabEntry BuildGsiSystemFstabEntry() {
+    // .logical_partition_name is required to look up AVB Hashtree descriptors.
+    FstabEntry system = {.blk_device = "system_gsi",
+                         .mount_point = "/system",
+                         .fs_type = "ext4",
+                         .flags = MS_RDONLY,
+                         .fs_options = "barrier=1",
+                         .avb_key = "/gsi.avbpubkey",
+                         .logical_partition_name = "system"};
+    system.fs_mgr_flags.wait = true;
+    system.fs_mgr_flags.logical = true;
+    system.fs_mgr_flags.first_stage_mount = true;
+    return system;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
+
+// FIXME: The same logic is duplicated in system/core/init/
+const std::string& get_android_dt_dir() {
+    // Set once and saves time for subsequent calls to this function
+    static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
+    return kAndroidDtDir;
+}
+
+bool is_dt_compatible() {
+    std::string file_name = get_android_dt_dir() + "/compatible";
+    std::string dt_value;
+    if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
+        if (dt_value == "android,firmware") {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+// Everything from here down is deprecated and will be removed shortly.
+
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
+using android::fs_mgr::ReadDefaultFstab;
+using android::fs_mgr::ReadFstabFromFile;
+
+struct fstab* fs_mgr_read_fstab(const char* fstab_path) {
+    Fstab fstab;
+    if (!ReadFstabFromFile(fstab_path, &fstab)) {
+        return nullptr;
+    }
+
+    return FstabToLegacyFstab(fstab);
+}
+
 struct fstab* fs_mgr_read_fstab_default() {
     Fstab fstab;
     if (!ReadDefaultFstab(&fstab)) {
@@ -789,8 +836,6 @@
     free(fstab);
 }
 
-// Returns the fstab_rec* whose mount_point is path.
-// Returns nullptr if not found.
 struct fstab_rec* fs_mgr_get_entry_for_mount_point(struct fstab* fstab, const std::string& path) {
     if (!fstab) {
         return nullptr;
@@ -803,39 +848,6 @@
     return nullptr;
 }
 
-FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path) {
-    if (fstab == nullptr) {
-        return nullptr;
-    }
-
-    for (auto& entry : *fstab) {
-        if (entry.mount_point == path) {
-            return &entry;
-        }
-    }
-
-    return nullptr;
-}
-
-std::set<std::string> fs_mgr_get_boot_devices() {
-    // First check the kernel commandline, then try the device tree otherwise
-    std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
-    std::string value;
-    if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
-        read_dt_file(dt_file_name, &value)) {
-        auto boot_devices = Split(value, ",");
-        return std::set<std::string>(boot_devices.begin(), boot_devices.end());
-    }
-
-    // Fallback to extract boot devices from fstab.
-    Fstab fstab;
-    if (!ReadDefaultFstab(&fstab)) {
-        return {};
-    }
-
-    return extract_boot_devices(fstab);
-}
-
 FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec) {
     FstabEntry entry;
     entry.blk_device = fstab_rec->blk_device;
@@ -977,17 +989,3 @@
 int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) {
     return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
 }
-
-FstabEntry BuildGsiSystemFstabEntry() {
-    FstabEntry system = {
-            .blk_device = "system_gsi",
-            .mount_point = "/system",
-            .fs_type = "ext4",
-            .flags = MS_RDONLY,
-            .fs_options = "barrier=1",
-    };
-    system.fs_mgr_flags.wait = true;
-    system.fs_mgr_flags.logical = true;
-    system.fs_mgr_flags.first_stage_mount = true;
-    return system;
-}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 3b9ddee..83e5d7b 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -143,10 +143,10 @@
                           FileWaitMode wait_mode = FileWaitMode::Exists);
 
 bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
-bool fs_mgr_update_for_slotselect(Fstab* fstab);
+bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab);
 bool fs_mgr_is_device_unlocked();
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
-int load_verity_state(const FstabEntry& entry, int* mode);
+int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
 
 #endif /* __CORE_FS_MGR_PRIV_H */
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index 41cd7dd..09c1b7e 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -21,6 +21,9 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
+// Realistically, this file should be part of the android::fs_mgr namespace;
+using namespace android::fs_mgr;
+
 // https://source.android.com/devices/tech/ota/ab/ab_implement#partitions
 // All partitions that are A/B-ed should be named as follows (slots are always
 // named a, b, etc.): boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 9adf8cc..c53e866 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -46,6 +46,9 @@
 #include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
+// Realistically, this file should be part of the android::fs_mgr namespace;
+using namespace android::fs_mgr;
+
 #define VERITY_TABLE_RSA_KEY "/verity_key"
 #define VERITY_TABLE_HASH_IDX 8
 #define VERITY_TABLE_SALT_IDX 9
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 2934363..6e9f1b0 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -60,7 +60,7 @@
 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
 #define FS_MGR_MNTALL_FAIL (-1)
 // fs_mgr_mount_all() updates fstab entries that reference device-mapper.
-int fs_mgr_mount_all(Fstab* fstab, int mount_mode);
+int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
 
 #define FS_MGR_DOMNT_FAILED (-1)
 #define FS_MGR_DOMNT_BUSY (-2)
@@ -68,28 +68,28 @@
 int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
 int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
                     bool needs_checkpoint);
-int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point);
-int fs_mgr_do_mount(Fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point,
-                    bool need_cp);
-int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point = "");
-int fs_mgr_do_mount_one(fstab_rec* rec);
+int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device,
+                    char* tmp_mount_point);
+int fs_mgr_do_mount(android::fs_mgr::Fstab* fstab, const char* n_name, char* n_blk_device,
+                    char* tmp_mount_point, bool need_cp);
+int fs_mgr_do_mount_one(const android::fs_mgr::FstabEntry& entry,
+                        const std::string& mount_point = "");
 int fs_mgr_do_tmpfs_mount(const char *n_name);
 fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab);
 void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
 bool fs_mgr_load_verity_state(int* mode);
 bool fs_mgr_update_verity_state(
         std::function<void(const std::string& mount_point, int mode)> callback);
-bool fs_mgr_swapon_all(const Fstab& fstab);
-bool fs_mgr_update_logical_partition(FstabEntry* entry);
+bool fs_mgr_swapon_all(const android::fs_mgr::Fstab& fstab);
+bool fs_mgr_update_logical_partition(android::fs_mgr::FstabEntry* entry);
 
-int fs_mgr_do_format(const FstabEntry& entry, bool reserve_footer);
-int fs_mgr_do_format(fstab_rec* rec, bool reserve_footer);
+int fs_mgr_do_format(const android::fs_mgr::FstabEntry& entry, bool reserve_footer);
 
 #define FS_MGR_SETUP_VERITY_SKIPPED  (-3)
 #define FS_MGR_SETUP_VERITY_DISABLED (-2)
 #define FS_MGR_SETUP_VERITY_FAIL (-1)
 #define FS_MGR_SETUP_VERITY_SUCCESS 0
-int fs_mgr_setup_verity(FstabEntry* fstab, bool wait_for_verity_dev);
+int fs_mgr_setup_verity(android::fs_mgr::FstabEntry* fstab, bool wait_for_verity_dev);
 
 // Return the name of the super partition if it exists. If a slot number is
 // specified, the super partition for the corresponding metadata slot will be
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 4bf2238..64682cc 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -21,8 +21,8 @@
 #include <string>
 #include <vector>
 
-bool fs_mgr_overlayfs_mount_all(Fstab* fstab);
-std::vector<std::string> fs_mgr_overlayfs_required_devices(Fstab* fstab);
+bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
+std::vector<std::string> fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab);
 bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
                             bool* change = nullptr);
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 549ff68..a942d43 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -65,7 +65,6 @@
 };
 
 struct fstab* fs_mgr_read_fstab_default();
-struct fstab* fs_mgr_read_fstab_dt();
 struct fstab* fs_mgr_read_fstab(const char* fstab_path);
 void fs_mgr_free_fstab(struct fstab* fstab);
 
@@ -88,7 +87,9 @@
 
 std::string fs_mgr_get_slot_suffix();
 std::string fs_mgr_get_other_slot_suffix();
-std::set<std::string> fs_mgr_get_boot_devices();
+
+namespace android {
+namespace fs_mgr {
 
 struct FstabEntry {
     std::string blk_device;
@@ -187,10 +188,15 @@
 
 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
 
-// Temporary conversion functions.
-FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec);
-Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab);
-fstab* FstabToLegacyFstab(const Fstab& fstab);
-
 // Helper method to build a GSI fstab entry for mounting /system.
 FstabEntry BuildGsiSystemFstabEntry();
+
+std::set<std::string> GetBootDevices();
+
+}  // namespace fs_mgr
+}  // namespace android
+
+// Temporary conversion functions.
+android::fs_mgr::FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec);
+android::fs_mgr::Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab);
+fstab* FstabToLegacyFstab(const android::fs_mgr::Fstab& fstab);
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index c6a9e0b..a4614d0 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -299,24 +299,25 @@
 // private methods of DeviceMapper
 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
                             std::vector<TargetInfo>* table) {
-    char buffer[4096];
-    struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer);
+    std::vector<char> buffer;
+    struct dm_ioctl* io = nullptr;
 
-    InitIo(io, name);
-    io->data_size = sizeof(buffer);
-    io->data_start = sizeof(*io);
-    io->flags = flags;
-    if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
-        PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
-        return false;
-    }
-    if (io->flags & DM_BUFFER_FULL_FLAG) {
-        PLOG(ERROR) << "DM_TABLE_STATUS result for " << name << " was too large";
-        return false;
+    for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
+        io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
+
+        InitIo(io, name);
+        io->data_size = buffer.size();
+        io->data_start = sizeof(*io);
+        io->flags = flags;
+        if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
+            PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
+            return false;
+        }
+        if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
     }
 
     uint32_t cursor = io->data_start;
-    uint32_t data_end = std::min(io->data_size, uint32_t(sizeof(buffer)));
+    uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
     for (uint32_t i = 0; i < io->target_count; i++) {
         if (cursor + sizeof(struct dm_target_spec) > data_end) {
             break;
@@ -324,14 +325,14 @@
         // After each dm_target_spec is a status string. spec->next is an
         // offset from |io->data_start|, and we clamp it to the size of our
         // buffer.
-        struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(buffer + cursor);
+        struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
         uint32_t data_offset = cursor + sizeof(dm_target_spec);
         uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
 
         std::string data;
         if (next_cursor > data_offset) {
             // Note: we use c_str() to eliminate any extra trailing 0s.
-            data = std::string(buffer + data_offset, next_cursor - data_offset).c_str();
+            data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
         }
         table->emplace_back(*spec, data);
         cursor = next_cursor;
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 773baf4..a1ae4e7 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -383,7 +383,8 @@
     return avb_handle;
 }
 
-AvbHashtreeResult AvbHandle::SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry) {
+AvbHashtreeResult AvbHandle::SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
+                                                        bool wait_for_verity_dev) {
     if (fstab_entry->avb_key.empty()) {
         LERROR << "avb_key=/path/to/key is missing for " << fstab_entry->mount_point;
         return AvbHashtreeResult::kFail;
@@ -400,7 +401,7 @@
                    << " for mount point: " << fstab_entry->mount_point;
             return AvbHashtreeResult::kFail;
         }
-        // Use empty key blob, which means no expectation, if allow verification error.
+        LWARNING << "Allowing no expected key blob when verification error is permitted";
         expected_key_blob.clear();
     }
 
@@ -423,7 +424,7 @@
     // Puts the vbmeta into a vector, for LoadAvbHashtreeToEnableVerity() to use.
     std::vector<VBMetaData> vbmeta_images;
     vbmeta_images.emplace_back(std::move(*vbmeta));
-    if (!LoadAvbHashtreeToEnableVerity(fstab_entry, true /* wait_for_verity_dev */, vbmeta_images,
+    if (!LoadAvbHashtreeToEnableVerity(fstab_entry, wait_for_verity_dev, vbmeta_images,
                                        fs_mgr_get_slot_suffix(), fs_mgr_get_other_slot_suffix())) {
         return AvbHashtreeResult::kFail;
     }
diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index 55a320e..d4e3a6e 100644
--- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -169,7 +169,8 @@
     AvbHashtreeResult SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev);
 
     // Similar to above, but loads the offline vbmeta from the end of fstab_entry->blk_device.
-    static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry);
+    static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
+                                                        bool wait_for_verity_dev = true);
 
     const std::string& avb_version() const { return avb_version_; }
     const VBMetaInfo& vbmeta_info() const { return vbmeta_info_; }
diff --git a/fs_mgr/libfs_avb/tests/avb_util_test.cpp b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
index 23faffc..cda9396 100644
--- a/fs_mgr/libfs_avb/tests/avb_util_test.cpp
+++ b/fs_mgr/libfs_avb/tests/avb_util_test.cpp
@@ -28,6 +28,7 @@
 // Target classes or functions to test:
 using android::fs_mgr::AvbPartitionToDevicePatition;
 using android::fs_mgr::DeriveAvbPartitionName;
+using android::fs_mgr::FstabEntry;
 using android::fs_mgr::GetAvbFooter;
 using android::fs_mgr::GetChainPartitionInfo;
 using android::fs_mgr::GetTotalSize;
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index ede0122..4d9bc61 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -569,6 +569,18 @@
   die "vendor hello"
 check_eq "${A}" "${B}" /vendor before reboot
 
+# download libc.so, append some gargage, push back, and check if the file is updated.
+tempdir="`mktemp -d`"
+cleanup() {
+  rm -rf ${tempdir}
+}
+adb pull /system/lib/bootstrap/libc.so ${tempdir} || die "pull libc.so from device"
+garbage="`hexdump -n 16 -e '4/4 "%08X" 1 "\n"' /dev/random`"
+echo ${garbage} >> ${tempdir}/libc.so
+adb push ${tempdir}/libc.so /system/lib/bootstrap/libc.so || die "push libc.so to device"
+adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice || die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+
 echo "${GREEN}[ RUN      ]${NORMAL} reboot to confirm content persistent" >&2
 
 adb_reboot &&
@@ -607,6 +619,14 @@
 check_eq "${A}" "${B}" vendor after reboot
 echo "${GREEN}[       OK ]${NORMAL} /vendor content remains after reboot" >&2
 
+# check if the updated libc.so is persistent after reboot
+adb_root &&
+  adb pull /system/lib/bootstrap/libc.so ${tempdir}/libc.so.fromdevice ||
+  die "pull libc.so from device"
+diff ${tempdir}/libc.so ${tempdir}/libc.so.fromdevice > /dev/null || die "libc.so differ"
+rm -r ${tempdir}
+echo "${GREEN}[       OK ]${NORMAL} /system/lib/bootstrap/libc.so content remains after reboot" >&2
+
 echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
 
 H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index e2b283a..870c98c 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -32,6 +32,8 @@
 
 #include "../fs_mgr_priv_boot_config.h"
 
+using namespace android::fs_mgr;
+
 namespace {
 
 const std::string cmdline =
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 3b6ff9b..63661f0 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -27,6 +27,7 @@
 #include <android-base/unique_fd.h>
 #include <libdm/dm.h>
 
+#include <fstream>
 #include <functional>
 #include <iomanip>
 #include <ios>
@@ -50,6 +51,7 @@
 
 static int Usage(void) {
     std::cerr << "usage: dmctl <command> [command options]" << std::endl;
+    std::cerr << "       dmctl -f file" << std::endl;
     std::cerr << "commands:" << std::endl;
     std::cerr << "  create <dm-name> [-ro] <targets...>" << std::endl;
     std::cerr << "  delete <dm-name>" << std::endl;
@@ -58,6 +60,8 @@
     std::cerr << "  table <dm-name>" << std::endl;
     std::cerr << "  help" << std::endl;
     std::cerr << std::endl;
+    std::cerr << "-f file reads command and all parameters from named file" << std::endl;
+    std::cerr << std::endl;
     std::cerr << "Target syntax:" << std::endl;
     std::cerr << "  <target_type> <start_sector> <num_sectors> [target_data]" << std::endl;
     return -EINVAL;
@@ -340,12 +344,40 @@
         // clang-format on
 };
 
+static bool ReadFile(const char* filename, std::vector<std::string>* args,
+                     std::vector<char*>* arg_ptrs) {
+    std::ifstream file(filename);
+    if (!file) return false;
+
+    std::string arg;
+    while (file >> arg) args->push_back(arg);
+
+    for (auto const& i : *args) arg_ptrs->push_back(const_cast<char*>(i.c_str()));
+    return true;
+}
+
 int main(int argc, char** argv) {
     android::base::InitLogging(argv, &android::base::StderrLogger);
     if (argc < 2) {
         return Usage();
     }
 
+    std::vector<std::string> args;
+    std::vector<char*> arg_ptrs;
+    if (std::string("-f") == argv[1]) {
+        if (argc != 3) {
+            return Usage();
+        }
+
+        args.push_back(argv[0]);
+        if (!ReadFile(argv[2], &args, &arg_ptrs)) {
+            return Usage();
+        }
+
+        argc = arg_ptrs.size();
+        argv = &arg_ptrs[0];
+    }
+
     for (const auto& cmd : cmdmap) {
         if (cmd.first == argv[1]) {
             return cmd.second(argc - 2, argv + 2);
diff --git a/init/Android.bp b/init/Android.bp
index 9f5d17d..67688f2 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -110,6 +110,7 @@
         "init.cpp",
         "keychords.cpp",
         "modalias_handler.cpp",
+        "mount_namespace.cpp",
         "parser.cpp",
         "persistent_properties.cpp",
         "persistent_properties.proto",
@@ -166,6 +167,7 @@
             exclude_shared_libs: ["libbinder", "libutils"],
         },
     },
+    ldflags: ["-Wl,--rpath,/system/${LIB}/bootstrap"],
 }
 
 // Tests
diff --git a/init/Android.mk b/init/Android.mk
index 69c63e1..59d7f11 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -47,6 +47,7 @@
     first_stage_init.cpp \
     first_stage_main.cpp \
     first_stage_mount.cpp \
+    mount_namespace.cpp \
     reboot_utils.cpp \
     selinux.cpp \
     switch_root.cpp \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 169edbe..c8ceb0c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -63,6 +63,7 @@
 #include "action_manager.h"
 #include "bootchart.h"
 #include "init.h"
+#include "mount_namespace.h"
 #include "parser.h"
 #include "property_service.h"
 #include "reboot.h"
@@ -75,6 +76,8 @@
 using namespace std::literals::string_literals;
 
 using android::base::unique_fd;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::ReadFstabFromFile;
 
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 
@@ -1098,6 +1101,14 @@
     }
 }
 
+static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
+    if (SwitchToDefaultMountNamespace()) {
+        return Success();
+    } else {
+        return Error() << "Failed to setup runtime bionic";
+    }
+}
+
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1145,6 +1156,7 @@
         {"rmdir",                   {1,     1,    {true,   do_rmdir}}},
         {"setprop",                 {2,     2,    {true,   do_setprop}}},
         {"setrlimit",               {3,     3,    {false,  do_setrlimit}}},
+        {"setup_runtime_bionic",    {0,     0,    {false,  do_setup_runtime_bionic}}},
         {"start",                   {1,     1,    {false,  do_start}}},
         {"stop",                    {1,     1,    {false,  do_stop}}},
         {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 153b857..7d5bf57 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -49,6 +49,11 @@
 using android::fs_mgr::AvbHandle;
 using android::fs_mgr::AvbHashtreeResult;
 using android::fs_mgr::AvbUniquePtr;
+using android::fs_mgr::BuildGsiSystemFstabEntry;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
+using android::fs_mgr::ReadDefaultFstab;
+using android::fs_mgr::ReadFstabFromDt;
 
 using namespace std::literals;
 
@@ -136,10 +141,6 @@
     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
 }
 
-static bool IsRecoveryMode() {
-    return access("/system/bin/recovery", F_OK) == 0;
-}
-
 static Fstab ReadFirstStageFstab() {
     Fstab fstab;
     if (!ReadFstabFromDt(&fstab)) {
@@ -160,7 +161,7 @@
 // -----------------
 FirstStageMount::FirstStageMount(Fstab fstab)
     : need_dm_verity_(false), fstab_(std::move(fstab)), uevent_listener_(16 * 1024 * 1024) {
-    auto boot_devices = fs_mgr_get_boot_devices();
+    auto boot_devices = android::fs_mgr::GetBootDevices();
     device_handler_ = std::make_unique<DeviceHandler>(
             std::vector<Permissions>{}, std::vector<SysfsPermissions>{}, std::vector<Subsystem>{},
             std::move(boot_devices), false);
@@ -683,22 +684,31 @@
 }
 
 bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
+    AvbHashtreeResult hashtree_result;
+
     if (fstab_entry->fs_mgr_flags.avb) {
         if (!InitAvbHandle()) return false;
-        AvbHashtreeResult hashtree_result =
+        hashtree_result =
                 avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
-        switch (hashtree_result) {
-            case AvbHashtreeResult::kDisabled:
-                return true;  // Returns true to mount the partition.
-            case AvbHashtreeResult::kSuccess:
-                // The exact block device name (fstab_rec->blk_device) is changed to
-                // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
-                // first stage.
-                return InitMappedDevice(fstab_entry->blk_device);
-            default:
-                return false;
-        }
+    } else if (!fstab_entry->avb_key.empty()) {
+        hashtree_result =
+                AvbHandle::SetUpStandaloneAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
+    } else {
+        return true;  // No need AVB, returns true to mount the partition directly.
     }
+
+    switch (hashtree_result) {
+        case AvbHashtreeResult::kDisabled:
+            return true;  // Returns true to mount the partition.
+        case AvbHashtreeResult::kSuccess:
+            // The exact block device name (fstab_rec->blk_device) is changed to
+            // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
+            // first stage.
+            return InitMappedDevice(fstab_entry->blk_device);
+        default:
+            return false;
+    }
+
     return true;  // Returns true to mount the partition.
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index d360fdd..4f4a15f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -54,6 +54,7 @@
 #include "first_stage_mount.h"
 #include "import_parser.h"
 #include "keychords.h"
+#include "mount_namespace.h"
 #include "property_service.h"
 #include "reboot.h"
 #include "reboot_utils.h"
@@ -666,6 +667,10 @@
     const BuiltinFunctionMap function_map;
     Action::set_function_map(&function_map);
 
+    if (!SetupMountNamespaces()) {
+        PLOG(FATAL) << "SetupMountNamespaces failed";
+    }
+
     subcontexts = InitializeSubcontexts();
 
     ActionManager& am = ActionManager::GetInstance();
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
new file mode 100644
index 0000000..413fe8f
--- /dev/null
+++ b/init/mount_namespace.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mount_namespace.h"
+
+#include <sys/mount.h>
+
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include "util.h"
+
+namespace android {
+namespace init {
+namespace {
+
+static constexpr const char* kLinkerMountPoint = "/bionic/bin/linker";
+static constexpr const char* kBootstrapLinkerPath = "/system/bin/bootstrap/linker";
+static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker";
+
+static constexpr const char* kBionicLibsMountPointDir = "/bionic/lib/";
+static constexpr const char* kBootstrapBionicLibsDir = "/system/lib/bootstrap/";
+static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/";
+
+static constexpr const char* kLinkerMountPoint64 = "/bionic/bin/linker64";
+static constexpr const char* kBootstrapLinkerPath64 = "/system/bin/bootstrap/linker64";
+static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64";
+
+static constexpr const char* kBionicLibsMountPointDir64 = "/bionic/lib64/";
+static constexpr const char* kBootstrapBionicLibsDir64 = "/system/lib64/bootstrap/";
+static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/";
+
+static const std::vector<std::string> kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"};
+
+static bool BindMount(const std::string& source, const std::string& mount_point,
+                      bool recursive = false) {
+    unsigned long mountflags = MS_BIND;
+    if (recursive) {
+        mountflags |= MS_REC;
+    }
+    if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+        PLOG(ERROR) << "Could not bind-mount " << source << " to " << mount_point;
+        return false;
+    }
+    return true;
+}
+
+static bool MakeShared(const std::string& mount_point, bool recursive = false) {
+    unsigned long mountflags = MS_SHARED;
+    if (recursive) {
+        mountflags |= MS_REC;
+    }
+    if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+        PLOG(ERROR) << "Failed to change propagation type to shared";
+        return false;
+    }
+    return true;
+}
+
+static bool MakePrivate(const std::string& mount_point, bool recursive = false) {
+    unsigned long mountflags = MS_PRIVATE;
+    if (recursive) {
+        mountflags |= MS_REC;
+    }
+    if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+        PLOG(ERROR) << "Failed to change propagation type to private";
+        return false;
+    }
+    return true;
+}
+
+static int OpenMountNamespace() {
+    int fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
+    if (fd < 0) {
+        PLOG(ERROR) << "Cannot open fd for current mount namespace";
+    }
+    return fd;
+}
+
+static std::string GetMountNamespaceId() {
+    std::string ret;
+    if (!android::base::Readlink("/proc/self/ns/mnt", &ret)) {
+        PLOG(ERROR) << "Failed to read namespace ID";
+        return "";
+    }
+    return ret;
+}
+
+static bool BindMountBionic(const std::string& linker_source, const std::string& lib_dir_source,
+                            const std::string& linker_mount_point,
+                            const std::string& lib_mount_dir) {
+    if (access(linker_source.c_str(), F_OK) != 0) {
+        PLOG(INFO) << linker_source << " does not exist. skipping mounting bionic there.";
+        // This can happen for 64-bit bionic in 32-bit only device.
+        // It is okay to skip mounting the 64-bit bionic.
+        return true;
+    }
+    if (!BindMount(linker_source, linker_mount_point)) {
+        return false;
+    }
+    if (!MakePrivate(linker_mount_point)) {
+        return false;
+    }
+    for (const auto& libname : kBionicLibFileNames) {
+        std::string mount_point = lib_mount_dir + libname;
+        std::string source = lib_dir_source + libname;
+        if (!BindMount(source, mount_point)) {
+            return false;
+        }
+        if (!MakePrivate(mount_point)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool IsBionicUpdatable() {
+    static bool result = android::base::GetBoolProperty("ro.apex.IsBionicUpdatable", false);
+    return result;
+}
+
+static android::base::unique_fd bootstrap_ns_fd;
+static android::base::unique_fd default_ns_fd;
+
+static std::string bootstrap_ns_id;
+static std::string default_ns_id;
+
+}  // namespace
+
+bool SetupMountNamespaces() {
+    // Set the propagation type of / as shared so that any mounting event (e.g.
+    // /data) is by default visible to all processes. When private mounting is
+    // needed for /foo/bar, then we will make /foo/bar as a mount point (by
+    // bind-mounting by to itself) and set the propagation type of the mount
+    // point to private.
+    if (!MakeShared("/", true /*recursive*/)) return false;
+
+    // Since different files (bootstrap or runtime APEX) should be mounted to
+    // the same mount point paths (e.g. /bionic/bin/linker, /bionic/lib/libc.so,
+    // etc.) across the two mount namespaces, we create a private mount point at
+    // /bionic so that a mount event for the bootstrap bionic in the mount
+    // namespace for pre-apexd processes is not propagated to the other mount
+    // namespace for post-apexd process, and vice versa.
+    //
+    // Other mount points other than /bionic, however, are all still shared.
+    if (!BindMount("/bionic", "/bionic", true /*recursive*/)) return false;
+    if (!MakePrivate("/bionic")) return false;
+
+    // Bind-mount bootstrap bionic.
+    if (!BindMountBionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir, kLinkerMountPoint,
+                         kBionicLibsMountPointDir))
+        return false;
+    if (!BindMountBionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64, kLinkerMountPoint64,
+                         kBionicLibsMountPointDir64))
+        return false;
+
+    bootstrap_ns_fd.reset(OpenMountNamespace());
+    bootstrap_ns_id = GetMountNamespaceId();
+
+    // When bionic is updatable via the runtime APEX, we create separate mount
+    // namespaces for processes that are started before and after the APEX is
+    // activated by apexd. In the namespace for pre-apexd processes, the bionic
+    // from the /system partition (that we call bootstrap bionic) is
+    // bind-mounted. In the namespace for post-apexd processes, the bionic from
+    // the runtime APEX is bind-mounted.
+    bool success = true;
+    if (IsBionicUpdatable() && !IsRecoveryMode()) {
+        // Creating a new namespace by cloning, saving, and switching back to
+        // the original namespace.
+        if (unshare(CLONE_NEWNS) == -1) {
+            PLOG(ERROR) << "Cannot create mount namespace";
+            return false;
+        }
+        default_ns_fd.reset(OpenMountNamespace());
+        default_ns_id = GetMountNamespaceId();
+
+        // By this unmount, the bootstrap bionic are not mounted in the default
+        // mount namespace.
+        if (umount2("/bionic", MNT_DETACH) == -1) {
+            PLOG(ERROR) << "Cannot unmount /bionic";
+            // Don't return here. We have to switch back to the bootstrap
+            // namespace.
+            success = false;
+        }
+
+        if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
+            PLOG(ERROR) << "Cannot switch back to bootstrap mount namespace";
+            return false;
+        }
+    } else {
+        // Otherwise, default == bootstrap
+        default_ns_fd.reset(OpenMountNamespace());
+        default_ns_id = GetMountNamespaceId();
+    }
+
+    LOG(INFO) << "SetupMountNamespaces done";
+    return success;
+}
+
+bool SwitchToDefaultMountNamespace() {
+    if (IsRecoveryMode()) {
+        // we don't have multiple namespaces in recovery mode
+        return true;
+    }
+    if (default_ns_id != GetMountNamespaceId()) {
+        if (setns(default_ns_fd.get(), CLONE_NEWNS) == -1) {
+            PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
+            return false;
+        }
+    }
+
+    // Bind-mount bionic from the runtime APEX since it is now available. Note
+    // that in case of IsBionicUpdatable() == false, these mounts are over the
+    // existing existing bind mounts for the bootstrap bionic, which effectively
+    // becomes hidden.
+    if (!BindMountBionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, kLinkerMountPoint,
+                         kBionicLibsMountPointDir))
+        return false;
+    if (!BindMountBionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, kLinkerMountPoint64,
+                         kBionicLibsMountPointDir64))
+        return false;
+
+    LOG(INFO) << "Switched to default mount namespace";
+    return true;
+}
+
+bool SwitchToBootstrapMountNamespaceIfNeeded() {
+    if (IsRecoveryMode()) {
+        // we don't have multiple namespaces in recovery mode
+        return true;
+    }
+    if (bootstrap_ns_id != GetMountNamespaceId() && bootstrap_ns_fd.get() != -1 &&
+        IsBionicUpdatable()) {
+        if (setns(bootstrap_ns_fd.get(), CLONE_NEWNS) == -1) {
+            PLOG(ERROR) << "Failed to switch to bootstrap mount namespace.";
+            return false;
+        }
+    }
+    return true;
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h b/init/mount_namespace.h
similarity index 65%
rename from debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
rename to init/mount_namespace.h
index 5d0d924..c41a449 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/elf_utils.h
+++ b/init/mount_namespace.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 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,16 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef _DEBUGGERD_ELF_UTILS_H
-#define _DEBUGGERD_ELF_UTILS_H
+#pragma once
 
-#include <stdint.h>
-#include <string>
+namespace android {
+namespace init {
 
-namespace unwindstack {
-class Memory;
-}
+bool SetupMountNamespaces();
+bool SwitchToDefaultMountNamespace();
+bool SwitchToBootstrapMountNamespaceIfNeeded();
 
-bool elf_get_build_id(unwindstack::Memory*, uintptr_t, std::string*);
-
-#endif // _DEBUGGERD_ELF_UTILS_H
+}  // namespace init
+}  // namespace android
diff --git a/init/service.cpp b/init/service.cpp
index 272809f..a6eb7f7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -50,6 +50,7 @@
 #include <sys/system_properties.h>
 
 #include "init.h"
+#include "mount_namespace.h"
 #include "property_service.h"
 #include "selinux.h"
 #else
@@ -207,6 +208,11 @@
     return execv(c_strings[0], c_strings.data()) == 0;
 }
 
+static bool IsRuntimeApexReady() {
+    struct stat buf;
+    return stat("/apex/com.android.runtime/", &buf) == 0;
+}
+
 unsigned long Service::next_start_order_ = 1;
 bool Service::is_exec_service_running_ = false;
 
@@ -929,6 +935,14 @@
         scon = *result;
     }
 
+    if (!IsRuntimeApexReady() && !pre_apexd_) {
+        // If this service is started before the runtime APEX gets available,
+        // mark it as pre-apexd one. Note that this marking is permanent. So
+        // for example, if the service is re-launched (e.g., due to crash),
+        // it is still recognized as pre-apexd... for consistency.
+        pre_apexd_ = true;
+    }
+
     LOG(INFO) << "starting service '" << name_ << "'...";
 
     pid_t pid = -1;
@@ -945,6 +959,15 @@
             LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error();
         }
 
+#if defined(__ANDROID__)
+        if (pre_apexd_) {
+            if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
+                LOG(FATAL) << "Service '" << name_ << "' could not enter "
+                           << "into the bootstrap mount namespace";
+            }
+        }
+#endif
+
         if (namespace_flags_ & CLONE_NEWNS) {
             if (auto result = SetUpMountNamespace(); !result) {
                 LOG(FATAL) << "Service '" << name_
diff --git a/init/service.h b/init/service.h
index 56e75b0..c29723a 100644
--- a/init/service.h
+++ b/init/service.h
@@ -242,6 +242,8 @@
     std::vector<std::string> args_;
 
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
+
+    bool pre_apexd_ = false;
 };
 
 class ServiceList {
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 7545d53..399ea4c 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -245,7 +245,7 @@
     uevent_handlers.emplace_back(std::make_unique<DeviceHandler>(
             std::move(ueventd_configuration.dev_permissions),
             std::move(ueventd_configuration.sysfs_permissions),
-            std::move(ueventd_configuration.subsystems), fs_mgr_get_boot_devices(), true));
+            std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), true));
     uevent_handlers.emplace_back(std::make_unique<FirmwareHandler>(
             std::move(ueventd_configuration.firmware_directories)));
 
diff --git a/init/util.cpp b/init/util.cpp
index 80fb03d..29d7a76 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -441,5 +441,9 @@
     android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function));
 }
 
+bool IsRecoveryMode() {
+    return access("/system/bin/recovery", F_OK) == 0;
+}
+
 }  // namespace init
 }  // namespace android
diff --git a/init/util.h b/init/util.h
index 2b57910..2232a0f 100644
--- a/init/util.h
+++ b/init/util.h
@@ -64,7 +64,7 @@
 bool IsLegalPropertyName(const std::string& name);
 
 void InitKernelLogging(char** argv, std::function<void(const char*)> abort_function);
-
+bool IsRecoveryMode();
 }  // namespace init
 }  // namespace android
 
diff --git a/libkeyutils/Android.bp b/libkeyutils/Android.bp
index b388e95..e816926 100644
--- a/libkeyutils/Android.bp
+++ b/libkeyutils/Android.bp
@@ -16,3 +16,16 @@
     srcs: ["keyutils_test.cpp"],
     test_suites: ["device-tests"],
 }
+
+cc_binary {
+    name: "mini-keyctl",
+    srcs: ["mini_keyctl.cpp"],
+
+    shared_libs: [
+        "libbase",
+        "libkeyutils",
+        "liblog",
+    ],
+
+    cflags: ["-Werror", "-Wall", "-Wextra"],
+}
diff --git a/libkeyutils/include/keyutils.h b/libkeyutils/include/keyutils.h
index 585767d..c508f27 100644
--- a/libkeyutils/include/keyutils.h
+++ b/libkeyutils/include/keyutils.h
@@ -51,6 +51,10 @@
 
 long keyctl_unlink(key_serial_t key, key_serial_t keyring);
 
+long keyctl_restrict_keyring(key_serial_t keyring, const char* type, const char* restriction);
+
+long keyctl_get_security(key_serial_t key, char* buffer, size_t buflen);
+
 __END_DECLS
 
 #endif
diff --git a/libkeyutils/keyutils.cpp b/libkeyutils/keyutils.cpp
index 58a2a17..8f63f70 100644
--- a/libkeyutils/keyutils.cpp
+++ b/libkeyutils/keyutils.cpp
@@ -69,3 +69,11 @@
 long keyctl_unlink(key_serial_t key, key_serial_t keyring) {
   return keyctl(KEYCTL_UNLINK, key, keyring);
 }
+
+long keyctl_restrict_keyring(key_serial_t keyring, const char* type, const char* restriction) {
+  return keyctl(KEYCTL_RESTRICT_KEYRING, keyring, type, restriction);
+}
+
+long keyctl_get_security(key_serial_t id, char* buffer, size_t buflen) {
+  return keyctl(KEYCTL_GET_SECURITY, id, buffer, buflen);
+}
diff --git a/libkeyutils/mini_keyctl.cpp b/libkeyutils/mini_keyctl.cpp
new file mode 100644
index 0000000..abc8f82
--- /dev/null
+++ b/libkeyutils/mini_keyctl.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A tool loads keys to keyring.
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <keyutils.h>
+
+static constexpr int kMaxCertSize = 4096;
+
+// Add all the certs from directory path to keyring with keyring_id. Returns the number of keys
+// added.
+int AddKeys(const std::string& path, const key_serial_t keyring_id, const std::string& keyring_desc,
+            int start_index) {
+  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(path.c_str()), closedir);
+  if (!dir) {
+    PLOG(WARNING) << "Failed to open directory " << path;
+    return 0;
+  }
+  int keys_added = 0;
+  struct dirent* dp;
+  while ((dp = readdir(dir.get())) != NULL) {
+    if (dp->d_type != DT_REG) {
+      continue;
+    }
+    std::string cert_path = path + "/" + dp->d_name;
+    std::string cert_buf;
+    if (!android::base::ReadFileToString(cert_path, &cert_buf, false /* follow_symlinks */)) {
+      LOG(ERROR) << "Failed to read " << cert_path;
+      continue;
+    }
+
+    if (cert_buf.size() > kMaxCertSize) {
+      LOG(ERROR) << "Certficate size too large: " << cert_path;
+      continue;
+    }
+
+    // Add key to keyring.
+    int key_desc_index = keys_added + start_index;
+    std::string key_desc = keyring_desc + "-key" + std::to_string(key_desc_index);
+    key_serial_t key =
+        add_key("asymmetric", key_desc.c_str(), &cert_buf[0], cert_buf.size(), keyring_id);
+    if (key < 0) {
+      PLOG(ERROR) << "Failed to add key to keyring: " << cert_path;
+      continue;
+    }
+    keys_added++;
+  }
+  return keys_added;
+}
+
+std::vector<std::string> SplitBySpace(const std::string& s) {
+  std::istringstream iss(s);
+  return std::vector<std::string>{std::istream_iterator<std::string>{iss},
+                                  std::istream_iterator<std::string>{}};
+}
+
+// Find the keyring id. Because request_key(2) syscall is not available or the key is
+// kernel keyring, the id is looked up from /proc/keys. The keyring description may contain other
+// information in the descritption section depending on the key type, only the first word in the
+// keyring description is used for searching.
+bool GetKeyringId(const std::string& keyring_desc, key_serial_t* keyring_id) {
+  if (!keyring_id) {
+    LOG(ERROR) << "keyring_id is null";
+    return false;
+  }
+
+  // Only keys allowed by SELinux rules will be shown here.
+  std::ifstream proc_keys_file("/proc/keys");
+  if (!proc_keys_file.is_open()) {
+    PLOG(ERROR) << "Failed to open /proc/keys";
+    return false;
+  }
+
+  std::string line;
+  while (getline(proc_keys_file, line)) {
+    std::vector<std::string> tokens = SplitBySpace(line);
+    if (tokens.size() < 9) {
+      continue;
+    }
+    std::string key_id = tokens[0];
+    std::string key_type = tokens[7];
+    // The key description may contain space.
+    std::string key_desc_prefix = tokens[8];
+    // The prefix has a ":" at the end
+    std::string key_desc_pattern = keyring_desc + ":";
+    if (key_type != "keyring" || key_desc_prefix != key_desc_pattern) {
+      continue;
+    }
+    *keyring_id = std::stoi(key_id, nullptr, 16);
+    return true;
+  }
+  return false;
+}
+
+static void Usage(int exit_code) {
+  fprintf(stderr, "usage: mini-keyctl -c PATHS -s DESCRIPTION\n");
+  fprintf(stderr, "\n");
+  fprintf(stderr, "-c, --cert_dirs     the certificate locations, separated by comma\n");
+  fprintf(stderr, "-k, --keyring       the keyring description\n");
+  _exit(exit_code);
+}
+
+int main(int argc, char** argv) {
+  if (argc < 5) Usage(1);
+
+  std::string arg_cert_dirs;
+  std::string arg_keyring_desc;
+
+  for (int i = 1; i < argc; i++) {
+    std::string option = argv[i];
+    if (option == "-c" || option == "--cert_dirs") {
+      if (i + 1 < argc) arg_cert_dirs = argv[++i];
+    } else if (option == "-k" || option == "--keyring") {
+      if (i + 1 < argc) arg_keyring_desc = argv[++i];
+    }
+  }
+
+  if (arg_cert_dirs.empty() || arg_keyring_desc.empty()) {
+    LOG(ERROR) << "Missing cert_dirs or keyring desc";
+    Usage(1);
+  }
+
+  // Get the keyring id
+  key_serial_t key_ring_id;
+  if (!GetKeyringId(arg_keyring_desc, &key_ring_id)) {
+    PLOG(ERROR) << "Can't find keyring with " << arg_keyring_desc;
+    return 1;
+  }
+
+  std::vector<std::string> cert_dirs = android::base::Split(arg_cert_dirs, ",");
+  int start_index = 0;
+  for (const auto& cert_dir : cert_dirs) {
+    int keys_added = AddKeys(cert_dir, key_ring_id, arg_keyring_desc, start_index);
+    start_index += keys_added;
+  }
+
+  // Prevent new keys to be added.
+  if (!android::base::GetBoolProperty("ro.debuggable", false) &&
+      keyctl_restrict_keyring(key_ring_id, nullptr, nullptr) < 0) {
+    PLOG(ERROR) << "Failed to restrict key ring " << arg_keyring_desc;
+    return 1;
+  }
+
+  return 0;
+}
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 2802d36..1ec21e9 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -23,6 +23,10 @@
         "llndk.libraries.txt",
         "vndksp.libraries.txt",
     ],
+    stubs: {
+        symbol_file: "libnativeloader.map.txt",
+        versions: ["1"],
+    },
 }
 
 cc_library_headers {
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 9e6bcd4..89a6a79 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -320,7 +320,8 @@
   }
   std::string printable_build_id;
   for (const char& c : raw_build_id) {
-    printable_build_id += android::base::StringPrintf("%02x", c);
+    // Use %hhx to avoid sign extension on abis that have signed chars.
+    printable_build_id += android::base::StringPrintf("%02hhx", c);
   }
   return printable_build_id;
 }
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
index ea9befc..16451d1 100644
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
@@ -78,6 +78,17 @@
   EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
 }
 
+TEST_F(MapInfoGetBuildIDTest, from_elf_no_sign_extension) {
+  map_info_->elf.reset(elf_container_.release());
+
+  std::string build_id = {static_cast<char>(0xfa), static_cast<char>(0xab), static_cast<char>(0x12),
+                          static_cast<char>(0x02)};
+  elf_interface_->FakeSetBuildID(build_id);
+
+  EXPECT_EQ("\xFA\xAB\x12\x2", map_info_->GetBuildID());
+  EXPECT_EQ("faab1202", map_info_->GetPrintableBuildID());
+}
+
 void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
   static constexpr size_t kNumConcurrentThreads = 100;
 
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index a854e93..48ca998 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -105,7 +105,8 @@
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = default
+namespace.conscrypt.links = runtime,default
+namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index bc8568e..582ce27 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -73,6 +73,8 @@
 namespace.default.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.permitted.paths += /data
 namespace.default.permitted.paths += /mnt/expand
+namespace.default.permitted.paths += /bionic/${LIB}
+namespace.default.permitted.paths += /system/${LIB}/bootstrap
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
@@ -104,6 +106,8 @@
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/app
 namespace.default.asan.permitted.paths += /%PRODUCT_SERVICES%/priv-app
 namespace.default.asan.permitted.paths += /mnt/expand
+namespace.default.asan.permitted.paths += /bionic/${LIB}
+namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
 
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 # If a shared library or an executable requests a shared library that
@@ -172,7 +176,8 @@
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = default
+namespace.conscrypt.links = runtime,default
+namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -462,7 +467,10 @@
 namespace.system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 namespace.system.links = runtime
-namespace.system.link.runtime.shared_libs = libdexfile_external.so
+namespace.system.link.runtime.shared_libs  = libdexfile_external.so
+namespace.system.link.runtime.shared_libs += libnativebridge.so
+namespace.system.link.runtime.shared_libs += libnativehelper.so
+namespace.system.link.runtime.shared_libs += libnativeloader.so
 
 ###############################################################################
 # Namespace config for binaries under /postinstall.
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index ae486ea..d0bdf3a 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -124,7 +124,8 @@
 # Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = default
+namespace.conscrypt.links = runtime,default
+namespace.conscrypt.link.runtime.shared_libs  = libjavacore.so
 namespace.conscrypt.link.default.shared_libs  = libc.so
 namespace.conscrypt.link.default.shared_libs += libm.so
 namespace.conscrypt.link.default.shared_libs += libdl.so
@@ -333,7 +334,10 @@
 namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
 namespace.default.links = runtime
-namespace.default.link.runtime.shared_libs = libdexfile_external.so
+namespace.default.link.runtime.shared_libs  = libdexfile_external.so
+namespace.default.link.runtime.shared_libs += libnativebridge.so
+namespace.default.link.runtime.shared_libs += libnativehelper.so
+namespace.default.link.runtime.shared_libs += libnativeloader.so
 
 ###############################################################################
 # "runtime" APEX namespace
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d081666..4a19e39 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -12,6 +12,12 @@
 import /init.${ro.zygote}.rc
 
 on early-init
+    # Mount shared so changes propagate into child namespaces
+    # Do this before other processes are started from init. Otherwise,
+    # processes launched while the propagation type of / is 'private'
+    # won't get mount events from others.
+    mount rootfs rootfs / shared rec
+
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
@@ -346,8 +352,6 @@
     # Once everything is setup, no need to modify /.
     # The bind+remount combination allows this to work in containers.
     mount rootfs rootfs / remount bind ro nodev
-    # Mount shared so changes propagate into child namespaces
-    mount rootfs rootfs / shared rec
     # Mount default storage into root namespace
     mount none /mnt/runtime/default /storage bind rec
     mount none none /storage slave rec
@@ -583,6 +587,14 @@
     # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
     exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
 
+    # Wait for apexd to finish activating APEXes before starting more processes.
+    # This certainly reduces the parallelism but is required to make as many processes
+    # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms
+    # so the impact on the booting time is not significant.
+    wait_for_prop apexd.status ready
+    setup_runtime_bionic
+    parse_apex_configs
+
     # If there is no post-fs-data action in the init.<device>.rc file, you
     # must uncomment this line, otherwise encrypted filesystems
     # won't work.
@@ -804,6 +816,3 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
-
-on property:apexd.status=ready
-    parse_apex_configs