Merge "fastboot: Mount /metadata before overlayfs teardown."
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 51d5755..d6945e3 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -25,6 +25,9 @@
       "name": "libcutils_test"
     },
     {
+      "name": "libmodprobe_tests"
+    },
+    {
       "name": "libprocinfo_test"
     },
     {
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 9b663be..460ddde 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1167,7 +1167,7 @@
         std::string host;
         int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
         std::string error;
-        if (address.starts_with("vsock:")) {
+        if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
             serial = address;
         } else if (!android::base::ParseNetAddress(address, &host, &port, &serial, &error)) {
             SendFail(reply_fd, android::base::StringPrintf("couldn't parse '%s': %s",
diff --git a/adb/adb.h b/adb/adb.h
index c6cb06a..7f7dd0d 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -185,14 +185,7 @@
     } while (0)
 #endif
 
-#if ADB_HOST_ON_TARGET
-/* adb and adbd are coexisting on the target, so use 5038 for adb
- * to avoid conflicting with adbd's usage of 5037
- */
-#define DEFAULT_ADB_PORT 5038
-#else
 #define DEFAULT_ADB_PORT 5037
-#endif
 
 #define DEFAULT_ADB_LOCAL_TRANSPORT_PORT 5555
 
@@ -200,7 +193,7 @@
 #define ADB_SUBCLASS 0x42
 #define ADB_PROTOCOL 0x1
 
-void local_init(int port);
+void local_init(const std::string& addr);
 bool local_connect(int port);
 int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
 
diff --git a/adb/apex/ld.config.txt b/adb/apex/ld.config.txt
index 85f9b29..d1858a4 100644
--- a/adb/apex/ld.config.txt
+++ b/adb/apex/ld.config.txt
@@ -5,22 +5,16 @@
 dir.adbd = /apex/com.android.adbd/bin/
 
 [adbd]
-additional.namespaces = platform,art,adbd
+additional.namespaces = platform,art
 
 namespace.default.isolated = true
-namespace.default.links = art,adbd,platform
+namespace.default.search.paths = /apex/com.android.adbd/${LIB}
+namespace.default.asan.search.paths = /apex/com.android.adbd/${LIB}
+namespace.default.permitted.paths = /system/${LIB}
+namespace.default.asan.permitted.paths = /system/${LIB}
+namespace.default.links = art,platform
 namespace.default.link.art.shared_libs = libadbconnection_server.so
-namespace.default.link.platform.allow_all_shared_libs = true
-namespace.default.link.adbd.allow_all_shared_libs = true
-
-###############################################################################
-# "adbd" APEX namespace
-###############################################################################
-namespace.adbd.isolated = true
-namespace.adbd.search.paths = /apex/com.android.adbd/${LIB}
-namespace.adbd.asan.search.paths = /apex/com.android.adbd/${LIB}
-namespace.adbd.links = platform
-namespace.adbd.link.platform.allow_all_shared_libs = true
+namespace.default.link.platform.shared_libs = libc.so:libdl.so:libm.so:libclang_rt.hwasan-aarch64-android.so
 
 ###############################################################################
 # "art" APEX namespace: used for libadbdconnection_server
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 813a8a9..83b9238 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -790,6 +790,15 @@
                        service_string);
 }
 
+static int adb_shell_noinput(int argc, const char** argv) {
+#if !defined(_WIN32)
+    unique_fd fd(adb_open("/dev/null", O_RDONLY));
+    CHECK_NE(STDIN_FILENO, fd.get());
+    dup2(fd.get(), STDIN_FILENO);
+#endif
+    return adb_shell(argc, argv);
+}
+
 static int adb_sideload_legacy(const char* filename, int in_fd, int size) {
     std::string error;
     unique_fd out_fd(adb_connect(android::base::StringPrintf("sideload:%d", size), &error));
@@ -1612,7 +1621,7 @@
         return adb_query_command(query);
     }
     else if (!strcmp(argv[0], "connect")) {
-        if (argc != 2) error_exit("usage: adb connect HOST[:PORT>]");
+        if (argc != 2) error_exit("usage: adb connect HOST[:PORT]");
 
         std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
         return adb_query_command(query);
@@ -1711,7 +1720,7 @@
         if (CanUseFeature(features, kFeatureRemountShell)) {
             std::vector<const char*> args = {"shell"};
             args.insert(args.cend(), argv, argv + argc);
-            return adb_shell(args.size(), args.data());
+            return adb_shell_noinput(args.size(), args.data());
         } else if (argc > 1) {
             auto command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
             return adb_connect_command(command);
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 0c5c28f..e5ffe4c 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -129,7 +129,7 @@
     }
 
     if (!getenv("ADB_EMU") || strcmp(getenv("ADB_EMU"), "0") != 0) {
-        local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+        local_init(android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
     }
 
     std::string error;
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 2e84ce6..ec4ab4a 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -16,36 +16,72 @@
 
 #define TRACE_TAG AUTH
 
-#include "adb.h"
-#include "adb_auth.h"
-#include "adb_io.h"
-#include "fdevent/fdevent.h"
 #include "sysdeps.h"
-#include "transport.h"
 
 #include <resolv.h>
 #include <stdio.h>
 #include <string.h>
-#include <iomanip>
 
 #include <algorithm>
+#include <iomanip>
+#include <map>
 #include <memory>
 
 #include <adbd_auth.h>
 #include <android-base/file.h>
+#include <android-base/no_destructor.h>
 #include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
 #include <openssl/obj_mac.h>
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_io.h"
+#include "fdevent/fdevent.h"
+#include "transport.h"
+#include "types.h"
+
 static AdbdAuthContext* auth_ctx;
 
 static void adb_disconnected(void* unused, atransport* t);
 static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
 
+static android::base::NoDestructor<std::map<uint32_t, weak_ptr<atransport>>> transports;
+static uint32_t transport_auth_id = 0;
+
 bool auth_required = true;
 
+static void* transport_to_callback_arg(atransport* transport) {
+    uint32_t id = transport_auth_id++;
+    (*transports)[id] = transport->weak();
+    return reinterpret_cast<void*>(id);
+}
+
+static atransport* transport_from_callback_arg(void* id) {
+    uint64_t id_u64 = reinterpret_cast<uint64_t>(id);
+    if (id_u64 > std::numeric_limits<uint32_t>::max()) {
+        LOG(FATAL) << "transport_from_callback_arg called on out of range value: " << id_u64;
+    }
+
+    uint32_t id_u32 = static_cast<uint32_t>(id_u64);
+    auto it = transports->find(id_u32);
+    if (it == transports->end()) {
+        LOG(ERROR) << "transport_from_callback_arg failed to find transport for id " << id_u32;
+        return nullptr;
+    }
+
+    atransport* t = it->second.get();
+    if (!t) {
+        LOG(WARNING) << "transport_from_callback_arg found already destructed transport";
+        return nullptr;
+    }
+
+    transports->erase(it);
+    return t;
+}
+
 static void IteratePublicKeys(std::function<bool(std::string_view public_key)> f) {
     adbd_auth_get_public_keys(
             auth_ctx,
@@ -111,9 +147,16 @@
 
 static void adbd_auth_key_authorized(void* arg, uint64_t id) {
     LOG(INFO) << "adb client authorized";
-    auto* transport = static_cast<atransport*>(arg);
-    transport->auth_id = id;
-    adbd_auth_verified(transport);
+    fdevent_run_on_main_thread([=]() {
+        LOG(INFO) << "arg = " << reinterpret_cast<uintptr_t>(arg);
+        auto* transport = transport_from_callback_arg(arg);
+        if (!transport) {
+            LOG(ERROR) << "authorization received for deleted transport, ignoring";
+            return;
+        }
+        transport->auth_id = id;
+        adbd_auth_verified(transport);
+    });
 }
 
 void adbd_auth_init(void) {
@@ -158,7 +201,8 @@
 void adbd_auth_confirm_key(atransport* t) {
     LOG(INFO) << "prompting user to authorize key";
     t->AddDisconnect(&adb_disconnect);
-    adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(), t);
+    adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(),
+                          transport_to_callback_arg(t));
 }
 
 void adbd_notify_framework_connected_key(atransport* t) {
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 7277cc8..3322574 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -32,11 +32,13 @@
 #include <sys/prctl.h>
 
 #include <memory>
+#include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #if defined(__ANDROID__)
 #include <libminijail.h>
@@ -51,6 +53,7 @@
 #include "adb_auth.h"
 #include "adb_listeners.h"
 #include "adb_utils.h"
+#include "socket_spec.h"
 #include "transport.h"
 
 #include "mdns.h"
@@ -179,12 +182,26 @@
 }
 #endif
 
-static void setup_port(int port) {
-    LOG(INFO) << "adbd listening on port " << port;
-    local_init(port);
+static void setup_adb(const std::vector<std::string>& addrs) {
 #if defined(__ANDROID__)
+    // Get the first valid port from addrs and setup mDNS.
+    int port = -1;
+    std::string error;
+    for (const auto& addr : addrs) {
+        port = get_host_socket_spec_port(addr, &error);
+        if (port != -1) {
+            break;
+        }
+    }
+    if (port == -1) {
+        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    }
     setup_mdns(port);
 #endif
+    for (const auto& addr : addrs) {
+        LOG(INFO) << "adbd listening on " << addr;
+        local_init(addr);
+    }
 }
 
 int adbd_main(int server_port) {
@@ -248,25 +265,38 @@
     // If one of these properties is set, also listen on that port.
     // If one of the properties isn't set and we couldn't listen on usb, listen
     // on the default port.
-    std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
-    if (prop_port.empty()) {
-        prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
-    }
+    std::vector<std::string> addrs;
+    std::string prop_addr = android::base::GetProperty("service.adb.listen_addrs", "");
+    if (prop_addr.empty()) {
+        std::string prop_port = android::base::GetProperty("service.adb.tcp.port", "");
+        if (prop_port.empty()) {
+            prop_port = android::base::GetProperty("persist.adb.tcp.port", "");
+        }
 
 #if !defined(__ANDROID__)
-    if (prop_port.empty() && getenv("ADBD_PORT")) {
-        prop_port = getenv("ADBD_PORT");
-    }
+        if (prop_port.empty() && getenv("ADBD_PORT")) {
+            prop_port = getenv("ADBD_PORT");
+        }
 #endif
 
-    int port;
-    if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
-        D("using port=%d", port);
-        // Listen on TCP port specified by service.adb.tcp.port property.
-        setup_port(port);
-    } else if (!is_usb) {
-        // Listen on default port.
-        setup_port(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+        int port;
+        if (sscanf(prop_port.c_str(), "%d", &port) == 1 && port > 0) {
+            D("using tcp port=%d", port);
+            // Listen on TCP and VSOCK port specified by service.adb.tcp.port property.
+            addrs.push_back(android::base::StringPrintf("tcp:%d", port));
+            addrs.push_back(android::base::StringPrintf("vsock:%d", port));
+            setup_adb(addrs);
+        } else if (!is_usb) {
+            // Listen on default port.
+            addrs.push_back(
+                    android::base::StringPrintf("tcp:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
+            addrs.push_back(
+                    android::base::StringPrintf("vsock:%d", DEFAULT_ADB_LOCAL_TRANSPORT_PORT));
+            setup_adb(addrs);
+        }
+    } else {
+        addrs = android::base::Split(prop_addr, ",");
+        setup_adb(addrs);
     }
 
     D("adbd_main(): pre init_jdwp()");
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 0fb14c4..f62032d 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -85,7 +85,6 @@
 #include <paths.h>
 #include <pty.h>
 #include <pwd.h>
-#include <sys/select.h>
 #include <termios.h>
 
 #include <memory>
@@ -141,6 +140,20 @@
     return true;
 }
 
+struct SubprocessPollfds {
+    adb_pollfd pfds[3];
+
+    adb_pollfd* data() { return pfds; }
+    size_t size() { return 3; }
+
+    adb_pollfd* begin() { return pfds; }
+    adb_pollfd* end() { return pfds + size(); }
+
+    adb_pollfd& stdinout_pfd() { return pfds[0]; }
+    adb_pollfd& stderr_pfd() { return pfds[1]; }
+    adb_pollfd& protocol_pfd() { return pfds[2]; }
+};
+
 class Subprocess {
   public:
     Subprocess(std::string command, const char* terminal_type, SubprocessType type,
@@ -176,8 +189,7 @@
     void PassDataStreams();
     void WaitForExit();
 
-    unique_fd* SelectLoop(fd_set* master_read_set_ptr,
-                          fd_set* master_write_set_ptr);
+    unique_fd* PollLoop(SubprocessPollfds* pfds);
 
     // Input/output stream handlers. Success returns nullptr, failure returns
     // a pointer to the failed FD.
@@ -545,23 +557,23 @@
     }
 
     // Start by trying to read from the protocol FD, stdout, and stderr.
-    fd_set master_read_set, master_write_set;
-    FD_ZERO(&master_read_set);
-    FD_ZERO(&master_write_set);
-    for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
-        if (*sfd != -1) {
-            FD_SET(sfd->get(), &master_read_set);
-        }
-    }
+    SubprocessPollfds pfds;
+    pfds.stdinout_pfd() = {.fd = stdinout_sfd_.get(), .events = POLLIN};
+    pfds.stderr_pfd() = {.fd = stderr_sfd_.get(), .events = POLLIN};
+    pfds.protocol_pfd() = {.fd = protocol_sfd_.get(), .events = POLLIN};
 
     // Pass data until the protocol FD or both the subprocess pipes die, at
     // which point we can't pass any more data.
     while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
-        unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
+        unique_fd* dead_sfd = PollLoop(&pfds);
         if (dead_sfd) {
             D("closing FD %d", dead_sfd->get());
-            FD_CLR(dead_sfd->get(), &master_read_set);
-            FD_CLR(dead_sfd->get(), &master_write_set);
+            auto it = std::find_if(pfds.begin(), pfds.end(), [=](const adb_pollfd& pfd) {
+                return pfd.fd == dead_sfd->get();
+            });
+            CHECK(it != pfds.end());
+            it->fd = -1;
+            it->events = 0;
             if (dead_sfd == &protocol_sfd_) {
                 // Using SIGHUP is a decent general way to indicate that the
                 // controlling process is going away. If specific signals are
@@ -583,30 +595,19 @@
     }
 }
 
-namespace {
-
-inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
-    return sfd != -1 && FD_ISSET(sfd.get(), set);
-}
-
-}   // namespace
-
-unique_fd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
-                                  fd_set* master_write_set_ptr) {
-    fd_set read_set, write_set;
-    int select_n =
-            std::max(std::max(protocol_sfd_.get(), stdinout_sfd_.get()), stderr_sfd_.get()) + 1;
+unique_fd* Subprocess::PollLoop(SubprocessPollfds* pfds) {
     unique_fd* dead_sfd = nullptr;
+    adb_pollfd& stdinout_pfd = pfds->stdinout_pfd();
+    adb_pollfd& stderr_pfd = pfds->stderr_pfd();
+    adb_pollfd& protocol_pfd = pfds->protocol_pfd();
 
-    // Keep calling select() and passing data until an FD closes/errors.
+    // Keep calling poll() and passing data until an FD closes/errors.
     while (!dead_sfd) {
-        memcpy(&read_set, master_read_set_ptr, sizeof(read_set));
-        memcpy(&write_set, master_write_set_ptr, sizeof(write_set));
-        if (select(select_n, &read_set, &write_set, nullptr, nullptr) < 0) {
+        if (adb_poll(pfds->data(), pfds->size(), -1) < 0) {
             if (errno == EINTR) {
                 continue;
             } else {
-                PLOG(ERROR) << "select failed, closing subprocess pipes";
+                PLOG(ERROR) << "poll failed, closing subprocess pipes";
                 stdinout_sfd_.reset(-1);
                 stderr_sfd_.reset(-1);
                 return nullptr;
@@ -614,34 +615,47 @@
         }
 
         // Read stdout, write to protocol FD.
-        if (ValidAndInSet(stdinout_sfd_, &read_set)) {
+        if (stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLIN)) {
             dead_sfd = PassOutput(&stdinout_sfd_, ShellProtocol::kIdStdout);
         }
 
         // Read stderr, write to protocol FD.
-        if (!dead_sfd && ValidAndInSet(stderr_sfd_, &read_set)) {
+        if (!dead_sfd && stderr_pfd.fd != 1 && (stderr_pfd.revents & POLLIN)) {
             dead_sfd = PassOutput(&stderr_sfd_, ShellProtocol::kIdStderr);
         }
 
         // Read protocol FD, write to stdin.
-        if (!dead_sfd && ValidAndInSet(protocol_sfd_, &read_set)) {
+        if (!dead_sfd && protocol_pfd.fd != -1 && (protocol_pfd.revents & POLLIN)) {
             dead_sfd = PassInput();
             // If we didn't finish writing, block on stdin write.
             if (input_bytes_left_) {
-                FD_CLR(protocol_sfd_.get(), master_read_set_ptr);
-                FD_SET(stdinout_sfd_.get(), master_write_set_ptr);
+                protocol_pfd.events &= ~POLLIN;
+                stdinout_pfd.events |= POLLOUT;
             }
         }
 
         // Continue writing to stdin; only happens if a previous write blocked.
-        if (!dead_sfd && ValidAndInSet(stdinout_sfd_, &write_set)) {
+        if (!dead_sfd && stdinout_pfd.fd != -1 && (stdinout_pfd.revents & POLLOUT)) {
             dead_sfd = PassInput();
             // If we finished writing, go back to blocking on protocol read.
             if (!input_bytes_left_) {
-                FD_SET(protocol_sfd_.get(), master_read_set_ptr);
-                FD_CLR(stdinout_sfd_.get(), master_write_set_ptr);
+                protocol_pfd.events |= POLLIN;
+                stdinout_pfd.events &= ~POLLOUT;
             }
         }
+
+        // After handling all of the events we've received, check to see if any fds have died.
+        if (stdinout_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+            return &stdinout_sfd_;
+        }
+
+        if (stderr_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+            return &stderr_sfd_;
+        }
+
+        if (protocol_pfd.revents & (POLLHUP | POLLRDHUP | POLLERR | POLLNVAL)) {
+            return &protocol_sfd_;
+        }
     }  // while (!dead_sfd)
 
     return dead_sfd;
diff --git a/adb/daemon/transport_qemu.cpp b/adb/daemon/transport_qemu.cpp
index aa760bc..901efee 100644
--- a/adb/daemon/transport_qemu.cpp
+++ b/adb/daemon/transport_qemu.cpp
@@ -18,6 +18,7 @@
 #include <qemu_pipe.h>
 
 #define TRACE_TAG TRANSPORT
+#include "socket_spec.h"
 #include "sysdeps.h"
 #include "transport.h"
 
@@ -55,7 +56,7 @@
  *   the transport registration is completed. That's why we need to send the
  *   'start' request after the transport is registered.
  */
-void qemu_socket_thread(int port) {
+void qemu_socket_thread(std::string_view addr) {
     /* 'accept' request to the adb QEMUD service. */
     static const char _accept_req[] = "accept";
     /* 'start' request to the adb QEMUD service. */
@@ -69,6 +70,12 @@
     adb_thread_setname("qemu socket");
     D("transport: qemu_socket_thread() starting");
 
+    std::string error;
+    int port = get_host_socket_spec_port(addr, &error);
+    if (port == -1) {
+        port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+    }
+
     /* adb QEMUD service connection request. */
     snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
 
@@ -78,7 +85,7 @@
         /* This could be an older version of the emulator, that doesn't
          * implement adb QEMUD service. Fall back to the old TCP way. */
         D("adb service is not available. Falling back to TCP socket.");
-        std::thread(server_socket_thread, tcp_listen_inaddr_any, port).detach();
+        std::thread(server_socket_thread, adb_listen, addr).detach();
         return;
     }
 
diff --git a/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp b/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp
index 3dc5e50..932d579 100644
--- a/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp
+++ b/adb/fastdeploy/deploypatchgenerator/apk_archive.cpp
@@ -36,7 +36,7 @@
     FileRegion(borrowed_fd fd, off64_t offset, size_t length)
         : mapped_(android::base::MappedFile::FromOsHandle(adb_get_os_handle(fd), offset, length,
                                                           PROT_READ)) {
-        if (mapped_.data() != nullptr) {
+        if (mapped_ != nullptr) {
             return;
         }
 
@@ -50,14 +50,14 @@
         }
     }
 
-    const char* data() const { return mapped_.data() ? mapped_.data() : buffer_.data(); }
-    size_t size() const { return mapped_.data() ? mapped_.size() : buffer_.size(); }
+    const char* data() const { return mapped_ ? mapped_->data() : buffer_.data(); }
+    size_t size() const { return mapped_ ? mapped_->size() : buffer_.size(); }
 
   private:
     FileRegion() = default;
     DISALLOW_COPY_AND_ASSIGN(FileRegion);
 
-    android::base::MappedFile mapped_;
+    std::unique_ptr<android::base::MappedFile> mapped_;
     std::string buffer_;
 };
 }  // namespace
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 9ce443e..d17036c 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -122,6 +122,41 @@
     return true;
 }
 
+int get_host_socket_spec_port(std::string_view spec, std::string* error) {
+    int port;
+    if (spec.starts_with("tcp:")) {
+        if (!parse_tcp_socket_spec(spec, nullptr, &port, nullptr, error)) {
+            return -1;
+        }
+    } else if (spec.starts_with("vsock:")) {
+#if ADB_LINUX
+        std::string spec_str(spec);
+        std::vector<std::string> fragments = android::base::Split(spec_str, ":");
+        if (fragments.size() != 2) {
+            *error = "given vsock server socket string was invalid";
+            return -1;
+        }
+        if (!android::base::ParseInt(fragments[1], &port)) {
+            *error = "could not parse vsock port";
+            errno = EINVAL;
+            return -1;
+        }
+        if (port < 0) {
+            *error = "vsock port was negative.";
+            errno = EINVAL;
+            return -1;
+        }
+#else   // ADB_LINUX
+        *error = "vsock is only supported on linux";
+        return -1;
+#endif  // ADB_LINUX
+    } else {
+        *error = "given socket spec string was invalid";
+        return -1;
+    }
+    return port;
+}
+
 static bool tcp_host_is_local(std::string_view hostname) {
     // FIXME
     return hostname.empty() || hostname == "localhost";
@@ -254,6 +289,14 @@
 
             fd->reset(network_local_client(&address[prefix.length()], it.second.socket_namespace,
                                            SOCK_STREAM, error));
+
+            if (fd->get() < 0) {
+                *error =
+                        android::base::StringPrintf("could not connect to %s address '%s'",
+                                                    it.first.c_str(), std::string(address).c_str());
+                return false;
+            }
+
             if (serial) {
                 *serial = address;
             }
@@ -275,7 +318,11 @@
         }
 
         int result;
+#if ADB_HOST
         if (hostname.empty() && gListenAll) {
+#else
+        if (hostname.empty()) {
+#endif
             result = network_inaddr_any_server(port, SOCK_STREAM, error);
         } else if (tcp_host_is_local(hostname)) {
             result = network_loopback_server(port, SOCK_STREAM, error, true);
diff --git a/adb/socket_spec.h b/adb/socket_spec.h
index 7cc2fac..94719c8 100644
--- a/adb/socket_spec.h
+++ b/adb/socket_spec.h
@@ -31,3 +31,5 @@
 
 bool parse_tcp_socket_spec(std::string_view spec, std::string* hostname, int* port,
                            std::string* serial, std::string* error);
+
+int get_host_socket_spec_port(std::string_view spec, std::string* error);
diff --git a/adb/socket_spec_test.cpp b/adb/socket_spec_test.cpp
index 3a2f60c..e9d5270 100644
--- a/adb/socket_spec_test.cpp
+++ b/adb/socket_spec_test.cpp
@@ -18,6 +18,10 @@
 
 #include <string>
 
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/stringprintf.h>
 #include <gtest/gtest.h>
 
 TEST(socket_spec, parse_tcp_socket_spec_just_port) {
@@ -88,3 +92,63 @@
     EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:", &hostname, &port, &serial, &error));
     EXPECT_FALSE(parse_tcp_socket_spec("tcp:[::1]:-1", &hostname, &port, &serial, &error));
 }
+
+TEST(socket_spec, get_host_socket_spec_port) {
+    std::string error;
+    EXPECT_EQ(5555, get_host_socket_spec_port("tcp:5555", &error));
+    EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost:5555", &error));
+    EXPECT_EQ(5555, get_host_socket_spec_port("tcp:[::1]:5555", &error));
+    EXPECT_EQ(5555, get_host_socket_spec_port("vsock:5555", &error));
+}
+
+TEST(socket_spec, get_host_socket_spec_port_no_port) {
+    std::string error;
+    EXPECT_EQ(5555, get_host_socket_spec_port("tcp:localhost", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("vsock:localhost", &error));
+}
+
+TEST(socket_spec, get_host_socket_spec_port_bad_ports) {
+    std::string error;
+    EXPECT_EQ(-1, get_host_socket_spec_port("tcp:65536", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("tcp:-5", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("vsock:-5", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("vsock:5:5555", &error));
+}
+
+TEST(socket_spec, get_host_socket_spec_port_bad_string) {
+    std::string error;
+    EXPECT_EQ(-1, get_host_socket_spec_port("tcpz:5555", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("vsockz:5555", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("abcd:5555", &error));
+    EXPECT_EQ(-1, get_host_socket_spec_port("abcd", &error));
+}
+
+TEST(socket_spec, socket_spec_listen_connect_tcp) {
+    std::string error, serial;
+    int port;
+    unique_fd server_fd, client_fd;
+    EXPECT_FALSE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
+    server_fd.reset(socket_spec_listen("tcp:7777", &error, &port));
+    EXPECT_NE(server_fd.get(), -1);
+    EXPECT_TRUE(socket_spec_connect(&client_fd, "tcp:localhost:7777", &port, &serial, &error));
+    EXPECT_NE(client_fd.get(), -1);
+}
+
+TEST(socket_spec, socket_spec_listen_connect_localfilesystem) {
+    std::string error, serial;
+    int port;
+    unique_fd server_fd, client_fd;
+    TemporaryDir sock_dir;
+
+    // Only run this test if the created directory is writable.
+    int result = access(sock_dir.path, W_OK);
+    if (result == 0) {
+        std::string sock_addr =
+                android::base::StringPrintf("localfilesystem:%s/af_unix_socket", sock_dir.path);
+        EXPECT_FALSE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
+        server_fd.reset(socket_spec_listen(sock_addr, &error, &port));
+        EXPECT_NE(server_fd.get(), -1);
+        EXPECT_TRUE(socket_spec_connect(&client_fd, sock_addr, &port, &serial, &error));
+        EXPECT_NE(client_fd.get(), -1);
+    }
+}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 7d5bf17..423af67 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -625,7 +625,8 @@
         return true;
     };
 
-    static constexpr std::string_view prefixes[] = {"usb:", "product:", "model:", "device:"};
+    static constexpr std::string_view prefixes[] = {
+            "usb:", "product:", "model:", "device:", "localfilesystem:"};
     for (std::string_view prefix : prefixes) {
         if (command.starts_with(prefix)) {
             consume(prefix.size());
diff --git a/adb/test_device.py b/adb/test_device.py
index 57925e8..083adce 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -536,6 +536,36 @@
         for i, success in result.iteritems():
             self.assertTrue(success)
 
+    def disabled_test_parallel(self):
+        """Spawn a bunch of `adb shell` instances in parallel.
+
+        This was broken historically due to the use of select, which only works
+        for fds that are numerically less than 1024.
+
+        Bug: http://b/141955761"""
+
+        n_procs = 2048
+        procs = dict()
+        for i in xrange(0, n_procs):
+            procs[i] = subprocess.Popen(
+                ['adb', 'shell', 'read foo; echo $foo; read rc; exit $rc'],
+                stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE
+            )
+
+        for i in xrange(0, n_procs):
+            procs[i].stdin.write("%d\n" % i)
+
+        for i in xrange(0, n_procs):
+            response = procs[i].stdout.readline()
+            assert(response == "%d\n" % i)
+
+        for i in xrange(0, n_procs):
+            procs[i].stdin.write("%d\n" % (i % 256))
+
+        for i in xrange(0, n_procs):
+            assert(procs[i].wait() == i % 256)
+
 
 class ArgumentEscapingTest(DeviceTest):
     def test_shell_escaping(self):
diff --git a/adb/transport.h b/adb/transport.h
index ea77117..5a750ee 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -38,6 +38,7 @@
 
 #include "adb.h"
 #include "adb_unique_fd.h"
+#include "types.h"
 #include "usb.h"
 
 typedef std::unordered_set<std::string> FeatureSet;
@@ -223,7 +224,7 @@
     Abort,
 };
 
-class atransport {
+class atransport : public enable_weak_from_this<atransport> {
   public:
     // TODO(danalbert): We expose waaaaaaay too much stuff because this was
     // historically just a struct, but making the whole thing a more idiomatic
@@ -246,7 +247,7 @@
     }
     atransport(ConnectionState state = kCsOffline)
         : atransport([](atransport*) { return ReconnectResult::Abort; }, state) {}
-    virtual ~atransport();
+    ~atransport();
 
     int Write(apacket* p);
     void Reset();
@@ -424,11 +425,12 @@
 asocket* create_device_tracker(bool long_output);
 
 #if !ADB_HOST
-unique_fd tcp_listen_inaddr_any(int port, std::string* error);
-void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_func, int port);
+unique_fd adb_listen(std::string_view addr, std::string* error);
+void server_socket_thread(std::function<unique_fd(std::string_view, std::string*)> listen_func,
+                          std::string_view addr);
 
 #if defined(__ANDROID__)
-void qemu_socket_thread(int port);
+void qemu_socket_thread(std::string_view addr);
 bool use_qemu_goldfish();
 #endif
 
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index b9f738d..c726186 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -85,22 +85,6 @@
     return local_connect_arbitrary_ports(port - 1, port, &dummy) == 0;
 }
 
-std::tuple<unique_fd, int, std::string> tcp_connect(const std::string& address,
-                                                    std::string* response) {
-    unique_fd fd;
-    int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
-    std::string serial;
-    std::string prefix_addr = address.starts_with("vsock:") ? address : "tcp:" + address;
-    if (socket_spec_connect(&fd, prefix_addr, &port, &serial, response)) {
-        close_on_exec(fd);
-        if (!set_tcp_keepalive(fd, 1)) {
-            D("warning: failed to configure TCP keepalives (%s)", strerror(errno));
-        }
-        return std::make_tuple(std::move(fd), port, serial);
-    }
-    return std::make_tuple(unique_fd(), 0, serial);
-}
-
 void connect_device(const std::string& address, std::string* response) {
     if (address.empty()) {
         *response = "empty address";
@@ -110,17 +94,25 @@
     D("connection requested to '%s'", address.c_str());
     unique_fd fd;
     int port;
-    std::string serial;
-    std::tie(fd, port, serial) = tcp_connect(address, response);
+    std::string serial, prefix_addr;
+
+    // If address does not match any socket type, it should default to TCP.
+    if (address.starts_with("vsock:") || address.starts_with("localfilesystem:")) {
+        prefix_addr = address;
+    } else {
+        prefix_addr = "tcp:" + address;
+    }
+
+    socket_spec_connect(&fd, prefix_addr, &port, &serial, response);
     if (fd.get() == -1) {
         return;
     }
-    auto reconnect = [address](atransport* t) {
+    auto reconnect = [prefix_addr](atransport* t) {
         std::string response;
         unique_fd fd;
         int port;
         std::string serial;
-        std::tie(fd, port, serial) = tcp_connect(address, &response);
+        socket_spec_connect(&fd, prefix_addr, &port, &serial, &response);
         if (fd == -1) {
             D("reconnect failed: %s", response.c_str());
             return ReconnectResult::Retry;
@@ -203,7 +195,7 @@
 std::mutex &retry_ports_lock = *new std::mutex;
 std::condition_variable &retry_ports_cond = *new std::condition_variable;
 
-static void client_socket_thread(int) {
+static void client_socket_thread(std::string_view) {
     adb_thread_setname("client_socket_thread");
     D("transport: client_socket_thread() starting");
     PollAllLocalPortsForEmulator();
@@ -248,7 +240,8 @@
 
 #else  // !ADB_HOST
 
-void server_socket_thread(std::function<unique_fd(int, std::string*)> listen_func, int port) {
+void server_socket_thread(std::function<unique_fd(std::string_view, std::string*)> listen_func,
+                          std::string_view addr) {
     adb_thread_setname("server socket");
 
     unique_fd serverfd;
@@ -256,7 +249,7 @@
 
     while (serverfd == -1) {
         errno = 0;
-        serverfd = listen_func(port, &error);
+        serverfd = listen_func(addr, &error);
         if (errno == EAFNOSUPPORT || errno == EINVAL || errno == EPROTONOSUPPORT) {
             D("unrecoverable error: '%s'", error.c_str());
             return;
@@ -276,7 +269,9 @@
             close_on_exec(fd.get());
             disable_tcp_nagle(fd.get());
             std::string serial = android::base::StringPrintf("host-%d", fd.get());
-            register_socket_transport(std::move(fd), std::move(serial), port, 1,
+            // We don't care about port value in "register_socket_transport" as it is used
+            // only from ADB_HOST. "server_socket_thread" is never called from ADB_HOST.
+            register_socket_transport(std::move(fd), std::move(serial), 0, 1,
                                       [](atransport*) { return ReconnectResult::Abort; });
         }
     }
@@ -285,38 +280,30 @@
 
 #endif
 
-unique_fd tcp_listen_inaddr_any(int port, std::string* error) {
-    return unique_fd{network_inaddr_any_server(port, SOCK_STREAM, error)};
-}
-
 #if !ADB_HOST
-static unique_fd vsock_listen(int port, std::string* error) {
-    return unique_fd{
-        socket_spec_listen(android::base::StringPrintf("vsock:%d", port), error, nullptr)
-    };
+unique_fd adb_listen(std::string_view addr, std::string* error) {
+    return unique_fd{socket_spec_listen(addr, error, nullptr)};
 }
 #endif
 
-void local_init(int port) {
+void local_init(const std::string& addr) {
 #if ADB_HOST
     D("transport: local client init");
-    std::thread(client_socket_thread, port).detach();
+    std::thread(client_socket_thread, addr).detach();
     adb_local_transport_max_port_env_override();
 #elif !defined(__ANDROID__)
     // Host adbd.
     D("transport: local server init");
-    std::thread(server_socket_thread, tcp_listen_inaddr_any, port).detach();
-    std::thread(server_socket_thread, vsock_listen, port).detach();
+    std::thread(server_socket_thread, adb_listen, addr).detach();
 #else
     D("transport: local server init");
     // For the adbd daemon in the system image we need to distinguish
     // between the device, and the emulator.
-    if (use_qemu_goldfish()) {
-        std::thread(qemu_socket_thread, port).detach();
+    if (addr.starts_with("tcp:") && use_qemu_goldfish()) {
+        std::thread(qemu_socket_thread, addr).detach();
     } else {
-        std::thread(server_socket_thread, tcp_listen_inaddr_any, port).detach();
+        std::thread(server_socket_thread, adb_listen, addr).detach();
     }
-    std::thread(server_socket_thread, vsock_listen, port).detach();
 #endif // !ADB_HOST
 }
 
diff --git a/adb/types.h b/adb/types.h
index 6b00224..c619fff 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -25,6 +25,7 @@
 
 #include <android-base/logging.h>
 
+#include "fdevent/fdevent.h"
 #include "sysdeps/uio.h"
 
 // Essentially std::vector<char>, except without zero initialization or reallocation.
@@ -245,3 +246,97 @@
     size_t start_index_ = 0;
     std::vector<block_type> chain_;
 };
+
+// An implementation of weak pointers tied to the fdevent run loop.
+//
+// This allows for code to submit a request for an object, and upon receiving
+// a response, know whether the object is still alive, or has been destroyed
+// because of other reasons. We keep a list of living weak_ptrs in each object,
+// and clear the weak_ptrs when the object is destroyed. This is safe, because
+// we require that both the destructor of the referent and the get method on
+// the weak_ptr are executed on the main thread.
+template <typename T>
+struct enable_weak_from_this;
+
+template <typename T>
+struct weak_ptr {
+    weak_ptr() = default;
+    explicit weak_ptr(T* ptr) { reset(ptr); }
+    weak_ptr(const weak_ptr& copy) { reset(copy.get()); }
+
+    weak_ptr(weak_ptr&& move) {
+        reset(move.get());
+        move.reset();
+    }
+
+    ~weak_ptr() { reset(); }
+
+    weak_ptr& operator=(const weak_ptr& copy) {
+        if (&copy == this) {
+            return *this;
+        }
+
+        reset(copy.get());
+        return *this;
+    }
+
+    weak_ptr& operator=(weak_ptr&& move) {
+        if (&move == this) {
+            return *this;
+        }
+
+        reset(move.get());
+        move.reset();
+        return *this;
+    }
+
+    T* get() {
+        check_main_thread();
+        return ptr_;
+    }
+
+    void reset(T* ptr = nullptr) {
+        check_main_thread();
+
+        if (ptr == ptr_) {
+            return;
+        }
+
+        if (ptr_) {
+            ptr_->weak_ptrs_.erase(
+                    std::remove(ptr_->weak_ptrs_.begin(), ptr_->weak_ptrs_.end(), this));
+        }
+
+        ptr_ = ptr;
+        if (ptr_) {
+            ptr_->weak_ptrs_.push_back(this);
+        }
+    }
+
+  private:
+    friend struct enable_weak_from_this<T>;
+    T* ptr_ = nullptr;
+};
+
+template <typename T>
+struct enable_weak_from_this {
+    ~enable_weak_from_this() {
+        if (!weak_ptrs_.empty()) {
+            check_main_thread();
+            for (auto& weak : weak_ptrs_) {
+                weak->ptr_ = nullptr;
+            }
+            weak_ptrs_.clear();
+        }
+    }
+
+    weak_ptr<T> weak() { return weak_ptr<T>(static_cast<T*>(this)); }
+
+    void schedule_deletion() {
+        fdevent_run_on_main_thread([this]() { delete this; });
+    }
+
+  private:
+    friend struct weak_ptr<T>;
+    std::vector<weak_ptr<T>*> weak_ptrs_;
+};
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index ab6476c..d099e52 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -222,20 +222,16 @@
 // 1) This will not check whether the severity is high enough. One should use WOULD_LOG to filter
 //    usage manually.
 // 2) This does not save and restore errno.
-#define LOG_STREAM(severity) LOG_STREAM_TO(DEFAULT, severity)
-
-// Get an ostream that can be used for logging at the given severity and to the
-// given destination. The same notes as for LOG_STREAM apply.
-#define LOG_STREAM_TO(dest, severity)                                           \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest,        \
-                              SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, -1) \
+#define LOG_STREAM(severity)                                                                    \
+  ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, \
+                              -1)                                                               \
       .stream()
 
 // Logs a message to logcat on Android otherwise to stderr. If the severity is
 // FATAL it also causes an abort. For example:
 //
 //     LOG(FATAL) << "We didn't expect to reach here";
-#define LOG(severity) LOG_TO(DEFAULT, severity)
+#define LOG(severity) LOGGING_PREAMBLE(severity) && LOG_STREAM(severity)
 
 // Checks if we want to log something, and sets up appropriate RAII objects if
 // so.
@@ -245,21 +241,12 @@
    ABORT_AFTER_LOG_EXPR_IF((SEVERITY_LAMBDA(severity)) == ::android::base::FATAL, true) && \
    ::android::base::ErrnoRestorer())
 
-// Logs a message to logcat with the specified log ID on Android otherwise to
-// stderr. If the severity is FATAL it also causes an abort.
-// Use an expression here so we can support the << operator following the macro,
-// like "LOG(DEBUG) << xxx;".
-#define LOG_TO(dest, severity) LOGGING_PREAMBLE(severity) && LOG_STREAM_TO(dest, severity)
-
 // A variant of LOG that also logs the current errno value. To be used when
 // library calls fail.
-#define PLOG(severity) PLOG_TO(DEFAULT, severity)
-
-// Behaves like PLOG, but logs to the specified log ID.
-#define PLOG_TO(dest, severity)                                                        \
-  LOGGING_PREAMBLE(severity) &&                                                        \
-      ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::dest,           \
-                                  SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, errno) \
+#define PLOG(severity)                                                           \
+  LOGGING_PREAMBLE(severity) &&                                                  \
+      ::android::base::LogMessage(__FILE__, __LINE__, SEVERITY_LAMBDA(severity), \
+                                  _LOG_TAG_INTERNAL, errno)                      \
           .stream()
 
 // Marker that code is yet to be implemented.
@@ -272,24 +259,23 @@
 //
 //     CHECK(false == true) results in a log message of
 //       "Check failed: false == true".
-#define CHECK(x)                                                                 \
-  LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) ||                            \
-      ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT,  \
-                                  ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
-              .stream()                                                          \
+#define CHECK(x)                                                                                 \
+  LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) ||                                            \
+      ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, \
+                                  -1)                                                            \
+              .stream()                                                                          \
           << "Check failed: " #x << " "
 
 // clang-format off
 // Helper for CHECK_xx(x,y) macros.
-#define CHECK_OP(LHS, RHS, OP)                                                                 \
-  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);                           \
-       UNLIKELY(!(_values.lhs OP _values.rhs));                                                \
-       /* empty */)                                                                            \
-  ABORT_AFTER_LOG_FATAL                                                                        \
-  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT,                    \
-                              ::android::base::FATAL, _LOG_TAG_INTERNAL, -1)                   \
-          .stream()                                                                            \
-      << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" << _values.lhs \
+#define CHECK_OP(LHS, RHS, OP)                                                                   \
+  for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS);                             \
+       UNLIKELY(!(_values.lhs OP _values.rhs));                                                  \
+       /* empty */)                                                                              \
+  ABORT_AFTER_LOG_FATAL                                                                          \
+  ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
+          .stream()                                                                              \
+      << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" << _values.lhs   \
       << ", " #RHS "=" << _values.rhs << ") "
 // clang-format on
 
@@ -311,8 +297,8 @@
 #define CHECK_STROP(s1, s2, sense)                                             \
   while (UNLIKELY((strcmp(s1, s2) == 0) != (sense)))                           \
     ABORT_AFTER_LOG_FATAL                                                      \
-    ::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT,  \
-                                ::android::base::FATAL, _LOG_TAG_INTERNAL, -1) \
+    ::android::base::LogMessage(__FILE__, __LINE__,  ::android::base::FATAL,   \
+                                 _LOG_TAG_INTERNAL, -1)                        \
         .stream()                                                              \
         << "Check failed: " << "\"" << (s1) << "\""                            \
         << ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
@@ -431,8 +417,10 @@
 // of a CHECK. The destructor will abort if the severity is FATAL.
 class LogMessage {
  public:
-  LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity, const char* tag,
+  // LogId has been deprecated, but this constructor must exist for prebuilts.
+  LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag,
              int error);
+  LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error);
 
   ~LogMessage();
 
@@ -441,8 +429,8 @@
   std::ostream& stream();
 
   // The routine that performs the actual logging.
-  static void LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
-                      const char* tag, const char* msg);
+  static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                      const char* msg);
 
  private:
   const std::unique_ptr<LogMessageData> data_;
diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h
index 6a19f1b..8c37f43 100644
--- a/base/include/android-base/mapped_file.h
+++ b/base/include/android-base/mapped_file.h
@@ -53,7 +53,8 @@
   /**
    * Same thing, but using the raw OS file handle instead of a CRT wrapper.
    */
-  static MappedFile FromOsHandle(os_handle h, off64_t offset, size_t length, int prot);
+  static std::unique_ptr<MappedFile> FromOsHandle(os_handle h, off64_t offset, size_t length,
+                                                  int prot);
 
   /**
    * Removes the mapping.
@@ -69,10 +70,6 @@
   char* data() const { return base_ + offset_; }
   size_t size() const { return size_; }
 
-  bool isValid() const { return base_ != nullptr; }
-
-  explicit operator bool() const { return isValid(); }
-
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);
 
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 1605daf..c4a0aad 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -116,6 +116,8 @@
   bool operator<(int rhs) const { return get() < rhs; }
   bool operator==(int rhs) const { return get() == rhs; }
   bool operator!=(int rhs) const { return get() != rhs; }
+  bool operator==(const unique_fd_impl& rhs) const { return get() == rhs.get(); }
+  bool operator!=(const unique_fd_impl& rhs) const { return get() != rhs.get(); }
 
   // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
   bool operator!() const = delete;
diff --git a/base/logging.cpp b/base/logging.cpp
index f89168c..598a522 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -350,11 +350,10 @@
 // checks/logging in a function.
 class LogMessageData {
  public:
-  LogMessageData(const char* file, unsigned int line, LogId id, LogSeverity severity,
-                 const char* tag, int error)
+  LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                 int error)
       : file_(GetFileBasename(file)),
         line_number_(line),
-        id_(id),
         severity_(severity),
         tag_(tag),
         error_(error) {}
@@ -373,10 +372,6 @@
 
   const char* GetTag() const { return tag_; }
 
-  LogId GetId() const {
-    return id_;
-  }
-
   int GetError() const {
     return error_;
   }
@@ -393,7 +388,6 @@
   std::ostringstream buffer_;
   const char* const file_;
   const unsigned int line_number_;
-  const LogId id_;
   const LogSeverity severity_;
   const char* const tag_;
   const int error_;
@@ -401,9 +395,13 @@
   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
 };
 
-LogMessage::LogMessage(const char* file, unsigned int line, LogId id, LogSeverity severity,
+LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity,
                        const char* tag, int error)
-    : data_(new LogMessageData(file, line, id, severity, tag, error)) {}
+    : LogMessage(file, line, severity, tag, error) {}
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                       int error)
+    : data_(new LogMessageData(file, line, severity, tag, error)) {}
 
 LogMessage::~LogMessage() {
   // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
@@ -429,16 +427,16 @@
     // Do the actual logging with the lock held.
     std::lock_guard<std::mutex> lock(LoggingLock());
     if (msg.find('\n') == std::string::npos) {
-      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), data_->GetSeverity(),
-              data_->GetTag(), msg.c_str());
+      LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(),
+              msg.c_str());
     } else {
       msg += '\n';
       size_t i = 0;
       while (i < msg.size()) {
         size_t nl = msg.find('\n', i);
         msg[nl] = '\0';
-        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(), data_->GetSeverity(),
-                data_->GetTag(), &msg[i]);
+        LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(),
+                &msg[i]);
         // Undo the zero-termination so we can give the complete message to the aborter.
         msg[nl] = '\n';
         i = nl + 1;
@@ -456,16 +454,16 @@
   return data_->GetBuffer();
 }
 
-void LogMessage::LogLine(const char* file, unsigned int line, LogId id, LogSeverity severity,
-                         const char* tag, const char* message) {
+void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                         const char* message) {
   if (tag == nullptr) {
     std::lock_guard<std::recursive_mutex> lock(TagLock());
     if (gDefaultTag == nullptr) {
       gDefaultTag = new std::string(getprogname());
     }
-    Logger()(id, severity, gDefaultTag->c_str(), file, line, message);
+    Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
   } else {
-    Logger()(id, severity, tag, file, line, message);
+    Logger()(DEFAULT, severity, tag, file, line, message);
   }
 }
 
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index 862b73b..fff3453 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -38,15 +38,14 @@
 std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
                                                int prot) {
 #if defined(_WIN32)
-  auto file =
-      FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
+  return FromOsHandle(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), offset, length, prot);
 #else
-  auto file = FromOsHandle(fd.get(), offset, length, prot);
+  return FromOsHandle(fd.get(), offset, length, prot);
 #endif
-  return file ? std::make_unique<MappedFile>(std::move(file)) : std::unique_ptr<MappedFile>{};
 }
 
-MappedFile MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length, int prot) {
+std::unique_ptr<MappedFile> MappedFile::FromOsHandle(os_handle h, off64_t offset, size_t length,
+                                                     int prot) {
   static const off64_t page_size = InitPageSize();
   size_t slop = offset % page_size;
   off64_t file_offset = offset - slop;
@@ -59,28 +58,30 @@
     // http://b/119818070 "app crashes when reading asset of zero length".
     // Return a MappedFile that's only valid for reading the size.
     if (length == 0 && ::GetLastError() == ERROR_FILE_INVALID) {
-      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0, nullptr};
+      return std::unique_ptr<MappedFile>(
+          new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0, nullptr));
     }
-    return MappedFile(nullptr, 0, 0, nullptr);
+    return nullptr;
   }
   void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
                              file_offset, file_length);
   if (base == nullptr) {
     CloseHandle(handle);
-    return MappedFile(nullptr, 0, 0, nullptr);
+    return nullptr;
   }
-  return MappedFile{static_cast<char*>(base), length, slop, handle};
+  return std::unique_ptr<MappedFile>(
+      new MappedFile(static_cast<char*>(base), length, slop, handle));
 #else
   void* base = mmap(nullptr, file_length, prot, MAP_SHARED, h, file_offset);
   if (base == MAP_FAILED) {
     // http://b/119818070 "app crashes when reading asset of zero length".
     // mmap fails with EINVAL for a zero length region.
     if (errno == EINVAL && length == 0) {
-      return MappedFile{const_cast<char*>(kEmptyBuffer), 0, 0};
+      return std::unique_ptr<MappedFile>(new MappedFile(const_cast<char*>(kEmptyBuffer), 0, 0));
     }
-    return MappedFile(nullptr, 0, 0);
+    return nullptr;
   }
-  return MappedFile{static_cast<char*>(base), length, slop};
+  return std::unique_ptr<MappedFile>(new MappedFile(static_cast<char*>(base), length, slop));
 #endif
 }
 
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
index 3629108..d21703c 100644
--- a/base/mapped_file_test.cpp
+++ b/base/mapped_file_test.cpp
@@ -44,8 +44,6 @@
   ASSERT_TRUE(tf.fd != -1);
 
   auto m = android::base::MappedFile::FromFd(tf.fd, 4096, 0, PROT_READ);
-  ASSERT_NE(nullptr, m);
-  EXPECT_TRUE((bool)*m);
   EXPECT_EQ(0u, m->size());
   EXPECT_NE(nullptr, m->data());
 }
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 0602e0a..780e48d 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -74,6 +74,7 @@
     header_libs: [
         "libbase_headers",
         "libdebuggerd_common_headers",
+        "bionic_libc_platform_headers",
     ],
 
     whole_static_libs: [
@@ -92,6 +93,9 @@
     defaults: ["debuggerd_defaults"],
     srcs: ["handler/debuggerd_fallback_nop.cpp"],
 
+    header_libs: ["bionic_libc_platform_headers"],
+    export_header_lib_headers: ["bionic_libc_platform_headers"],
+
     whole_static_libs: [
         "libdebuggerd_handler_core",
     ],
@@ -119,6 +123,10 @@
         "liblzma",
         "libcutils",
     ],
+
+    header_libs: ["bionic_libc_platform_headers"],
+    export_header_lib_headers: ["bionic_libc_platform_headers"],
+
     target: {
         recovery: {
             exclude_static_libs: [
@@ -138,15 +146,21 @@
         "util.cpp",
     ],
 
-    header_libs: ["libdebuggerd_common_headers"],
-
     shared_libs: [
         "libbase",
         "libcutils",
         "libprocinfo",
     ],
 
-    export_header_lib_headers: ["libdebuggerd_common_headers"],
+    header_libs: [
+        "libdebuggerd_common_headers",
+        "bionic_libc_platform_headers",
+    ],
+    export_header_lib_headers: [
+        "libdebuggerd_common_headers",
+        "bionic_libc_platform_headers",
+    ],
+
     export_include_dirs: ["include"],
 }
 
@@ -167,6 +181,7 @@
 
     // Needed for private/bionic_fdsan.h
     include_dirs: ["bionic/libc"],
+    header_libs: ["bionic_libc_platform_headers"],
 
     static_libs: [
         "libdexfile_support_static",  // libunwindstack dependency
@@ -176,6 +191,7 @@
         "libcutils",
         "liblog",
     ],
+
     target: {
         recovery: {
             exclude_static_libs: [
@@ -232,6 +248,10 @@
         "libdebuggerd",
     ],
 
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
+
     local_include_dirs: [
         "libdebuggerd",
     ],
@@ -277,6 +297,10 @@
         },
     },
 
+    header_libs: [
+        "bionic_libc_platform_headers",
+    ],
+
     static_libs: [
         "libtombstoned_client_static",
         "libdebuggerd",
@@ -317,7 +341,10 @@
     ],
     defaults: ["debuggerd_defaults"],
 
-    header_libs: ["libdebuggerd_common_headers"],
+    header_libs: [
+        "bionic_libc_platform_headers",
+        "libdebuggerd_common_headers"
+    ],
 
     static_libs: [
         "libbase",
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
index 7e35a2f..5c02738 100644
--- a/debuggerd/client/debuggerd_client.cpp
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -35,6 +35,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/reserved_signals.h>
 #include <cutils/sockets.h>
 #include <procinfo/process.h>
 
@@ -50,7 +51,7 @@
 using android::base::WriteStringToFd;
 
 static bool send_signal(pid_t pid, const DebuggerdDumpType dump_type) {
-  const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : DEBUGGER_SIGNAL;
+  const int signal = (dump_type == kDebuggerdJavaBacktrace) ? SIGQUIT : BIONIC_SIGNAL_DEBUGGER;
   sigval val;
   val.sival_int = (dump_type == kDebuggerdNativeBacktrace) ? 1 : 0;
 
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index cb55745..e8f366f 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -40,6 +40,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/reserved_signals.h>
 #include <cutils/sockets.h>
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
@@ -511,13 +512,13 @@
 
   // Defer the message until later, for readability.
   bool wait_for_gdb = android::base::GetBoolProperty("debug.debuggerd.wait_for_gdb", false);
-  if (siginfo.si_signo == DEBUGGER_SIGNAL) {
+  if (siginfo.si_signo == BIONIC_SIGNAL_DEBUGGER) {
     wait_for_gdb = false;
   }
 
   // Detach from all of our attached threads before resuming.
   for (const auto& [tid, thread] : thread_info) {
-    int resume_signal = thread.signo == DEBUGGER_SIGNAL ? 0 : thread.signo;
+    int resume_signal = thread.signo == BIONIC_SIGNAL_DEBUGGER ? 0 : thread.signo;
     if (wait_for_gdb) {
       resume_signal = 0;
       if (tgkill(target_process, tid, SIGSTOP) != 0) {
@@ -555,10 +556,10 @@
             << " (target tid = " << g_target_thread << ")";
 
   int signo = siginfo.si_signo;
-  bool fatal_signal = signo != DEBUGGER_SIGNAL;
+  bool fatal_signal = signo != BIONIC_SIGNAL_DEBUGGER;
   bool backtrace = false;
 
-  // si_value is special when used with DEBUGGER_SIGNAL.
+  // si_value is special when used with BIONIC_SIGNAL_DEBUGGER.
   //   0: dump tombstone
   //   1: dump backtrace
   if (!fatal_signal) {
diff --git a/debuggerd/crasher/Android.bp b/debuggerd/crasher/Android.bp
index 7bec470..e86f499 100644
--- a/debuggerd/crasher/Android.bp
+++ b/debuggerd/crasher/Android.bp
@@ -44,6 +44,7 @@
     name: "crasher",
 
     defaults: ["crasher-defaults"],
+    header_libs: ["bionic_libc_platform_headers"],
     shared_libs: [
         "libbase",
         "liblog",
@@ -65,6 +66,7 @@
     defaults: ["crasher-defaults"],
     cppflags: ["-DSTATIC_CRASHER"],
     static_executable: true,
+    header_libs: ["bionic_libc_platform_headers"],
     static_libs: [
         "libdebuggerd_handler",
         "libbase",
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 99729dc..6a8cc56 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -31,6 +31,7 @@
 
 #include <android/fdsan.h>
 #include <android/set_abort_message.h>
+#include <bionic/reserved_signals.h>
 
 #include <android-base/cmsg.h>
 #include <android-base/file.h>
@@ -398,7 +399,7 @@
   unique_fd output_fd;
   StartProcess([]() {
     android_set_abort_message("not actually aborting");
-    raise(DEBUGGER_SIGNAL);
+    raise(BIONIC_SIGNAL_DEBUGGER);
     exit(0);
   });
   StartIntercept(&output_fd);
@@ -466,7 +467,7 @@
 
   sigval val;
   val.sival_int = 1;
-  ASSERT_EQ(0, sigqueue(crasher_pid, DEBUGGER_SIGNAL, val)) << strerror(errno);
+  ASSERT_EQ(0, sigqueue(crasher_pid, BIONIC_SIGNAL_DEBUGGER, val)) << strerror(errno);
   FinishIntercept(&intercept_result);
   ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
   ConsumeFd(std::move(output_fd), &result);
@@ -734,7 +735,7 @@
 
   siginfo.si_value.sival_int = dump_type == kDebuggerdNativeBacktrace;
 
-  if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), DEBUGGER_SIGNAL, &siginfo) != 0) {
+  if (syscall(__NR_rt_tgsigqueueinfo, getpid(), gettid(), BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
     PLOG(ERROR) << "libdebuggerd_client: failed to send signal to self";
     return false;
   }
@@ -887,7 +888,7 @@
       errx(2, "first waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
     }
 
-    raise(DEBUGGER_SIGNAL);
+    raise(BIONIC_SIGNAL_DEBUGGER);
 
     errno = 0;
     rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index bbec612..9bcbdb3 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,6 +42,7 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
 #include <unwindstack/DexFiles.h>
 #include <unwindstack/JitDebug.h>
 #include <unwindstack/Maps.h>
@@ -272,7 +273,7 @@
         siginfo.si_pid = getpid();
         siginfo.si_uid = getuid();
 
-        if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, DEBUGGER_SIGNAL, &siginfo) != 0) {
+        if (syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, BIONIC_SIGNAL_DEBUGGER, &siginfo) != 0) {
           async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to send trace signal to %d: %s",
                                 tid, strerror(errno));
           return false;
@@ -340,7 +341,7 @@
 
 extern "C" void debuggerd_fallback_handler(siginfo_t* info, ucontext_t* ucontext,
                                            void* abort_message) {
-  if (info->si_signo == DEBUGGER_SIGNAL && info->si_value.sival_ptr != nullptr) {
+  if (info->si_signo == BIONIC_SIGNAL_DEBUGGER && info->si_value.sival_ptr != nullptr) {
     return trace_handler(info, ucontext);
   } else {
     return crash_handler(info, ucontext, abort_message);
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index b90ca80..6e01289 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -51,6 +51,7 @@
 
 #include <android-base/unique_fd.h>
 #include <async_safe/log.h>
+#include <bionic/reserved_signals.h>
 #include <cutils/properties.h>
 
 #include <libdebuggerd/utility.h>
@@ -175,7 +176,7 @@
     thread_name[MAX_TASK_NAME_LEN] = 0;
   }
 
-  if (info->si_signo == DEBUGGER_SIGNAL) {
+  if (info->si_signo == BIONIC_SIGNAL_DEBUGGER) {
     async_safe_format_log(ANDROID_LOG_INFO, "libc", "Requested dump for tid %d (%s)", __gettid(),
                           thread_name);
     return;
@@ -307,7 +308,7 @@
 static void* pseudothread_stack;
 
 static DebuggerdDumpType get_dump_type(const debugger_thread_info* thread_info) {
-  if (thread_info->siginfo->si_signo == DEBUGGER_SIGNAL &&
+  if (thread_info->siginfo->si_signo == BIONIC_SIGNAL_DEBUGGER &&
       thread_info->siginfo->si_value.sival_int) {
     return kDebuggerdNativeBacktrace;
   }
@@ -429,7 +430,7 @@
     async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped");
   }
 
-  if (thread_info->siginfo->si_signo != DEBUGGER_SIGNAL) {
+  if (thread_info->siginfo->si_signo != BIONIC_SIGNAL_DEBUGGER) {
     // For crashes, we don't need to minimize pause latency.
     // Wait for the dump to complete before having the process exit, to avoid being murdered by
     // ActivityManager or init.
@@ -446,7 +447,7 @@
   // exited with the correct exit status (e.g. so that sh will report
   // "Segmentation fault" instead of "Killed"). For this to work, we need
   // to deregister our signal handler for that signal before continuing.
-  if (info->si_signo != DEBUGGER_SIGNAL) {
+  if (info->si_signo != BIONIC_SIGNAL_DEBUGGER) {
     signal(info->si_signo, SIG_DFL);
     int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info);
     if (rc != 0) {
@@ -485,7 +486,7 @@
 
   void* abort_message = nullptr;
   uintptr_t si_val = reinterpret_cast<uintptr_t>(info->si_ptr);
-  if (signal_number == DEBUGGER_SIGNAL) {
+  if (signal_number == BIONIC_SIGNAL_DEBUGGER) {
     if (info->si_code == SI_QUEUE && info->si_pid == __getpid()) {
       // Allow for the abort message to be explicitly specified via the sigqueue value.
       // Keep the bottom bit intact for representing whether we want a backtrace or a tombstone.
@@ -576,7 +577,7 @@
     fatal_errno("failed to restore traceable");
   }
 
-  if (info->si_signo == DEBUGGER_SIGNAL) {
+  if (info->si_signo == BIONIC_SIGNAL_DEBUGGER) {
     // If the signal is fatal, don't unlock the mutex to prevent other crashing threads from
     // starting to dump right before our death.
     pthread_mutex_unlock(&crash_mutex);
diff --git a/debuggerd/include/debuggerd/handler.h b/debuggerd/include/debuggerd/handler.h
index 7196e0a..cd6fc05 100644
--- a/debuggerd/include/debuggerd/handler.h
+++ b/debuggerd/include/debuggerd/handler.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <bionic/reserved_signals.h>
 #include <signal.h>
 #include <stdint.h>
 #include <sys/cdefs.h>
@@ -33,11 +34,11 @@
 void debuggerd_init(debuggerd_callbacks_t* callbacks);
 
 // DEBUGGER_ACTION_DUMP_TOMBSTONE and DEBUGGER_ACTION_DUMP_BACKTRACE are both
-// triggered via DEBUGGER_SIGNAL. The debugger_action_t is sent via si_value
+// triggered via BIONIC_SIGNAL_DEBUGGER. The debugger_action_t is sent via si_value
 // using sigqueue(2) or equivalent. If no si_value is specified (e.g. if the
 // signal is sent by kill(2)), the default behavior is to print the backtrace
 // to the log.
-#define DEBUGGER_SIGNAL (__SIGRTMIN + 3)
+#define DEBUGGER_SIGNAL BIONIC_SIGNAL_DEBUGGER
 
 static void __attribute__((__unused__)) debuggerd_register_handlers(struct sigaction* action) {
   sigaction(SIGABRT, action, nullptr);
@@ -50,7 +51,7 @@
 #endif
   sigaction(SIGSYS, action, nullptr);
   sigaction(SIGTRAP, action, nullptr);
-  sigaction(DEBUGGER_SIGNAL, action, nullptr);
+  sigaction(BIONIC_SIGNAL_DEBUGGER, action, nullptr);
 }
 
 __END_DECLS
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 236fcf7..b64e260 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -52,9 +52,6 @@
 #include <unwindstack/Regs.h>
 #include <unwindstack/Unwinder.h>
 
-// Needed to get DEBUGGER_SIGNAL.
-#include "debuggerd/handler.h"
-
 #include "libdebuggerd/backtrace.h"
 #include "libdebuggerd/open_files_list.h"
 #include "libdebuggerd/utility.h"
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index 5ce26fc..0a1d2a4 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,6 +35,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic/reserved_signals.h>
 #include <debuggerd/handler.h>
 #include <log/log.h>
 #include <unwindstack/Memory.h>
@@ -296,7 +297,8 @@
     case SIGSTOP: return "SIGSTOP";
     case SIGSYS: return "SIGSYS";
     case SIGTRAP: return "SIGTRAP";
-    case DEBUGGER_SIGNAL: return "<debuggerd signal>";
+    case BIONIC_SIGNAL_DEBUGGER:
+      return "<debuggerd signal>";
     default: return "?";
   }
 }
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index 277cc3a..d48cfa9 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -31,6 +31,8 @@
     "libext4_utils",
   ],
 
+  stl: "libc++_static",
+
   // Static libs (libfastboot2) shared library dependencies are not transitively included
   // This is needed to avoid link time errors when building for mac
   target: {
@@ -40,5 +42,13 @@
           "-framework IOKit",
       ],
     },
-  }
+  },
+
+  // Disable auto-generation of test config as this binary itself is not a test in the test suites,
+  // rather it is used by other tests.
+  auto_gen_config: false,
+  test_suites: [
+    "general-tests",
+    "vts-core",
+  ],
 }
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index eb737bb..34c64d2 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -26,14 +26,14 @@
     ],
 }
 
-cc_library {
-    // Do not ever allow this library to be vendor_available as a shared library.
-    // It does not have a stable interface.
-    name: "libfs_mgr",
+cc_defaults {
+    name: "libfs_mgr_defaults",
     defaults: ["fs_mgr_defaults"],
-    recovery_available: true,
     export_include_dirs: ["include"],
     include_dirs: ["system/vold"],
+    cflags: [
+        "-D_FILE_OFFSET_BITS=64",
+    ],
     srcs: [
         "file_wait.cpp",
         "fs_mgr.cpp",
@@ -43,6 +43,7 @@
         "fs_mgr_overlayfs.cpp",
         "fs_mgr_roots.cpp",
         "fs_mgr_vendor_overlay.cpp",
+        ":libfiemap_srcs",
     ],
     shared_libs: [
         "libbase",
@@ -88,6 +89,42 @@
             ],
         },
     },
+    header_libs: [
+        "libfiemap_headers",
+    ],
+    export_header_lib_headers: [
+        "libfiemap_headers",
+    ],
+}
+
+// Two variants of libfs_mgr are provided: libfs_mgr and libfs_mgr_binder.
+// Use libfs_mgr in recovery, first-stage-init, or when libfiemap or overlayfs
+// is not used.
+//
+// Use libfs_mgr_binder when not in recovery/first-stage init, or when overlayfs
+// or libfiemap is needed. In this case, libfiemap will proxy over binder to
+// gsid.
+cc_library {
+    // Do not ever allow this library to be vendor_available as a shared library.
+    // It does not have a stable interface.
+    name: "libfs_mgr",
+    recovery_available: true,
+    defaults: [
+        "libfs_mgr_defaults",
+    ],
+    srcs: [
+        ":libfiemap_passthrough_srcs",
+    ],
+}
+
+cc_library {
+    // Do not ever allow this library to be vendor_available as a shared library.
+    // It does not have a stable interface.
+    name: "libfs_mgr_binder",
+    defaults: [
+        "libfs_mgr_defaults",
+        "libfiemap_binder_defaults",
+    ],
 }
 
 cc_library_static {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 5c0401e..03c7943 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -34,6 +34,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include <chrono>
 #include <functional>
 #include <map>
 #include <memory>
@@ -42,6 +43,7 @@
 #include <utility>
 #include <vector>
 
+#include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
@@ -94,6 +96,7 @@
 using android::base::GetBoolProperty;
 using android::base::Realpath;
 using android::base::StartsWith;
+using android::base::Timer;
 using android::base::unique_fd;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
@@ -907,6 +910,10 @@
     return true;
 }
 
+static bool SupportsCheckpoint(FstabEntry* entry) {
+    return entry->fs_mgr_flags.checkpoint_blk || entry->fs_mgr_flags.checkpoint_fs;
+}
+
 class CheckpointManager {
   public:
     CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
@@ -923,7 +930,7 @@
     }
 
     bool Update(FstabEntry* entry, const std::string& block_device = std::string()) {
-        if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
+        if (!SupportsCheckpoint(entry)) {
             return true;
         }
 
@@ -944,7 +951,7 @@
     }
 
     bool Revert(FstabEntry* entry) {
-        if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
+        if (!SupportsCheckpoint(entry)) {
             return true;
         }
 
@@ -1358,6 +1365,49 @@
     return ret;
 }
 
+static bool fs_mgr_unmount_all_data_mounts(const std::string& block_device) {
+    LINFO << __FUNCTION__ << "(): about to umount everything on top of " << block_device;
+    Timer t;
+    // TODO(b/135984674): should be configured via a read-only property.
+    std::chrono::milliseconds timeout = 5s;
+    while (true) {
+        bool umount_done = true;
+        Fstab proc_mounts;
+        if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
+            LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
+            return false;
+        }
+        // Now proceed with other bind mounts on top of /data.
+        for (const auto& entry : proc_mounts) {
+            if (entry.blk_device == block_device) {
+                if (umount2(entry.mount_point.c_str(), 0) != 0) {
+                    PERROR << __FUNCTION__ << "(): Failed to umount " << entry.mount_point;
+                    umount_done = false;
+                }
+            }
+        }
+        if (umount_done) {
+            LINFO << __FUNCTION__ << "(): Unmounting /data took " << t;
+            return true;
+        }
+        if (t.duration() > timeout) {
+            LERROR << __FUNCTION__ << "(): Timed out unmounting all mounts on " << block_device;
+            Fstab remaining_mounts;
+            if (!ReadFstabFromFile("/proc/mounts", &remaining_mounts)) {
+                LERROR << __FUNCTION__ << "(): Can't read /proc/mounts";
+            } else {
+                LERROR << __FUNCTION__ << "(): Following mounts remaining";
+                for (const auto& e : remaining_mounts) {
+                    LERROR << __FUNCTION__ << "(): mount point: " << e.mount_point
+                           << " block device: " << e.blk_device;
+                }
+            }
+            return false;
+        }
+        std::this_thread::sleep_for(50ms);
+    }
+}
+
 // TODO(b/143970043): return different error codes based on which step failed.
 int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
     Fstab proc_mounts;
@@ -1377,18 +1427,20 @@
         LERROR << "Can't find /data in fstab";
         return -1;
     }
-    if (!fstab_entry->fs_mgr_flags.checkpoint_blk && !fstab_entry->fs_mgr_flags.checkpoint_fs) {
+    bool force_umount = GetBoolProperty("sys.init.userdata_remount.force_umount", false);
+    if (force_umount) {
+        LINFO << "Will force an umount of userdata even if it's not required";
+    }
+    if (!force_umount && !SupportsCheckpoint(fstab_entry)) {
         LINFO << "Userdata doesn't support checkpointing. Nothing to do";
         return 0;
     }
     CheckpointManager checkpoint_manager;
-    if (!checkpoint_manager.NeedsCheckpoint()) {
+    if (!force_umount && !checkpoint_manager.NeedsCheckpoint()) {
         LINFO << "Checkpointing not needed. Don't remount";
         return 0;
     }
-    bool force_umount_for_f2fs =
-            GetBoolProperty("sys.init.userdata_remount.force_umount_f2fs", false);
-    if (fstab_entry->fs_mgr_flags.checkpoint_fs && !force_umount_for_f2fs) {
+    if (!force_umount && fstab_entry->fs_mgr_flags.checkpoint_fs) {
         // Userdata is f2fs, simply remount it.
         if (!checkpoint_manager.Update(fstab_entry)) {
             LERROR << "Failed to remount userdata in checkpointing mode";
@@ -1401,17 +1453,8 @@
         }
     } else {
         LINFO << "Unmounting /data before remounting into checkpointing mode";
-        // First make sure that all the bind-mounts on top of /data are unmounted.
-        for (const auto& entry : proc_mounts) {
-            if (entry.blk_device == block_device && entry.mount_point != "/data") {
-                LINFO << "Unmounting bind-mount " << entry.mount_point;
-                if (umount2(entry.mount_point.c_str(), UMOUNT_NOFOLLOW) != 0) {
-                    PWARNING << "Failed to unmount " << entry.mount_point;
-                }
-            }
-        }
-        if (umount2("/data", UMOUNT_NOFOLLOW) != 0) {
-            PERROR << "Failed to umount /data";
+        if (!fs_mgr_unmount_all_data_mounts(block_device)) {
+            LERROR << "Failed to umount /data";
             return -1;
         }
         DeviceMapper& dm = DeviceMapper::Instance();
diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp
index 0dcb9fe..ea9c957 100644
--- a/fs_mgr/fs_mgr_dm_linear.cpp
+++ b/fs_mgr/fs_mgr_dm_linear.cpp
@@ -151,6 +151,10 @@
             LINFO << "Skipping zero-length logical partition: " << GetPartitionName(partition);
             continue;
         }
+        if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
+            LINFO << "Skipping disabled partition: " << GetPartitionName(partition);
+            continue;
+        }
 
         params.partition = &partition;
 
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 27971da..c043754 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -811,66 +811,48 @@
     return "auto";
 }
 
-enum class ScratchStrategy {
-    kNone,
-    // DAP device, use logical partitions.
-    kDynamicPartition,
-    // Retrofit DAP device, use super_<other>.
-    kSuperOther,
-    // Pre-DAP device, uses the other slot.
-    kSystemOther
-};
-
-// Return the strategy this device must use for creating a scratch partition.
-static ScratchStrategy GetScratchStrategy(std::string* backing_device = nullptr) {
+// Note: we do not check access() here except for the super partition, since
+// in first-stage init we wouldn't have registed by-name symlinks for "other"
+// partitions that won't be mounted.
+static std::string GetPhysicalScratchDevice() {
     auto slot_number = fs_mgr_overlayfs_slot_number();
     auto super_device = fs_mgr_overlayfs_super_device(slot_number);
     auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
     if (super_device != path) {
-        // Note: we do not check access() here, since in first-stage init we
-        // wouldn't have registed by-name symlinks for the device as it's
-        // normally not needed. The access checks elsewhere in this function
-        // are safe because system/super are always required.
-        if (backing_device) *backing_device = path;
-        return ScratchStrategy::kSuperOther;
+        return path;
     }
     if (fs_mgr_access(super_device)) {
-        if (backing_device) *backing_device = super_device;
-        return ScratchStrategy::kDynamicPartition;
+        // Do not try to use system_other on a DAP device.
+        return "";
     }
 
     auto other_slot = fs_mgr_get_other_slot_suffix();
     if (!other_slot.empty()) {
-        path = kPhysicalDevice + "system" + other_slot;
-        if (fs_mgr_access(path)) {
-            if (backing_device) *backing_device = path;
-            return ScratchStrategy::kSystemOther;
-        }
+        return kPhysicalDevice + "system" + other_slot;
     }
-    return ScratchStrategy::kNone;
+    return "";
 }
 
-// Return the scratch device if it exists.
-static std::string GetScratchDevice() {
-    std::string device;
-    ScratchStrategy strategy = GetScratchStrategy(&device);
+// This returns the scratch device that was detected during early boot (first-
+// stage init). If the device was created later, for example during setup for
+// the adb remount command, it can return an empty string since it does not
+// query ImageManager.
+static std::string GetBootScratchDevice() {
+    auto& dm = DeviceMapper::Instance();
 
-    switch (strategy) {
-        case ScratchStrategy::kSuperOther:
-        case ScratchStrategy::kSystemOther:
-            return device;
-        case ScratchStrategy::kDynamicPartition: {
-            auto& dm = DeviceMapper::Instance();
-            auto partition_name = android::base::Basename(kScratchMountPoint);
-            if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
-                dm.GetDmDevicePathByName(partition_name, &device)) {
-                return device;
-            }
-            return "";
-        }
-        default:
-            return "";
+    // If there is a scratch partition allocated in /data or on super, we
+    // automatically prioritize that over super_other or system_other.
+    // Some devices, for example, have a write-protected eMMC and the
+    // super partition cannot be used even if it exists.
+    std::string device;
+    auto partition_name = android::base::Basename(kScratchMountPoint);
+    if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
+        dm.GetDmDevicePathByName(partition_name, &device)) {
+        return device;
     }
+
+    // There is no dynamic scratch, so try and find a physical one.
+    return GetPhysicalScratchDevice();
 }
 
 bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {
@@ -915,8 +897,8 @@
 }
 
 // Create or update a scratch partition within super.
-static bool CreateDynamicScratch(const Fstab& fstab, std::string* scratch_device,
-                                 bool* partition_exists, bool* change) {
+static bool CreateDynamicScratch(std::string* scratch_device, bool* partition_exists,
+                                 bool* change) {
     const auto partition_name = android::base::Basename(kScratchMountPoint);
 
     auto& dm = DeviceMapper::Instance();
@@ -925,8 +907,6 @@
     auto partition_create = !*partition_exists;
     auto slot_number = fs_mgr_overlayfs_slot_number();
     auto super_device = fs_mgr_overlayfs_super_device(slot_number);
-    if (!fs_mgr_rw_access(super_device)) return false;
-    if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
     auto builder = MetadataBuilder::New(super_device, slot_number);
     if (!builder) {
         LERROR << "open " << super_device << " metadata";
@@ -1012,25 +992,33 @@
     return true;
 }
 
-bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
-                                     bool* partition_exists, bool* change) {
-    auto strategy = GetScratchStrategy();
-    if (strategy == ScratchStrategy::kDynamicPartition) {
-        return CreateDynamicScratch(fstab, scratch_device, partition_exists, change);
-    }
-
-    // The scratch partition can only be landed on a physical partition if we
-    // get here. If there are no viable candidates that are R/W, just return
-    // that there is no device.
-    *scratch_device = GetScratchDevice();
-    if (scratch_device->empty()) {
-        errno = ENXIO;
+static bool CanUseSuperPartition(const Fstab& fstab) {
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device) || !fs_mgr_overlayfs_has_logical(fstab)) {
         return false;
     }
-    *partition_exists = true;
     return true;
 }
 
+bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
+                                     bool* partition_exists, bool* change) {
+    // Try a physical partition first.
+    *scratch_device = GetPhysicalScratchDevice();
+    if (!scratch_device->empty() && fs_mgr_rw_access(*scratch_device)) {
+        *partition_exists = true;
+        return true;
+    }
+
+    // If that fails, see if we can land on super.
+    if (CanUseSuperPartition(fstab)) {
+        return CreateDynamicScratch(scratch_device, partition_exists, change);
+    }
+
+    errno = ENXIO;
+    return false;
+}
+
 // Create and mount kScratchMountPoint storage if we have logical partitions
 bool fs_mgr_overlayfs_setup_scratch(const Fstab& fstab, bool* change) {
     if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
@@ -1120,7 +1108,12 @@
 }
 
 static void TryMountScratch() {
-    auto scratch_device = GetScratchDevice();
+    // Note we get the boot scratch device here, which means if scratch was
+    // just created through ImageManager, this could fail. In practice this
+    // should not happen because "remount" detects this scenario (by checking
+    // if verity is still disabled, i.e. no reboot occurred), and skips calling
+    // fs_mgr_overlayfs_mount_all().
+    auto scratch_device = GetBootScratchDevice();
     if (!fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device)) {
         return;
     }
@@ -1166,11 +1159,23 @@
         return {};
     }
 
+    bool want_scratch = false;
     for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
-        if (fs_mgr_is_verity_enabled(entry)) continue;
-        if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) continue;
-        auto device = GetScratchDevice();
-        if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break;
+        if (fs_mgr_is_verity_enabled(entry)) {
+            continue;
+        }
+        if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) {
+            continue;
+        }
+        want_scratch = true;
+        break;
+    }
+    if (!want_scratch) {
+        return {};
+    }
+
+    auto device = GetBootScratchDevice();
+    if (!device.empty()) {
         return {device};
     }
     return {};
@@ -1241,25 +1246,39 @@
     return ret;
 }
 
-static bool GetAndMapScratchDeviceIfNeeded(std::string* device) {
-    *device = GetScratchDevice();
+static bool GetAndMapScratchDeviceIfNeeded(std::string* device, bool* mapped) {
+    *mapped = false;
+    *device = GetBootScratchDevice();
     if (!device->empty()) {
         return true;
     }
 
-    auto strategy = GetScratchStrategy();
-    if (strategy == ScratchStrategy::kDynamicPartition) {
-        auto metadata_slot = fs_mgr_overlayfs_slot_number();
-        CreateLogicalPartitionParams params = {
-                .block_device = fs_mgr_overlayfs_super_device(metadata_slot),
-                .metadata_slot = metadata_slot,
-                .partition_name = android::base::Basename(kScratchMountPoint),
-                .force_writable = true,
-                .timeout_ms = 10s,
-        };
-        return CreateLogicalPartition(params, device);
+    // Avoid uart spam by first checking for a scratch partition.
+    auto metadata_slot = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(metadata_slot);
+    auto metadata = ReadCurrentMetadata(super_device);
+    if (!metadata) {
+        return false;
     }
-    return false;
+
+    auto partition_name = android::base::Basename(kScratchMountPoint);
+    auto partition = FindPartition(*metadata.get(), partition_name);
+    if (!partition) {
+        return false;
+    }
+
+    CreateLogicalPartitionParams params = {
+            .block_device = super_device,
+            .metadata = metadata.get(),
+            .partition = partition,
+            .force_writable = true,
+            .timeout_ms = 10s,
+    };
+    if (!CreateLogicalPartition(params, device)) {
+        return false;
+    }
+    *mapped = true;
+    return true;
 }
 
 // Returns false if teardown not permitted, errno set to last error.
@@ -1267,12 +1286,14 @@
 bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) {
     if (change) *change = false;
     auto ret = true;
+
     // If scratch exists, but is not mounted, lets gain access to clean
     // specific override entries.
     auto mount_scratch = false;
+    bool unmap = false;
     if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
         std::string scratch_device;
-        if (GetAndMapScratchDeviceIfNeeded(&scratch_device)) {
+        if (GetAndMapScratchDeviceIfNeeded(&scratch_device, &unmap)) {
             mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
                                                            fs_mgr_overlayfs_scratch_mount_type());
         }
@@ -1294,8 +1315,12 @@
         PERROR << "teardown";
         ret = false;
     }
-    if (mount_scratch) fs_mgr_overlayfs_umount_scratch();
-
+    if (mount_scratch) {
+        fs_mgr_overlayfs_umount_scratch();
+    }
+    if (unmap) {
+        DestroyLogicalPartition(android::base::Basename(kScratchMountPoint));
+    }
     return ret;
 }
 
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index 8dbbf4c..1bf457f 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -20,71 +20,42 @@
     export_include_dirs: ["include"],
 }
 
-cc_defaults {
-    name: "libfiemap_defaults",
-    defaults: ["fs_mgr_defaults"],
-    cflags: [
-        "-D_FILE_OFFSET_BITS=64",
-        "-Wall",
-        "-Werror",
-    ],
-
+filegroup {
+    name: "libfiemap_srcs",
     srcs: [
         "fiemap_writer.cpp",
+        "fiemap_status.cpp",
         "image_manager.cpp",
         "metadata.cpp",
         "split_fiemap_writer.cpp",
         "utility.cpp",
     ],
-
-    static_libs: [
-        "libdm",
-        "libext2_uuid",
-        "libext4_utils",
-        "liblp",
-        "libfs_mgr",
-    ],
-
-    shared_libs: [
-        "libbase",
-    ],
-
-    header_libs: [
-        "libfiemap_headers",
-        "liblog_headers",
-    ],
-
-    export_shared_lib_headers: [
-        "libbase",
-    ],
-
-    export_header_lib_headers: [
-        "libfiemap_headers",
-    ],
 }
 
-// Open up a binder IImageManager interface.
-cc_library_static {
-    name: "libfiemap_binder",
-    defaults: ["libfiemap_defaults"],
+filegroup {
+    name: "libfiemap_binder_srcs",
     srcs: [
         "binder.cpp",
     ],
+}
+
+cc_defaults {
+    name: "libfiemap_binder_defaults",
+    srcs: [":libfiemap_binder_srcs"],
     whole_static_libs: [
         "gsi_aidl_interface-cpp",
         "libgsi",
     ],
     shared_libs: [
         "libbinder",
+        "libutils",
     ],
 }
 
 // Open up a passthrough IImageManager interface. Use libfiemap_binder whenever
 // possible. This should only be used when binder is not available.
-cc_library_static {
-    name: "libfiemap_passthrough",
-    defaults: ["libfiemap_defaults"],
-    recovery_available: true,
+filegroup {
+    name: "libfiemap_passthrough_srcs",
     srcs: [
         "passthrough.cpp",
     ],
@@ -92,10 +63,10 @@
 
 cc_test {
     name: "fiemap_writer_test",
-    defaults: ["libfiemap_defaults"],
     static_libs: [
         "libbase",
         "libdm",
+        "libfs_mgr",
         "liblog",
     ],
 
@@ -108,11 +79,15 @@
     srcs: [
         "fiemap_writer_test.cpp",
     ],
+
+    test_suites: ["vts-core", "device-tests"],
+    auto_gen_config: true,
+    test_min_api_level: 29,
+    require_root: true,
 }
 
 cc_test {
     name: "fiemap_image_test",
-    defaults: ["libfiemap_defaults"],
     static_libs: [
         "libdm",
         "libext4_utils",
@@ -120,6 +95,7 @@
         "liblp",
     ],
     shared_libs: [
+        "libbase",
         "libcrypto",
         "libcrypto_utils",
         "libcutils",
@@ -129,7 +105,3 @@
         "image_test.cpp",
     ],
 }
-
-vts_config {
-    name: "VtsFiemapWriterTest",
-}
diff --git a/fs_mgr/libfiemap/AndroidTest.xml b/fs_mgr/libfiemap/AndroidTest.xml
deleted file mode 100644
index 44c80fc..0000000
--- a/fs_mgr/libfiemap/AndroidTest.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<configuration description="Config for VTS VtsFiemapWriterTest">
-    <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
-        <option name="abort-on-push-failure" value="false"/>
-        <option name="push-group" value="HostDrivenTest.push"/>
-    </target_preparer>
-    <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
-      <option name="test-module-name" value="VtsFiemapWriterTest"/>
-        <option name="binary-test-source" value="_32bit::DATA/nativetest/fiemap_writer_test/fiemap_writer_test" />
-        <option name="binary-test-source" value="_64bit::DATA/nativetest64/fiemap_writer_test/fiemap_writer_test" />
-        <option name="binary-test-type" value="gtest"/>
-        <option name="precondition-first-api-level" value="29" />
-        <option name="test-timeout" value="1m"/>
-    </test>
-</configuration>
diff --git a/fs_mgr/libfiemap/binder.cpp b/fs_mgr/libfiemap/binder.cpp
index 49779f4..96c36ed 100644
--- a/fs_mgr/libfiemap/binder.cpp
+++ b/fs_mgr/libfiemap/binder.cpp
@@ -17,6 +17,7 @@
 #if !defined(__ANDROID_RECOVERY__)
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <android/gsi/BnProgressCallback.h>
 #include <android/gsi/IGsiService.h>
 #include <android/gsi/IGsid.h>
 #include <binder/IServiceManager.h>
@@ -29,10 +30,29 @@
 using namespace android::gsi;
 using namespace std::chrono_literals;
 
+class ProgressCallback final : public BnProgressCallback {
+  public:
+    ProgressCallback(std::function<bool(uint64_t, uint64_t)>&& callback)
+        : callback_(std::move(callback)) {
+        CHECK(callback_);
+    }
+    android::binder::Status onProgress(int64_t current, int64_t total) {
+        if (callback_(static_cast<uint64_t>(current), static_cast<uint64_t>(total))) {
+            return android::binder::Status::ok();
+        }
+        return android::binder::Status::fromServiceSpecificError(UNKNOWN_ERROR,
+                                                                 "Progress callback failed");
+    }
+
+  private:
+    std::function<bool(uint64_t, uint64_t)> callback_;
+};
+
 class ImageManagerBinder final : public IImageManager {
   public:
     ImageManagerBinder(android::sp<IGsiService>&& service, android::sp<IImageService>&& manager);
-    bool CreateBackingImage(const std::string& name, uint64_t size, int flags) override;
+    FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
+                                    std::function<bool(uint64_t, uint64_t)>&& on_progress) override;
     bool DeleteBackingImage(const std::string& name) override;
     bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
                         std::string* path) override;
@@ -41,8 +61,12 @@
     bool IsImageMapped(const std::string& name) override;
     bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
                                   std::string* dev) override;
-    bool ZeroFillNewImage(const std::string& name, uint64_t bytes) override;
+    FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes) override;
     bool RemoveAllImages() override;
+    bool DisableImage(const std::string& name) override;
+    bool RemoveDisabledImages() override;
+    bool GetMappedImageDevice(const std::string& name, std::string* device) override;
+    bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
 
     std::vector<std::string> GetAllBackingImages() override;
 
@@ -51,18 +75,31 @@
     android::sp<IImageService> manager_;
 };
 
+static FiemapStatus ToFiemapStatus(const char* func, const binder::Status& status) {
+    if (!status.isOk()) {
+        LOG(ERROR) << func << " binder returned: " << status.toString8().string();
+        if (status.serviceSpecificErrorCode() != 0) {
+            return FiemapStatus::FromErrorCode(status.serviceSpecificErrorCode());
+        } else {
+            return FiemapStatus::Error();
+        }
+    }
+    return FiemapStatus::Ok();
+}
+
 ImageManagerBinder::ImageManagerBinder(android::sp<IGsiService>&& service,
                                        android::sp<IImageService>&& manager)
     : service_(std::move(service)), manager_(std::move(manager)) {}
 
-bool ImageManagerBinder::CreateBackingImage(const std::string& name, uint64_t size, int flags) {
-    auto status = manager_->createBackingImage(name, size, flags);
-    if (!status.isOk()) {
-        LOG(ERROR) << __PRETTY_FUNCTION__
-                   << " binder returned: " << status.exceptionMessage().string();
-        return false;
+FiemapStatus ImageManagerBinder::CreateBackingImage(
+        const std::string& name, uint64_t size, int flags,
+        std::function<bool(uint64_t, uint64_t)>&& on_progress) {
+    sp<IProgressCallback> callback = nullptr;
+    if (on_progress) {
+        callback = new ProgressCallback(std::move(on_progress));
     }
-    return true;
+    auto status = manager_->createBackingImage(name, size, flags, callback);
+    return ToFiemapStatus(__PRETTY_FUNCTION__, status);
 }
 
 bool ImageManagerBinder::DeleteBackingImage(const std::string& name) {
@@ -143,14 +180,9 @@
     return retval;
 }
 
-bool ImageManagerBinder::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
+FiemapStatus ImageManagerBinder::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
     auto status = manager_->zeroFillNewImage(name, bytes);
-    if (!status.isOk()) {
-        LOG(ERROR) << __PRETTY_FUNCTION__
-                   << " binder returned: " << status.exceptionMessage().string();
-        return false;
-    }
-    return true;
+    return ToFiemapStatus(__PRETTY_FUNCTION__, status);
 }
 
 bool ImageManagerBinder::RemoveAllImages() {
@@ -163,6 +195,36 @@
     return true;
 }
 
+bool ImageManagerBinder::DisableImage(const std::string&) {
+    LOG(ERROR) << __PRETTY_FUNCTION__ << " is not available over binder";
+    return false;
+}
+
+bool ImageManagerBinder::RemoveDisabledImages() {
+    auto status = manager_->removeDisabledImages();
+    if (!status.isOk()) {
+        LOG(ERROR) << __PRETTY_FUNCTION__
+                   << " binder returned: " << status.exceptionMessage().string();
+        return false;
+    }
+    return true;
+}
+
+bool ImageManagerBinder::GetMappedImageDevice(const std::string& name, std::string* device) {
+    auto status = manager_->getMappedImageDevice(name, device);
+    if (!status.isOk()) {
+        LOG(ERROR) << __PRETTY_FUNCTION__
+                   << " binder returned: " << status.exceptionMessage().string();
+        return false;
+    }
+    return !device->empty();
+}
+
+bool ImageManagerBinder::MapAllImages(const std::function<bool(std::set<std::string>)>&) {
+    LOG(ERROR) << __PRETTY_FUNCTION__ << " not available over binder";
+    return false;
+}
+
 static android::sp<IGsid> AcquireIGsid(const std::chrono::milliseconds& timeout_ms) {
     if (android::base::GetProperty("init.svc.gsid", "") != "running") {
         if (!android::base::SetProperty("ctl.start", "gsid") ||
diff --git a/fs_mgr/libfiemap/fiemap_status.cpp b/fs_mgr/libfiemap/fiemap_status.cpp
new file mode 100644
index 0000000..92ac935
--- /dev/null
+++ b/fs_mgr/libfiemap/fiemap_status.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 <libfiemap/fiemap_status.h>
+
+namespace android::fiemap {
+
+// FiemapStatus -> string
+std::string FiemapStatus::string() const {
+    if (error_code() == ErrorCode::ERROR) {
+        return "Error";
+    }
+    return strerror(-static_cast<int>(error_code()));
+}
+
+// -errno -> known ErrorCode
+// unknown ErrorCode -> known ErrorCode
+FiemapStatus::ErrorCode FiemapStatus::CastErrorCode(int error_code) {
+    switch (error_code) {
+        case static_cast<int32_t>(ErrorCode::SUCCESS):
+        case static_cast<int32_t>(ErrorCode::NO_SPACE):
+            return static_cast<ErrorCode>(error_code);
+        case static_cast<int32_t>(ErrorCode::ERROR):
+        default:
+            return ErrorCode::ERROR;
+    }
+}
+
+}  // namespace android::fiemap
diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp
index 961533e..b911234 100644
--- a/fs_mgr/libfiemap/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer.cpp
@@ -233,8 +233,7 @@
     return sb.st_size;
 }
 
-static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, uint64_t* blocksz,
-                              uint32_t* fs_type) {
+static bool PerformFileChecks(const std::string& file_path, uint64_t* blocksz, uint32_t* fs_type) {
     struct statfs64 sfs;
     if (statfs64(file_path.c_str(), &sfs)) {
         PLOG(ERROR) << "Failed to read file system status at: " << file_path;
@@ -258,20 +257,14 @@
             return false;
     }
 
-    uint64_t available_bytes = sfs.f_bsize * sfs.f_bavail;
-    if (access(file_path.c_str(), F_OK) != 0 && available_bytes <= file_size) {
-        LOG(ERROR) << "Not enough free space in file system to create file of size : " << file_size;
-        return false;
-    }
-
     *blocksz = sfs.f_bsize;
     *fs_type = sfs.f_type;
     return true;
 }
 
-static bool FallocateFallback(int file_fd, uint64_t block_size, uint64_t file_size,
-                              const std::string& file_path,
-                              const std::function<bool(uint64_t, uint64_t)>& on_progress) {
+static FiemapStatus FallocateFallback(int file_fd, uint64_t block_size, uint64_t file_size,
+                                      const std::string& file_path,
+                                      const std::function<bool(uint64_t, uint64_t)>& on_progress) {
     // Even though this is much faster than writing zeroes, it is still slow
     // enough that we need to fire the progress callback periodically. To
     // easily achieve this, we seek in chunks. We use 1000 chunks since
@@ -287,22 +280,22 @@
         auto rv = TEMP_FAILURE_RETRY(lseek(file_fd, cursor - 1, SEEK_SET));
         if (rv < 0) {
             PLOG(ERROR) << "Failed to lseek " << file_path;
-            return false;
+            return FiemapStatus::FromErrno(errno);
         }
         if (rv != cursor - 1) {
             LOG(ERROR) << "Seek returned wrong offset " << rv << " for file " << file_path;
-            return false;
+            return FiemapStatus::Error();
         }
         char buffer[] = {0};
         if (!android::base::WriteFully(file_fd, buffer, 1)) {
             PLOG(ERROR) << "Write failed: " << file_path;
-            return false;
+            return FiemapStatus::FromErrno(errno);
         }
         if (on_progress && !on_progress(cursor, file_size)) {
-            return false;
+            return FiemapStatus::Error();
         }
     }
-    return true;
+    return FiemapStatus::Ok();
 }
 
 // F2FS-specific ioctl
@@ -386,53 +379,22 @@
     return true;
 }
 
-// Reserve space for the file on the file system and write it out to make sure the extents
-// don't come back unwritten. Return from this function with the kernel file offset set to 0.
-// If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
-// aren't moved around.
-static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
-                         uint64_t file_size, unsigned int fs_type,
-                         std::function<bool(uint64_t, uint64_t)> on_progress) {
-    switch (fs_type) {
-        case EXT4_SUPER_MAGIC:
-            break;
-        case F2FS_SUPER_MAGIC: {
-            bool supported;
-            if (!F2fsPinBeforeAllocate(file_fd, &supported)) {
-                return false;
-            }
-            if (supported && !PinFile(file_fd, file_path, fs_type)) {
-                return false;
-            }
-            break;
-        }
-        case MSDOS_SUPER_MAGIC:
-            // fallocate() is not supported, and not needed, since VFAT does not support holes.
-            // Instead we can perform a much faster allocation.
-            return FallocateFallback(file_fd, blocksz, file_size, file_path, on_progress);
-        default:
-            LOG(ERROR) << "Missing fallocate() support for file system " << fs_type;
-            return false;
-    }
-
-    if (fallocate(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) {
-        PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size;
-        return false;
-    }
-
-    // write zeroes in 'blocksz' byte increments until we reach file_size to make sure the data
-    // blocks are actually written to by the file system and thus getting rid of the holes in the
-    // file.
+// write zeroes in 'blocksz' byte increments until we reach file_size to make sure the data
+// blocks are actually written to by the file system and thus getting rid of the holes in the
+// file.
+static FiemapStatus WriteZeroes(int file_fd, const std::string& file_path, size_t blocksz,
+                                uint64_t file_size,
+                                const std::function<bool(uint64_t, uint64_t)>& on_progress) {
     auto buffer = std::unique_ptr<void, decltype(&free)>(calloc(1, blocksz), free);
     if (buffer == nullptr) {
         LOG(ERROR) << "failed to allocate memory for writing file";
-        return false;
+        return FiemapStatus::Error();
     }
 
     off64_t offset = lseek64(file_fd, 0, SEEK_SET);
     if (offset < 0) {
         PLOG(ERROR) << "Failed to seek at the beginning of : " << file_path;
-        return false;
+        return FiemapStatus::FromErrno(errno);
     }
 
     int permille = -1;
@@ -440,7 +402,7 @@
         if (!::android::base::WriteFully(file_fd, buffer.get(), blocksz)) {
             PLOG(ERROR) << "Failed to write" << blocksz << " bytes at offset" << offset
                         << " in file " << file_path;
-            return false;
+            return FiemapStatus::FromErrno(errno);
         }
 
         offset += blocksz;
@@ -450,7 +412,7 @@
         int new_permille = (static_cast<uint64_t>(offset) * 1000) / file_size;
         if (new_permille != permille && static_cast<uint64_t>(offset) != file_size) {
             if (on_progress && !on_progress(offset, file_size)) {
-                return false;
+                return FiemapStatus::Error();
             }
             permille = new_permille;
         }
@@ -458,20 +420,67 @@
 
     if (lseek64(file_fd, 0, SEEK_SET) < 0) {
         PLOG(ERROR) << "Failed to reset offset at the beginning of : " << file_path;
-        return false;
+        return FiemapStatus::FromErrno(errno);
+    }
+    return FiemapStatus::Ok();
+}
+
+// Reserve space for the file on the file system and write it out to make sure the extents
+// don't come back unwritten. Return from this function with the kernel file offset set to 0.
+// If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks
+// aren't moved around.
+static FiemapStatus AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz,
+                                 uint64_t file_size, unsigned int fs_type,
+                                 std::function<bool(uint64_t, uint64_t)> on_progress) {
+    bool need_explicit_writes = true;
+    switch (fs_type) {
+        case EXT4_SUPER_MAGIC:
+            break;
+        case F2FS_SUPER_MAGIC: {
+            bool supported;
+            if (!F2fsPinBeforeAllocate(file_fd, &supported)) {
+                return FiemapStatus::Error();
+            }
+            if (supported) {
+                if (!PinFile(file_fd, file_path, fs_type)) {
+                    return FiemapStatus::Error();
+                }
+                need_explicit_writes = false;
+            }
+            break;
+        }
+        case MSDOS_SUPER_MAGIC:
+            // fallocate() is not supported, and not needed, since VFAT does not support holes.
+            // Instead we can perform a much faster allocation.
+            return FallocateFallback(file_fd, blocksz, file_size, file_path, on_progress);
+        default:
+            LOG(ERROR) << "Missing fallocate() support for file system " << fs_type;
+            return FiemapStatus::Error();
+    }
+
+    if (fallocate(file_fd, 0, 0, file_size)) {
+        PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size;
+        return FiemapStatus::FromErrno(errno);
+    }
+
+    if (need_explicit_writes) {
+        auto status = WriteZeroes(file_fd, file_path, blocksz, file_size, on_progress);
+        if (!status.is_ok()) {
+            return status;
+        }
     }
 
     // flush all writes here ..
     if (fsync(file_fd)) {
         PLOG(ERROR) << "Failed to synchronize written file:" << file_path;
-        return false;
+        return FiemapStatus::FromErrno(errno);
     }
 
     // Send one last progress notification.
     if (on_progress && !on_progress(file_size, file_size)) {
-        return false;
+        return FiemapStatus::Error();
     }
-    return true;
+    return FiemapStatus::Ok();
 }
 
 bool FiemapWriter::HasPinnedExtents(const std::string& file_path) {
@@ -665,6 +674,18 @@
 
 FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create,
                                    std::function<bool(uint64_t, uint64_t)> progress) {
+    FiemapUniquePtr ret;
+    if (!Open(file_path, file_size, &ret, create, progress).is_ok()) {
+        return nullptr;
+    }
+    return ret;
+}
+
+FiemapStatus FiemapWriter::Open(const std::string& file_path, uint64_t file_size,
+                                FiemapUniquePtr* out, bool create,
+                                std::function<bool(uint64_t, uint64_t)> progress) {
+    out->reset();
+
     // if 'create' is false, open an existing file and do not truncate.
     int open_flags = O_RDWR | O_CLOEXEC;
     if (create) {
@@ -677,52 +698,55 @@
             TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags, S_IRUSR | S_IWUSR)));
     if (file_fd < 0) {
         PLOG(ERROR) << "Failed to create file at: " << file_path;
-        return nullptr;
+        return FiemapStatus::FromErrno(errno);
     }
 
     std::string abs_path;
     if (!::android::base::Realpath(file_path, &abs_path)) {
+        int saved_errno = errno;
         PLOG(ERROR) << "Invalid file path: " << file_path;
         cleanup(file_path, create);
-        return nullptr;
+        return FiemapStatus::FromErrno(saved_errno);
     }
 
     std::string bdev_path;
     if (!GetBlockDeviceForFile(abs_path, &bdev_path)) {
         LOG(ERROR) << "Failed to get block dev path for file: " << file_path;
         cleanup(abs_path, create);
-        return nullptr;
+        return FiemapStatus::Error();
     }
 
     ::android::base::unique_fd bdev_fd(
             TEMP_FAILURE_RETRY(open(bdev_path.c_str(), O_RDONLY | O_CLOEXEC)));
     if (bdev_fd < 0) {
+        int saved_errno = errno;
         PLOG(ERROR) << "Failed to open block device: " << bdev_path;
         cleanup(file_path, create);
-        return nullptr;
+        return FiemapStatus::FromErrno(saved_errno);
     }
 
     uint64_t bdevsz;
     if (!GetBlockDeviceSize(bdev_fd, bdev_path, &bdevsz)) {
+        int saved_errno = errno;
         LOG(ERROR) << "Failed to get block device size for : " << bdev_path;
         cleanup(file_path, create);
-        return nullptr;
+        return FiemapStatus::FromErrno(saved_errno);
     }
 
     if (!create) {
         file_size = GetFileSize(abs_path);
         if (file_size == 0) {
             LOG(ERROR) << "Invalid file size of zero bytes for file: " << abs_path;
-            return nullptr;
+            return FiemapStatus::FromErrno(errno);
         }
     }
 
     uint64_t blocksz;
     uint32_t fs_type;
-    if (!PerformFileChecks(abs_path, file_size, &blocksz, &fs_type)) {
+    if (!PerformFileChecks(abs_path, &blocksz, &fs_type)) {
         LOG(ERROR) << "Failed to validate file or file system for file:" << abs_path;
         cleanup(abs_path, create);
-        return nullptr;
+        return FiemapStatus::Error();
     }
 
     // Align up to the nearest block size.
@@ -731,11 +755,13 @@
     }
 
     if (create) {
-        if (!AllocateFile(file_fd, abs_path, blocksz, file_size, fs_type, std::move(progress))) {
+        auto status =
+                AllocateFile(file_fd, abs_path, blocksz, file_size, fs_type, std::move(progress));
+        if (!status.is_ok()) {
             LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size
                        << " bytes";
             cleanup(abs_path, create);
-            return nullptr;
+            return status;
         }
     }
 
@@ -743,7 +769,7 @@
     if (!PinFile(file_fd, abs_path, fs_type)) {
         cleanup(abs_path, create);
         LOG(ERROR) << "Failed to pin the file in storage";
-        return nullptr;
+        return FiemapStatus::Error();
     }
 
     // now allocate the FiemapWriter and start setting it up
@@ -754,14 +780,14 @@
             if (!ReadFiemap(file_fd, abs_path, &fmap->extents_)) {
                 LOG(ERROR) << "Failed to read fiemap of file: " << abs_path;
                 cleanup(abs_path, create);
-                return nullptr;
+                return FiemapStatus::Error();
             }
             break;
         case MSDOS_SUPER_MAGIC:
             if (!ReadFibmap(file_fd, abs_path, &fmap->extents_)) {
                 LOG(ERROR) << "Failed to read fibmap of file: " << abs_path;
                 cleanup(abs_path, create);
-                return nullptr;
+                return FiemapStatus::Error();
             }
             break;
     }
@@ -775,7 +801,8 @@
 
     LOG(VERBOSE) << "Successfully created FiemapWriter for file " << abs_path << " on block device "
                  << bdev_path;
-    return fmap;
+    *out = std::move(fmap);
+    return FiemapStatus::Ok();
 }
 
 }  // namespace fiemap
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index 4ac7161..22a3722 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -193,7 +193,9 @@
 }
 
 TEST_F(FiemapWriterTest, MaxBlockSize) {
-    ASSERT_GT(DetermineMaximumFileSize(testfile), 0);
+    uint64_t max_piece_size = 0;
+    ASSERT_TRUE(DetermineMaximumFileSize(testfile, &max_piece_size));
+    ASSERT_GT(max_piece_size, 0);
 }
 
 TEST_F(FiemapWriterTest, FibmapBlockAddressing) {
diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index fe2018d..30eb5a0 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -42,7 +42,10 @@
 using android::dm::LoopControl;
 using android::fs_mgr::CreateLogicalPartition;
 using android::fs_mgr::CreateLogicalPartitionParams;
+using android::fs_mgr::CreateLogicalPartitions;
 using android::fs_mgr::DestroyLogicalPartition;
+using android::fs_mgr::GetBlockDevicePartitionName;
+using android::fs_mgr::GetBlockDevicePartitionNames;
 using android::fs_mgr::GetPartitionName;
 
 static constexpr char kTestImageMetadataDir[] = "/metadata/gsi/test";
@@ -130,27 +133,25 @@
     return access(header_file.c_str(), F_OK) == 0;
 }
 
-bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, int flags) {
-    return CreateBackingImage(name, size, flags, nullptr);
-}
-
 static bool IsUnreliablePinningAllowed(const std::string& path) {
     return android::base::StartsWith(path, "/data/gsi/dsu/") ||
            android::base::StartsWith(path, "/data/gsi/test/") ||
            android::base::StartsWith(path, "/data/gsi/ota/test/");
 }
 
-bool ImageManager::CreateBackingImage(const std::string& name, uint64_t size, int flags,
-                                      std::function<bool(uint64_t, uint64_t)>&& on_progress) {
+FiemapStatus ImageManager::CreateBackingImage(
+        const std::string& name, uint64_t size, int flags,
+        std::function<bool(uint64_t, uint64_t)>&& on_progress) {
     auto data_path = GetImageHeaderPath(name);
-    auto fw = SplitFiemap::Create(data_path, size, 0, on_progress);
-    if (!fw) {
-        return false;
+    std::unique_ptr<SplitFiemap> fw;
+    auto status = SplitFiemap::Create(data_path, size, 0, &fw, on_progress);
+    if (!status.is_ok()) {
+        return status;
     }
 
     bool reliable_pinning;
     if (!FilesystemHasReliablePinning(data_path, &reliable_pinning)) {
-        return false;
+        return FiemapStatus::Error();
     }
     if (!reliable_pinning && !IsUnreliablePinningAllowed(data_path)) {
         // For historical reasons, we allow unreliable pinning for certain use
@@ -161,7 +162,7 @@
         // proper pinning.
         LOG(ERROR) << "File system does not have reliable block pinning";
         SplitFiemap::RemoveSplitFiles(data_path);
-        return false;
+        return FiemapStatus::Error();
     }
 
     // Except for testing, we do not allow persisting metadata that references
@@ -177,24 +178,25 @@
 
         fw = {};
         SplitFiemap::RemoveSplitFiles(data_path);
-        return false;
+        return FiemapStatus::Error();
     }
 
     bool readonly = !!(flags & CREATE_IMAGE_READONLY);
     if (!UpdateMetadata(metadata_dir_, name, fw.get(), size, readonly)) {
-        return false;
+        return FiemapStatus::Error();
     }
 
     if (flags & CREATE_IMAGE_ZERO_FILL) {
-        if (!ZeroFillNewImage(name, 0)) {
+        auto res = ZeroFillNewImage(name, 0);
+        if (!res.is_ok()) {
             DeleteBackingImage(name);
-            return false;
+            return res;
         }
     }
-    return true;
+    return FiemapStatus::Ok();
 }
 
-bool ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
+FiemapStatus ImageManager::ZeroFillNewImage(const std::string& name, uint64_t bytes) {
     auto data_path = GetImageHeaderPath(name);
 
     // See the comment in MapImageDevice() about how this works.
@@ -202,13 +204,13 @@
     bool can_use_devicemapper;
     if (!FiemapWriter::GetBlockDeviceForFile(data_path, &block_device, &can_use_devicemapper)) {
         LOG(ERROR) << "Could not determine block device for " << data_path;
-        return false;
+        return FiemapStatus::Error();
     }
 
     if (!can_use_devicemapper) {
         // We've backed with loop devices, and since we store files in an
         // unencrypted folder, the initial zeroes we wrote will suffice.
-        return true;
+        return FiemapStatus::Ok();
     }
 
     // data is dm-crypt, or FBE + dm-default-key. This means the zeroes written
@@ -216,7 +218,7 @@
     // this.
     auto device = MappedDevice::Open(this, 10s, name);
     if (!device) {
-        return false;
+        return FiemapStatus::Error();
     }
 
     static constexpr size_t kChunkSize = 4096;
@@ -229,7 +231,7 @@
         remaining = get_block_device_size(device->fd());
         if (!remaining) {
             PLOG(ERROR) << "Could not get block device size for " << device->path();
-            return false;
+            return FiemapStatus::FromErrno(errno);
         }
     }
     while (remaining) {
@@ -237,11 +239,11 @@
         if (!android::base::WriteFully(device->fd(), zeroes.data(),
                                        static_cast<size_t>(to_write))) {
             PLOG(ERROR) << "write failed: " << device->path();
-            return false;
+            return FiemapStatus::FromErrno(errno);
         }
         remaining -= to_write;
     }
-    return true;
+    return FiemapStatus::Ok();
 }
 
 bool ImageManager::DeleteBackingImage(const std::string& name) {
@@ -632,6 +634,66 @@
     return true;
 }
 
+bool ImageManager::DisableImage(const std::string& name) {
+    return AddAttributes(metadata_dir_, name, LP_PARTITION_ATTR_DISABLED);
+}
+
+bool ImageManager::RemoveDisabledImages() {
+    if (!MetadataExists(metadata_dir_)) {
+        return true;
+    }
+
+    auto metadata = OpenMetadata(metadata_dir_);
+    if (!metadata) {
+        return false;
+    }
+
+    bool ok = true;
+    for (const auto& partition : metadata->partitions) {
+        if (partition.attributes & LP_PARTITION_ATTR_DISABLED) {
+            ok &= DeleteBackingImage(GetPartitionName(partition));
+        }
+    }
+    return ok;
+}
+
+bool ImageManager::GetMappedImageDevice(const std::string& name, std::string* device) {
+    auto prop_name = GetStatusPropertyName(name);
+    *device = android::base::GetProperty(prop_name, "");
+    if (!device->empty()) {
+        return true;
+    }
+
+    auto& dm = DeviceMapper::Instance();
+    if (dm.GetState(name) == DmDeviceState::INVALID) {
+        return false;
+    }
+    return dm.GetDmDevicePathByName(name, device);
+}
+
+bool ImageManager::MapAllImages(const std::function<bool(std::set<std::string>)>& init) {
+    if (!MetadataExists(metadata_dir_)) {
+        return true;
+    }
+
+    auto metadata = OpenMetadata(metadata_dir_);
+    if (!metadata) {
+        return false;
+    }
+
+    std::set<std::string> devices;
+    for (const auto& name : GetBlockDevicePartitionNames(*metadata.get())) {
+        devices.emplace(name);
+    }
+    if (!init(std::move(devices))) {
+        return false;
+    }
+
+    auto data_device = GetMetadataSuperBlockDevice(*metadata.get());
+    auto data_partition_name = GetBlockDevicePartitionName(*data_device);
+    return CreateLogicalPartitions(*metadata.get(), data_partition_name);
+}
+
 std::unique_ptr<MappedDevice> MappedDevice::Open(IImageManager* manager,
                                                  const std::chrono::milliseconds& timeout_ms,
                                                  const std::string& name) {
diff --git a/fs_mgr/libfiemap/image_test.cpp b/fs_mgr/libfiemap/image_test.cpp
index f05825c..80c340f 100644
--- a/fs_mgr/libfiemap/image_test.cpp
+++ b/fs_mgr/libfiemap/image_test.cpp
@@ -112,6 +112,25 @@
     ASSERT_EQ(android::base::GetProperty(PropertyName(), ""), "");
 }
 
+TEST_F(NativeTest, DisableImage) {
+    ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
+    ASSERT_TRUE(manager_->BackingImageExists(base_name_));
+    ASSERT_TRUE(manager_->DisableImage(base_name_));
+    ASSERT_TRUE(manager_->RemoveDisabledImages());
+    ASSERT_TRUE(!manager_->BackingImageExists(base_name_));
+}
+
+TEST_F(NativeTest, GetMappedImageDevice) {
+    ASSERT_TRUE(manager_->CreateBackingImage(base_name_, kTestImageSize, false, nullptr));
+
+    std::string path1, path2;
+    ASSERT_TRUE(manager_->MapImageDevice(base_name_, 5s, &path1));
+    ASSERT_TRUE(manager_->GetMappedImageDevice(base_name_, &path2));
+    EXPECT_EQ(path1, path2);
+
+    ASSERT_TRUE(manager_->UnmapImageDevice(base_name_));
+}
+
 // This fixture is for tests against a simulated device environment. Rather
 // than use /data, we create an image and then layer a new filesystem within
 // it. Each test then decides how to mount and create layered images. This
@@ -220,9 +239,19 @@
 
     ASSERT_TRUE(submanager_->CreateBackingImage(test_image_name_, kTestImageSize, false, nullptr));
 
+    std::set<std::string> backing_devices;
+    auto init = [&](std::set<std::string> devices) -> bool {
+        backing_devices = std::move(devices);
+        return true;
+    };
+
     std::string path;
     ASSERT_TRUE(submanager_->MapImageDevice(test_image_name_, 5s, &path));
     ASSERT_TRUE(android::base::StartsWith(path, "/dev/block/dm-"));
+    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
+    ASSERT_TRUE(submanager_->MapAllImages(init));
+    ASSERT_FALSE(backing_devices.empty());
+    ASSERT_TRUE(submanager_->UnmapImageDevice(test_image_name_));
 }
 
 bool Mkdir(const std::string& path) {
diff --git a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h
new file mode 100644
index 0000000..d7b2cf1
--- /dev/null
+++ b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <string>
+
+namespace android::fiemap {
+
+// Represent error status of libfiemap classes.
+class FiemapStatus {
+  public:
+    enum class ErrorCode : int32_t {
+        SUCCESS = 0,
+        // Generic non-recoverable failure.
+        ERROR = INT32_MIN,
+        // Not enough space
+        NO_SPACE = -ENOSPC,
+    };
+
+    // Create from a given errno (specified in errno,h)
+    static FiemapStatus FromErrno(int error_num) { return FiemapStatus(CastErrorCode(-error_num)); }
+
+    // Create from an integer error code that is expected to be an ErrorCode
+    // value. If it isn't, Error() is returned.
+    static FiemapStatus FromErrorCode(int32_t error_code) {
+        return FiemapStatus(CastErrorCode(error_code));
+    }
+
+    // Generic error.
+    static FiemapStatus Error() { return FiemapStatus(ErrorCode::ERROR); }
+
+    // Success.
+    static FiemapStatus Ok() { return FiemapStatus(ErrorCode::SUCCESS); }
+
+    ErrorCode error_code() const { return error_code_; }
+    bool is_ok() const { return error_code() == ErrorCode::SUCCESS; }
+    operator bool() const { return is_ok(); }
+
+    // For logging and debugging only.
+    std::string string() const;
+
+  protected:
+    FiemapStatus(ErrorCode code) : error_code_(code) {}
+
+  private:
+    ErrorCode error_code_;
+
+    static ErrorCode CastErrorCode(int error);
+};
+
+}  // namespace android::fiemap
diff --git a/fs_mgr/libfiemap/include/libfiemap/fiemap_writer.h b/fs_mgr/libfiemap/include/libfiemap/fiemap_writer.h
index c692265..dd345f6 100644
--- a/fs_mgr/libfiemap/include/libfiemap/fiemap_writer.h
+++ b/fs_mgr/libfiemap/include/libfiemap/fiemap_writer.h
@@ -27,6 +27,8 @@
 
 #include <android-base/unique_fd.h>
 
+#include <libfiemap/fiemap_status.h>
+
 namespace android {
 namespace fiemap {
 
@@ -47,6 +49,9 @@
     static FiemapUniquePtr Open(const std::string& file_path, uint64_t file_size,
                                 bool create = true,
                                 std::function<bool(uint64_t, uint64_t)> progress = {});
+    static FiemapStatus Open(const std::string& file_path, uint64_t file_size, FiemapUniquePtr* out,
+                             bool create = true,
+                             std::function<bool(uint64_t, uint64_t)> progress = {});
 
     // Check that a file still has the same extents since it was last opened with FiemapWriter,
     // assuming the file was not resized outside of FiemapWriter. Returns false either on error
diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
index 5ff4628..2c13229 100644
--- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h
+++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h
@@ -21,9 +21,11 @@
 #include <chrono>
 #include <functional>
 #include <memory>
+#include <set>
 #include <string>
 
 #include <android-base/unique_fd.h>
+#include <libfiemap/fiemap_status.h>
 #include <liblp/partition_opener.h>
 
 namespace android {
@@ -51,7 +53,9 @@
     // of the image is undefined. If zero-fill is requested, and the operation
     // cannot be completed, the image will be deleted and this function will
     // return false.
-    virtual bool CreateBackingImage(const std::string& name, uint64_t size, int flags) = 0;
+    virtual FiemapStatus CreateBackingImage(
+            const std::string& name, uint64_t size, int flags,
+            std::function<bool(uint64_t, uint64_t)>&& on_progress = nullptr) = 0;
 
     // Delete an image created with CreateBackingImage. Its entry will be
     // removed from the associated lp_metadata file.
@@ -84,12 +88,35 @@
     virtual bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
                                           std::string* dev) = 0;
 
+    // If an image was mapped, return the path to its device. Otherwise, return
+    // false. Errors are not reported in this case, calling IsImageMapped is
+    // not necessary.
+    virtual bool GetMappedImageDevice(const std::string& name, std::string* device) = 0;
+
+    // Map all images owned by this manager. This is only intended to be used
+    // during first-stage init, and as such, it does not provide a timeout
+    // (meaning libdm races can't be resolved, as ueventd is not available),
+    // and is not available over binder.
+    //
+    // The callback provided is given the list of dependent block devices.
+    virtual bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) = 0;
+
+    // Mark an image as disabled. This is useful for marking an image as
+    // will-be-deleted in recovery, since recovery cannot mount /data.
+    //
+    // This is not available in binder, since it is intended for recovery.
+    // When binder is available, images can simply be removed.
+    virtual bool DisableImage(const std::string& name) = 0;
+
+    // Remove all images that been marked as disabled.
+    virtual bool RemoveDisabledImages() = 0;
+
     // Get all backing image names.
     virtual std::vector<std::string> GetAllBackingImages() = 0;
 
     // Writes |bytes| zeros to |name| file. If |bytes| is 0, then the
     // whole file if filled with zeros.
-    virtual bool ZeroFillNewImage(const std::string& name, uint64_t bytes) = 0;
+    virtual FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes) = 0;
 
     // Find and remove all images and metadata for this manager.
     virtual bool RemoveAllImages() = 0;
@@ -109,7 +136,8 @@
     static std::unique_ptr<ImageManager> Open(const std::string& dir_prefix);
 
     // Methods that must be implemented from IImageManager.
-    bool CreateBackingImage(const std::string& name, uint64_t size, int flags) override;
+    FiemapStatus CreateBackingImage(const std::string& name, uint64_t size, int flags,
+                                    std::function<bool(uint64_t, uint64_t)>&& on_progress) override;
     bool DeleteBackingImage(const std::string& name) override;
     bool MapImageDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms,
                         std::string* path) override;
@@ -119,11 +147,12 @@
     bool MapImageWithDeviceMapper(const IPartitionOpener& opener, const std::string& name,
                                   std::string* dev) override;
     bool RemoveAllImages() override;
+    bool DisableImage(const std::string& name) override;
+    bool RemoveDisabledImages() override;
+    bool GetMappedImageDevice(const std::string& name, std::string* device) override;
+    bool MapAllImages(const std::function<bool(std::set<std::string>)>& init) override;
 
     std::vector<std::string> GetAllBackingImages();
-    // Same as CreateBackingImage, but provides a progress notification.
-    bool CreateBackingImage(const std::string& name, uint64_t size, int flags,
-                            std::function<bool(uint64_t, uint64_t)>&& on_progress);
 
     // Returns true if the named partition exists. This does not check the
     // consistency of the backing image/data file.
@@ -136,7 +165,7 @@
     void set_partition_opener(std::unique_ptr<IPartitionOpener>&& opener);
 
     // Writes |bytes| zeros at the beginning of the passed image
-    bool ZeroFillNewImage(const std::string& name, uint64_t bytes);
+    FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes);
 
   private:
     ImageManager(const std::string& metadata_dir, const std::string& data_dir);
diff --git a/fs_mgr/libfiemap/include/libfiemap/split_fiemap_writer.h b/fs_mgr/libfiemap/include/libfiemap/split_fiemap_writer.h
index feffb3d..d739fcf 100644
--- a/fs_mgr/libfiemap/include/libfiemap/split_fiemap_writer.h
+++ b/fs_mgr/libfiemap/include/libfiemap/split_fiemap_writer.h
@@ -25,7 +25,8 @@
 
 #include <android-base/unique_fd.h>
 
-#include "fiemap_writer.h"
+#include <libfiemap/fiemap_status.h>
+#include <libfiemap/fiemap_writer.h>
 
 namespace android {
 namespace fiemap {
@@ -43,6 +44,9 @@
     static std::unique_ptr<SplitFiemap> Create(const std::string& file_path, uint64_t file_size,
                                                uint64_t max_piece_size,
                                                ProgressCallback progress = {});
+    static FiemapStatus Create(const std::string& file_path, uint64_t file_size,
+                               uint64_t max_piece_size, std::unique_ptr<SplitFiemap>* out_val,
+                               ProgressCallback progress = {});
 
     // Open an existing split fiemap file.
     static std::unique_ptr<SplitFiemap> Open(const std::string& file_path);
diff --git a/fs_mgr/libfiemap/metadata.cpp b/fs_mgr/libfiemap/metadata.cpp
index 597efe9..ea1f508 100644
--- a/fs_mgr/libfiemap/metadata.cpp
+++ b/fs_mgr/libfiemap/metadata.cpp
@@ -192,5 +192,23 @@
     return SaveMetadata(builder.get(), metadata_dir);
 }
 
+bool AddAttributes(const std::string& metadata_dir, const std::string& partition_name,
+                   uint32_t attributes) {
+    auto metadata = OpenMetadata(metadata_dir);
+    if (!metadata) {
+        return false;
+    }
+    auto builder = MetadataBuilder::New(*metadata.get());
+    if (!builder) {
+        return false;
+    }
+    auto partition = builder->FindPartition(partition_name);
+    if (!partition) {
+        return false;
+    }
+    partition->set_attributes(partition->attributes() | attributes);
+    return SaveMetadata(builder.get(), metadata_dir);
+}
+
 }  // namespace fiemap
 }  // namespace android
diff --git a/fs_mgr/libfiemap/metadata.h b/fs_mgr/libfiemap/metadata.h
index f0ce23e..4eb3ad5 100644
--- a/fs_mgr/libfiemap/metadata.h
+++ b/fs_mgr/libfiemap/metadata.h
@@ -29,6 +29,8 @@
 std::unique_ptr<android::fs_mgr::LpMetadata> OpenMetadata(const std::string& metadata_dir);
 bool UpdateMetadata(const std::string& metadata_dir, const std::string& partition_name,
                     SplitFiemap* file, uint64_t partition_size, bool readonly);
+bool AddAttributes(const std::string& metadata_dir, const std::string& partition_name,
+                   uint32_t attributes);
 bool RemoveImageMetadata(const std::string& metadata_dir, const std::string& partition_name);
 bool RemoveAllMetadata(const std::string& dir);
 
diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp
index cc54f20..12c7397 100644
--- a/fs_mgr/libfiemap/split_fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp
@@ -45,16 +45,28 @@
 std::unique_ptr<SplitFiemap> SplitFiemap::Create(const std::string& file_path, uint64_t file_size,
                                                  uint64_t max_piece_size,
                                                  ProgressCallback progress) {
+    std::unique_ptr<SplitFiemap> ret;
+    if (!Create(file_path, file_size, max_piece_size, &ret, progress).is_ok()) {
+        return nullptr;
+    }
+    return ret;
+}
+
+FiemapStatus SplitFiemap::Create(const std::string& file_path, uint64_t file_size,
+                                 uint64_t max_piece_size, std::unique_ptr<SplitFiemap>* out_val,
+                                 ProgressCallback progress) {
+    out_val->reset();
+
     if (!file_size) {
         LOG(ERROR) << "Cannot create a fiemap for a 0-length file: " << file_path;
-        return nullptr;
+        return FiemapStatus::Error();
     }
 
     if (!max_piece_size) {
-        max_piece_size = DetermineMaximumFileSize(file_path);
-        if (!max_piece_size) {
+        auto status = DetermineMaximumFileSize(file_path, &max_piece_size);
+        if (!status.is_ok()) {
             LOG(ERROR) << "Could not determine maximum file size for " << file_path;
-            return nullptr;
+            return status;
         }
     }
 
@@ -75,7 +87,6 @@
         }
         return true;
     };
-
     std::unique_ptr<SplitFiemap> out(new SplitFiemap());
     out->creating_ = true;
     out->list_file_ = file_path;
@@ -85,14 +96,17 @@
     while (remaining_bytes) {
         if (out->files_.size() >= kMaxFilePieces) {
             LOG(ERROR) << "Requested size " << file_size << " created too many split files";
-            return nullptr;
+            out.reset();
+            return FiemapStatus::Error();
         }
         std::string chunk_path =
                 android::base::StringPrintf("%s.%04d", file_path.c_str(), (int)out->files_.size());
         uint64_t chunk_size = std::min(max_piece_size, remaining_bytes);
-        auto writer = FiemapWriter::Open(chunk_path, chunk_size, true, on_progress);
-        if (!writer) {
-            return nullptr;
+        FiemapUniquePtr writer;
+        auto status = FiemapWriter::Open(chunk_path, chunk_size, &writer, true, on_progress);
+        if (!status.is_ok()) {
+            out.reset();
+            return status;
         }
 
         // To make sure the alignment doesn't create too much inconsistency, we
@@ -110,20 +124,23 @@
     unique_fd fd(open(out->list_file_.c_str(), O_CREAT | O_WRONLY | O_CLOEXEC, 0660));
     if (fd < 0) {
         PLOG(ERROR) << "Failed to open " << file_path;
-        return nullptr;
+        out.reset();
+        return FiemapStatus::FromErrno(errno);
     }
 
     for (const auto& writer : out->files_) {
         std::string line = android::base::Basename(writer->file_path()) + "\n";
         if (!android::base::WriteFully(fd, line.data(), line.size())) {
             PLOG(ERROR) << "Write failed " << file_path;
-            return nullptr;
+            out.reset();
+            return FiemapStatus::FromErrno(errno);
         }
     }
 
     // Unset this bit, so we don't unlink on destruction.
     out->creating_ = false;
-    return out;
+    *out_val = std::move(out);
+    return FiemapStatus::Ok();
 }
 
 std::unique_ptr<SplitFiemap> SplitFiemap::Open(const std::string& file_path) {
diff --git a/fs_mgr/libfiemap/utility.cpp b/fs_mgr/libfiemap/utility.cpp
index 955e544..bbb0510 100644
--- a/fs_mgr/libfiemap/utility.cpp
+++ b/fs_mgr/libfiemap/utility.cpp
@@ -37,29 +37,30 @@
 
 static constexpr char kUserdataDevice[] = "/dev/block/by-name/userdata";
 
-uint64_t DetermineMaximumFileSize(const std::string& file_path) {
+FiemapStatus DetermineMaximumFileSize(const std::string& file_path, uint64_t* result) {
     // Create the smallest file possible (one block).
-    auto writer = FiemapWriter::Open(file_path, 1);
-    if (!writer) {
-        return 0;
+    FiemapUniquePtr writer;
+    auto status = FiemapWriter::Open(file_path, 1, &writer);
+    if (!status.is_ok()) {
+        return status;
     }
 
-    uint64_t result = 0;
+    *result = 0;
     switch (writer->fs_type()) {
         case EXT4_SUPER_MAGIC:
             // The minimum is 16GiB, so just report that. If we wanted we could parse the
             // superblock and figure out if 64-bit support is enabled.
-            result = 17179869184ULL;
+            *result = 17179869184ULL;
             break;
         case F2FS_SUPER_MAGIC:
             // Formula is from https://www.kernel.org/doc/Documentation/filesystems/f2fs.txt
             // 4KB * (923 + 2 * 1018 + 2 * 1018 * 1018 + 1018 * 1018 * 1018) := 3.94TB.
-            result = 4329690886144ULL;
+            *result = 4329690886144ULL;
             break;
         case MSDOS_SUPER_MAGIC:
             // 4GB-1, which we want aligned to the block size.
-            result = 4294967295;
-            result -= (result % writer->block_size());
+            *result = 4294967295;
+            *result -= (*result % writer->block_size());
             break;
         default:
             LOG(ERROR) << "Unknown file system type: " << writer->fs_type();
@@ -70,7 +71,7 @@
     writer = nullptr;
     unlink(file_path.c_str());
 
-    return result;
+    return FiemapStatus::Ok();
 }
 
 // Given a SplitFiemap, this returns a device path that will work during first-
diff --git a/fs_mgr/libfiemap/utility.h b/fs_mgr/libfiemap/utility.h
index 24ebc57..4c0bc2b 100644
--- a/fs_mgr/libfiemap/utility.h
+++ b/fs_mgr/libfiemap/utility.h
@@ -28,7 +28,7 @@
 // Given a file that will be created, determine the maximum size its containing
 // filesystem allows. Note this is a theoretical maximum size; free space is
 // ignored entirely.
-uint64_t DetermineMaximumFileSize(const std::string& file_path);
+FiemapStatus DetermineMaximumFileSize(const std::string& file_path, uint64_t* result);
 
 // Given a SplitFiemap, this returns a device path that will work during first-
 // stage init (i.e., its path can be found by InitRequiredDevices).
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 4406696..d496466 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -852,7 +852,7 @@
             return nullptr;
         }
 
-        if (partition->attributes() & LP_PARTITION_ATTR_UPDATED) {
+        if (partition->attributes() & LP_PARTITION_ATTRIBUTE_MASK_V1) {
             static const uint16_t kMinVersion = LP_METADATA_VERSION_FOR_UPDATED_ATTR;
             metadata->header.minor_version = std::max(metadata->header.minor_version, kMinVersion);
         }
@@ -1125,6 +1125,11 @@
     auto_slot_suffixing_ = true;
 }
 
+void MetadataBuilder::SetVirtualABDeviceFlag() {
+    RequireExpandedMetadataHeader();
+    header_.flags |= LP_HEADER_FLAG_VIRTUAL_AB_DEVICE;
+}
+
 bool MetadataBuilder::IsABDevice() {
     return !IPropertyFetcher::GetInstance()->GetProperty("ro.boot.slot_suffix", "").empty();
 }
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 7a334fb..f7738fb 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -145,6 +145,7 @@
     std::vector<std::unique_ptr<Extent>> extents_;
     uint32_t attributes_;
     uint64_t size_;
+    bool disabled_;
 };
 
 // An interval in the metadata. This is similar to a LinearExtent with one difference.
@@ -318,6 +319,8 @@
 
     // Set the LP_METADATA_AUTO_SLOT_SUFFIXING flag.
     void SetAutoSlotSuffixing();
+    // Set the LP_HEADER_FLAG_VIRTUAL_AB_DEVICE flag.
+    void SetVirtualABDeviceFlag();
 
     // If set, checks for slot suffixes will be ignored internally.
     void IgnoreSlotSuffixing();
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 26cbf07..41d8b0c 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -72,13 +72,17 @@
  */
 #define LP_PARTITION_ATTR_UPDATED (1 << 2)
 
+/* This flag marks a partition as disabled. It should not be used or mapped. */
+#define LP_PARTITION_ATTR_DISABLED (1 << 3)
+
 /* Mask that defines all valid attributes. When changing this, make sure to
  * update ParseMetadata().
  */
 #define LP_PARTITION_ATTRIBUTE_MASK_V0 \
     (LP_PARTITION_ATTR_READONLY | LP_PARTITION_ATTR_SLOT_SUFFIXED)
-#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTR_UPDATED)
-#define LP_PARTITION_ATTRIBUTE_MASK LP_PARTITION_ATTRIBUTE_MASK_V1
+#define LP_PARTITION_ATTRIBUTE_MASK_V1 (LP_PARTITION_ATTR_UPDATED | LP_PARTITION_ATTR_DISABLED)
+#define LP_PARTITION_ATTRIBUTE_MASK \
+    (LP_PARTITION_ATTRIBUTE_MASK_V0 | LP_PARTITION_ATTRIBUTE_MASK_V1)
 
 /* Default name of the physical partition that holds logical partition entries.
  * The layout of this partition will look like:
@@ -224,8 +228,6 @@
     /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
      * independent of the version number and intended to be informational only.
      * New flags can be added without bumping the version.
-     *
-     * (Note there are no flags currently defined.)
      */
     uint32_t flags;
 
@@ -233,6 +235,11 @@
     uint8_t reserved[124];
 } __attribute__((packed)) LpMetadataHeader;
 
+/* This device uses Virtual A/B. Note that on retrofit devices, the expanded
+ * header may not be present.
+ */
+#define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
+
 /* This struct defines a logical partition entry, similar to what would be
  * present in a GUID Partition Table.
  */
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 30c17e4..e6fd9f7 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -280,11 +280,9 @@
         return nullptr;
     }
 
-    uint32_t valid_attributes = 0;
+    uint32_t valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
     if (metadata->header.minor_version >= LP_METADATA_VERSION_FOR_UPDATED_ATTR) {
-        valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V1;
-    } else {
-        valid_attributes = LP_PARTITION_ATTRIBUTE_MASK_V0;
+        valid_attributes |= LP_PARTITION_ATTRIBUTE_MASK_V1;
     }
 
     // ValidateTableSize ensured that |cursor| is valid for the number of
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 30d01a6..eadcecc 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -30,7 +30,6 @@
     static_libs: [
         "libcutils",
         "libdm",
-        "libfs_mgr",
         "libfstab",
         "liblp",
         "update_metadata-protos",
@@ -93,8 +92,8 @@
         "libsnapshot_hal_deps",
     ],
     srcs: [":libsnapshot_sources"],
-    whole_static_libs: [
-        "libfiemap_binder",
+    static_libs: [
+        "libfs_mgr_binder"
     ],
 }
 
@@ -103,8 +102,8 @@
     defaults: ["libsnapshot_defaults"],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
-    whole_static_libs: [
-        "libfiemap_passthrough",
+    static_libs: [
+        "libfs_mgr",
     ],
 }
 
@@ -116,8 +115,8 @@
     ],
     srcs: [":libsnapshot_sources"],
     recovery_available: true,
-    whole_static_libs: [
-        "libfiemap_passthrough",
+    static_libs: [
+        "libfs_mgr",
     ],
 }
 
@@ -144,6 +143,7 @@
         "libstorage_literals_headers",
     ],
     static_libs: [
+        "libfs_mgr",
         "libgtest",
         "libgmock",
     ],
@@ -170,6 +170,7 @@
         "android.hardware.boot@1.1",
         "libfs_mgr",
         "libgmock",
+        "libgsi",
         "liblp",
         "libsnapshot",
         "libsnapshot_test_helpers",
@@ -189,7 +190,6 @@
     static_libs: [
         "libdm",
         "libext2_uuid",
-        "libfiemap_binder",
         "libfstab",
         "libsnapshot",
     ],
@@ -200,7 +200,7 @@
         "libbinder",
         "libbinderthreadstate",
         "libext4_utils",
-        "libfs_mgr",
+        "libfs_mgr_binder",
         "libhidlbase",
         "liblog",
         "liblp",
diff --git a/fs_mgr/libsnapshot/OWNERS b/fs_mgr/libsnapshot/OWNERS
index 0cfa7e4..801c446 100644
--- a/fs_mgr/libsnapshot/OWNERS
+++ b/fs_mgr/libsnapshot/OWNERS
@@ -1,2 +1,3 @@
+balsini@google.com
 dvander@google.com
 elsk@google.com
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 445e6db..6e613ba 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -74,6 +74,12 @@
 
 bool SourceCopyOperationIsClone(const chromeos_update_engine::InstallOperation& operation);
 
+enum class CreateResult : unsigned int {
+    ERROR,
+    CREATED,
+    NOT_CREATED,
+};
+
 enum class UpdateState : unsigned int {
     // No update or merge is in progress.
     None,
@@ -110,8 +116,30 @@
     using MetadataBuilder = android::fs_mgr::MetadataBuilder;
     using DeltaArchiveManifest = chromeos_update_engine::DeltaArchiveManifest;
     using MergeStatus = android::hardware::boot::V1_1::MergeStatus;
+    using FiemapStatus = android::fiemap::FiemapStatus;
 
   public:
+    // SnapshotManager functions return either bool or Return objects. "Return" types provides
+    // more information about the reason of the failure.
+    class Return : public FiemapStatus {
+      public:
+        // Total required size on /userdata.
+        uint64_t required_size() const { return required_size_; }
+
+        static Return Ok() { return Return(FiemapStatus::ErrorCode::SUCCESS); }
+        static Return Error() { return Return(FiemapStatus::ErrorCode::ERROR); }
+        static Return NoSpace(uint64_t size) {
+            return Return(FiemapStatus::ErrorCode::NO_SPACE, size);
+        }
+        // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
+        explicit Return(const FiemapStatus& status) : Return(status.error_code()) {}
+
+      private:
+        uint64_t required_size_;
+        Return(FiemapStatus::ErrorCode code, uint64_t required_size = 0)
+            : FiemapStatus(code), required_size_(required_size) {}
+    };
+
     // Dependency injection for testing.
     class IDeviceInfo {
       public:
@@ -216,7 +244,7 @@
     // Create necessary COW device / files for OTA clients. New logical partitions will be added to
     // group "cow" in target_metadata. Regions of partitions of current_metadata will be
     // "write-protected" and snapshotted.
-    bool CreateUpdateSnapshots(const DeltaArchiveManifest& manifest);
+    Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest);
 
     // Map a snapshotted partition for OTA clients to write to. Write-protected regions are
     // determined previously in CreateSnapshots.
@@ -246,6 +274,17 @@
     // optional callback fires periodically to query progress via GetUpdateState.
     bool HandleImminentDataWipe(const std::function<void()>& callback = {});
 
+    // This method is only allowed in recovery and is used as a helper to
+    // initialize the snapshot devices as a requirement to mount a snapshotted
+    // /system in recovery.
+    // This function returns:
+    // - CreateResult::CREATED if snapshot devices were successfully created;
+    // - CreateResult::NOT_CREATED if it was not necessary to create snapshot
+    // devices;
+    // - CreateResult::ERROR if a fatal error occurred, mounting /system should
+    // be aborted.
+    CreateResult RecoveryCreateSnapshotDevices();
+
     // Dump debug information.
     bool Dump(std::ostream& os);
 
@@ -342,7 +381,7 @@
 
     // |name| should be the base partition name (e.g. "system_a"). Create the
     // backing COW image using the size previously passed to CreateSnapshot().
-    bool CreateCowImage(LockedFile* lock, const std::string& name);
+    Return CreateCowImage(LockedFile* lock, const std::string& name);
 
     // Map a snapshot device that was previously created with CreateSnapshot.
     // If a merge was previously initiated, the device-mapper table will have a
@@ -482,14 +521,14 @@
 
     // Helper for CreateUpdateSnapshots.
     // Creates all underlying images, COW partitions and snapshot files. Does not initialize them.
-    bool CreateUpdateSnapshotsInternal(LockedFile* lock, const DeltaArchiveManifest& manifest,
-                                       PartitionCowCreator* cow_creator,
-                                       AutoDeviceList* created_devices,
-                                       std::map<std::string, SnapshotStatus>* all_snapshot_status);
+    Return CreateUpdateSnapshotsInternal(
+            LockedFile* lock, const DeltaArchiveManifest& manifest,
+            PartitionCowCreator* cow_creator, AutoDeviceList* created_devices,
+            std::map<std::string, SnapshotStatus>* all_snapshot_status);
 
     // Initialize snapshots so that they can be mapped later.
     // Map the COW partition and zero-initialize the header.
-    bool InitializeUpdateSnapshots(
+    Return InitializeUpdateSnapshots(
             LockedFile* lock, MetadataBuilder* target_metadata,
             const LpMetadata* exported_target_metadata, const std::string& target_suffix,
             const std::map<std::string, SnapshotStatus>& all_snapshot_status);
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 2bf1b57..11de6ed 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -14,10 +14,12 @@
 
 #pragma once
 
+#include <memory>
 #include <optional>
 #include <string>
 #include <unordered_set>
 
+#include <android-base/file.h>
 #include <android/hardware/boot/1.1/IBootControl.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -155,5 +157,28 @@
 // Get partition size from update package metadata.
 uint64_t GetSize(PartitionUpdate* partition_update);
 
+// Util class for test cases on low space scenario. These tests assumes image manager
+// uses /data as backup device.
+class LowSpaceUserdata {
+  public:
+    // Set the maximum free space allowed for this test. If /userdata has more space than the given
+    // number, a file is allocated to consume space.
+    AssertionResult Init(uint64_t max_free_space);
+
+    uint64_t free_space() const;
+    uint64_t available_space() const;
+    uint64_t bsize() const;
+
+  private:
+    AssertionResult ReadUserdataStats();
+
+    static constexpr const char* kUserDataDevice = "/data";
+    std::unique_ptr<TemporaryFile> big_file_;
+    bool initialized_ = false;
+    uint64_t free_space_ = 0;
+    uint64_t available_space_ = 0;
+    uint64_t bsize_ = 0;
+};
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a0ec068..b79b65c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -54,6 +54,7 @@
 using android::dm::DmTargetSnapshot;
 using android::dm::kSectorSize;
 using android::dm::SnapshotStorageMode;
+using android::fiemap::FiemapStatus;
 using android::fiemap::IImageManager;
 using android::fs_mgr::CreateDmTable;
 using android::fs_mgr::CreateLogicalPartition;
@@ -289,14 +290,14 @@
     return true;
 }
 
-bool SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
+SnapshotManager::Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
     CHECK(lock);
     CHECK(lock->lock_mode() == LOCK_EX);
-    if (!EnsureImageManager()) return false;
+    if (!EnsureImageManager()) return Return::Error();
 
     SnapshotStatus status;
     if (!ReadSnapshotStatus(lock, name, &status)) {
-        return false;
+        return Return::Error();
     }
 
     // The COW file size should have been rounded up to the nearest sector in CreateSnapshot.
@@ -304,12 +305,12 @@
     if (status.cow_file_size() % kSectorSize != 0) {
         LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: "
                    << status.cow_file_size();
-        return false;
+        return Return::Error();
     }
 
     std::string cow_image_name = GetCowImageDeviceName(name);
     int cow_flags = IImageManager::CREATE_IMAGE_DEFAULT;
-    return images_->CreateBackingImage(cow_image_name, status.cow_file_size(), cow_flags);
+    return Return(images_->CreateBackingImage(cow_image_name, status.cow_file_size(), cow_flags));
 }
 
 bool SnapshotManager::MapSnapshot(LockedFile* lock, const std::string& name,
@@ -1844,9 +1845,23 @@
     }
 }
 
-bool SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) {
+static SnapshotManager::Return AddRequiredSpace(
+        SnapshotManager::Return orig,
+        const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
+    if (orig.error_code() != SnapshotManager::Return::ErrorCode::NO_SPACE) {
+        return orig;
+    }
+    uint64_t sum = 0;
+    for (auto&& [name, status] : all_snapshot_status) {
+        sum += status.cow_file_size();
+    }
+    return SnapshotManager::Return::NoSpace(sum);
+}
+
+SnapshotManager::Return SnapshotManager::CreateUpdateSnapshots(
+        const DeltaArchiveManifest& manifest) {
     auto lock = LockExclusive();
-    if (!lock) return false;
+    if (!lock) return Return::Error();
 
     // TODO(b/134949511): remove this check. Right now, with overlayfs mounted, the scratch
     // partition takes up a big chunk of space in super, causing COW images to be created on
@@ -1854,7 +1869,7 @@
     if (device_->IsOverlayfsSetup()) {
         LOG(ERROR) << "Cannot create update snapshots with overlayfs setup. Run `adb enable-verity`"
                    << ", reboot, then try again.";
-        return false;
+        return Return::Error();
     }
 
     const auto& opener = device_->GetPartitionOpener();
@@ -1879,7 +1894,7 @@
     SnapshotMetadataUpdater metadata_updater(target_metadata.get(), target_slot, manifest);
     if (!metadata_updater.Update()) {
         LOG(ERROR) << "Cannot calculate new metadata.";
-        return false;
+        return Return::Error();
     }
 
     // Delete previous COW partitions in current_metadata so that PartitionCowCreator marks those as
@@ -1911,36 +1926,34 @@
             .extra_extents = {},
     };
 
-    if (!CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
-                                       &all_snapshot_status)) {
-        return false;
-    }
+    auto ret = CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
+                                             &all_snapshot_status);
+    if (!ret.is_ok()) return ret;
 
     auto exported_target_metadata = target_metadata->Export();
     if (exported_target_metadata == nullptr) {
         LOG(ERROR) << "Cannot export target metadata";
-        return false;
+        return Return::Error();
     }
 
-    if (!InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
-                                   exported_target_metadata.get(), target_suffix,
-                                   all_snapshot_status)) {
-        return false;
-    }
+    ret = InitializeUpdateSnapshots(lock.get(), target_metadata.get(),
+                                    exported_target_metadata.get(), target_suffix,
+                                    all_snapshot_status);
+    if (!ret.is_ok()) return ret;
 
     if (!UpdatePartitionTable(opener, device_->GetSuperDevice(target_slot),
                               *exported_target_metadata, target_slot)) {
         LOG(ERROR) << "Cannot write target metadata";
-        return false;
+        return Return::Error();
     }
 
     created_devices.Release();
     LOG(INFO) << "Successfully created all snapshots for target slot " << target_suffix;
 
-    return true;
+    return Return::Ok();
 }
 
-bool SnapshotManager::CreateUpdateSnapshotsInternal(
+SnapshotManager::Return SnapshotManager::CreateUpdateSnapshotsInternal(
         LockedFile* lock, const DeltaArchiveManifest& manifest, PartitionCowCreator* cow_creator,
         AutoDeviceList* created_devices,
         std::map<std::string, SnapshotStatus>* all_snapshot_status) {
@@ -1951,7 +1964,7 @@
 
     if (!target_metadata->AddGroup(kCowGroupName, 0)) {
         LOG(ERROR) << "Cannot add group " << kCowGroupName;
-        return false;
+        return Return::Error();
     }
 
     std::map<std::string, const RepeatedPtrField<InstallOperation>*> install_operation_map;
@@ -1963,7 +1976,7 @@
         if (!inserted) {
             LOG(ERROR) << "Duplicated partition " << partition_update.partition_name()
                        << " in update manifest.";
-            return false;
+            return Return::Error();
         }
 
         auto& extra_extents = extra_extents_map[suffixed_name];
@@ -1992,7 +2005,7 @@
         // Compute the device sizes for the partition.
         auto cow_creator_ret = cow_creator->Run();
         if (!cow_creator_ret.has_value()) {
-            return false;
+            return Return::Error();
         }
 
         LOG(INFO) << "For partition " << target_partition->name()
@@ -2006,7 +2019,7 @@
         if (!DeleteSnapshot(lock, target_partition->name())) {
             LOG(ERROR) << "Cannot delete existing snapshot before creating a new one for partition "
                        << target_partition->name();
-            return false;
+            return Return::Error();
         }
 
         // It is possible that the whole partition uses free space in super, and snapshot / COW
@@ -2024,7 +2037,7 @@
 
         // Store these device sizes to snapshot status file.
         if (!CreateSnapshot(lock, &cow_creator_ret->snapshot_status)) {
-            return false;
+            return Return::Error();
         }
         created_devices->EmplaceBack<AutoDeleteSnapshot>(this, lock, target_partition->name());
 
@@ -2038,7 +2051,7 @@
             auto cow_partition = target_metadata->AddPartition(GetCowName(target_partition->name()),
                                                                kCowGroupName, 0 /* flags */);
             if (cow_partition == nullptr) {
-                return false;
+                return Return::Error();
             }
 
             if (!target_metadata->ResizePartition(
@@ -2046,28 +2059,34 @@
                         cow_creator_ret->cow_partition_usable_regions)) {
                 LOG(ERROR) << "Cannot create COW partition on metadata with size "
                            << cow_creator_ret->snapshot_status.cow_partition_size();
-                return false;
+                return Return::Error();
             }
             // Only the in-memory target_metadata is modified; nothing to clean up if there is an
             // error in the future.
         }
 
-        // Create the backing COW image if necessary.
-        if (cow_creator_ret->snapshot_status.cow_file_size() > 0) {
-            if (!CreateCowImage(lock, target_partition->name())) {
-                return false;
-            }
-        }
-
         all_snapshot_status->emplace(target_partition->name(),
                                      std::move(cow_creator_ret->snapshot_status));
 
-        LOG(INFO) << "Successfully created snapshot for " << target_partition->name();
+        LOG(INFO) << "Successfully created snapshot partition for " << target_partition->name();
     }
-    return true;
+
+    LOG(INFO) << "Allocating CoW images.";
+
+    for (auto&& [name, snapshot_status] : *all_snapshot_status) {
+        // Create the backing COW image if necessary.
+        if (snapshot_status.cow_file_size() > 0) {
+            auto ret = CreateCowImage(lock, name);
+            if (!ret.is_ok()) return AddRequiredSpace(ret, *all_snapshot_status);
+        }
+
+        LOG(INFO) << "Successfully created snapshot for " << name;
+    }
+
+    return Return::Ok();
 }
 
-bool SnapshotManager::InitializeUpdateSnapshots(
+SnapshotManager::Return SnapshotManager::InitializeUpdateSnapshots(
         LockedFile* lock, MetadataBuilder* target_metadata,
         const LpMetadata* exported_target_metadata, const std::string& target_suffix,
         const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
@@ -2086,7 +2105,7 @@
         if (!UnmapPartitionWithSnapshot(lock, target_partition->name())) {
             LOG(ERROR) << "Cannot unmap existing COW devices before re-mapping them for zero-fill: "
                        << target_partition->name();
-            return false;
+            return Return::Error();
         }
 
         auto it = all_snapshot_status.find(target_partition->name());
@@ -2094,23 +2113,24 @@
         cow_params.partition_name = target_partition->name();
         std::string cow_name;
         if (!MapCowDevices(lock, cow_params, it->second, &created_devices_for_cow, &cow_name)) {
-            return false;
+            return Return::Error();
         }
 
         std::string cow_path;
         if (!dm.GetDmDevicePathByName(cow_name, &cow_path)) {
             LOG(ERROR) << "Cannot determine path for " << cow_name;
-            return false;
+            return Return::Error();
         }
 
-        if (!InitializeCow(cow_path)) {
+        auto ret = InitializeCow(cow_path);
+        if (!ret.is_ok()) {
             LOG(ERROR) << "Can't zero-fill COW device for " << target_partition->name() << ": "
                        << cow_path;
-            return false;
+            return AddRequiredSpace(ret, all_snapshot_status);
         }
         // Let destructor of created_devices_for_cow to unmap the COW devices.
     };
-    return true;
+    return Return::Ok();
 }
 
 bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
@@ -2356,5 +2376,37 @@
     return true;
 }
 
+CreateResult SnapshotManager::RecoveryCreateSnapshotDevices() {
+    if (!device_->IsRecovery()) {
+        LOG(ERROR) << __func__ << " is only allowed in recovery.";
+        return CreateResult::NOT_CREATED;
+    }
+
+    auto mount = EnsureMetadataMounted();
+    if (!mount || !mount->HasDevice()) {
+        LOG(ERROR) << "Couldn't mount Metadata.";
+        return CreateResult::NOT_CREATED;
+    }
+
+    auto state_file = GetStateFilePath();
+    if (access(state_file.c_str(), F_OK) != 0 && errno == ENOENT) {
+        LOG(ERROR) << "Couldn't access state file.";
+        return CreateResult::NOT_CREATED;
+    }
+
+    if (!NeedSnapshotsInFirstStageMount()) {
+        return CreateResult::NOT_CREATED;
+    }
+
+    auto slot_suffix = device_->GetOtherSlotSuffix();
+    auto slot_number = SlotNumberForSlotSuffix(slot_suffix);
+    auto super_path = device_->GetSuperDevice(slot_number);
+    if (!CreateLogicalAndSnapshotPartitions(super_path)) {
+        LOG(ERROR) << "Unable to map partitions.";
+        return CreateResult::ERROR;
+    }
+    return CreateResult::CREATED;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 0f5af14..cea9d69 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -47,6 +47,7 @@
 using android::base::unique_fd;
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
+using android::fiemap::FiemapStatus;
 using android::fiemap::IImageManager;
 using android::fs_mgr::BlockDeviceInfo;
 using android::fs_mgr::CreateLogicalPartitionParams;
@@ -606,17 +607,17 @@
 std::ostream& operator<<(std::ostream& os, Request request) {
     switch (request) {
         case Request::LOCK_SHARED:
-            return os << "LOCK_SHARED";
+            return os << "Shared";
         case Request::LOCK_EXCLUSIVE:
-            return os << "LOCK_EXCLUSIVE";
+            return os << "Exclusive";
         case Request::UNLOCK:
-            return os << "UNLOCK";
+            return os << "Unlock";
         case Request::EXIT:
-            return os << "EXIT";
+            return os << "Exit";
         case Request::UNKNOWN:
             [[fallthrough]];
         default:
-            return os << "UNKNOWN";
+            return os << "Unknown";
     }
 }
 
@@ -746,7 +747,7 @@
                         LockTestParam{Request::LOCK_SHARED, Request::LOCK_EXCLUSIVE}),
         [](const testing::TestParamInfo<LockTestP::ParamType>& info) {
             std::stringstream ss;
-            ss << info.param.first << "_" << info.param.second;
+            ss << info.param.first << info.param.second;
             return ss.str();
         });
 
@@ -1585,6 +1586,29 @@
     ASSERT_THAT(merger.get(), AnyOf(UpdateState::None, UpdateState::MergeCompleted));
 }
 
+TEST_F(SnapshotUpdateTest, LowSpace) {
+    static constexpr auto kMaxFree = 10_MiB;
+    auto userdata = std::make_unique<LowSpaceUserdata>();
+    ASSERT_TRUE(userdata->Init(kMaxFree));
+
+    // Grow all partitions to 5_MiB, total 15_MiB. This requires 15 MiB of CoW space. After
+    // using the empty space in super (< 1 MiB), it uses at least 14 MiB of /userdata space.
+    constexpr uint64_t partition_size = 5_MiB;
+    SetSize(sys_, partition_size);
+    SetSize(vnd_, partition_size);
+    SetSize(prd_, partition_size);
+
+    AddOperationForPartitions();
+
+    // Execute the update.
+    ASSERT_TRUE(sm->BeginUpdate());
+    auto res = sm->CreateUpdateSnapshots(manifest_);
+    ASSERT_FALSE(res);
+    ASSERT_EQ(SnapshotManager::Return::ErrorCode::NO_SPACE, res.error_code());
+    ASSERT_GE(res.required_size(), 14_MiB);
+    ASSERT_LT(res.required_size(), 15_MiB);
+}
+
 class FlashAfterUpdateTest : public SnapshotUpdateTest,
                              public WithParamInterface<std::tuple<uint32_t, bool>> {
   public:
@@ -1700,6 +1724,55 @@
                                     "Merge"s;
                          });
 
+// Test behavior of ImageManager::Create on low space scenario. These tests assumes image manager
+// uses /data as backup device.
+class ImageManagerTest : public SnapshotTest, public WithParamInterface<uint64_t> {
+  public:
+    void SetUp() override {
+        SnapshotTest::SetUp();
+        userdata_ = std::make_unique<LowSpaceUserdata>();
+        ASSERT_TRUE(userdata_->Init(GetParam()));
+    }
+    void TearDown() override {
+        EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
+                    image_manager_->DeleteBackingImage(kImageName));
+    }
+    static constexpr const char* kImageName = "my_image";
+    std::unique_ptr<LowSpaceUserdata> userdata_;
+};
+
+TEST_P(ImageManagerTest, CreateImageEnoughAvailSpace) {
+    if (userdata_->available_space() == 0) {
+        GTEST_SKIP() << "/data is full (" << userdata_->available_space()
+                     << " bytes available), skipping";
+    }
+    ASSERT_TRUE(image_manager_->CreateBackingImage(kImageName, userdata_->available_space(),
+                                                   IImageManager::CREATE_IMAGE_DEFAULT))
+            << "Should be able to create image with size = " << userdata_->available_space()
+            << " bytes";
+    ASSERT_TRUE(image_manager_->DeleteBackingImage(kImageName))
+            << "Should be able to delete created image";
+}
+
+TEST_P(ImageManagerTest, CreateImageNoSpace) {
+    uint64_t to_allocate = userdata_->free_space() + userdata_->bsize();
+    auto res = image_manager_->CreateBackingImage(kImageName, to_allocate,
+                                                  IImageManager::CREATE_IMAGE_DEFAULT);
+    ASSERT_FALSE(res) << "Should not be able to create image with size = " << to_allocate
+                      << " bytes because only " << userdata_->free_space() << " bytes are free";
+    ASSERT_EQ(FiemapStatus::ErrorCode::NO_SPACE, res.error_code()) << res.string();
+}
+
+std::vector<uint64_t> ImageManagerTestParams() {
+    std::vector<uint64_t> ret;
+    for (uint64_t size = 1_MiB; size <= 512_MiB; size *= 2) {
+        ret.push_back(size);
+    }
+    return ret;
+}
+
+INSTANTIATE_TEST_SUITE_P(ImageManagerTest, ImageManagerTest, ValuesIn(ImageManagerTestParams()));
+
 }  // namespace snapshot
 }  // namespace android
 
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index f7f25af..b036606 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -14,8 +14,11 @@
 
 #include <libsnapshot/test_helpers.h>
 
+#include <sys/statvfs.h>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
 #include <openssl/sha.h>
@@ -167,5 +170,67 @@
     return partition_update->mutable_new_partition_info()->size();
 }
 
+AssertionResult LowSpaceUserdata::Init(uint64_t max_free_space) {
+    auto res = ReadUserdataStats();
+    if (!res) return res;
+
+    // Try to fill up the disk as much as possible until free_space_ <= max_free_space.
+    big_file_ = std::make_unique<TemporaryFile>();
+    if (big_file_->fd == -1) {
+        return AssertionFailure() << strerror(errno);
+    }
+    if (!android::base::StartsWith(big_file_->path, kUserDataDevice)) {
+        return AssertionFailure() << "Temp file allocated to " << big_file_->path << ", not in "
+                                  << kUserDataDevice;
+    }
+    uint64_t next_consume =
+            std::min(free_space_ - max_free_space, (uint64_t)std::numeric_limits<off_t>::max());
+    off_t allocated = 0;
+    while (next_consume > 0 && free_space_ > max_free_space) {
+        int status = fallocate(big_file_->fd, 0, allocated, next_consume);
+        if (status == -1 && errno == ENOSPC) {
+            next_consume /= 2;
+            continue;
+        }
+        if (status == -1) {
+            return AssertionFailure() << strerror(errno);
+        }
+        allocated += next_consume;
+
+        res = ReadUserdataStats();
+        if (!res) return res;
+    }
+
+    LOG(INFO) << allocated << " bytes allocated to " << big_file_->path;
+    initialized_ = true;
+    return AssertionSuccess();
+}
+
+AssertionResult LowSpaceUserdata::ReadUserdataStats() {
+    struct statvfs buf;
+    if (statvfs(kUserDataDevice, &buf) == -1) {
+        return AssertionFailure() << strerror(errno);
+    }
+    bsize_ = buf.f_bsize;
+    free_space_ = buf.f_bsize * buf.f_bfree;
+    available_space_ = buf.f_bsize * buf.f_bavail;
+    return AssertionSuccess();
+}
+
+uint64_t LowSpaceUserdata::free_space() const {
+    CHECK(initialized_);
+    return free_space_;
+}
+
+uint64_t LowSpaceUserdata::available_space() const {
+    CHECK(initialized_);
+    return available_space_;
+}
+
+uint64_t LowSpaceUserdata::bsize() const {
+    CHECK(initialized_);
+    return bsize_;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index fa1d7f0..f01500f 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -14,12 +14,15 @@
 
 #include "utility.h"
 
+#include <errno.h>
+
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <fs_mgr/roots.h>
 
 using android::dm::kSectorSize;
+using android::fiemap::FiemapStatus;
 using android::fs_mgr::EnsurePathMounted;
 using android::fs_mgr::EnsurePathUnmounted;
 using android::fs_mgr::Fstab;
@@ -83,7 +86,9 @@
     }
 }
 
-bool InitializeCow(const std::string& device) {
+SnapshotManager::Return InitializeCow(const std::string& device) {
+    using Return = SnapshotManager::Return;
+
     // When the kernel creates a persistent dm-snapshot, it requires a CoW file
     // to store the modifications. The kernel interface does not specify how
     // the CoW is used, and there is no standard associated.
@@ -103,15 +108,15 @@
     android::base::unique_fd fd(open(device.c_str(), O_WRONLY | O_BINARY));
     if (fd < 0) {
         PLOG(ERROR) << "Can't open COW device: " << device;
-        return false;
+        return Return(FiemapStatus::FromErrno(errno));
     }
 
     LOG(INFO) << "Zero-filling COW device: " << device;
     if (!android::base::WriteFully(fd, zeros.data(), kDmSnapZeroFillSize)) {
         PLOG(ERROR) << "Can't zero-fill COW device for " << device;
-        return false;
+        return Return(FiemapStatus::FromErrno(errno));
     }
-    return true;
+    return Return::Ok();
 }
 
 std::unique_ptr<AutoUnmountDevice> AutoUnmountDevice::New(const std::string& path) {
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 5cc572e..0453256 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -26,6 +26,7 @@
 #include <update_engine/update_metadata.pb.h>
 
 #include <libsnapshot/auto_device.h>
+#include <libsnapshot/snapshot.h>
 
 namespace android {
 namespace snapshot {
@@ -110,7 +111,7 @@
         android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
 
 // Initialize a device before using it as the COW device for a dm-snapshot device.
-bool InitializeCow(const std::string& device);
+SnapshotManager::Return InitializeCow(const std::string& device);
 
 // "Atomically" write string to file. This is done by a series of actions:
 // 1. Write to path + ".tmp"
diff --git a/fs_mgr/tests/AndroidTest.xml b/fs_mgr/tests/AndroidTest.xml
index 91c3fb9..0ff8995 100644
--- a/fs_mgr/tests/AndroidTest.xml
+++ b/fs_mgr/tests/AndroidTest.xml
@@ -15,6 +15,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsFsMgrTestCases->/data/local/tmp/CtsFsMgrTestCases" />
diff --git a/init/AndroidTest.xml b/init/AndroidTest.xml
index 667911d..920dc6c 100644
--- a/init/AndroidTest.xml
+++ b/init/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsInitTestCases->/data/local/tmp/CtsInitTestCases" />
diff --git a/init/README.md b/init/README.md
index b8300fa..4f0a7ec 100644
--- a/init/README.md
+++ b/init/README.md
@@ -487,6 +487,25 @@
   -f: force installation of the module even if the version of the running kernel
   and the version of the kernel for which the module was compiled do not match.
 
+`interface_start <name>` \
+`interface_restart <name>` \
+`interface_stop <name>`
+> Find the service that provides the interface _name_ if it exists and run the `start`, `restart`,
+or `stop` commands on it respectively.  _name_ may be either a fully qualified HIDL name, in which
+case it is specified as `<interface>/<instance>`, or an AIDL name, in which case it is specified as
+`aidl/<interface>` for example `android.hardware.secure_element@1.1::ISecureElement/eSE1` or
+`aidl/aidl_lazy_test_1`.
+
+> Note that these commands only act on interfaces specified by the `interface` service option, not
+on interfaces registered at runtime.
+
+> Example usage of these commands: \
+`interface_start android.hardware.secure_element@1.1::ISecureElement/eSE1`
+will start the HIDL Service that provides the `android.hardware.secure_element@1.1` and `eSI1`
+instance. \
+`interface_start aidl/aidl_lazy_test_1` will start the AIDL service that
+provides the `aidl_lazy_test_1` interface.
+
 `load_system_props`
 > (This action is deprecated and no-op.)
 
@@ -700,6 +719,26 @@
   `/sys/fs/ext4/${dev.mnt.blk.<mount_point>}/` to tune the block device
   characteristics in a device agnostic manner.
 
+Init responds to properties that begin with `ctl.`.  These properties take the format of
+`ctl.<command>` and the _value_ of the system property is used as a parameter, for example:
+`SetProperty("ctl.start", "logd")` will run the `start` command on `logd`.  Note that these
+properties are only settable; they will have no value when read.
+
+`ctl.start` \
+`ctl.restart` \
+`ctl.stop`
+> These are equivalent to using the `start`, `restart`, and `stop` commands on the service specified
+by the _value_ of the property.
+
+`ctl.interface_start` \
+`ctl.interface_restart` \
+`ctl.interface_stop`
+> These are equivalent to using the `interface_start`, `interface_restart`, and `interface_stop`
+commands on the interface specified by the _value_ of the property.
+
+`ctl.sigstop_on` and `ctl.sigstop_off` will turn on or off the _sigstop_ feature for the service
+specified by the _value_ of the property.  See the _Debugging init_ section below for more details
+about this feature.
 
 Boot timing
 -----------
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 62a19ab..2a6df84 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -59,6 +59,8 @@
 #include <fs_mgr.h>
 #include <fscrypt/fscrypt.h>
 #include <libgsi/libgsi.h>
+#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
 #include <selinux/android.h>
 #include <selinux/label.h>
 #include <selinux/selinux.h>
@@ -1176,6 +1178,37 @@
     return {};
 }
 
+static Result<void> GenerateLinkerConfiguration() {
+    const char* linkerconfig_binary = "/system/bin/linkerconfig";
+    const char* linkerconfig_target = "/linkerconfig";
+    const char* arguments[] = {linkerconfig_binary, "--target", linkerconfig_target};
+
+    if (logwrap_fork_execvp(arraysize(arguments), arguments, nullptr, false, LOG_KLOG, false,
+                            nullptr) != 0) {
+        return ErrnoError() << "failed to execute linkerconfig";
+    }
+
+    LOG(INFO) << "linkerconfig generated " << linkerconfig_target
+              << " with mounted APEX modules info";
+
+    return {};
+}
+
+static bool IsApexUpdatable() {
+    static bool updatable = android::sysprop::ApexProperties::updatable().value_or(false);
+    return updatable;
+}
+
+static Result<void> do_update_linker_config(const BuiltinArguments&) {
+    // If APEX is not updatable, then all APEX information are already included in the first
+    // linker config generation, so there is no need to update linker configuration again.
+    if (IsApexUpdatable()) {
+        return GenerateLinkerConfiguration();
+    }
+
+    return {};
+}
+
 static Result<void> parse_apex_configs() {
     glob_t glob_result;
     static constexpr char glob_pattern[] = "/apex/*/etc/*.rc";
@@ -1234,9 +1267,7 @@
         if (strchr(name, '@') != nullptr) continue;
 
         auto path = "/data/misc/apexdata/" + std::string(name);
-        auto system_uid = DecodeUid("system");
-        auto options =
-                MkdirOptions{path, 0700, *system_uid, *system_uid, FscryptAction::kNone, "ref"};
+        auto options = MkdirOptions{path, 0770, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
         make_dir_with_options(options);
     }
     return {};
@@ -1251,6 +1282,12 @@
     if (!parse_configs) {
         return parse_configs.error();
     }
+
+    auto update_linker_config = do_update_linker_config(args);
+    if (!update_linker_config) {
+        return update_linker_config.error();
+    }
+
     return {};
 }
 
@@ -1317,6 +1354,7 @@
         {"perform_apex_config",     {0,     0,    {false,  do_perform_apex_config}}},
         {"umount",                  {1,     1,    {false,  do_umount}}},
         {"umount_all",              {1,     1,    {false,  do_umount_all}}},
+        {"update_linker_config",    {0,     0,    {false,  do_update_linker_config}}},
         {"readahead",               {1,     2,    {true,   do_readahead}}},
         {"remount_userdata",        {0,     0,    {false,  do_remount_userdata}}},
         {"restart",                 {1,     1,    {false,  do_restart}}},
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 9121bac..6d1259d 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -34,6 +34,7 @@
 #include <fs_mgr.h>
 #include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
+#include <libfiemap/image_manager.h>
 #include <libgsi/libgsi.h>
 #include <liblp/liblp.h>
 #include <libsnapshot/snapshot.h>
@@ -46,6 +47,7 @@
 
 using android::base::Split;
 using android::base::Timer;
+using android::fiemap::IImageManager;
 using android::fs_mgr::AvbHandle;
 using android::fs_mgr::AvbHandleStatus;
 using android::fs_mgr::AvbHashtreeResult;
@@ -93,7 +95,7 @@
     bool IsDmLinearEnabled();
     void GetDmLinearMetadataDevice(std::set<std::string>* devices);
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
-    void UseGsiIfPresent();
+    void UseDsuIfPresent();
 
     ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
 
@@ -102,7 +104,7 @@
     virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
 
     bool need_dm_verity_;
-    bool gsi_not_on_userdata_ = false;
+    bool dsu_not_on_userdata_ = false;
 
     Fstab fstab_;
     std::string lp_metadata_partition_;
@@ -511,7 +513,7 @@
 // this case, we mount system first then pivot to it.  From that point on,
 // we are effectively identical to a system-as-root device.
 bool FirstStageMount::TrySwitchSystemAsRoot() {
-    UseGsiIfPresent();
+    UseDsuIfPresent();
 
     auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
         return entry.mount_point == "/system";
@@ -520,7 +522,7 @@
     if (system_partition == fstab_.end()) return true;
 
     if (MountPartition(system_partition, false /* erase_same_mounts */)) {
-        if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
+        if (dsu_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
             LOG(ERROR) << "check_most_at_once forbidden on external media";
             return false;
         }
@@ -556,6 +558,14 @@
             continue;
         }
 
+        // Skip raw partition entries such as boot, dtbo, etc.
+        // Having emmc fstab entries allows us to probe current->vbmeta_partition
+        // in InitDevices() when they are AVB chained partitions.
+        if (current->fs_type == "emmc") {
+            ++current;
+            continue;
+        }
+
         Fstab::iterator end;
         if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
             if (current->fs_mgr_flags.no_fail) {
@@ -596,49 +606,40 @@
     return true;
 }
 
-void FirstStageMount::UseGsiIfPresent() {
+void FirstStageMount::UseDsuIfPresent() {
     std::string error;
 
     if (!android::gsi::CanBootIntoGsi(&error)) {
-        LOG(INFO) << "GSI " << error << ", proceeding with normal boot";
+        LOG(INFO) << "DSU " << error << ", proceeding with normal boot";
         return;
     }
 
-    auto metadata = android::fs_mgr::ReadFromImageFile(gsi::kDsuLpMetadataFile);
-    if (!metadata) {
-        LOG(ERROR) << "GSI partition layout could not be read";
-        return;
-    }
-
-    if (!InitDmLinearBackingDevices(*metadata.get())) {
-        return;
-    }
-
-    // Find the super name. PartitionOpener will ensure this translates to the
-    // correct block device path.
-    auto super = GetMetadataSuperBlockDevice(*metadata.get());
-    auto super_name = android::fs_mgr::GetBlockDevicePartitionName(*super);
-    if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_name)) {
-        LOG(ERROR) << "GSI partition layout could not be instantiated";
+    auto init_devices = [this](std::set<std::string> devices) -> bool {
+        if (devices.count("userdata") == 0 || devices.size() > 1) {
+            dsu_not_on_userdata_ = true;
+        }
+        return InitRequiredDevices(std::move(devices));
+    };
+    auto images = IImageManager::Open("dsu", 0ms);
+    if (!images || !images->MapAllImages(init_devices)) {
+        LOG(ERROR) << "DSU partition layout could not be instantiated";
         return;
     }
 
     if (!android::gsi::MarkSystemAsGsi()) {
-        PLOG(ERROR) << "GSI indicator file could not be written";
+        PLOG(ERROR) << "DSU indicator file could not be written";
         return;
     }
 
     std::string lp_names = "";
     std::vector<std::string> dsu_partitions;
-    for (auto&& partition : metadata->partitions) {
-        auto name = fs_mgr::GetPartitionName(partition);
+    for (auto&& name : images->GetAllBackingImages()) {
         dsu_partitions.push_back(name);
         lp_names += name + ",";
     }
     // Publish the logical partition names for TransformFstabForDsu
     WriteFile(gsi::kGsiLpNamesFile, lp_names);
     TransformFstabForDsu(&fstab_, dsu_partitions);
-    gsi_not_on_userdata_ = (super_name != "userdata");
 }
 
 bool FirstStageMountVBootV1::GetDmVerityDevices(std::set<std::string>* devices) {
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 648b3bb..b811622 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -35,6 +35,19 @@
 namespace init {
 namespace {
 
+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) << "Failed to bind mount " << source;
+        return false;
+    }
+    return true;
+}
+
 static bool MakeShared(const std::string& mount_point, bool recursive = false) {
     unsigned long mountflags = MS_SHARED;
     if (recursive) {
@@ -47,6 +60,18 @@
     return true;
 }
 
+static bool MakeSlave(const std::string& mount_point, bool recursive = false) {
+    unsigned long mountflags = MS_SLAVE;
+    if (recursive) {
+        mountflags |= MS_REC;
+    }
+    if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) {
+        PLOG(ERROR) << "Failed to change propagation type to slave";
+        return false;
+    }
+    return true;
+}
+
 static bool MakePrivate(const std::string& mount_point, bool recursive = false) {
     unsigned long mountflags = MS_PRIVATE;
     if (recursive) {
@@ -151,6 +176,20 @@
     return true;
 }
 
+static Result<void> MountLinkerConfigForDefaultNamespace() {
+    // No need to mount linkerconfig for default mount namespace if the path does not exist (which
+    // would mean it is already mounted)
+    if (access("/linkerconfig/default", 0) != 0) {
+        return {};
+    }
+
+    if (mount("/linkerconfig/default", "/linkerconfig", nullptr, MS_BIND | MS_REC, nullptr) != 0) {
+        return ErrnoError() << "Failed to mount linker configuration for default mount namespace.";
+    }
+
+    return {};
+}
+
 static android::base::unique_fd bootstrap_ns_fd;
 static android::base::unique_fd default_ns_fd;
 
@@ -177,6 +216,39 @@
     // namespace
     if (!(MakePrivate("/linkerconfig"))) return false;
 
+    // The two mount namespaces present challenges for scoped storage, because
+    // vold, which is responsible for most of the mounting, lives in the
+    // bootstrap mount namespace, whereas most other daemons and all apps live
+    // in the default namespace.  Scoped storage has a need for a
+    // /mnt/installer view that is a slave bind mount of /mnt/user - in other
+    // words, all mounts under /mnt/user should automatically show up under
+    // /mnt/installer. However, additional mounts done under /mnt/installer
+    // should not propagate back to /mnt/user. In a single mount namespace
+    // this is easy to achieve, by simply marking the /mnt/installer a slave
+    // bind mount. Unfortunately, if /mnt/installer is only created and
+    // bind mounted after the two namespaces are created below, we end up
+    // with the following situation:
+    // /mnt/user and /mnt/installer share the same peer group in both the
+    // bootstrap and default namespaces. Marking /mnt/installer slave in either
+    // namespace means that it won't propagate events to the /mnt/installer in
+    // the other namespace, which is still something we require - vold is the
+    // one doing the mounting under /mnt/installer, and those mounts should
+    // show up in the default namespace as well.
+    //
+    // The simplest solution is to do the bind mount before the two namespaces
+    // are created: the effect is that in both namespaces, /mnt/installer is a
+    // slave to the /mnt/user mount, and at the same time /mnt/installer in the
+    // bootstrap namespace shares a peer group with /mnt/installer in the
+    // default namespace.
+    if (!mkdir_recursive("/mnt/user", 0755)) return false;
+    if (!mkdir_recursive("/mnt/installer", 0755)) return false;
+    if (!(BindMount("/mnt/user", "/mnt/installer", true))) return false;
+    // First, make /mnt/installer a slave bind mount
+    if (!(MakeSlave("/mnt/installer"))) return false;
+    // Then, make it shared again - effectively creating a new peer group, that
+    // will be inherited by new mount namespaces.
+    if (!(MakeShared("/mnt/installer"))) return false;
+
     bootstrap_ns_fd.reset(OpenMountNamespace());
     bootstrap_ns_id = GetMountNamespaceId();
 
@@ -222,6 +294,11 @@
             PLOG(ERROR) << "Failed to switch back to the default mount namespace.";
             return false;
         }
+
+        if (auto result = MountLinkerConfigForDefaultNamespace(); !result) {
+            LOG(ERROR) << result.error();
+            return false;
+        }
     }
 
     LOG(INFO) << "Switched to default mount namespace";
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 0e61234..4ee7188 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -834,6 +834,10 @@
 }
 
 static void HandleUserspaceReboot() {
+    if (!android::sysprop::InitProperties::is_userspace_reboot_supported().value_or(false)) {
+        LOG(ERROR) << "Attempted a userspace reboot on a device that doesn't support it";
+        return;
+    }
     // Spinnig up a separate thread will fail the setns call later in the boot sequence.
     // Fork a new process to monitor userspace reboot while we are investigating a better solution.
     pid_t pid = fork();
@@ -856,6 +860,30 @@
     am.QueueBuiltinAction(handler, "userspace-reboot");
 }
 
+/**
+ * Check if "command" field is set in bootloader message.
+ *
+ * If "command" field is broken (contains non-printable characters prior to
+ * terminating zero), it will be zeroed.
+ *
+ * @param[in,out] boot Bootloader message (BCB) structure
+ * @return true if "command" field is already set, and false if it's empty
+ */
+static bool CommandIsPresent(bootloader_message* boot) {
+    if (boot->command[0] == '\0')
+        return false;
+
+    for (size_t i = 0; i < arraysize(boot->command); ++i) {
+        if (boot->command[i] == '\0')
+            return true;
+        if (!isprint(boot->command[i]))
+            break;
+    }
+
+    memset(boot->command, 0, sizeof(boot->command));
+    return false;
+}
+
 void HandlePowerctlMessage(const std::string& command) {
     unsigned int cmd = 0;
     std::vector<std::string> cmd_params = Split(command, ",");
@@ -908,7 +936,7 @@
                 }
                 // Update the boot command field if it's empty, and preserve
                 // the other arguments in the bootloader message.
-                if (boot.command[0] == '\0') {
+                if (!CommandIsPresent(&boot)) {
                     strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
                     if (std::string err; !write_bootloader_message(boot, &err)) {
                         LOG(ERROR) << "Failed to set bootloader message: " << err;
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index dac0cf4..485188b 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -34,12 +34,16 @@
 namespace init {
 
 static std::string init_fatal_reboot_target = "bootloader";
+static bool init_fatal_panic = false;
 
 void SetFatalRebootTarget() {
     std::string cmdline;
     android::base::ReadFileToString("/proc/cmdline", &cmdline);
     cmdline = android::base::Trim(cmdline);
 
+    const char kInitFatalPanicString[] = "androidboot.init_fatal_panic=true";
+    init_fatal_panic = cmdline.find(kInitFatalPanicString) != std::string::npos;
+
     const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target=";
     auto start_pos = cmdline.find(kRebootTargetString);
     if (start_pos == std::string::npos) {
@@ -133,6 +137,9 @@
     for (size_t i = 0; i < backtrace->NumFrames(); i++) {
         LOG(ERROR) << backtrace->FormatFrameData(i);
     }
+    if (init_fatal_panic) {
+        _exit(signal_number);
+    }
     RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target);
 }
 
diff --git a/init/service.cpp b/init/service.cpp
index a97935e..0e27ff1 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -325,8 +325,8 @@
                     LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times "
                                << (boot_completed ? "in 4 minutes" : "before boot completed");
                     // Notifies update_verifier and apexd
-                    SetProperty("sys.init.updatable_crashing", "1");
                     SetProperty("sys.init.updatable_crashing_process_name", name_);
+                    SetProperty("sys.init.updatable_crashing", "1");
                 }
             }
         } else {
diff --git a/init/sysprop/InitProperties.sysprop b/init/sysprop/InitProperties.sysprop
index d6a1ab6..c856358 100644
--- a/init/sysprop/InitProperties.sysprop
+++ b/init/sysprop/InitProperties.sysprop
@@ -25,3 +25,12 @@
     integer_as_bool: true
 }
 
+# Shows whenever the device supports userspace reboot or not.
+prop {
+    api_name: "is_userspace_reboot_supported"
+    type: Boolean
+    scope: System
+    access: Readonly
+    prop_name: "ro.init.userspace_reboot.is_supported"
+    integer_as_bool: true
+}
diff --git a/init/sysprop/api/com.android.sysprop.init-current.txt b/init/sysprop/api/com.android.sysprop.init-current.txt
index 8da50e0..b8bcef9 100644
--- a/init/sysprop/api/com.android.sysprop.init-current.txt
+++ b/init/sysprop/api/com.android.sysprop.init-current.txt
@@ -1,6 +1,11 @@
 props {
   module: "android.sysprop.InitProperties"
   prop {
+    api_name: "is_userspace_reboot_supported"
+    prop_name: "ro.init.userspace_reboot.is_supported"
+    integer_as_bool: true
+  }
+  prop {
     api_name: "userspace_reboot_in_progress"
     access: ReadWrite
     prop_name: "sys.init.userspace_reboot.in_progress"
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 2b39ca6..65c59bd 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -86,6 +86,7 @@
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/apex/*/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system_ext/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system_ext/apex/*/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
@@ -195,10 +196,6 @@
     { 00750, AID_ROOT,      AID_SHELL,     CAP_MASK_LONG(CAP_SETUID) |
                                            CAP_MASK_LONG(CAP_SETGID),
                                               "system/bin/simpleperf_app_runner" },
-
-    // Support FIFO scheduling mode in SurfaceFlinger.
-    { 00755, AID_SYSTEM,    AID_GRAPHICS,  CAP_MASK_LONG(CAP_SYS_NICE),
-                                              "system/bin/surfaceflinger" },
     // generic defaults
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
@@ -209,6 +206,7 @@
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/*/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system_ext/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system_ext/apex/*/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index 79b4b35..e12c32c 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -25,7 +25,6 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 #include <unistd.h>
-
 #include <cutils/compiler.h>
 
 __BEGIN_DECLS
@@ -89,6 +88,12 @@
 #error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h
 #endif
 
+// Set this to 0 to revert to the old Binder-based atrace implementation.
+// This is only here in case rollbacks do not apply cleanly.
+// TODO(fmayer): Remove this once we are confident this won't need to be
+// rolled back, no later than 2020-03-01.
+#define ATRACE_SHMEM 1
+
 /**
  * Opens the trace file for writing and reads the property for initial tags.
  * The atrace.tags.enableflags property sets the tags to trace.
@@ -116,11 +121,15 @@
  * prevent tracing within the Zygote process.
  */
 void atrace_set_tracing_enabled(bool enabled);
-
 /**
- * Flag indicating whether setup has been completed, initialized to 0.
- * Nonzero indicates setup has completed.
- * Note: This does NOT indicate whether or not setup was successful.
+ * If !ATRACE_SHMEM:
+ *   Flag indicating whether setup has been completed, initialized to 0.
+ *   Nonzero indicates setup has completed.
+ *   Note: This does NOT indicate whether or not setup was successful.
+ * If ATRACE_SHMEM:
+ *   This is always set to false. This forces code that uses an old version
+ *   of this header to always call into atrace_setup, in which we call
+ *   atrace_init unconditionally.
  */
 extern atomic_bool atrace_is_ready;
 
@@ -143,6 +152,12 @@
  * This can be explicitly run to avoid setup delay on first trace function.
  */
 #define ATRACE_INIT() atrace_init()
+#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
+
+#if ATRACE_SHMEM
+void atrace_init();
+uint64_t atrace_get_enabled_tags();
+#else
 static inline void atrace_init()
 {
     if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
@@ -155,12 +170,12 @@
  * It can be used as a guard condition around more expensive trace calculations.
  * Every trace function calls this, which ensures atrace_init is run.
  */
-#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags()
 static inline uint64_t atrace_get_enabled_tags()
 {
     atrace_init();
     return atrace_enabled_tags;
 }
+#endif
 
 /**
  * Test if a given tag is currently enabled.
diff --git a/libcutils/trace-container.cpp b/libcutils/trace-container.cpp
index d981f8f..c23d5e2 100644
--- a/libcutils/trace-container.cpp
+++ b/libcutils/trace-container.cpp
@@ -39,6 +39,11 @@
 static pthread_mutex_t  atrace_enabling_mutex        = PTHREAD_MUTEX_INITIALIZER;
 static pthread_rwlock_t atrace_container_sock_rwlock = PTHREAD_RWLOCK_INITIALIZER;
 
+static void atrace_seq_number_changed(uint32_t, uint32_t seq_no) {
+    pthread_once(&atrace_once_control, atrace_init_once);
+    atomic_store_explicit(&last_sequence_number, seq_no, memory_order_relaxed);
+}
+
 static bool atrace_init_container_sock()
 {
     pthread_rwlock_wrlock(&atrace_container_sock_rwlock);
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index bff16c1..2ee39d3 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -37,12 +37,39 @@
     } else {
       atrace_enabled_tags = atrace_get_property();
     }
+#if !ATRACE_SHMEM
     atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
+#endif
+}
+
+static void atrace_seq_number_changed(uint32_t prev_seq_no, uint32_t seq_no) {
+    if (!atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
+        return;
+    }
+
+    // Someone raced us.
+    if (!atomic_compare_exchange_strong(&last_sequence_number, &prev_seq_no, seq_no)) {
+        return;
+    }
+
+    if (CC_UNLIKELY(prev_seq_no == kSeqNoNotInit)) {
+#if defined(__BIONIC__)
+        const prop_info* new_pi = __system_property_find("debug.atrace.tags.enableflags");
+        if (new_pi) atrace_property_info = new_pi;
+#endif
+        pthread_once(&atrace_once_control, atrace_init_once);
+    }
+
+    atrace_update_tags();
 }
 
 void atrace_setup()
 {
+#if ATRACE_SHMEM
+    atrace_init();
+#else
     pthread_once(&atrace_once_control, atrace_init_once);
+#endif
 }
 
 void atrace_begin_body(const char* name)
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index e3da77b..a57a4c5 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -34,6 +34,11 @@
 #include <log/log.h>
 #include <log/log_properties.h>
 
+#if defined(__BIONIC__)
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
+#endif
+
 /**
  * Maximum size of a message that can be logged to the trace buffer.
  * Note this message includes a tag, the pid, and the string given as the name.
@@ -41,12 +46,57 @@
  */
 #define ATRACE_MESSAGE_LENGTH 1024
 
-atomic_bool             atrace_is_ready      = ATOMIC_VAR_INIT(false);
-int                     atrace_marker_fd     = -1;
-uint64_t                atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
-static bool             atrace_is_debuggable = false;
-static atomic_bool      atrace_is_enabled    = ATOMIC_VAR_INIT(true);
-static pthread_mutex_t  atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
+constexpr uint32_t kSeqNoNotInit = static_cast<uint32_t>(-1);
+
+atomic_bool              atrace_is_ready      = ATOMIC_VAR_INIT(false);
+int                      atrace_marker_fd     = -1;
+uint64_t                 atrace_enabled_tags  = ATRACE_TAG_NOT_READY;
+static bool              atrace_is_debuggable = false;
+static atomic_bool       atrace_is_enabled    = ATOMIC_VAR_INIT(true);
+static pthread_mutex_t   atrace_tags_mutex    = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Sequence number of debug.atrace.tags.enableflags the last time the enabled
+ * tags were reloaded.
+ **/
+static _Atomic(uint32_t) last_sequence_number = ATOMIC_VAR_INIT(kSeqNoNotInit);
+
+#if defined(__BIONIC__)
+// All zero prop_info that has a sequence number of 0. This is easier than
+// depending on implementation details of the property implementation.
+//
+// prop_info is static_assert-ed to be 96 bytes, which cannot change due to
+// ABI compatibility.
+alignas(uint64_t) static char empty_pi[96];
+static const prop_info* atrace_property_info = reinterpret_cast<const prop_info*>(empty_pi);
+#endif
+
+#if ATRACE_SHMEM
+
+/**
+ * This is called when the sequence number of debug.atrace.tags.enableflags
+ * changes and we need to reload the enabled tags.
+ **/
+static void atrace_seq_number_changed(uint32_t prev_seq_no, uint32_t seq_no);
+
+void atrace_init() {
+#if defined(__BIONIC__)
+    uint32_t seq_no = __system_property_serial(atrace_property_info);  // Acquire semantics.
+#else
+    uint32_t seq_no = 0;
+#endif
+    uint32_t prev_seq_no = atomic_load_explicit(&last_sequence_number, memory_order_relaxed);
+    if (CC_UNLIKELY(seq_no != prev_seq_no)) {
+        atrace_seq_number_changed(prev_seq_no, seq_no);
+    }
+}
+
+uint64_t atrace_get_enabled_tags()
+{
+    atrace_init();
+    return atrace_enabled_tags;
+}
+#endif
 
 // Set whether this process is debuggable, which determines whether
 // application-level tracing is allowed when the ro.debuggable system property
@@ -136,7 +186,7 @@
 void atrace_update_tags()
 {
     uint64_t tags;
-    if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+    if (ATRACE_SHMEM || CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
         if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
             tags = atrace_get_property();
             pthread_mutex_lock(&atrace_tags_mutex);
diff --git a/libcutils/trace-host.cpp b/libcutils/trace-host.cpp
index d47cc18..c21d0ee 100644
--- a/libcutils/trace-host.cpp
+++ b/libcutils/trace-host.cpp
@@ -30,3 +30,10 @@
 void atrace_async_end_body(const char* /*name*/, int32_t /*cookie*/) {}
 void atrace_int_body(const char* /*name*/, int32_t /*value*/) {}
 void atrace_int64_body(const char* /*name*/, int64_t /*value*/) {}
+#if ATRACE_SHMEM
+void atrace_init() {}
+uint64_t atrace_get_enabled_tags()
+{
+    return ATRACE_TAG_NOT_READY;
+}
+#endif
diff --git a/liblog/Android.bp b/liblog/Android.bp
index de0c636..bab57c0 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -95,7 +95,10 @@
         },
     },
 
-    header_libs: ["liblog_headers"],
+    header_libs: [
+        "libbase_headers",
+        "liblog_headers",
+    ],
     export_header_lib_headers: ["liblog_headers"],
 
     stubs: {
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index fb3b9bc..af9f18b 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -31,6 +31,7 @@
 
 #include <mutex>
 
+#include <android-base/no_destructor.h>
 #include <android/log.h>
 #include <log/log_id.h>
 #include <log/logprint.h>
@@ -48,14 +49,6 @@
 #define TRACE(...) ((void)0)
 #endif
 
-static void FakeClose();
-static int FakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr);
-
-struct android_log_transport_write fakeLoggerWrite = {
-    .close = FakeClose,
-    .write = FakeWrite,
-};
-
 typedef struct LogState {
   bool initialized = false;
   /* global minimum priority */
@@ -72,7 +65,7 @@
 } LogState;
 
 static LogState log_state;
-static std::mutex fake_log_mutex;
+static android::base::NoDestructor<std::mutex> fake_log_mutex;
 
 /*
  * Configure logging based on ANDROID_LOG_TAGS environment variable.  We
@@ -452,12 +445,12 @@
  *  tag (N bytes -- null-terminated ASCII string)
  *  message (N bytes -- null-terminated ASCII string)
  */
-static int FakeWrite(log_id_t log_id, struct timespec*, struct iovec* vector, size_t count) {
+int FakeWrite(log_id_t log_id, struct timespec*, struct iovec* vector, size_t count) {
   /* Make sure that no-one frees the LogState while we're using it.
    * Also guarantees that only one thread is in showLog() at a given
    * time (if it matters).
    */
-  auto lock = std::lock_guard{fake_log_mutex};
+  auto lock = std::lock_guard{*fake_log_mutex};
 
   if (!log_state.initialized) {
     InitializeLogStateLocked();
@@ -518,8 +511,8 @@
  * call is in the exit handler. Logging can continue in the exit handler to
  * help debug HOST tools ...
  */
-static void FakeClose() {
-  auto lock = std::lock_guard{fake_log_mutex};
+void FakeClose() {
+  auto lock = std::lock_guard{*fake_log_mutex};
 
   memset(&log_state, 0, sizeof(log_state));
 }
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index bd2256c..a2b40e2 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -18,16 +18,14 @@
 
 #include <sys/types.h>
 
-#include "log_portability.h"
-#include "uio.h"
+#include <android/log.h>
 
-struct iovec;
+#include "log_portability.h"
 
 __BEGIN_DECLS
 
-int fakeLogOpen(const char* pathName);
-int fakeLogClose(int fd);
-ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
+void FakeClose();
+int FakeWrite(log_id_t log_id, struct timespec* ts, struct iovec* vec, size_t nr);
 
 int __android_log_is_loggable(int prio, const char*, int def);
 int __android_log_is_loggable_len(int prio, const char*, size_t, int def);
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
index 6865c14..82ed6b2 100644
--- a/liblog/logd_reader.cpp
+++ b/liblog/logd_reader.cpp
@@ -35,8 +35,6 @@
 
 #include <string>
 
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index 3c6eb69..f49c59e 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "logd_writer.h"
+
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -32,7 +34,6 @@
 
 #include <shared_mutex>
 
-#include <cutils/sockets.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
@@ -41,14 +42,6 @@
 #include "rwlock.h"
 #include "uio.h"
 
-static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-static void LogdClose();
-
-struct android_log_transport_write logdLoggerWrite = {
-    .close = LogdClose,
-    .write = LogdWrite,
-};
-
 static int logd_socket;
 static RwLock logd_socket_lock;
 
@@ -90,7 +83,7 @@
   OpenSocketLocked();
 }
 
-static void LogdClose() {
+void LogdClose() {
   auto lock = std::unique_lock{logd_socket_lock};
   if (logd_socket > 0) {
     close(logd_socket);
@@ -98,7 +91,7 @@
   logd_socket = 0;
 }
 
-static int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
   ssize_t ret;
   static const unsigned headerLength = 1;
   struct iovec newVec[nr + headerLength];
@@ -119,7 +112,7 @@
   }
 
   /* logd, after initialization and priv drop */
-  if (__android_log_uid() == AID_LOGD) {
+  if (getuid() == AID_LOGD) {
     /*
      * ignore log messages we send to ourself (logd).
      * Such log messages are often generated by libraries we depend on
diff --git a/liblog/logd_writer.h b/liblog/logd_writer.h
new file mode 100644
index 0000000..41197b5
--- /dev/null
+++ b/liblog/logd_writer.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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 <stddef.h>
+
+#include <android/log.h>
+
+int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+void LogdClose();
diff --git a/liblog/logger.h b/liblog/logger.h
index 40d5fe5..078e778 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -18,7 +18,6 @@
 
 #include <stdatomic.h>
 
-#include <cutils/list.h>
 #include <log/log.h>
 
 #include "log_portability.h"
@@ -26,13 +25,6 @@
 
 __BEGIN_DECLS
 
-struct android_log_transport_write {
-  void (*close)(); /* free up resources */
-  /* write log to transport, returns number of bytes propagated, or -errno */
-  int (*write)(log_id_t logId, struct timespec* ts, struct iovec* vec,
-               size_t nr);
-};
-
 struct logger_list {
   atomic_int fd;
   int mode;
@@ -56,18 +48,4 @@
   return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
 }
 
-/* OS specific dribs and drabs */
-
-#if defined(_WIN32)
-#include <private/android_filesystem_config.h>
-typedef uint32_t uid_t;
-static inline uid_t __android_log_uid() {
-  return AID_SYSTEM;
-}
-#else
-static inline uid_t __android_log_uid() {
-  return getuid();
-}
-#endif
-
 __END_DECLS
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index 0d383ff..a13ab36 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -27,8 +27,6 @@
 #include <unistd.h>
 
 #include <android/log.h>
-#include <cutils/list.h>
-#include <private/android_filesystem_config.h>
 
 #include "log_portability.h"
 #include "logd_reader.h"
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index d38b402..77be581 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -15,7 +15,6 @@
  */
 
 #include <errno.h>
-#include <stdatomic.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
@@ -31,24 +30,18 @@
 #include "logger.h"
 #include "uio.h"
 
-#define LOG_BUF_SIZE 1024
-
 #if (FAKE_LOG_DEVICE == 0)
-extern struct android_log_transport_write logdLoggerWrite;
-extern struct android_log_transport_write pmsgLoggerWrite;
-
-android_log_transport_write* android_log_write = &logdLoggerWrite;
-android_log_transport_write* android_log_persist_write = &pmsgLoggerWrite;
+#include "logd_writer.h"
+#include "pmsg_writer.h"
 #else
-extern android_log_transport_write fakeLoggerWrite;
-
-android_log_transport_write* android_log_write = &fakeLoggerWrite;
-android_log_transport_write* android_log_persist_write = nullptr;
+#include "fake_log_device.h"
 #endif
 
+#define LOG_BUF_SIZE 1024
+
 #if defined(__ANDROID__)
 static int check_log_uid_permissions() {
-  uid_t uid = __android_log_uid();
+  uid_t uid = getuid();
 
   /* Matches clientHasLogCredentials() in logd */
   if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
@@ -92,14 +85,12 @@
  * Release any logger resources. A new log write will immediately re-acquire.
  */
 void __android_log_close() {
-  if (android_log_write != nullptr) {
-    android_log_write->close();
-  }
-
-  if (android_log_persist_write != nullptr) {
-    android_log_persist_write->close();
-  }
-
+#if (FAKE_LOG_DEVICE == 0)
+  LogdClose();
+  PmsgClose();
+#else
+  FakeClose();
+#endif
 }
 
 static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
@@ -158,17 +149,12 @@
 
   ret = 0;
 
-  if (android_log_write != nullptr) {
-    ssize_t retval;
-    retval = android_log_write->write(log_id, &ts, vec, nr);
-    if (ret >= 0) {
-      ret = retval;
-    }
-  }
-
-  if (android_log_persist_write != nullptr) {
-    android_log_persist_write->write(log_id, &ts, vec, nr);
-  }
+#if (FAKE_LOG_DEVICE == 0)
+  ret = LogdWrite(log_id, &ts, vec, nr);
+  PmsgWrite(log_id, &ts, vec, nr);
+#else
+  ret = FakeWrite(log_id, &ts, vec, nr);
+#endif
 
   errno = save_errno;
   return ret;
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
index 9390fec..64a92b7 100644
--- a/liblog/pmsg_reader.cpp
+++ b/liblog/pmsg_reader.cpp
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <sys/types.h>
 
-#include <private/android_filesystem_config.h>
+#include <cutils/list.h>
 #include <private/android_logger.h>
 
 #include "logger.h"
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 4f45780..319360f 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-/*
- * pmsg write handler
- */
+#include "pmsg_writer.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -28,7 +26,6 @@
 #include <shared_mutex>
 
 #include <log/log_properties.h>
-#include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
 #include "log_portability.h"
@@ -36,14 +33,6 @@
 #include "rwlock.h"
 #include "uio.h"
 
-static void PmsgClose();
-static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-
-struct android_log_transport_write pmsgLoggerWrite = {
-    .close = PmsgClose,
-    .write = PmsgWrite,
-};
-
 static int pmsg_fd;
 static RwLock pmsg_fd_lock;
 
@@ -57,7 +46,7 @@
   pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
 }
 
-static void PmsgClose() {
+void PmsgClose() {
   auto lock = std::unique_lock{pmsg_fd_lock};
   if (pmsg_fd > 0) {
     close(pmsg_fd);
@@ -65,7 +54,7 @@
   pmsg_fd = 0;
 }
 
-static int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
+int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
   static const unsigned headerLength = 2;
   struct iovec newVec[nr + headerLength];
   android_log_header_t header;
@@ -123,7 +112,7 @@
 
   pmsgHeader.magic = LOGGER_MAGIC;
   pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
-  pmsgHeader.uid = __android_log_uid();
+  pmsgHeader.uid = getuid();
   pmsgHeader.pid = getpid();
 
   header.id = logId;
diff --git a/liblog/pmsg_writer.h b/liblog/pmsg_writer.h
new file mode 100644
index 0000000..d5e1a1c
--- /dev/null
+++ b/liblog/pmsg_writer.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2020 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 <stddef.h>
+
+#include <android/log.h>
+
+int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
+void PmsgClose();
diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml
index c167478..fcb46b1 100644
--- a/liblog/tests/AndroidTest.xml
+++ b/liblog/tests/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" />
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index 333fc55..ee6ae7a 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -44,6 +44,9 @@
     bool Rmmod(const std::string& module_name);
     std::vector<std::string> GetDependencies(const std::string& module);
     bool ModuleExists(const std::string& module_name);
+    void AddOption(const std::string& module_name, const std::string& option_name,
+                   const std::string& value);
+    std::string GetKernelCmdline();
 
     bool ParseDepCallback(const std::string& base_path, const std::vector<std::string>& args);
     bool ParseAliasCallback(const std::vector<std::string>& args);
@@ -51,6 +54,7 @@
     bool ParseLoadCallback(const std::vector<std::string>& args);
     bool ParseOptionsCallback(const std::vector<std::string>& args);
     bool ParseBlacklistCallback(const std::vector<std::string>& args);
+    void ParseKernelCmdlineOptions();
     void ParseCfg(const std::string& cfg, std::function<bool(const std::vector<std::string>&)> f);
 
     std::vector<std::pair<std::string, std::string>> module_aliases_;
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 6b9107f..f22bbf1 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -238,6 +238,80 @@
     return;
 }
 
+void Modprobe::AddOption(const std::string& module_name, const std::string& option_name,
+                         const std::string& value) {
+    auto canonical_name = MakeCanonical(module_name);
+    auto options_iter = module_options_.find(canonical_name);
+    auto option_str = option_name + "=" + value;
+    if (options_iter != module_options_.end()) {
+        options_iter->second = options_iter->second + " " + option_str;
+    } else {
+        module_options_.emplace(canonical_name, option_str);
+    }
+}
+
+void Modprobe::ParseKernelCmdlineOptions(void) {
+    std::string cmdline = GetKernelCmdline();
+    std::string module_name = "";
+    std::string option_name = "";
+    std::string value = "";
+    bool in_module = true;
+    bool in_option = false;
+    bool in_value = false;
+    bool in_quotes = false;
+    int start = 0;
+
+    for (int i = 0; i < cmdline.size(); i++) {
+        if (cmdline[i] == '"') {
+            in_quotes = !in_quotes;
+        }
+
+        if (in_quotes) continue;
+
+        if (cmdline[i] == ' ') {
+            if (in_value) {
+                value = cmdline.substr(start, i - start);
+                if (!module_name.empty() && !option_name.empty()) {
+                    AddOption(module_name, option_name, value);
+                }
+            }
+            module_name = "";
+            option_name = "";
+            value = "";
+            in_value = false;
+            start = i + 1;
+            in_module = true;
+            continue;
+        }
+
+        if (cmdline[i] == '.') {
+            if (in_module) {
+                module_name = cmdline.substr(start, i - start);
+                start = i + 1;
+                in_module = false;
+            }
+            in_option = true;
+            continue;
+        }
+
+        if (cmdline[i] == '=') {
+            if (in_option) {
+                option_name = cmdline.substr(start, i - start);
+                start = i + 1;
+                in_option = false;
+            }
+            in_value = true;
+            continue;
+        }
+    }
+    if (in_value && !in_quotes) {
+        value = cmdline.substr(start, cmdline.size() - start);
+        if (!module_name.empty() && !option_name.empty()) {
+            AddOption(module_name, option_name, value);
+        }
+    }
+}
+
 Modprobe::Modprobe(const std::vector<std::string>& base_paths) {
     using namespace std::placeholders;
 
@@ -261,6 +335,7 @@
         ParseCfg(base_path + "/modules.blacklist", blacklist_callback);
     }
 
+    ParseKernelCmdlineOptions();
     android::base::SetMinimumLogSeverity(android::base::INFO);
 }
 
diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp
index 8bebe4c..99472c1 100644
--- a/libmodprobe/libmodprobe_ext.cpp
+++ b/libmodprobe/libmodprobe_ext.cpp
@@ -17,11 +17,20 @@
 #include <sys/stat.h>
 #include <sys/syscall.h>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 
 #include <modprobe/modprobe.h>
 
+std::string Modprobe::GetKernelCmdline(void) {
+    std::string cmdline;
+    if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
+        return "";
+    }
+    return cmdline;
+}
+
 bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
     android::base::unique_fd fd(
             TEMP_FAILURE_RETRY(open(path_name.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)));
diff --git a/libmodprobe/libmodprobe_ext_test.cpp b/libmodprobe/libmodprobe_ext_test.cpp
index 7d817b1..057dea3 100644
--- a/libmodprobe/libmodprobe_ext_test.cpp
+++ b/libmodprobe/libmodprobe_ext_test.cpp
@@ -29,6 +29,10 @@
 
 #include "libmodprobe_test.h"
 
+std::string Modprobe::GetKernelCmdline(void) {
+    return kernel_cmdline;
+}
+
 bool Modprobe::Insmod(const std::string& path_name, const std::string& parameters) {
     auto deps = GetDependencies(MakeCanonical(path_name));
     if (deps.empty()) {
@@ -57,7 +61,7 @@
 
 bool Modprobe::Rmmod(const std::string& module_name) {
     for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
-        if (*it == module_name) {
+        if (*it == module_name || android::base::StartsWith(*it, module_name + " ")) {
             modules_loaded.erase(it);
             return true;
         }
diff --git a/libmodprobe/libmodprobe_test.cpp b/libmodprobe/libmodprobe_test.cpp
index a711631..879c7f2 100644
--- a/libmodprobe/libmodprobe_test.cpp
+++ b/libmodprobe/libmodprobe_test.cpp
@@ -31,7 +31,13 @@
 // Used by libmodprobe_ext_test to report which modules would have been loaded.
 std::vector<std::string> modules_loaded;
 
+// Used by libmodprobe_ext_test to fake a kernel commandline
+std::string kernel_cmdline;
+
 TEST(libmodprobe, Test) {
+    kernel_cmdline =
+            "flag1 flag2 test1.option1=50 test4.option3=\"set x\" test1.option2=60 "
+            "test8. test5.option1= test10.option1=1";
     test_modules = {
             "/test1.ko",  "/test2.ko",  "/test3.ko",  "/test4.ko",  "/test5.ko",
             "/test6.ko",  "/test7.ko",  "/test8.ko",  "/test9.ko",  "/test10.ko",
@@ -42,25 +48,33 @@
             "/test14.ko",
             "/test15.ko",
             "/test3.ko",
-            "/test4.ko",
-            "/test1.ko",
+            "/test4.ko option3=\"set x\"",
+            "/test1.ko option1=50 option2=60",
             "/test6.ko",
             "/test2.ko",
-            "/test5.ko",
+            "/test5.ko option1=",
             "/test8.ko",
             "/test7.ko param1=4",
             "/test9.ko param_x=1 param_y=2 param_z=3",
-            "/test10.ko",
+            "/test10.ko option1=1",
             "/test12.ko",
             "/test11.ko",
             "/test13.ko",
     };
 
     std::vector<std::string> expected_after_remove = {
-            "/test14.ko", "/test15.ko",         "/test1.ko",
-            "/test6.ko",  "/test2.ko",          "/test5.ko",
-            "/test8.ko",  "/test7.ko param1=4", "/test9.ko param_x=1 param_y=2 param_z=3",
-            "/test10.ko", "/test12.ko",         "/test11.ko",
+            "/test14.ko",
+            "/test15.ko",
+            "/test1.ko option1=50 option2=60",
+            "/test6.ko",
+            "/test2.ko",
+            "/test5.ko option1=",
+            "/test8.ko",
+            "/test7.ko param1=4",
+            "/test9.ko param_x=1 param_y=2 param_z=3",
+            "/test10.ko option1=1",
+            "/test12.ko",
+            "/test11.ko",
             "/test13.ko",
     };
 
diff --git a/libmodprobe/libmodprobe_test.h b/libmodprobe/libmodprobe_test.h
index a001b69..e7b949f 100644
--- a/libmodprobe/libmodprobe_test.h
+++ b/libmodprobe/libmodprobe_test.h
@@ -19,5 +19,6 @@
 #include <string>
 #include <vector>
 
+extern std::string kernel_cmdline;
 extern std::vector<std::string> test_modules;
 extern std::vector<std::string> modules_loaded;
diff --git a/libstats/Android.bp b/libstats/Android.bp
deleted file mode 100644
index f5ee1da..0000000
--- a/libstats/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Copyright (C) 2018 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.
-//
-
-// ==========================================================
-// Native library to write stats log to statsd socket
-// ==========================================================
-cc_library {
-    name: "libstatssocket",
-    srcs: [
-        "stats_event_list.c",
-        "statsd_writer.c",
-    ],
-    host_supported: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-DLIBLOG_LOG_TAG=1006",
-        "-DWRITE_TO_STATSD=1",
-        "-DWRITE_TO_LOGD=0",
-    ],
-    export_include_dirs: ["include"],
-    shared_libs: [
-        "libcutils",
-        "liblog",
-    ],
-}
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
new file mode 100644
index 0000000..465c05a
--- /dev/null
+++ b/libstats/push_compat/Android.bp
@@ -0,0 +1,59 @@
+//
+// 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.
+//
+
+// =========================================================================
+// Native library that toggles between the old and new statsd socket
+// protocols. This library should only be used by DNS resolver or other
+// native modules on Q that log pushed atoms to statsd.
+// =========================================================================
+cc_defaults {
+    name: "libstatspush_compat_defaults",
+    srcs: [
+        "statsd_writer.c",
+        "stats_event_list.c",
+        "StatsEventCompat.cpp"
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DWRITE_TO_STATSD=1",
+        "-DWRITE_TO_LOGD=0",
+    ],
+    header_libs: ["libstatssocket_headers"],
+    static_libs: [
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+}
+
+cc_library {
+    name: "libstatspush_compat",
+    defaults: ["libstatspush_compat_defaults"],
+    export_include_dirs: ["include"],
+    static_libs: ["libgtest_prod"],
+}
+
+cc_test {
+    name: "libstatspush_compat_test",
+    defaults: ["libstatspush_compat_defaults"],
+    test_suites: ["device_tests"],
+    srcs: [
+        "tests/StatsEventCompat_test.cpp",
+    ],
+    static_libs: ["libgmock"],
+}
+
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
new file mode 100644
index 0000000..edfa070
--- /dev/null
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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 "include/StatsEventCompat.h"
+#include <android-base/properties.h>
+#include <android/api-level.h>
+#include <android/log.h>
+#include <dlfcn.h>
+#include <utils/SystemClock.h>
+
+using android::base::GetProperty;
+
+const static int kStatsEventTag = 1937006964;
+
+/* Checking ro.build.version.release is fragile, as the release field is
+ * an opaque string without structural guarantees. However, testing confirms
+ * that on Q devices, the property is "10," and on R, it is "R." Until
+ * android_get_device_api_level() is updated, this is the only solution.
+ *
+ * TODO(b/146019024): migrate to android_get_device_api_level()
+ */
+const bool StatsEventCompat::mPlatformAtLeastR =
+        GetProperty("ro.build.version.codename", "") == "R" ||
+        android_get_device_api_level() > __ANDROID_API_Q__;
+
+// definitions of static class variables
+bool StatsEventCompat::mAttemptedLoad = false;
+struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
+std::mutex StatsEventCompat::mLoadLock;
+
+StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
+    // guard loading because StatsEventCompat might be called from multithreaded
+    // environment
+    {
+        std::lock_guard<std::mutex> lg(mLoadLock);
+        if (!mAttemptedLoad) {
+            void* handle = dlopen("libstatssocket.so", RTLD_NOW);
+            if (handle) {
+                mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+            } else {
+                ALOGE("dlopen failed: %s\n", dlerror());
+            }
+        }
+        mAttemptedLoad = true;
+    }
+
+    if (mStatsEventApi) {
+        mEventR = mStatsEventApi->obtain();
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << android::elapsedRealtimeNano();
+    }
+}
+
+StatsEventCompat::~StatsEventCompat() {
+    if (mStatsEventApi) mStatsEventApi->release(mEventR);
+}
+
+void StatsEventCompat::setAtomId(int32_t atomId) {
+    if (mStatsEventApi) {
+        mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << atomId;
+    }
+}
+
+void StatsEventCompat::writeInt32(int32_t value) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_int32(mEventR, value);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << value;
+    }
+}
+
+void StatsEventCompat::writeInt64(int64_t value) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_int64(mEventR, value);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << value;
+    }
+}
+
+void StatsEventCompat::writeFloat(float value) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_float(mEventR, value);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << value;
+    }
+}
+
+void StatsEventCompat::writeBool(bool value) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_bool(mEventR, value);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << value;
+    }
+}
+
+void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ.AppendCharArray(buffer, length);
+    }
+}
+
+void StatsEventCompat::writeString(const char* value) {
+    if (value == nullptr) value = "";
+
+    if (mStatsEventApi) {
+        mStatsEventApi->write_string8(mEventR, value);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ << value;
+    }
+}
+
+void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
+                                             const vector<const char*>& tags) {
+    if (mStatsEventApi) {
+        mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
+                                                (uint8_t)numUids);
+    } else if (!mPlatformAtLeastR) {
+        mEventQ.begin();
+        for (size_t i = 0; i < numUids; i++) {
+            mEventQ.begin();
+            mEventQ << uids[i];
+            const char* tag = tags[i] ? tags[i] : "";
+            mEventQ << tag;
+            mEventQ.end();
+        }
+        mEventQ.end();
+    }
+}
+
+void StatsEventCompat::writeKeyValuePairs(const map<int, int32_t>& int32Map,
+                                          const map<int, int64_t>& int64Map,
+                                          const map<int, const char*>& stringMap,
+                                          const map<int, float>& floatMap) {
+    if (mStatsEventApi) {
+        vector<struct key_value_pair> pairs;
+
+        for (const auto& it : int32Map) {
+            pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
+        }
+        for (const auto& it : int64Map) {
+            pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
+        }
+        for (const auto& it : stringMap) {
+            pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
+        }
+        for (const auto& it : floatMap) {
+            pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
+        }
+
+        mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
+    }
+
+    else if (!mPlatformAtLeastR) {
+        mEventQ.begin();
+        writeKeyValuePairMap(int32Map);
+        writeKeyValuePairMap(int64Map);
+        writeKeyValuePairMap(stringMap);
+        writeKeyValuePairMap(floatMap);
+        mEventQ.end();
+    }
+}
+
+template <class T>
+void StatsEventCompat::writeKeyValuePairMap(const map<int, T>& keyValuePairMap) {
+    for (const auto& it : keyValuePairMap) {
+        mEventQ.begin();
+        mEventQ << it.first;
+        mEventQ << it.second;
+        mEventQ.end();
+    }
+}
+
+// explicitly specify which types we're going to use
+template void StatsEventCompat::writeKeyValuePairMap<int32_t>(const map<int, int32_t>&);
+template void StatsEventCompat::writeKeyValuePairMap<int64_t>(const map<int, int64_t>&);
+template void StatsEventCompat::writeKeyValuePairMap<float>(const map<int, float>&);
+template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
+
+void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
+    if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+    // Don't do anything if on Q.
+}
+
+void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
+    if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+    // Don't do anything if on Q.
+}
+
+int StatsEventCompat::writeToSocket() {
+    if (mStatsEventApi) {
+        mStatsEventApi->build(mEventR);
+        return mStatsEventApi->write(mEventR);
+    }
+
+    if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
+
+    // We reach here only if we're on R, but libstatspush_compat was unable to
+    // be loaded using dlopen.
+    return -ENOLINK;
+}
+
+bool StatsEventCompat::usesNewSchema() {
+    return mStatsEventApi != nullptr;
+}
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
new file mode 100644
index 0000000..a8cde68
--- /dev/null
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <gtest/gtest_prod.h>
+#include <map>
+#include <mutex>
+#include <vector>
+#include "stats_event.h"
+#include "stats_event_list.h"
+
+using std::map;
+using std::vector;
+
+class StatsEventCompat {
+  public:
+    StatsEventCompat();
+    ~StatsEventCompat();
+
+    void setAtomId(int32_t atomId);
+    void writeInt32(int32_t value);
+    void writeInt64(int64_t value);
+    void writeFloat(float value);
+    void writeBool(bool value);
+    void writeByteArray(const char* buffer, size_t length);
+    void writeString(const char* value);
+
+    // Pre-condition: numUids == tags.size()
+    void writeAttributionChain(const int32_t* uids, size_t numUids,
+                               const vector<const char*>& tags);
+
+    void writeKeyValuePairs(const map<int, int32_t>& int32Map, const map<int, int64_t>& int64Map,
+                            const map<int, const char*>& stringMap,
+                            const map<int, float>& floatMap);
+
+    void addBoolAnnotation(uint8_t annotationId, bool value);
+    void addInt32Annotation(uint8_t annotationId, int32_t value);
+
+    int writeToSocket();
+
+  private:
+    // static member variables
+    const static bool mPlatformAtLeastR;
+    static bool mAttemptedLoad;
+    static std::mutex mLoadLock;
+    static struct stats_event_api_table* mStatsEventApi;
+
+    // non-static member variables
+    struct stats_event* mEventR = nullptr;
+    stats_event_list mEventQ;
+
+    template <class T>
+    void writeKeyValuePairMap(const map<int, T>& keyValuePairMap);
+
+    bool usesNewSchema();
+    FRIEND_TEST(StatsEventCompatTest, TestDynamicLoading);
+};
diff --git a/libstats/include/stats_event_list.h b/libstats/push_compat/include/stats_event_list.h
similarity index 100%
rename from libstats/include/stats_event_list.h
rename to libstats/push_compat/include/stats_event_list.h
diff --git a/libstats/stats_event_list.c b/libstats/push_compat/stats_event_list.c
similarity index 100%
rename from libstats/stats_event_list.c
rename to libstats/push_compat/stats_event_list.c
diff --git a/libstats/statsd_writer.c b/libstats/push_compat/statsd_writer.c
similarity index 98%
rename from libstats/statsd_writer.c
rename to libstats/push_compat/statsd_writer.c
index 073b67f..04d3b46 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/push_compat/statsd_writer.c
@@ -101,7 +101,7 @@
             strcpy(un.sun_path, "/dev/socket/statsdw");
 
             if (TEMP_FAILURE_RETRY(
-                    connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) < 0) {
+                        connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) < 0) {
                 ret = -errno;
                 switch (ret) {
                     case -ENOTCONN:
diff --git a/libstats/statsd_writer.h b/libstats/push_compat/statsd_writer.h
similarity index 100%
copy from libstats/statsd_writer.h
copy to libstats/push_compat/statsd_writer.h
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
new file mode 100644
index 0000000..2be24ec
--- /dev/null
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "include/StatsEventCompat.h"
+#include <android-base/properties.h>
+#include <android/api-level.h>
+#include <gtest/gtest.h>
+
+using android::base::GetProperty;
+
+/* Checking ro.build.version.release is fragile, as the release field is
+ * an opaque string without structural guarantees. However, testing confirms
+ * that on Q devices, the property is "10," and on R, it is "R." Until
+ * android_get_device_api_level() is updated, this is the only solution.
+ *
+ *
+ * TODO(b/146019024): migrate to android_get_device_api_level()
+ */
+const static bool mPlatformAtLeastR = GetProperty("ro.build.version.release", "") == "R" ||
+                                      android_get_device_api_level() > __ANDROID_API_Q__;
+
+TEST(StatsEventCompatTest, TestDynamicLoading) {
+    StatsEventCompat event;
+    EXPECT_EQ(mPlatformAtLeastR, event.usesNewSchema());
+}
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
new file mode 100644
index 0000000..3b6efbb
--- /dev/null
+++ b/libstats/socket/Android.bp
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2018 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.
+//
+
+// =========================================================================
+// Native library to write stats log to statsd socket on Android R and later
+// =========================================================================
+cc_library {
+    name: "libstatssocket",
+    srcs: [
+        "stats_buffer_writer.c",
+        "stats_event.c",
+        // TODO(b/145573568): Remove stats_event_list once stats_event
+        // migration is complete.
+        "stats_event_list.c",
+        "statsd_writer.c",
+    ],
+    host_supported: true,
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-DLIBLOG_LOG_TAG=1006",
+        "-DWRITE_TO_STATSD=1",
+        "-DWRITE_TO_LOGD=0",
+    ],
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "libcutils",
+        "liblog",
+    ],
+
+    // enumerate stable entry points for APEX use
+    stubs: {
+        symbol_file: "libstatssocket.map.txt",
+        versions: [
+            "1",
+        ],
+    }
+}
+
+cc_library_headers {
+    name: "libstatssocket_headers",
+    export_include_dirs: ["include"],
+    host_supported: true,
+}
+
+cc_benchmark {
+    name: "libstatssocket_benchmark",
+    srcs: [
+        "benchmark/main.cpp",
+        "benchmark/stats_event_benchmark.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    static_libs: [
+        "libstatssocket",
+    ],
+    shared_libs: [
+        "libcutils",
+        "liblog",
+        "libgtest_prod",
+    ],
+}
diff --git a/libstats/socket/benchmark/main.cpp b/libstats/socket/benchmark/main.cpp
new file mode 100644
index 0000000..5ebdf6e
--- /dev/null
+++ b/libstats/socket/benchmark/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * 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 <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
new file mode 100644
index 0000000..9488168
--- /dev/null
+++ b/libstats/socket/benchmark/stats_event_benchmark.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "benchmark/benchmark.h"
+#include "stats_event.h"
+
+static struct stats_event* constructStatsEvent() {
+    struct stats_event* event = stats_event_obtain();
+    stats_event_set_atom_id(event, 100);
+
+    // randomly sample atom size
+    int numElements = rand() % 800;
+    for (int i = 0; i < numElements; i++) {
+        stats_event_write_int32(event, i);
+    }
+
+    return event;
+}
+
+static void BM_stats_event_truncate_buffer(benchmark::State& state) {
+    while (state.KeepRunning()) {
+        struct stats_event* event = constructStatsEvent();
+        stats_event_build(event);
+        stats_event_write(event);
+        stats_event_release(event);
+    }
+}
+
+BENCHMARK(BM_stats_event_truncate_buffer);
+
+static void BM_stats_event_full_buffer(benchmark::State& state) {
+    while (state.KeepRunning()) {
+        struct stats_event* event = constructStatsEvent();
+        stats_event_truncate_buffer(event, false);
+        stats_event_build(event);
+        stats_event_write(event);
+        stats_event_release(event);
+    }
+}
+
+BENCHMARK(BM_stats_event_full_buffer);
diff --git a/libstats/socket/include/stats_buffer_writer.h b/libstats/socket/include/stats_buffer_writer.h
new file mode 100644
index 0000000..de4a5e2
--- /dev/null
+++ b/libstats/socket/include/stats_buffer_writer.h
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __CPLUSPLUS
+void stats_log_close();
+int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId);
+#ifdef __cplusplus
+}
+#endif  // __CPLUSPLUS
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
new file mode 100644
index 0000000..080e957
--- /dev/null
+++ b/libstats/socket/include/stats_event.h
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_STATS_LOG_STATS_EVENT_H
+#define ANDROID_STATS_LOG_STATS_EVENT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/*
+ * Functionality to build and store the buffer sent over the statsd socket.
+ * This code defines and encapsulates the socket protocol.
+ *
+ * Usage:
+ *      struct stats_event* event = stats_event_obtain();
+ *
+ *      stats_event_set_atom_id(event, atomId);
+ *      stats_event_write_int32(event, 24);
+ *      stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
+ *      stats_event_add_int32_annotation(event, 2, 128);
+ *      stats_event_write_float(event, 2.0);
+ *
+ *      stats_event_build(event);
+ *      stats_event_write(event);
+ *      stats_event_release(event);
+ *
+ * Notes:
+ *    (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
+ *        and annotations are defined in the atom.
+ *    (b) set_atom_id() can be called anytime before stats_event_write().
+ *    (c) add_<type>_annotation() calls apply to the previous field.
+ *    (d) If errors occur, stats_event_write() will write a bitmask of the errors to the socket.
+ *    (e) All strings should be encoded using UTF8.
+ */
+
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __CPLUSPLUS
+
+struct stats_event;
+
+/* SYSTEM API */
+struct stats_event* stats_event_obtain();
+// The build function can be called multiple times without error. If the event
+// has been built before, this function is a no-op.
+void stats_event_build(struct stats_event* event);
+int stats_event_write(struct stats_event* event);
+void stats_event_release(struct stats_event* event);
+
+void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
+
+void stats_event_write_int32(struct stats_event* event, int32_t value);
+void stats_event_write_int64(struct stats_event* event, int64_t value);
+void stats_event_write_float(struct stats_event* event, float value);
+void stats_event_write_bool(struct stats_event* event, bool value);
+
+void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
+
+// Buf must be null-terminated.
+void stats_event_write_string8(struct stats_event* event, const char* value);
+
+// Tags must be null-terminated.
+void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
+                                         const char* const* tags, uint8_t numNodes);
+
+/* key_value_pair struct can be constructed as follows:
+ *    struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
+ *                                  .stringValue = buf};
+ */
+struct key_value_pair {
+    int32_t key;
+    uint8_t valueType;  // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
+    union {
+        int32_t int32Value;
+        int64_t int64Value;
+        float floatValue;
+        const char* stringValue;  // must be null terminated
+    };
+};
+
+void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
+                                       uint8_t numPairs);
+
+void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
+void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
+                                      int32_t value);
+
+uint32_t stats_event_get_atom_id(struct stats_event* event);
+// Size is an output parameter.
+uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
+uint32_t stats_event_get_errors(struct stats_event* event);
+
+// This table is used by StatsEventCompat to access the stats_event API.
+struct stats_event_api_table {
+    struct stats_event* (*obtain)(void);
+    void (*build)(struct stats_event*);
+    int (*write)(struct stats_event*);
+    void (*release)(struct stats_event*);
+    void (*set_atom_id)(struct stats_event*, uint32_t);
+    void (*write_int32)(struct stats_event*, int32_t);
+    void (*write_int64)(struct stats_event*, int64_t);
+    void (*write_float)(struct stats_event*, float);
+    void (*write_bool)(struct stats_event*, bool);
+    void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
+    void (*write_string8)(struct stats_event*, const char*);
+    void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
+                                    uint8_t);
+    void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
+    void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
+    void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
+    uint32_t (*get_atom_id)(struct stats_event*);
+    uint8_t* (*get_buffer)(struct stats_event*, size_t*);
+    uint32_t (*get_errors)(struct stats_event*);
+};
+
+// exposed for benchmarking only
+void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+
+#ifdef __cplusplus
+}
+#endif  // __CPLUSPLUS
+
+#endif  // ANDROID_STATS_LOG_STATS_EVENT_H
diff --git a/libstats/socket/include/stats_event_list.h b/libstats/socket/include/stats_event_list.h
new file mode 100644
index 0000000..7a26536
--- /dev/null
+++ b/libstats/socket/include/stats_event_list.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2018, 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 <log/log_event_list.h>
+#include <sys/uio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void reset_log_context(android_log_context ctx);
+int write_to_logger(android_log_context context, log_id_t id);
+void note_log_drop(int error, int atomId);
+void stats_log_close();
+int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
+/**
+ * A copy of android_log_event_list class.
+ *
+ * android_log_event_list is going to be deprecated soon, so copy it here to
+ * avoid creating dependency on upstream code. TODO(b/78304629): Rewrite this
+ * code.
+ */
+class stats_event_list {
+  private:
+    android_log_context ctx;
+    int ret;
+
+    stats_event_list(const stats_event_list&) = delete;
+    void operator=(const stats_event_list&) = delete;
+
+  public:
+    explicit stats_event_list(int tag) : ret(0) {
+        ctx = create_android_logger(static_cast<uint32_t>(tag));
+    }
+    ~stats_event_list() { android_log_destroy(&ctx); }
+
+    int close() {
+        int retval = android_log_destroy(&ctx);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return retval;
+    }
+
+    /* To allow above C calls to use this class as parameter */
+    operator android_log_context() const { return ctx; }
+
+    /* return errors or transmit status */
+    int status() const { return ret; }
+
+    int begin() {
+        int retval = android_log_write_list_begin(ctx);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret;
+    }
+    int end() {
+        int retval = android_log_write_list_end(ctx);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret;
+    }
+
+    stats_event_list& operator<<(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(uint32_t value) {
+        int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(bool value) {
+        int retval = android_log_write_int32(ctx, value ? 1 : 0);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(uint64_t value) {
+        int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    stats_event_list& operator<<(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return *this;
+    }
+
+    int write(log_id_t id = LOG_ID_EVENTS) {
+        /* facilitate -EBUSY retry */
+        if ((ret == -EBUSY) || (ret > 0)) {
+            ret = 0;
+        }
+        int retval = write_to_logger(ctx, id);
+        /* existing errors trump transmission errors */
+        if (!ret) {
+            ret = retval;
+        }
+        return ret;
+    }
+
+    /*
+     * Append<Type> methods removes any integer promotion
+     * confusion, and adds access to string with length.
+     * Append methods are also added for all types for
+     * convenience.
+     */
+
+    bool AppendInt(int32_t value) {
+        int retval = android_log_write_int32(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    bool AppendLong(int64_t value) {
+        int retval = android_log_write_int64(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value) {
+        int retval = android_log_write_string8(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    bool AppendString(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    bool AppendString(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret;
+    }
+
+    bool Append(const std::string& value) {
+        int retval = android_log_write_string8_len(ctx, value.data(), value.length());
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret;
+    }
+
+    bool AppendFloat(float value) {
+        int retval = android_log_write_float32(ctx, value);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    template <typename Tvalue>
+    bool Append(Tvalue value) {
+        *this << value;
+        return ret >= 0;
+    }
+
+    bool Append(const char* value, size_t len) {
+        int retval = android_log_write_string8_len(ctx, value, len);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+
+    bool AppendCharArray(const char* value, size_t len) {
+        int retval = android_log_write_char_array(ctx, value, len);
+        if (retval < 0) {
+            ret = retval;
+        }
+        return ret >= 0;
+    }
+};
+
+#endif
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
new file mode 100644
index 0000000..55bfbda
--- /dev/null
+++ b/libstats/socket/libstatssocket.map.txt
@@ -0,0 +1,23 @@
+LIBSTATSSOCKET {
+    global:
+        stats_event_obtain; # apex # introduced=1
+        stats_event_build; # apex # introduced=1
+        stats_event_write; # apex # introduced=1
+        stats_event_release; # apex # introduced=1
+        stats_event_set_atom_id; # apex # introduced=1
+        stats_event_write_int32; # apex # introduced=1
+        stats_event_write_int64; # apex # introduced=1
+        stats_event_write_float; # apex # introduced=1
+        stats_event_write_bool; # apex # introduced=1
+        stats_event_write_byte_array; # apex # introduced=1
+        stats_event_write_string8; # apex # introduced=1
+        stats_event_write_attribution_chain; # apex # introduced=1
+        stats_event_write_key_value_pairs; # apex # introduced=1
+        stats_event_add_bool_annotation; # apex # introduced=1
+        stats_event_add_int32_annotation; # apex # introduced=1
+        stats_event_get_atom_id; # apex # introduced=1
+        stats_event_get_buffer; # apex # introduced=1
+        stats_event_get_errors; # apex # introduced=1
+    local:
+        *;
+};
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
new file mode 100644
index 0000000..c5c591d
--- /dev/null
+++ b/libstats/socket/stats_buffer_writer.c
@@ -0,0 +1,130 @@
+/*
+ * 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 "include/stats_buffer_writer.h"
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include "statsd_writer.h"
+
+static const uint32_t kStatsEventTag = 1937006964;
+
+extern struct android_log_transport_write statsdLoggerWrite;
+
+static int __write_to_statsd_init(struct iovec* vec, size_t nr);
+static int (*__write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init;
+
+void note_log_drop(int error, int atomId) {
+    statsdLoggerWrite.noteDrop(error, atomId);
+}
+
+void stats_log_close() {
+    statsd_writer_init_lock();
+    __write_to_statsd = __write_to_statsd_init;
+    if (statsdLoggerWrite.close) {
+        (*statsdLoggerWrite.close)();
+    }
+    statsd_writer_init_unlock();
+}
+
+int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
+    int ret = 1;
+
+#ifdef __ANDROID__
+    bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
+#else
+    bool statsdEnabled = false;
+#endif
+
+    if (statsdEnabled) {
+        struct iovec vecs[2];
+        vecs[0].iov_base = (void*)&kStatsEventTag;
+        vecs[0].iov_len = sizeof(kStatsEventTag);
+        vecs[1].iov_base = buffer;
+        vecs[1].iov_len = size;
+
+        ret = __write_to_statsd(vecs, 2);
+
+        if (ret < 0) {
+            note_log_drop(ret, atomId);
+        }
+    }
+
+    return ret;
+}
+
+static int __write_to_stats_daemon(struct iovec* vec, size_t nr) {
+    int save_errno;
+    struct timespec ts;
+    size_t len, i;
+
+    for (len = i = 0; i < nr; ++i) {
+        len += vec[i].iov_len;
+    }
+    if (!len) {
+        return -EINVAL;
+    }
+
+    save_errno = errno;
+#if defined(__ANDROID__)
+    clock_gettime(CLOCK_REALTIME, &ts);
+#else
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    ts.tv_sec = tv.tv_sec;
+    ts.tv_nsec = tv.tv_usec * 1000;
+#endif
+
+    int ret = (int)(*statsdLoggerWrite.write)(&ts, vec, nr);
+    errno = save_errno;
+    return ret;
+}
+
+static int __write_to_statsd_initialize_locked() {
+    if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) {
+        if (statsdLoggerWrite.close) {
+            (*statsdLoggerWrite.close)();
+            return -ENODEV;
+        }
+    }
+    return 1;
+}
+
+static int __write_to_statsd_init(struct iovec* vec, size_t nr) {
+    int ret, save_errno = errno;
+
+    statsd_writer_init_lock();
+
+    if (__write_to_statsd == __write_to_statsd_init) {
+        ret = __write_to_statsd_initialize_locked();
+        if (ret < 0) {
+            statsd_writer_init_unlock();
+            errno = save_errno;
+            return ret;
+        }
+
+        __write_to_statsd = __write_to_stats_daemon;
+    }
+
+    statsd_writer_init_unlock();
+
+    ret = __write_to_statsd(vec, nr);
+    errno = save_errno;
+    return ret;
+}
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
new file mode 100644
index 0000000..15039c6
--- /dev/null
+++ b/libstats/socket/stats_event.c
@@ -0,0 +1,354 @@
+/*
+ * 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 "include/stats_event.h"
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "stats_buffer_writer.h"
+
+#define LOGGER_ENTRY_MAX_PAYLOAD 4068
+// Max payload size is 4 bytes less as 4 bytes are reserved for stats_eventTag.
+// See android_util_Stats_Log.cpp
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
+
+/* POSITIONS */
+#define POS_NUM_ELEMENTS 1
+#define POS_TIMESTAMP (POS_NUM_ELEMENTS + sizeof(uint8_t))
+#define POS_ATOM_ID (POS_TIMESTAMP + sizeof(uint8_t) + sizeof(uint64_t))
+#define POS_FIRST_FIELD (POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t))
+
+/* LIMITS */
+#define MAX_ANNOTATION_COUNT 15
+#define MAX_BYTE_VALUE 127  // parsing side requires that lengths fit in 7 bits
+
+// The stats_event struct holds the serialized encoding of an event
+// within a buf. Also includes other required fields.
+struct stats_event {
+    uint8_t* buf;
+    size_t lastFieldPos;  // location of last field within the buf
+    size_t size;          // number of valid bytes within buffer
+    uint32_t numElements;
+    uint32_t atomId;
+    uint32_t errors;
+    bool truncate;
+    bool built;
+};
+
+static int64_t get_elapsed_realtime_ns() {
+    struct timespec t;
+    t.tv_sec = t.tv_nsec = 0;
+    clock_gettime(CLOCK_BOOTTIME, &t);
+    return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
+}
+
+struct stats_event* stats_event_obtain() {
+    struct stats_event* event = malloc(sizeof(struct stats_event));
+    event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
+    event->buf[0] = OBJECT_TYPE;
+    event->atomId = 0;
+    event->errors = 0;
+    event->truncate = true;  // truncate for both pulled and pushed atoms
+    event->built = false;
+
+    // place the timestamp
+    uint64_t timestampNs = get_elapsed_realtime_ns();
+    event->buf[POS_TIMESTAMP] = INT64_TYPE;
+    memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], &timestampNs, sizeof(timestampNs));
+
+    event->numElements = 1;
+    event->lastFieldPos = 0;  // 0 since we haven't written a field yet
+    event->size = POS_FIRST_FIELD;
+
+    return event;
+}
+
+void stats_event_release(struct stats_event* event) {
+    free(event->buf);
+    free(event);
+}
+
+void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+    event->atomId = atomId;
+    event->buf[POS_ATOM_ID] = INT32_TYPE;
+    memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
+    event->numElements++;
+}
+
+// Side-effect: modifies event->errors if the buffer would overflow
+static bool overflows(struct stats_event* event, size_t size) {
+    if (event->size + size > MAX_EVENT_PAYLOAD) {
+        event->errors |= ERROR_OVERFLOW;
+        return true;
+    }
+    return false;
+}
+
+// Side-effect: all append functions increment event->size if there is
+// sufficient space within the buffer to place the value
+static void append_byte(struct stats_event* event, uint8_t value) {
+    if (!overflows(event, sizeof(value))) {
+        event->buf[event->size] = value;
+        event->size += sizeof(value);
+    }
+}
+
+static void append_bool(struct stats_event* event, bool value) {
+    append_byte(event, (uint8_t)value);
+}
+
+static void append_int32(struct stats_event* event, int32_t value) {
+    if (!overflows(event, sizeof(value))) {
+        memcpy(&event->buf[event->size], &value, sizeof(value));
+        event->size += sizeof(value);
+    }
+}
+
+static void append_int64(struct stats_event* event, int64_t value) {
+    if (!overflows(event, sizeof(value))) {
+        memcpy(&event->buf[event->size], &value, sizeof(value));
+        event->size += sizeof(value);
+    }
+}
+
+static void append_float(struct stats_event* event, float value) {
+    if (!overflows(event, sizeof(value))) {
+        memcpy(&event->buf[event->size], &value, sizeof(value));
+        event->size += sizeof(float);
+    }
+}
+
+static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+    if (!overflows(event, size)) {
+        memcpy(&event->buf[event->size], buf, size);
+        event->size += size;
+    }
+}
+
+// Side-effect: modifies event->errors if buf is not properly null-terminated
+static void append_string(struct stats_event* event, const char* buf) {
+    size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
+    if (size == MAX_EVENT_PAYLOAD) {
+        event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
+        return;
+    }
+
+    append_int32(event, size);
+    append_byte_array(event, (uint8_t*)buf, size);
+}
+
+static void start_field(struct stats_event* event, uint8_t typeId) {
+    event->lastFieldPos = event->size;
+    append_byte(event, typeId);
+    event->numElements++;
+}
+
+void stats_event_write_int32(struct stats_event* event, int32_t value) {
+    if (event->errors) return;
+
+    start_field(event, INT32_TYPE);
+    append_int32(event, value);
+}
+
+void stats_event_write_int64(struct stats_event* event, int64_t value) {
+    if (event->errors) return;
+
+    start_field(event, INT64_TYPE);
+    append_int64(event, value);
+}
+
+void stats_event_write_float(struct stats_event* event, float value) {
+    if (event->errors) return;
+
+    start_field(event, FLOAT_TYPE);
+    append_float(event, value);
+}
+
+void stats_event_write_bool(struct stats_event* event, bool value) {
+    if (event->errors) return;
+
+    start_field(event, BOOL_TYPE);
+    append_bool(event, value);
+}
+
+void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
+    if (event->errors) return;
+
+    start_field(event, BYTE_ARRAY_TYPE);
+    append_int32(event, numBytes);
+    append_byte_array(event, buf, numBytes);
+}
+
+// Value is assumed to be encoded using UTF8
+void stats_event_write_string8(struct stats_event* event, const char* value) {
+    if (event->errors) return;
+
+    start_field(event, STRING_TYPE);
+    append_string(event, value);
+}
+
+// Tags are assumed to be encoded using UTF8
+void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
+                                         const char* const* tags, uint8_t numNodes) {
+    if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
+    if (event->errors) return;
+
+    start_field(event, ATTRIBUTION_CHAIN_TYPE);
+    append_byte(event, numNodes);
+
+    for (uint8_t i = 0; i < numNodes; i++) {
+        append_int32(event, uids[i]);
+        append_string(event, tags[i]);
+    }
+}
+
+void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
+                                       uint8_t numPairs) {
+    if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
+    if (event->errors) return;
+
+    start_field(event, KEY_VALUE_PAIRS_TYPE);
+    append_byte(event, numPairs);
+
+    for (uint8_t i = 0; i < numPairs; i++) {
+        append_int32(event, pairs[i].key);
+        append_byte(event, pairs[i].valueType);
+        switch (pairs[i].valueType) {
+            case INT32_TYPE:
+                append_int32(event, pairs[i].int32Value);
+                break;
+            case INT64_TYPE:
+                append_int64(event, pairs[i].int64Value);
+                break;
+            case FLOAT_TYPE:
+                append_float(event, pairs[i].floatValue);
+                break;
+            case STRING_TYPE:
+                append_string(event, pairs[i].stringValue);
+                break;
+            default:
+                event->errors |= ERROR_INVALID_VALUE_TYPE;
+                return;
+        }
+    }
+}
+
+// Side-effect: modifies event->errors if field has too many annotations
+static void increment_annotation_count(struct stats_event* event) {
+    uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
+    uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
+    uint32_t newAnnotationCount = oldAnnotationCount + 1;
+
+    if (newAnnotationCount > MAX_ANNOTATION_COUNT) {
+        event->errors |= ERROR_TOO_MANY_ANNOTATIONS;
+        return;
+    }
+
+    event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
+}
+
+void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
+    if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+    if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+    if (event->errors) return;
+
+    append_byte(event, annotationId);
+    append_byte(event, BOOL_TYPE);
+    append_bool(event, value);
+    increment_annotation_count(event);
+}
+
+void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
+                                      int32_t value) {
+    if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+    if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+    if (event->errors) return;
+
+    append_byte(event, annotationId);
+    append_byte(event, INT32_TYPE);
+    append_int32(event, value);
+    increment_annotation_count(event);
+}
+
+uint32_t stats_event_get_atom_id(struct stats_event* event) {
+    return event->atomId;
+}
+
+uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
+    if (size) *size = event->size;
+    return event->buf;
+}
+
+uint32_t stats_event_get_errors(struct stats_event* event) {
+    return event->errors;
+}
+
+void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
+    event->truncate = truncate;
+}
+
+void stats_event_build(struct stats_event* event) {
+    if (event->built) return;
+
+    if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
+
+    if (event->numElements > MAX_BYTE_VALUE) {
+        event->errors |= ERROR_TOO_MANY_FIELDS;
+    } else {
+        event->buf[POS_NUM_ELEMENTS] = event->numElements;
+    }
+
+    // If there are errors, rewrite buffer.
+    if (event->errors) {
+        event->buf[POS_NUM_ELEMENTS] = 3;
+        event->buf[POS_FIRST_FIELD] = ERROR_TYPE;
+        memcpy(&event->buf[POS_FIRST_FIELD + sizeof(uint8_t)], &event->errors,
+               sizeof(event->errors));
+        event->size = POS_FIRST_FIELD + sizeof(uint8_t) + sizeof(uint32_t);
+    }
+
+    // Truncate the buffer to the appropriate length in order to limit our
+    // memory usage.
+    if (event->truncate) event->buf = (uint8_t*)realloc(event->buf, event->size);
+
+    event->built = true;
+}
+
+int stats_event_write(struct stats_event* event) {
+    stats_event_build(event);
+    return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
+}
+
+struct stats_event_api_table table = {
+        stats_event_obtain,
+        stats_event_build,
+        stats_event_write,
+        stats_event_release,
+        stats_event_set_atom_id,
+        stats_event_write_int32,
+        stats_event_write_int64,
+        stats_event_write_float,
+        stats_event_write_bool,
+        stats_event_write_byte_array,
+        stats_event_write_string8,
+        stats_event_write_attribution_chain,
+        stats_event_write_key_value_pairs,
+        stats_event_add_bool_annotation,
+        stats_event_add_int32_annotation,
+        stats_event_get_atom_id,
+        stats_event_get_buffer,
+        stats_event_get_errors,
+};
diff --git a/libstats/socket/stats_event_list.c b/libstats/socket/stats_event_list.c
new file mode 100644
index 0000000..661a223
--- /dev/null
+++ b/libstats/socket/stats_event_list.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2018, 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 "include/stats_event_list.h"
+
+#include <string.h>
+#include <sys/time.h>
+#include "stats_buffer_writer.h"
+
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
+
+typedef struct {
+    uint32_t tag;
+    unsigned pos;                                    /* Read/write position into buffer */
+    unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements   */
+    unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1];  /* pos for list counter */
+    unsigned list_nest_depth;
+    unsigned len; /* Length or raw buffer. */
+    bool overflow;
+    bool list_stop; /* next call decrement list_nest_depth and issue a stop */
+    enum {
+        kAndroidLoggerRead = 1,
+        kAndroidLoggerWrite = 2,
+    } read_write_flag;
+    uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
+} android_log_context_internal;
+
+// Similar to create_android_logger(), but instead of allocation a new buffer,
+// this function resets the buffer for resuse.
+void reset_log_context(android_log_context ctx) {
+    if (!ctx) {
+        return;
+    }
+    android_log_context_internal* context = (android_log_context_internal*)(ctx);
+    uint32_t tag = context->tag;
+    memset(context, 0, sizeof(android_log_context_internal));
+
+    context->tag = tag;
+    context->read_write_flag = kAndroidLoggerWrite;
+    size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        context->overflow = true;
+    }
+    /* Everything is a list */
+    context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+    context->list[0] = context->pos + 1;
+    context->pos += needed;
+}
+
+int stats_write_list(android_log_context ctx) {
+    android_log_context_internal* context;
+    const char* msg;
+    ssize_t len;
+
+    context = (android_log_context_internal*)(ctx);
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+
+    if (context->list_nest_depth) {
+        return -EIO;
+    }
+
+    /* NB: if there was overflow, then log is truncated. Nothing reported */
+    context->storage[1] = context->count[0];
+    len = context->len = context->pos;
+    msg = (const char*)context->storage;
+    /* it's not a list */
+    if (context->count[0] <= 1) {
+        len -= sizeof(uint8_t) + sizeof(uint8_t);
+        if (len < 0) {
+            len = 0;
+        }
+        msg += sizeof(uint8_t) + sizeof(uint8_t);
+    }
+
+    return write_buffer_to_statsd((void*)msg, len, 0);
+}
+
+int write_to_logger(android_log_context ctx, log_id_t id) {
+    int retValue = 0;
+
+    if (WRITE_TO_LOGD) {
+        retValue = android_log_write_list(ctx, id);
+    }
+
+    if (WRITE_TO_STATSD) {
+        // log_event_list's cast operator is overloaded.
+        int ret = stats_write_list(ctx);
+        // In debugging phase, we may write to both logd and statsd. Prefer to
+        // return statsd socket write error code here.
+        if (ret < 0) {
+            retValue = ret;
+        }
+    }
+
+    return retValue;
+}
+
+static inline void copy4LE(uint8_t* buf, uint32_t val) {
+    buf[0] = val & 0xFF;
+    buf[1] = (val >> 8) & 0xFF;
+    buf[2] = (val >> 16) & 0xFF;
+    buf[3] = (val >> 24) & 0xFF;
+}
+
+// Note: this function differs from android_log_write_string8_len in that the length passed in
+// should be treated as actual length and not max length.
+int android_log_write_char_array(android_log_context ctx, const char* value, size_t actual_len) {
+    size_t needed;
+    ssize_t len = actual_len;
+    android_log_context_internal* context;
+
+    context = (android_log_context_internal*)ctx;
+    if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+        return -EBADF;
+    }
+    if (context->overflow) {
+        return -EIO;
+    }
+    if (!value) {
+        value = "";
+        len = 0;
+    }
+    needed = sizeof(uint8_t) + sizeof(int32_t) + len;
+    if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+        /* Truncate string for delivery */
+        len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
+        if (len <= 0) {
+            context->overflow = true;
+            return -EIO;
+        }
+    }
+    context->count[context->list_nest_depth]++;
+    context->storage[context->pos + 0] = EVENT_TYPE_STRING;
+    copy4LE(&context->storage[context->pos + 1], len);
+    if (len) {
+        memcpy(&context->storage[context->pos + 5], value, len);
+    }
+    context->pos += needed;
+    return len;
+}
diff --git a/libstats/statsd_writer.c b/libstats/socket/statsd_writer.c
similarity index 98%
copy from libstats/statsd_writer.c
copy to libstats/socket/statsd_writer.c
index 073b67f..04d3b46 100644
--- a/libstats/statsd_writer.c
+++ b/libstats/socket/statsd_writer.c
@@ -101,7 +101,7 @@
             strcpy(un.sun_path, "/dev/socket/statsdw");
 
             if (TEMP_FAILURE_RETRY(
-                    connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) < 0) {
+                        connect(sock, (struct sockaddr*)&un, sizeof(struct sockaddr_un))) < 0) {
                 ret = -errno;
                 switch (ret) {
                     case -ENOTCONN:
diff --git a/libstats/statsd_writer.h b/libstats/socket/statsd_writer.h
similarity index 100%
rename from libstats/statsd_writer.h
rename to libstats/socket/statsd_writer.h
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index 7676289..341275d 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -78,10 +78,31 @@
   CrcGenerateTable();
   Crc64GenerateTable();
 
-  std::vector<uint8_t> src(gnu_debugdata_size_);
-  if (!memory_->ReadFully(gnu_debugdata_offset_, src.data(), gnu_debugdata_size_)) {
-    gnu_debugdata_offset_ = 0;
-    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
+  // Verify the request is not larger than the max size_t value.
+  if (gnu_debugdata_size_ > SIZE_MAX) {
+    return nullptr;
+  }
+  size_t initial_buffer_size;
+  if (__builtin_mul_overflow(5, gnu_debugdata_size_, &initial_buffer_size)) {
+    return nullptr;
+  }
+
+  size_t buffer_increment;
+  if (__builtin_mul_overflow(2, gnu_debugdata_size_, &buffer_increment)) {
+    return nullptr;
+  }
+
+  std::unique_ptr<uint8_t[]> src(new (std::nothrow) uint8_t[gnu_debugdata_size_]);
+  if (src.get() == nullptr) {
+    return nullptr;
+  }
+
+  std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
+  if (!dst->Resize(initial_buffer_size)) {
+    return nullptr;
+  }
+
+  if (!memory_->ReadFully(gnu_debugdata_offset_, src.get(), gnu_debugdata_size_)) {
     return nullptr;
   }
 
@@ -89,21 +110,23 @@
   CXzUnpacker state;
   alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
   alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
-
   XzUnpacker_Construct(&state, &alloc);
 
-  std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
   int return_val;
   size_t src_offset = 0;
   size_t dst_offset = 0;
   ECoderStatus status;
-  dst->Resize(5 * gnu_debugdata_size_);
   do {
-    size_t src_remaining = src.size() - src_offset;
+    size_t src_remaining = gnu_debugdata_size_ - src_offset;
     size_t dst_remaining = dst->Size() - dst_offset;
-    if (dst_remaining < 2 * gnu_debugdata_size_) {
-      dst->Resize(dst->Size() + 2 * gnu_debugdata_size_);
-      dst_remaining += 2 * gnu_debugdata_size_;
+    if (dst_remaining < buffer_increment) {
+      size_t new_size;
+      if (__builtin_add_overflow(dst->Size(), buffer_increment, &new_size) ||
+          !dst->Resize(new_size)) {
+        XzUnpacker_Free(&state);
+        return nullptr;
+      }
+      dst_remaining += buffer_increment;
     }
     return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
                                  &src_remaining, true, CODER_FINISH_ANY, &status);
@@ -112,13 +135,13 @@
   } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
   XzUnpacker_Free(&state);
   if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
-    gnu_debugdata_offset_ = 0;
-    gnu_debugdata_size_ = static_cast<uint64_t>(-1);
     return nullptr;
   }
 
   // Shrink back down to the exact size.
-  dst->Resize(dst_offset);
+  if (!dst->Resize(dst_offset)) {
+    return nullptr;
+  }
 
   return dst.release();
 }
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index a66cd5b..8de3d98 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -206,12 +206,12 @@
 }
 
 size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
-  if (addr >= raw_.size()) {
+  if (addr >= size_) {
     return 0;
   }
 
-  size_t bytes_left = raw_.size() - static_cast<size_t>(addr);
-  const unsigned char* actual_base = static_cast<const unsigned char*>(raw_.data()) + addr;
+  size_t bytes_left = size_ - static_cast<size_t>(addr);
+  const unsigned char* actual_base = static_cast<const unsigned char*>(raw_) + addr;
   size_t actual_len = std::min(bytes_left, size);
 
   memcpy(dst, actual_base, actual_len);
@@ -219,7 +219,7 @@
 }
 
 uint8_t* MemoryBuffer::GetPtr(size_t offset) {
-  if (offset < raw_.size()) {
+  if (offset < size_) {
     return &raw_[offset];
   }
   return nullptr;
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
index 3fe4bbb..a91e59f 100644
--- a/libunwindstack/MemoryBuffer.h
+++ b/libunwindstack/MemoryBuffer.h
@@ -29,18 +29,27 @@
 class MemoryBuffer : public Memory {
  public:
   MemoryBuffer() = default;
-  virtual ~MemoryBuffer() = default;
+  virtual ~MemoryBuffer() { free(raw_); }
 
   size_t Read(uint64_t addr, void* dst, size_t size) override;
 
   uint8_t* GetPtr(size_t offset);
 
-  void Resize(size_t size) { raw_.resize(size); }
+  bool Resize(size_t size) {
+    raw_ = reinterpret_cast<uint8_t*>(realloc(raw_, size));
+    if (raw_ == nullptr) {
+      size_ = 0;
+      return false;
+    }
+    size_ = size;
+    return true;
+  }
 
-  uint64_t Size() { return raw_.size(); }
+  uint64_t Size() { return size_; }
 
  private:
-  std::vector<uint8_t> raw_;
+  uint8_t* raw_ = nullptr;
+  size_t size_ = 0;
 };
 
 }  // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
index c33908d..fc90dab 100644
--- a/libunwindstack/tests/ElfFake.h
+++ b/libunwindstack/tests/ElfFake.h
@@ -105,6 +105,9 @@
   void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; }
   void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; }
 
+  void FakeSetGnuDebugdataOffset(uint64_t offset) { gnu_debugdata_offset_ = offset; }
+  void FakeSetGnuDebugdataSize(uint64_t size) { gnu_debugdata_size_ = size; }
+
  private:
   std::unordered_map<std::string, uint64_t> globals_;
   std::string fake_build_id_;
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index ea27e3e..3cf90fe 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -1944,4 +1944,23 @@
   CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000);
 }
 
+TEST_F(ElfInterfaceTest, huge_gnu_debugdata_size) {
+  ElfInterfaceFake interface(nullptr);
+
+  interface.FakeSetGnuDebugdataOffset(0x1000);
+  interface.FakeSetGnuDebugdataSize(0xffffffffffffffffUL);
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+
+  interface.FakeSetGnuDebugdataSize(0x4000000000000UL);
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+
+  // This should exceed the size_t value of the first allocation.
+#if defined(__LP64__)
+  interface.FakeSetGnuDebugdataSize(0x3333333333333334ULL);
+#else
+  interface.FakeSetGnuDebugdataSize(0x33333334);
+#endif
+  ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
+}
+
 }  // namespace unwindstack
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 953b859..17c5e10 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -52,7 +52,12 @@
 
     template<size_t N>
     static size_t align(void*& buffer) {
-        return align<N>( const_cast<void const*&>(buffer) );
+        static_assert(!(N & (N - 1)), "Can only align to a power of 2.");
+        void* b = buffer;
+        buffer = reinterpret_cast<void*>((uintptr_t(buffer) + (N-1)) & ~(N-1));
+        size_t delta = size_t(uintptr_t(buffer) - uintptr_t(b));
+        memset(b, 0, delta);
+        return delta;
     }
 
     static void advance(void*& buffer, size_t& size, size_t offset) {
diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h
index 42c6efb..89f048d 100644
--- a/libutils/include/utils/RefBase.h
+++ b/libutils/include/utils/RefBase.h
@@ -455,6 +455,7 @@
 };
 
 #undef COMPARE_WEAK
+#undef COMPARE_WEAK_FUNCTIONAL
 
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 07dd3f1..100e507 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -134,7 +134,8 @@
 void sp_report_race();
 void sp_report_stack_pointer();
 
-#undef COMPARE
+#undef COMPARE_STRONG
+#undef COMPARE_STRONG_FUNCTIONAL
 
 // ---------------------------------------------------------------------------
 // No user serviceable parts below here.
diff --git a/libvndksupport/linker.cpp b/libvndksupport/linker.cpp
index cf0f618..30b9c2e 100644
--- a/libvndksupport/linker.cpp
+++ b/libvndksupport/linker.cpp
@@ -26,9 +26,7 @@
 
 #include <initializer_list>
 
-__attribute__((weak)) extern "C" android_namespace_t* android_get_exported_namespace(const char*);
-__attribute__((weak)) extern "C" void* android_dlopen_ext(const char*, int,
-                                                          const android_dlextinfo*);
+extern "C" android_namespace_t* android_get_exported_namespace(const char*);
 
 namespace {
 
@@ -42,10 +40,8 @@
 static VendorNamespace get_vendor_namespace() {
     static VendorNamespace result = ([] {
         for (const char* name : {"sphal", "default"}) {
-            if (android_get_exported_namespace != nullptr) {
-                if (android_namespace_t* ns = android_get_exported_namespace(name)) {
-                    return VendorNamespace{ns, name};
-                }
+            if (android_namespace_t* ns = android_get_exported_namespace(name)) {
+                return VendorNamespace{ns, name};
             }
         }
         return VendorNamespace{};
@@ -59,10 +55,6 @@
     if (getpid() == 1) {
         return 0;
     }
-    if (android_get_exported_namespace == nullptr) {
-        ALOGD("android_get_exported_namespace() not available. Assuming system process.");
-        return 0;
-    }
 
     // In vendor process, 'vndk' namespace is not visible, whereas in system
     // process, it is.
@@ -76,10 +68,7 @@
                 .flags = ANDROID_DLEXT_USE_NAMESPACE,
                 .library_namespace = vendor_namespace.ptr,
         };
-        void* handle = nullptr;
-        if (android_dlopen_ext != nullptr) {
-            handle = android_dlopen_ext(name, flag, &dlextinfo);
-        }
+        void* handle = android_dlopen_ext(name, flag, &dlextinfo);
         if (!handle) {
             ALOGE("Could not load %s from %s namespace: %s.", name, vendor_namespace.name,
                   dlerror());
diff --git a/libziparchive/testdata/empty.zip b/libziparchive/testdata/empty.zip
new file mode 100644
index 0000000..15cb0ec
--- /dev/null
+++ b/libziparchive/testdata/empty.zip
Binary files differ
diff --git a/libziparchive/testdata/zero-size-cd.zip b/libziparchive/testdata/zero-size-cd.zip
new file mode 100644
index 0000000..b6c8cbe
--- /dev/null
+++ b/libziparchive/testdata/zero-size-cd.zip
Binary files differ
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index ef29188..68837cc 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -265,14 +265,10 @@
   ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32, eocd->num_records,
         eocd->cd_size, eocd->cd_start_offset);
 
-  /*
-   * It all looks good.  Create a mapping for the CD, and set the fields
-   * in archive.
-   */
-
+  // It all looks good.  Create a mapping for the CD, and set the fields
+  // in archive.
   if (!archive->InitializeCentralDirectory(static_cast<off64_t>(eocd->cd_start_offset),
                                            static_cast<size_t>(eocd->cd_size))) {
-    ALOGE("Zip: failed to intialize central directory.\n");
     return kMmapFailed;
   }
 
@@ -354,7 +350,7 @@
   if (archive->hash_table == nullptr) {
     ALOGW("Zip: unable to allocate the %u-entry hash_table, entry size: %zu",
           archive->hash_table_size, sizeof(ZipStringOffset));
-    return -1;
+    return kAllocationFailed;
   }
 
   /*
@@ -365,24 +361,25 @@
   const uint8_t* ptr = cd_ptr;
   for (uint16_t i = 0; i < num_entries; i++) {
     if (ptr > cd_end - sizeof(CentralDirectoryRecord)) {
-      ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
+      ALOGW("Zip: ran off the end (item #%" PRIu16 ", %zu bytes of central directory)", i,
+            cd_length);
 #if defined(__ANDROID__)
       android_errorWriteLog(0x534e4554, "36392138");
 #endif
-      return -1;
+      return kInvalidFile;
     }
 
     const CentralDirectoryRecord* cdr = reinterpret_cast<const CentralDirectoryRecord*>(ptr);
     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
-      return -1;
+      return kInvalidFile;
     }
 
     const off64_t local_header_offset = cdr->local_file_header_offset;
     if (local_header_offset >= archive->directory_offset) {
       ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
             static_cast<int64_t>(local_header_offset), i);
-      return -1;
+      return kInvalidFile;
     }
 
     const uint16_t file_name_length = cdr->file_name_length;
@@ -394,12 +391,12 @@
       ALOGW("Zip: file name for entry %" PRIu16
             " exceeds the central directory range, file_name_length: %" PRIu16 ", cd_length: %zu",
             i, file_name_length, cd_length);
-      return -1;
+      return kInvalidEntryName;
     }
     // Check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters.
     if (!IsValidEntryName(file_name, file_name_length)) {
       ALOGW("Zip: invalid file name at entry %" PRIu16, i);
-      return -1;
+      return kInvalidEntryName;
     }
 
     // Add the CDE filename to the hash table.
@@ -414,7 +411,7 @@
     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, ptr - cd_ptr, cd_length, i);
-      return -1;
+      return kInvalidFile;
     }
   }
 
@@ -422,7 +419,7 @@
   if (!archive->mapped_zip.ReadAtOffset(reinterpret_cast<uint8_t*>(&lfh_start_bytes),
                                         sizeof(uint32_t), 0)) {
     ALOGW("Zip: Unable to read header for entry at offset == 0.");
-    return -1;
+    return kInvalidFile;
   }
 
   if (lfh_start_bytes != LocalFileHeader::kSignature) {
@@ -430,7 +427,7 @@
 #if defined(__ANDROID__)
     android_errorWriteLog(0x534e4554, "64211847");
 #endif
-    return -1;
+    return kInvalidFile;
   }
 
   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
@@ -439,16 +436,8 @@
 }
 
 static int32_t OpenArchiveInternal(ZipArchive* archive, const char* debug_file_name) {
-  int32_t result = -1;
-  if ((result = MapCentralDirectory(debug_file_name, archive)) != 0) {
-    return result;
-  }
-
-  if ((result = ParseZipArchive(archive))) {
-    return result;
-  }
-
-  return 0;
+  int32_t result = MapCentralDirectory(debug_file_name, archive);
+  return result != 0 ? result : ParseZipArchive(archive);
 }
 
 int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
@@ -1185,7 +1174,7 @@
     return result;
   } else {
     if (base_ptr_ == nullptr) {
-      ALOGE("Zip: invalid file map\n");
+      ALOGE("Zip: invalid file map");
       return -1;
     }
     return static_cast<off64_t>(data_length_);
@@ -1196,12 +1185,12 @@
 bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
   if (has_fd_) {
     if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
-      ALOGE("Zip: failed to read at offset %" PRId64 "\n", off);
+      ALOGE("Zip: failed to read at offset %" PRId64, off);
       return false;
     }
   } else {
     if (off < 0 || off > static_cast<off64_t>(data_length_)) {
-      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64 "\n", off, data_length_);
+      ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64, off, data_length_);
       return false;
     }
     memcpy(buf, static_cast<const uint8_t*>(base_ptr_) + off, len);
@@ -1219,13 +1208,17 @@
   if (mapped_zip.HasFd()) {
     directory_map = android::base::MappedFile::FromFd(mapped_zip.GetFileDescriptor(),
                                                       cd_start_offset, cd_size, PROT_READ);
-    if (!directory_map) return false;
+    if (!directory_map) {
+      ALOGE("Zip: failed to map central directory (offset %" PRId64 ", size %zu): %s",
+            cd_start_offset, cd_size, strerror(errno));
+      return false;
+    }
 
     CHECK_EQ(directory_map->size(), cd_size);
     central_directory.Initialize(directory_map->data(), 0 /*offset*/, cd_size);
   } else {
     if (mapped_zip.GetBasePtr() == nullptr) {
-      ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
+      ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer");
       return false;
     }
     if (static_cast<off64_t>(cd_start_offset) + static_cast<off64_t>(cd_size) >
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 60fdec0..1d05fc7 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -42,6 +42,7 @@
     "Invalid entry name",
     "I/O error",
     "File mapping failed",
+    "Allocation failed",
 };
 
 enum ErrorCodes : int32_t {
@@ -87,7 +88,10 @@
   // We were not able to mmap the central directory or entry contents.
   kMmapFailed = -12,
 
-  kLastErrorCode = kMmapFailed,
+  // An allocation failed.
+  kAllocationFailed = -13,
+
+  kLastErrorCode = kAllocationFailed,
 };
 
 class MappedZipFile {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 8781ab7..0916304 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -36,13 +36,9 @@
 
 static std::string test_data_dir = android::base::GetExecutableDirectory() + "/testdata";
 
-static const std::string kMissingZip = "missing.zip";
 static const std::string kValidZip = "valid.zip";
 static const std::string kLargeZip = "large.zip";
 static const std::string kBadCrcZip = "bad_crc.zip";
-static const std::string kCrashApk = "crash.apk";
-static const std::string kBadFilenameZip = "bad_filename.zip";
-static const std::string kUpdateZip = "dummy-update.zip";
 
 static const std::vector<uint8_t> kATxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'a',
                                                 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
@@ -52,13 +48,6 @@
 
 static const std::vector<uint8_t> kBTxtContents{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', '\n'};
 
-static const std::string kATxtName("a.txt");
-static const std::string kBTxtName("b.txt");
-static const std::string kNonexistentTxtName("nonexistent.txt");
-static const std::string kEmptyTxtName("empty.txt");
-static const std::string kLargeCompressTxtName("compress.txt");
-static const std::string kLargeUncompressTxtName("uncompress.txt");
-
 static int32_t OpenArchiveWrapper(const std::string& name, ZipArchiveHandle* handle) {
   const std::string abs_path = test_data_dir + "/" + name;
   return OpenArchive(abs_path.c_str(), handle);
@@ -69,19 +58,31 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
   CloseArchive(handle);
 
-  ASSERT_EQ(-1, OpenArchiveWrapper(kBadFilenameZip, &handle));
+  ASSERT_EQ(kInvalidEntryName, OpenArchiveWrapper("bad_filename.zip", &handle));
   CloseArchive(handle);
 }
 
 TEST(ziparchive, OutOfBound) {
   ZipArchiveHandle handle;
-  ASSERT_EQ(-8, OpenArchiveWrapper(kCrashApk, &handle));
+  ASSERT_EQ(kInvalidOffset, OpenArchiveWrapper("crash.apk", &handle));
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, EmptyArchive) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(kEmptyArchive, OpenArchiveWrapper("empty.zip", &handle));
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, ZeroSizeCentralDirectory) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(kInvalidFile, OpenArchiveWrapper("zero-size-cd.zip", &handle));
   CloseArchive(handle);
 }
 
 TEST(ziparchive, OpenMissing) {
   ZipArchiveHandle handle;
-  ASSERT_NE(0, OpenArchiveWrapper(kMissingZip, &handle));
+  ASSERT_NE(0, OpenArchiveWrapper("missing.zip", &handle));
 
   // Confirm the file descriptor is not going to be mistaken for a valid one.
   ASSERT_EQ(-1, GetFileDescriptor(handle));
@@ -200,7 +201,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, kATxtName, &data));
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
 
   // Known facts about a.txt, from zipinfo -v.
   ASSERT_EQ(63, data.offset);
@@ -211,7 +212,7 @@
   ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
 
   // An entry that doesn't exist. Should be a negative return code.
-  ASSERT_LT(FindEntry(handle, kNonexistentTxtName, &data), 0);
+  ASSERT_LT(FindEntry(handle, "this file does not exist", &data), 0);
 
   CloseArchive(handle);
 }
@@ -259,7 +260,7 @@
 
   // An entry that's deflated.
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, kATxtName, &data));
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
   const uint32_t a_size = data.uncompressed_length;
   ASSERT_EQ(a_size, kATxtContents.size());
   uint8_t* buffer = new uint8_t[a_size];
@@ -268,7 +269,7 @@
   delete[] buffer;
 
   // An entry that's stored.
-  ASSERT_EQ(0, FindEntry(handle, kBTxtName, &data));
+  ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
   const uint32_t b_size = data.uncompressed_length;
   ASSERT_EQ(b_size, kBTxtContents.size());
   buffer = new uint8_t[b_size];
@@ -323,7 +324,7 @@
   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
 
   ZipEntry entry;
-  ASSERT_EQ(0, FindEntry(handle, kEmptyTxtName, &entry));
+  ASSERT_EQ(0, FindEntry(handle, "empty.txt", &entry));
   ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
   uint8_t buffer[1];
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
@@ -403,7 +404,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry entry;
-  ASSERT_EQ(0, FindEntry(handle, kATxtName, &entry));
+  ASSERT_EQ(0, FindEntry(handle, "a.txt", &entry));
   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
 
   // Assert that the first 8 bytes of the file haven't been clobbered.
@@ -425,7 +426,7 @@
 
 #if !defined(_WIN32)
 TEST(ziparchive, OpenFromMemory) {
-  const std::string zip_path = test_data_dir + "/" + kUpdateZip;
+  const std::string zip_path = test_data_dir + "/dummy-update.zip";
   android::base::unique_fd fd(open(zip_path.c_str(), O_RDONLY | O_BINARY));
   ASSERT_NE(-1, fd);
   struct stat sb;
@@ -510,27 +511,27 @@
 }
 
 TEST(ziparchive, StreamCompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContents, false);
+  ZipArchiveStreamTestUsingContents(kValidZip, "a.txt", kATxtContents, false);
 }
 
 TEST(ziparchive, StreamUncompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, false);
+  ZipArchiveStreamTestUsingContents(kValidZip, "b.txt", kBTxtContents, false);
 }
 
 TEST(ziparchive, StreamRawCompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, kATxtName, kATxtContentsCompressed, true);
+  ZipArchiveStreamTestUsingContents(kValidZip, "a.txt", kATxtContentsCompressed, true);
 }
 
 TEST(ziparchive, StreamRawUncompressed) {
-  ZipArchiveStreamTestUsingContents(kValidZip, kBTxtName, kBTxtContents, true);
+  ZipArchiveStreamTestUsingContents(kValidZip, "b.txt", kBTxtContents, true);
 }
 
 TEST(ziparchive, StreamLargeCompressed) {
-  ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeCompressTxtName);
+  ZipArchiveStreamTestUsingMemory(kLargeZip, "compress.txt");
 }
 
 TEST(ziparchive, StreamLargeUncompressed) {
-  ZipArchiveStreamTestUsingMemory(kLargeZip, kLargeUncompressTxtName);
+  ZipArchiveStreamTestUsingMemory(kLargeZip, "uncompress.txt");
 }
 
 TEST(ziparchive, StreamCompressedBadCrc) {
@@ -539,7 +540,7 @@
 
   ZipEntry entry;
   std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, kATxtName, false, false, &entry, &read_data);
+  ZipArchiveStreamTest(handle, "a.txt", false, false, &entry, &read_data);
 
   CloseArchive(handle);
 }
@@ -550,7 +551,7 @@
 
   ZipEntry entry;
   std::vector<uint8_t> read_data;
-  ZipArchiveStreamTest(handle, kBTxtName, false, false, &entry, &read_data);
+  ZipArchiveStreamTest(handle, "b.txt", false, false, &entry, &read_data);
 
   CloseArchive(handle);
 }
@@ -647,7 +648,8 @@
 
   // Out of bounds.
   ASSERT_STREQ("Unknown return code", ErrorCodeString(1));
-  ASSERT_STREQ("Unknown return code", ErrorCodeString(-13));
+  ASSERT_STRNE("Unknown return code", ErrorCodeString(kLastErrorCode));
+  ASSERT_STREQ("Unknown return code", ErrorCodeString(kLastErrorCode - 1));
 
   ASSERT_STREQ("I/O error", ErrorCodeString(kIoError));
 }
@@ -698,7 +700,7 @@
   ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0],
                                         kZipFileWithBrokenLfhSignature.size()));
   ZipArchiveHandle handle;
-  ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle, false));
+  ASSERT_EQ(kInvalidFile, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle, false));
 }
 
 class VectorReader : public zip_archive::Reader {
diff --git a/logd/tests/AndroidTest.xml b/logd/tests/AndroidTest.xml
index 9a18edb..a25dc44 100644
--- a/logd/tests/AndroidTest.xml
+++ b/logd/tests/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 2dbdb60..5821379 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -156,132 +156,6 @@
 )
 endef
 
-
-#######################################
-# ld.config.txt selection variables
-#
-_enforce_vndk_at_runtime := false
-ifdef BOARD_VNDK_VERSION
-  ifneq ($(BOARD_VNDK_RUNTIME_DISABLE),true)
-    _enforce_vndk_at_runtime := true
-  endif
-endif
-
-_enforce_vndk_lite_at_runtime := false
-ifeq ($(_enforce_vndk_at_runtime),false)
-  ifeq ($(PRODUCT_TREBLE_LINKER_NAMESPACES)|$(SANITIZE_TARGET),true|)
-    _enforce_vndk_lite_at_runtime := true
-  endif
-endif
-
-#######################################
-# ld.config.txt
-#
-# For VNDK enforced devices that have defined BOARD_VNDK_VERSION, use
-# "ld.config.txt" as a source file. This configuration includes strict VNDK
-# run-time restrictions for vendor process.
-#
-# Other treblized devices, that have not defined BOARD_VNDK_VERSION or that
-# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.vndk_lite.txt"
-# as a source file. This configuration does not have strict VNDK run-time
-# restrictions.
-#
-# If the device is not treblized, use "ld.config.legacy.txt" for legacy
-# namespace configuration.
-#
-include $(CLEAR_VARS)
-LOCAL_MODULE := ld.config.txt
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-
-# Start of i18n and ART APEX compatibility.
-#
-# Meta-comment:
-# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD
-# entries need to be associated with something that goes into /system.
-# ld.config.txt qualifies but it could be anything else in /system until soong
-# supports creation of symlinks. http://b/123333111
-#
-# Keeping the appearance of files/dirs having old locations for apps that have
-# come to rely on them.
-
-# http://b/121248172 - create a link from /system/usr/icu to
-# /apex/com.android.i18n/etc/icu so that apps can find the ICU .dat file.
-# A symlink can't overwrite a directory and the /system/usr/icu directory once
-# existed so the required structure must be created whatever we find.
-LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu
-LOCAL_POST_INSTALL_CMD += && ln -sf /apex/com.android.i18n/etc/icu $(TARGET_OUT)/usr/icu
-
-# TODO(b/124106384): Clean up compat symlinks for ART binaries.
-ART_BINARIES := dalvikvm dex2oat
-LOCAL_POST_INSTALL_CMD += && mkdir -p $(TARGET_OUT)/bin
-$(foreach b,$(ART_BINARIES), \
-  $(eval LOCAL_POST_INSTALL_CMD += \
-    && ln -sf /apex/com.android.art/bin/$(b) $(TARGET_OUT)/bin/$(b)) \
-)
-
-# End of i18n and ART APEX compatibilty.
-
-ifeq ($(_enforce_vndk_at_runtime),true)
-
-# for VNDK enforced devices
-# This file will be replaced with dynamically generated one from system/linkerconfig
-LOCAL_MODULE_STEM := $(LOCAL_MODULE)
-LOCAL_SRC_FILES := etc/ld.config.txt
-include $(BUILD_PREBUILT)
-
-else ifeq ($(_enforce_vndk_lite_at_runtime),true)
-
-# for treblized but VNDK lightly enforced devices
-LOCAL_MODULE_STEM := ld.config.vndk_lite.txt
-include $(BUILD_SYSTEM)/base_rules.mk
-ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
-vndk_version := $(PLATFORM_VNDK_VERSION)
-libz_is_llndk := true
-include $(LOCAL_PATH)/update_and_install_ld_config.mk
-
-else
-
-# for legacy non-treblized devices
-LOCAL_MODULE_STEM := $(LOCAL_MODULE)
-LOCAL_SRC_FILES := etc/ld.config.legacy.txt
-include $(BUILD_PREBUILT)
-
-endif  # ifeq ($(_enforce_vndk_at_runtime),true)
-
-#######################################
-# ld.config.vndk_lite.txt
-#
-# This module is only for GSI.
-#
-ifeq ($(_enforce_vndk_lite_at_runtime),false)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ld.config.vndk_lite.txt
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
-LOCAL_MODULE_STEM := $(LOCAL_MODULE)
-include $(BUILD_SYSTEM)/base_rules.mk
-ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt
-vndk_version := $(PLATFORM_VNDK_VERSION)
-libz_is_llndk := true
-include $(LOCAL_PATH)/update_and_install_ld_config.mk
-
-endif  # ifeq ($(_enforce_vndk_lite_at_runtime),false)
-
-_enforce_vndk_at_runtime :=
-_enforce_vndk_lite_at_runtime :=
-
-#######################################
-# ld.config.txt for recovery
-include $(CLEAR_VARS)
-LOCAL_MODULE := ld.config.recovery.txt
-LOCAL_MODULE_CLASS := ETC
-LOCAL_SRC_FILES := etc/ld.config.recovery.txt
-LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/system/etc
-LOCAL_MODULE_STEM := ld.config.txt
-include $(BUILD_PREBUILT)
-
 #######################################
 # sanitizer.libraries.txt
 include $(CLEAR_VARS)
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index a99756a..5c87843 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -1,198 +1,3 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-# This gives the exactly the same namespace setup in pre-O.
-#
-
-# All binaries gets the same configuration 'legacy'
-dir.legacy = /system
-dir.legacy = /product
-dir.legacy = /vendor
-dir.legacy = /odm
-dir.legacy = /sbin
-
-# Except for /postinstall, where only /system and /product are searched
-dir.postinstall = /postinstall
-
-# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
-# This must be last.
-dir.legacy = /data
-
-[legacy]
-namespace.default.isolated = false
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/product/${LIB}
-namespace.default.asan.search.paths +=           /product/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-
-###############################################################################
-# APEX related namespaces.
-###############################################################################
-
-additional.namespaces = art,conscrypt,media,neuralnetworks,resolv
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-# If a shared library or an executable requests a shared library that
-# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the art namespace. And then, if the
-# shared library cannot be loaded from the art namespace either, the
-# dynamic linker tries to load the shared library from the resolv namespace.
-# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = art,resolv,neuralnetworks
-namespace.default.asan.links = art,resolv,neuralnetworks
-namespace.default.link.art.shared_libs  = libandroidicu.so
-namespace.default.link.art.shared_libs += libdexfile_external.so
-namespace.default.link.art.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.art.shared_libs += libicui18n.so
-namespace.default.link.art.shared_libs += libicuuc.so
-namespace.default.link.art.shared_libs += libnativebridge.so
-namespace.default.link.art.shared_libs += libnativehelper.so
-namespace.default.link.art.shared_libs += libnativeloader.so
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.art.shared_libs += libpac.so
-
-# When libnetd_resolv.so can't be found in the default namespace, search for it
-# in the resolv namespace. Don't allow any other libraries from the resolv namespace
-# to be loaded in the default namespace.
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "art" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the ART APEX.
-# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.art.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.art.visible = true
-
-namespace.art.search.paths = /apex/com.android.art/${LIB}
-namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.art.links = default,neuralnetworks
-# Need allow_all_shared_libs because libart.so can dlopen oat files in
-# /system/framework and /data.
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.art.link.default.allow_all_shared_libs = true
-namespace.art.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default
-namespace.media.link.default.shared_libs  = libbinder_ndk.so
-namespace.media.link.default.shared_libs += libc.so
-namespace.media.link.default.shared_libs += libcgrouprc.so
-namespace.media.link.default.shared_libs += libdl.so
-namespace.media.link.default.shared_libs += liblog.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += libmediandk.so
-namespace.media.link.default.shared_libs += libm.so
-namespace.media.link.default.shared_libs += libvndksupport.so
-
-namespace.media.link.default.shared_libs += libclang_rt.asan-aarch64-android.so
-namespace.media.link.default.shared_libs += libclang_rt.asan-arm-android.so
-namespace.media.link.default.shared_libs += libclang_rt.asan-i686-android.so
-namespace.media.link.default.shared_libs += libclang_rt.asan-x86_64-android.so
-namespace.media.link.default.shared_libs += libclang_rt.hwasan-aarch64-android.so
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = art,default
-namespace.conscrypt.link.art.shared_libs = libandroidio.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
-namespace.conscrypt.link.default.shared_libs += liblog.so
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs  = libc.so
-namespace.resolv.link.default.shared_libs += libcgrouprc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-namespace.resolv.link.default.shared_libs += libvndksupport.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-
-
-###############################################################################
-# Namespace config for binaries under /postinstall.
-# Only one default namespace is defined and it has no directories other than
-# /system/lib and /product/lib in the search paths. This is because linker
-# calls realpath on the search paths and this causes selinux denial if the
-# paths (/vendor, /odm) are not allowed to the poinstall binaries.
-# There is no reason to allow the binaries to access the paths.
-###############################################################################
-[postinstall]
-namespace.default.isolated = false
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /product/${LIB}
+# This file is no longer in use.
+# Please update linker configuration generator instead.
+# You can find the code from /system/linkerconfig
\ No newline at end of file
diff --git a/rootdir/etc/ld.config.recovery.txt b/rootdir/etc/ld.config.recovery.txt
index 5d6c01a..5c87843 100644
--- a/rootdir/etc/ld.config.recovery.txt
+++ b/rootdir/etc/ld.config.recovery.txt
@@ -1,9 +1,3 @@
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Bionic loader config file for recovery mode
-#
-
-dir.recovery = /system/bin
-
-[recovery]
-namespace.default.search.paths = /system/${LIB}
+# This file is no longer in use.
+# Please update linker configuration generator instead.
+# You can find the code from /system/linkerconfig
\ No newline at end of file
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 9c9f4a9..5c87843 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -1,609 +1,3 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-dir.system = /%SYSTEM_EXT%/bin/
-dir.system = /%PRODUCT%/bin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.unrestricted = /data/nativetest/unrestricted
-dir.unrestricted = /data/nativetest64/unrestricted
-
-# TODO(b/123864775): Ensure tests are run from /data/nativetest{,64} or (if
-# necessary) the unrestricted subdirs above. Then clean this up.
-dir.unrestricted = /data/local/tmp
-
-dir.postinstall = /postinstall
-
-# Fallback entry to provide APEX namespace lookups for binaries anywhere else.
-# This must be last.
-dir.system = /data
-
-[system]
-additional.namespaces = art,conscrypt,media,neuralnetworks,resolv,sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. However, libs from other
-# partitions are also allowed temporarily.
-###############################################################################
-namespace.default.isolated = false
-# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
-# libart.
-namespace.default.visible = true
-
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-# If a shared library or an executable requests a shared library that
-# cannot be loaded into the default namespace, the dynamic linker tries
-# to load the shared library from the art namespace. And then, if the
-# shared library cannot be loaded from the art namespace either, the
-# dynamic linker tries to load the shared library from the resolv namespace.
-# Finally, if all attempts fail, the dynamic linker returns an error.
-namespace.default.links = art,resolv,neuralnetworks
-namespace.default.link.art.shared_libs  = libandroidicu.so
-namespace.default.link.art.shared_libs += libdexfile_external.so
-namespace.default.link.art.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.art.shared_libs += libicui18n.so
-namespace.default.link.art.shared_libs += libicuuc.so
-namespace.default.link.art.shared_libs += libnativebridge.so
-namespace.default.link.art.shared_libs += libnativehelper.so
-namespace.default.link.art.shared_libs += libnativeloader.so
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.art.shared_libs += libpac.so
-
-# When libnetd_resolv.so can't be found in the default namespace, search for it
-# in the resolv namespace. Don't allow any other libraries from the resolv namespace
-# to be loaded in the default namespace.
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "art" APEX namespace
-#
-# This namespace pulls in externally accessible libs from the ART APEX.
-# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.art.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.art.visible = true
-
-namespace.art.search.paths = /apex/com.android.art/${LIB}
-namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.art.links = default,neuralnetworks
-# Need allow_all_shared_libs because libart.so can dlopen oat files in
-# /system/framework and /data.
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.art.link.default.allow_all_shared_libs = true
-namespace.art.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = art,default
-namespace.conscrypt.link.art.shared_libs = libandroidio.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
-namespace.conscrypt.link.default.shared_libs += liblog.so
-namespace.conscrypt.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs  = libc.so
-namespace.resolv.link.default.shared_libs += libcgrouprc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += liblog.so
-namespace.resolv.link.default.shared_libs += libvndksupport.so
-namespace.resolv.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths  = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}/hw
-
-namespace.sphal.permitted.paths  = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-namespace.sphal.permitted.paths += /system/vendor/${LIB}
-
-namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths +=           /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths +=           /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths +=           /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths +=           /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used. Order is important here as the namespaces are
-# tried in this order. rs should be before vndk because both are capable
-# of loading libRS_internal.so
-namespace.sphal.links = rs,default,vndk,neuralnetworks
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-namespace.sphal.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.sphal.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths  = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths  = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /system/vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths +=           /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths +=           /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths  = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths +=           /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths +=           /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,neuralnetworks
-
-namespace.rs.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
-# namespace because RS framework libs are using them.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.rs.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths  = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths  = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-namespace.vndk.permitted.paths += /system/vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths  = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths +=           /vendor/${LIB}/egl
-
-namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
-namespace.vndk.asan.permitted.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the default namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = default,neuralnetworks
-
-namespace.vndk.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.vndk.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for vendor processes. In O, no restriction is enforced for
-# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = art,neuralnetworks
-
-namespace.default.isolated = false
-
-namespace.default.search.paths  = /odm/${LIB}
-namespace.default.search.paths += /odm/${LIB}/vndk
-namespace.default.search.paths += /odm/${LIB}/vndk-sp
-namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /vendor/${LIB}/vndk
-namespace.default.search.paths += /vendor/${LIB}/vndk-sp
-
-# Access to system libraries is allowed
-namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
-# Put /system/lib/vndk at the last search order in vndk_lite for GSI
-namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.default.asan.search.paths  = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
-namespace.default.asan.search.paths +=           /odm/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths +=           /odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths +=           /vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths +=           /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths +=           /%SYSTEM_EXT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/%PRODUCT%/${LIB}
-namespace.default.asan.search.paths +=           /%PRODUCT%/${LIB}
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths +=           /system/${LIB}/vndk%VNDK_VER%
-
-namespace.default.links = art,neuralnetworks
-namespace.default.link.art.shared_libs  = libdexfile_external.so
-namespace.default.link.art.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.art.shared_libs += libicui18n.so
-namespace.default.link.art.shared_libs += libicuuc.so
-namespace.default.link.art.shared_libs += libnativebridge.so
-namespace.default.link.art.shared_libs += libnativehelper.so
-namespace.default.link.art.shared_libs += libnativeloader.so
-# Workaround for b/124772622
-namespace.default.link.art.shared_libs += libandroidicu.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "art" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the ART APEX.
-# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.art.isolated = true
-
-namespace.art.search.paths = /apex/com.android.art/${LIB}
-namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.art.links = default
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.art.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for native tests that need access to both system and vendor
-# libraries. This replicates the default linker config (done by
-# init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
-# includes the requisite namespace setup for APEXes.
-###############################################################################
-[unrestricted]
-additional.namespaces = art,media,conscrypt,resolv,neuralnetworks
-
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.default.visible = true
-
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.asan.search.paths  = /data/asan/system/${LIB}
-namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths +=           /vendor/${LIB}
-
-# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
-namespace.default.links = art,resolv,neuralnetworks
-namespace.default.link.art.shared_libs  = libandroidicu.so
-namespace.default.link.art.shared_libs += libdexfile_external.so
-namespace.default.link.art.shared_libs += libdexfiled_external.so
-# TODO(b/120786417 or b/134659294): libicuuc.so and libicui18n.so are kept for app compat.
-namespace.default.link.art.shared_libs += libicui18n.so
-namespace.default.link.art.shared_libs += libicuuc.so
-namespace.default.link.art.shared_libs += libnativebridge.so
-namespace.default.link.art.shared_libs += libnativehelper.so
-namespace.default.link.art.shared_libs += libnativeloader.so
-
-# TODO(b/122876336): Remove libpac.so once it's migrated to Webview
-namespace.default.link.art.shared_libs += libpac.so
-
-namespace.default.link.resolv.shared_libs = libnetd_resolv.so
-
-# LLNDK library moved into apex
-namespace.default.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "art" APEX namespace
-#
-# This namespace exposes externally accessible libraries from the ART APEX.
-# Keep in sync with the "art" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.art.isolated = true
-# Visible to allow links to be created at runtime, e.g. through
-# android_link_namespaces in libnativeloader.
-namespace.art.visible = true
-
-namespace.art.search.paths = /apex/com.android.art/${LIB}
-namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
-namespace.art.links = default
-# TODO(b/130340935): Use a dynamically created linker namespace similar to
-# classloader-namespace for oat files, and tighten this up.
-namespace.runtime.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "media" APEX namespace
-#
-# This namespace is for libraries within the media APEX.
-###############################################################################
-namespace.media.isolated = true
-namespace.media.visible = true
-
-namespace.media.search.paths = /apex/com.android.media/${LIB}
-namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
-
-namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
-
-namespace.media.links = default,neuralnetworks
-namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
-namespace.media.link.default.shared_libs += libbinder_ndk.so
-namespace.media.link.default.shared_libs += libmediametrics.so
-namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-# LLNDK library moved into apex
-namespace.media.link.neuralnetworks.shared_libs = libneuralnetworks.so
-
-###############################################################################
-# "conscrypt" APEX namespace
-#
-# This namespace is for libraries within the conscrypt APEX.
-# Keep in sync with the "conscrypt" namespace in art/build/apex/ld.config.txt.
-###############################################################################
-namespace.conscrypt.isolated = true
-namespace.conscrypt.visible = true
-
-namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
-namespace.conscrypt.links = art,default
-namespace.conscrypt.link.art.shared_libs = libandroidio.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
-namespace.conscrypt.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "resolv" APEX namespace
-#
-# This namespace is for libraries within the resolv APEX.
-###############################################################################
-namespace.resolv.isolated = true
-namespace.resolv.visible = true
-
-namespace.resolv.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB}
-namespace.resolv.links = default
-namespace.resolv.link.default.shared_libs  = libc.so
-namespace.resolv.link.default.shared_libs += libcgrouprc.so
-namespace.resolv.link.default.shared_libs += libm.so
-namespace.resolv.link.default.shared_libs += libdl.so
-namespace.resolv.link.default.shared_libs += libbinder_ndk.so
-namespace.resolv.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# "neuralnetworks" APEX namespace
-#
-# This namespace is for libraries within the NNAPI APEX.
-###############################################################################
-namespace.neuralnetworks.isolated = true
-namespace.neuralnetworks.visible = true
-
-namespace.neuralnetworks.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.asan.search.paths = /apex/com.android.neuralnetworks/${LIB}
-namespace.neuralnetworks.links = default
-namespace.neuralnetworks.link.default.shared_libs  = libc.so
-namespace.neuralnetworks.link.default.shared_libs += libcgrouprc.so
-namespace.neuralnetworks.link.default.shared_libs += libdl.so
-namespace.neuralnetworks.link.default.shared_libs += liblog.so
-namespace.neuralnetworks.link.default.shared_libs += libm.so
-namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
-namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
-namespace.neuralnetworks.link.default.shared_libs += libsync.so
-namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
-namespace.neuralnetworks.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for binaries under /postinstall.
-# Only default namespace is defined and default has no directories
-# other than /system/lib in the search paths. This is because linker calls
-# realpath on the search paths and this causes selinux denial if the paths
-# (/vendor, /odm) are not allowed to the postinstall binaries. There is no
-# reason to allow the binaries to access the paths.
-###############################################################################
-[postinstall]
-namespace.default.isolated = false
-namespace.default.search.paths  = /system/${LIB}
-namespace.default.search.paths += /%SYSTEM_EXT%/${LIB}
-namespace.default.search.paths += /%PRODUCT%/${LIB}
+# This file is no longer in use.
+# Please update linker configuration generator instead.
+# You can find the code from /system/linkerconfig
\ No newline at end of file
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b89c45e..7a3339d 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,9 +38,18 @@
     # Allow up to 32K FDs per process
     setrlimit nofile 32768 32768
 
+    # Set up linker config subdirectories based on mount namespaces
+    mkdir /linkerconfig/bootstrap 0755
+    mkdir /linkerconfig/default 0755
+
     # Generate ld.config.txt for early executed processes
-    exec -- /system/bin/linkerconfig --target /linkerconfig/ld.config.txt
-    chmod 444 /linkerconfig/ld.config.txt
+    exec -- /system/bin/linkerconfig --target /linkerconfig/bootstrap
+    chmod 644 /linkerconfig/bootstrap/ld.config.txt
+    copy /linkerconfig/bootstrap/ld.config.txt /linkerconfig/default/ld.config.txt
+    chmod 644 /linkerconfig/default/ld.config.txt
+
+    # Mount bootstrap linker configuration as current
+    mount none /linkerconfig/bootstrap /linkerconfig bind rec
 
     start ueventd
 
@@ -49,6 +58,9 @@
     # the libraries are available to the processes started after this statement.
     exec_start apexd-bootstrap
 
+    # Generate linker config based on apex mounted in bootstrap namespace
+    update_linker_config
+
     # These must already exist by the time boringssl_self_test32 / boringssl_self_test64 run.
     mkdir /dev/boringssl 0755 root root
     mkdir /dev/boringssl/selftest 0755 root root
@@ -688,6 +700,9 @@
     mkdir /data/rollback 0700 system system encryption=DeleteIfNecessary
     mkdir /data/rollback-observer 0700 system system encryption=DeleteIfNecessary
 
+    # Create root dir for Incremental Service
+    mkdir /data/incremental 0770 system system encryption=None
+
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
     perform_apex_config
@@ -963,9 +978,12 @@
 
 on userspace-reboot-requested
   # TODO(b/135984674): reset all necessary properties here.
-  setprop sys.boot_completed 0
-  setprop sys.init.updatable_crashing 0
+  setprop sys.boot_completed ""
+  setprop sys.init.updatable_crashing ""
+  setprop sys.init.updatable_crashing_process_name ""
   setprop apexd.status ""
+  setprop sys.user.0.ce_available ""
+  setprop sys.shutdown.requested ""
 
 on userspace-reboot-fs-remount
   # Make sure that vold is running.
diff --git a/rootdir/ld_config_backward_compatibility_check.py b/rootdir/ld_config_backward_compatibility_check.py
deleted file mode 100755
index 1a27578..0000000
--- a/rootdir/ld_config_backward_compatibility_check.py
+++ /dev/null
@@ -1,177 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 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.
-#
-
-import glob
-import os.path
-import re
-import sys
-
-PREBUILTS_VNDK_DIR = "prebuilts/vndk"
-VENDOR_DIRECTORIES = ('/vendor', '/odm')
-
-def find_latest_vndk_snapshot_version():
-  """Returns latest vndk snapshot version in current source tree.
-  It will skip the test if the snapshot directories are not found.
-
-  Returns:
-    latest_version: string
-  """
-  vndk_dir_list = glob.glob(PREBUILTS_VNDK_DIR + "/v*")
-  if not vndk_dir_list:
-    """Exit without error because we may have source trees that do not include
-    VNDK snapshot directories in it.
-    """
-    sys.exit(0)
-  vndk_ver_list = [re.match(r".*/v(\d+)", vndk_dir).group(1)
-                                          for vndk_dir in vndk_dir_list]
-  latest_version = max(vndk_ver_list)
-  if latest_version == '27':
-    """Exit without error because VNDK v27 is not using ld.config.txt template
-    """
-    sys.exit(0)
-  return latest_version
-
-def get_vendor_configuration(ld_config_file):
-  """Reads the ld.config.txt file to parse the namespace configurations.
-  It finds the configurations that include vendor directories.
-
-  Args:
-    ld_config_file: string, path (relative to build top) of the ld.config.txt
-                    file.
-  Returns:
-    configs: dict{string:[string]}, dictionary of namespace configurations.
-             it has 'section + property' names as keys and the directory list
-             as values.
-  """
-  try:
-    conf_file = open(ld_config_file)
-  except IOError:
-    print("error: could not read %s" % ld_config_file)
-    sys.exit(1)
-
-  configs = dict()
-  current_section = None
-
-  with conf_file:
-    for line in conf_file:
-      # ignore comments
-      found = line.find('#')
-      if found != -1:
-        line = line[:found]
-      line = line.strip()
-      if not line:
-        continue
-
-      if line[0] == '[' and line[-1] == ']':
-        # new section started
-        current_section = line[1:-1]
-        continue
-
-      if current_section == None:
-        continue
-
-      found = line.find('+=')
-      opr_len = 2
-      if found == -1:
-        found = line.find('=')
-        opr_len = 1
-      if found == -1:
-        continue
-
-      namespace = line[:found].strip()
-      if not namespace.endswith(".paths"):
-        # check ".paths" only
-        continue
-      namespace = '[' + current_section + ']' + namespace
-      values = line[found + opr_len:].strip()
-      directories = values.split(':')
-
-      for directory in directories:
-        if any(vendor_dir in directory for vendor_dir in VENDOR_DIRECTORIES):
-          if namespace in configs:
-            configs[namespace].append(directory)
-          else:
-            configs[namespace] = [directory]
-
-  return configs
-
-def get_snapshot_config(version):
-  """Finds the ld.config.{version}.txt file from the VNDK snapshot directory.
-  In the vndk prebuilt directory (prebuilts/vndk/v{version}), it searches
-  {arch}/configs/ld.config.{version}.txt file, where {arch} is one of ('arm64',
-  'arm', 'x86_64', 'x86').
-
-  Args:
-    version: string, the VNDK snapshot version to search.
-  Returns:
-    ld_config_file: string, relative path to ld.config.{version}.txt
-  """
-  arch_list = ('arm64', 'arm', 'x86_64', 'x86')
-  for arch in arch_list:
-    ld_config_file = (PREBUILTS_VNDK_DIR
-                + "/v{0}/{1}/configs/ld.config.{0}.txt".format(version, arch))
-    if os.path.isfile(ld_config_file):
-      return ld_config_file
-  print("error: cannot find ld.config.{0}.txt file in snapshot v{0}"
-                                                        .format(version))
-  sys.exit(1)
-
-def check_backward_compatibility(ld_config, vndk_snapshot_version):
-  """Checks backward compatibility for current ld.config.txt file with the
-  old ld.config.txt file. If any of the vendor directories in the old namespace
-  configurations are missing, the test will fail. It is allowed to have new
-  vendor directories in current ld.config.txt file.
-
-  Args:
-    ld_config: string, relative path to current ld.config.txt file.
-    vndk_snapshot_version: string, the VNDK snapshot version that has an old
-                           ld.config.txt file to compare.
-  Returns:
-    result: bool, True if the current configuration is backward compatible.
-  """
-  current_config = get_vendor_configuration(ld_config)
-  old_config = get_vendor_configuration(
-                                get_snapshot_config(vndk_snapshot_version))
-  for namespace in old_config:
-    if namespace not in current_config:
-      print("error: cannot find %s which was provided in ld.config.%s.txt"
-                                        % (namespace, vndk_snapshot_version))
-      return False
-    for path in old_config[namespace]:
-      if not path in current_config[namespace]:
-        print("error: %s for %s in ld.config.%s.txt are missing in %s"
-                % (path, namespace, vndk_snapshot_version, ld_config))
-        return False
-  return True
-
-def main():
-  if len(sys.argv) != 2:
-    print ("Usage: %s target_ld_config_txt_file_name" % sys.argv[0])
-    sys.exit(1)
-
-  latest_vndk_snapshot_version = find_latest_vndk_snapshot_version()
-  if not check_backward_compatibility(sys.argv[1],
-                                          latest_vndk_snapshot_version):
-    print("error: %s has backward incompatible changes to old "
-          "vendor partition." % sys.argv[1])
-    sys.exit(1)
-
-  # Current ld.config.txt file is backward compatible
-  sys.exit(0)
-
-if __name__ == '__main__':
-  main()
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
deleted file mode 100644
index 44f7b65..0000000
--- a/rootdir/update_and_install_ld_config.mk
+++ /dev/null
@@ -1,207 +0,0 @@
-#####################################################################
-# Builds linker config file, ld.config.txt, from the specified template
-# under $(LOCAL_PATH)/etc/*.
-#
-# Inputs:
-#   (expected to follow an include of $(BUILD_SYSTEM)/base_rules.mk)
-#   ld_config_template: template linker config file to use,
-#                       e.g. $(LOCAL_PATH)/etc/ld.config.txt
-#   vndk_version: version of the VNDK library lists used to update the
-#                 template linker config file, e.g. 28
-#   lib_list_from_prebuilts: should be set to 'true' if the VNDK library
-#                            lists should be read from /prebuilts/vndk/*
-#   libz_is_llndk: should be set to 'true' if libz must be included in
-#                  llndk and not in vndk-sp
-# Outputs:
-#   Builds and installs ld.config.$VER.txt or ld.config.vndk_lite.txt
-#####################################################################
-
-# Read inputs
-ld_config_template := $(strip $(ld_config_template))
-check_backward_compatibility := $(strip $(check_backward_compatibility))
-vndk_version := $(strip $(vndk_version))
-lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts))
-libz_is_llndk := $(strip $(libz_is_llndk))
-
-my_vndk_use_core_variant := $(TARGET_VNDK_USE_CORE_VARIANT)
-ifeq ($(lib_list_from_prebuilts),true)
-my_vndk_use_core_variant := false
-endif
-
-compatibility_check_script := \
-  $(LOCAL_PATH)/ld_config_backward_compatibility_check.py
-intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE))
-library_lists_dir := $(intermediates_dir)
-ifeq ($(lib_list_from_prebuilts),true)
-  library_lists_dir := prebuilts/vndk/v$(vndk_version)/$(TARGET_ARCH)/configs
-endif
-
-llndk_libraries_file := $(library_lists_dir)/llndk.libraries.$(vndk_version).txt
-vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
-vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.$(vndk_version).txt
-vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.$(vndk_version).txt
-llndk_moved_to_apex_libraries_file := $(library_lists_dir)/llndkinapex.libraries.txt
-ifeq ($(my_vndk_use_core_variant),true)
-vndk_using_core_variant_libraries_file := $(library_lists_dir)/vndk_using_core_variant.libraries.$(vndk_version).txt
-endif
-
-sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
-  $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(UBSAN_RUNTIME_LIBRARY) \
-  $(TSAN_RUNTIME_LIBRARY) \
-  $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_HWADDRESS_SANITIZER_RUNTIME_LIBRARY) \
-  $(2ND_UBSAN_RUNTIME_LIBRARY) \
-  $(2ND_TSAN_RUNTIME_LIBRARY)))
-# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used.
-vndk_version_suffix := $(if $(vndk_version),-$(vndk_version))
-
-ifneq ($(lib_list_from_prebuilts),true)
-ifeq ($(libz_is_llndk),true)
-  llndk_libraries_list := $(LLNDK_LIBRARIES) libz
-  vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))
-else
-  llndk_libraries_list := $(LLNDK_LIBRARIES)
-  vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)
-endif
-
-# LLNDK libraries that has been moved to an apex package and no longer are present on
-# /system image.
-llndk_libraries_moved_to_apex_list:=$(LLNDK_MOVED_TO_APEX_LIBRARIES)
-
-# Returns the unique installed basenames of a module, or module.so if there are
-# none.  The guess is to handle cases like libc, where the module itself is
-# marked uninstallable but a symlink is installed with the name libc.so.
-# $(1): list of libraries
-# $(2): suffix to to add to each library (not used for guess)
-define module-installed-files-or-guess
-$(foreach lib,$(1),$(or $(strip $(sort $(notdir $(call module-installed-files,$(lib)$(2))))),$(lib).so))
-endef
-
-# $(1): list of libraries
-# $(2): suffix to add to each library
-# $(3): output file to write the list of libraries to
-define write-libs-to-file
-$(3): PRIVATE_LIBRARIES := $(1)
-$(3): PRIVATE_SUFFIX := $(2)
-$(3):
-	echo -n > $$@ && $$(foreach so,$$(call module-installed-files-or-guess,$$(PRIVATE_LIBRARIES),$$(PRIVATE_SUFFIX)),echo $$(so) >> $$@;)
-endef
-$(eval $(call write-libs-to-file,$(llndk_libraries_list),,$(llndk_libraries_file)))
-$(eval $(call write-libs-to-file,$(vndksp_libraries_list),.vendor,$(vndksp_libraries_file)))
-$(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),.vendor,$(vndkcore_libraries_file)))
-$(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),.vendor,$(vndkprivate_libraries_file)))
-ifeq ($(my_vndk_use_core_variant),true)
-$(eval $(call write-libs-to-file,$(VNDK_USING_CORE_VARIANT_LIBRARIES),,$(vndk_using_core_variant_libraries_file)))
-endif
-endif # ifneq ($(lib_list_from_prebuilts),true)
-
-# Given a file with a list of libs, filter-out the VNDK private libraries
-# and write resulting list to a new file in "a:b:c" format
-#
-# $(1): libs file from which to filter-out VNDK private libraries
-# $(2): output file with the filtered list of lib names
-$(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \
-  paste -sd ":" $(1) > $(2) && \
-  while read -r privatelib; do sed -i.bak "s/$$privatelib//" $(2) ; done < $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) && \
-  sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) && \
-  rm -f $(2).bak
-
-# # Given a file with a list of libs in "a:b:c" format, filter-out the LLNDK libraries migrated into apex file
-# # and write resulting list to a new file in "a:b:c" format
- $(LOCAL_BUILT_MODULE): private-filter-out-llndk-in-apex-libs = \
-   for lib in $(PRIVATE_LLNDK_LIBRARIES_MOVED_TO_APEX_LIST); do sed -i.bak s/$$lib.so// $(1); done && \
-   sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(1) && \
-   rm -f $(1).bak
-
-$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE := $(vndkprivate_libraries_file)
-$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix)
-$(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir)
-$(LOCAL_BUILT_MODULE): PRIVATE_COMP_CHECK_SCRIPT := $(compatibility_check_script)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_TAG := \#VNDK$(vndk_version)\#
-$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_MOVED_TO_APEX_LIST := $(llndk_libraries_moved_to_apex_list)
-deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
-  $(vndkprivate_libraries_file)
-ifeq ($(check_backward_compatibility),true)
-deps += $(compatibility_check_script) $(wildcard prebuilts/vndk/*/*/configs/ld.config.*.txt)
-endif
-ifeq ($(my_vndk_use_core_variant),true)
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE := $(vndk_using_core_variant_libraries_file)
-deps += $(vndk_using_core_variant_libraries_file)
-endif
-
-$(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps)
-	@echo "Generate: $< -> $@"
-ifeq ($(check_backward_compatibility),true)
-	@echo "Checking backward compatibility..."
-	$(hide) $(PRIVATE_COMP_CHECK_SCRIPT) $<
-endif
-	@mkdir -p $(dir $@)
-	$(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
-	$(call private-filter-out-llndk-in-apex-libs,$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)
-	$(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@
-	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)
-	$(hide) sed -i.bak -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@
-	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)
-	$(hide) sed -i.bak -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@
-
-ifeq ($(my_vndk_use_core_variant),true)
-	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)
-	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%?,vndk_in_system?g" $@
-	$(hide) sed -i.bak -e "s?%VNDK_USING_CORE_VARIANT_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)?g" $@
-else
-	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%??g" $@
-	# Unlike LLNDK or VNDK-SP, VNDK_USING_CORE_VARIANT_LIBRARIES can be nothing
-	# if TARGET_VNDK_USE_CORE_VARIANT is not set.  In this case, we need to remove
-	# the entire line in the linker config so that we are not left with a line
-	# like:
-	#   namespace.vndk.link.vndk_in_system.shared_libs =
-	$(hide) sed -i.bak -e 's?^.*= %VNDK_USING_CORE_VARIANT_LIBRARIES%$$??' $@
-endif
-
-	$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
-	while read -r privatelib; \
-	do (grep $$privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk ; \
-	done < $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) && \
-	paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \
-	sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@
-
-	$(hide) sed -i.bak -e "s?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g" $@
-	$(hide) sed -i.bak -e "s?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g" $@
-	$(hide) sed -i.bak -e "s?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g" $@
-	$(hide) sed -i.bak -e "s?%SYSTEM_EXT%?$(TARGET_COPY_OUT_SYSTEM_EXT)?g" $@
-	$(hide) sed -i.bak -e "s?^$(PRIVATE_VNDK_VERSION_TAG)??g" $@
-	$(hide) sed -i.bak "/^\#VNDK[0-9]\{2\}\#.*$$/d" $@
-	$(hide) rm -f $@.bak
-
-ld_config_template :=
-check_backward_compatibility :=
-vndk_version :=
-lib_list_from_prebuilts :=
-libz_is_llndk :=
-compatibility_check_script :=
-intermediates_dir :=
-library_lists_dir :=
-llndk_libraries_file :=
-llndk_moved_to_apex_libraries_file :=
-vndksp_libraries_file :=
-vndkcore_libraries_file :=
-vndkprivate_libraries_file :=
-deps :=
-sanitizer_runtime_libraries :=
-vndk_version_suffix :=
-llndk_libraries_list :=
-vndksp_libraries_list :=
-write-libs-to-file :=
-
-ifeq ($(my_vndk_use_core_variant),true)
-vndk_using_core_variant_libraries_file :=
-vndk_using_core_variant_libraries_list :=
-endif
-
-my_vndk_use_core_variant :=
diff --git a/storaged/main.cpp b/storaged/main.cpp
index 3817fb5..e35bd6f 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -51,7 +51,7 @@
     storaged_sp->init();
     storaged_sp->report_storage_info();
 
-    LOG_TO(SYSTEM, INFO) << "storaged: Start";
+    LOG(INFO) << "storaged: Start";
 
     for (;;) {
         storaged_sp->event_checked();
@@ -76,6 +76,8 @@
     bool flag_dump_perf = false;
     int opt;
 
+    android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+
     for (;;) {
         int opt_idx = 0;
         static struct option long_options[] = {
@@ -124,13 +126,13 @@
         pthread_t storaged_main_thread;
         errno = pthread_create(&storaged_main_thread, NULL, storaged_main, NULL);
         if (errno != 0) {
-            PLOG_TO(SYSTEM, ERROR) << "Failed to create main thread";
+            PLOG(ERROR) << "Failed to create main thread";
             return -1;
         }
 
         if (StoragedService::start() != android::OK ||
             StoragedPrivateService::start() != android::OK) {
-            PLOG_TO(SYSTEM, ERROR) << "Failed to start storaged service";
+            PLOG(ERROR) << "Failed to start storaged service";
             return -1;
         }
 
diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp
index 1d934a2..573b8c5 100644
--- a/storaged/storaged.cpp
+++ b/storaged/storaged.cpp
@@ -97,25 +97,23 @@
 
     health = get_health_service();
     if (health == NULL) {
-        LOG_TO(SYSTEM, WARNING) << "health: failed to find IHealth service";
+        LOG(WARNING) << "health: failed to find IHealth service";
         return;
     }
 
     BatteryStatus status = BatteryStatus::UNKNOWN;
     auto ret = health->getChargeStatus([&](Result r, BatteryStatus v) {
         if (r != Result::SUCCESS) {
-            LOG_TO(SYSTEM, WARNING)
-                << "health: cannot get battery status " << toString(r);
+            LOG(WARNING) << "health: cannot get battery status " << toString(r);
             return;
         }
         if (v == BatteryStatus::UNKNOWN) {
-            LOG_TO(SYSTEM, WARNING) << "health: invalid battery status";
+            LOG(WARNING) << "health: invalid battery status";
         }
         status = v;
     });
     if (!ret.isOk()) {
-        LOG_TO(SYSTEM, WARNING) << "health: get charge status transaction error "
-            << ret.description();
+        LOG(WARNING) << "health: get charge status transaction error " << ret.description();
     }
 
     mUidm.init(is_charger_on(status));
@@ -126,11 +124,11 @@
 
 void storaged_t::serviceDied(uint64_t cookie, const wp<::android::hidl::base::V1_0::IBase>& who) {
     if (health != NULL && interfacesEqual(health, who.promote())) {
-        LOG_TO(SYSTEM, ERROR) << "health service died, exiting";
+        LOG(ERROR) << "health service died, exiting";
         android::hardware::IPCThreadState::self()->stopProcess();
         exit(1);
     } else {
-        LOG_TO(SYSTEM, ERROR) << "unknown service died";
+        LOG(ERROR) << "unknown service died";
     }
 }
 
@@ -192,7 +190,7 @@
         reinterpret_cast<const Bytef*>(uid_io_usage.SerializeAsString().c_str()),
         uid_io_usage.ByteSize());
     if (proto.crc() != computed_crc) {
-        LOG_TO(SYSTEM, WARNING) << "CRC mismatch in " << proto_file;
+        LOG(WARNING) << "CRC mismatch in " << proto_file;
         return;
     }
 
@@ -228,8 +226,7 @@
     char* data = nullptr;
     if (posix_memalign(reinterpret_cast<void**>(&data),
                        pagesize, proto->ByteSize())) {
-        PLOG_TO(SYSTEM, ERROR) << "Faied to alloc aligned buffer (size: "
-                               << proto->ByteSize() << ")";
+        PLOG(ERROR) << "Faied to alloc aligned buffer (size: " << proto->ByteSize() << ")";
         return data;
     }
 
@@ -246,7 +243,7 @@
                     (user_id == USER_SYSTEM ? O_DIRECT : 0),
                  S_IRUSR | S_IWUSR)));
     if (fd == -1) {
-        PLOG_TO(SYSTEM, ERROR) << "Faied to open tmp file: " << tmp_file;
+        PLOG(ERROR) << "Faied to open tmp file: " << tmp_file;
         return;
     }
 
@@ -261,7 +258,7 @@
             start = steady_clock::now();
             ret = write(fd, data, MIN(benchmark_unit_size, size));
             if (ret <= 0) {
-                PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
+                PLOG(ERROR) << "Faied to write tmp file: " << tmp_file;
                 return;
             }
             end = steady_clock::now();
@@ -284,7 +281,7 @@
         }
     } else {
         if (!WriteFully(fd, data, size)) {
-            PLOG_TO(SYSTEM, ERROR) << "Faied to write tmp file: " << tmp_file;
+            PLOG(ERROR) << "Faied to write tmp file: " << tmp_file;
             return;
         }
     }
@@ -343,22 +340,21 @@
     if (mConfig.event_time_check_usec &&
         clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ts) < 0) {
         check_time = false;
-        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        PLOG(ERROR) << "clock_gettime() failed";
     }
 
     event();
 
     if (mConfig.event_time_check_usec && check_time) {
         if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ts) < 0) {
-            PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+            PLOG(ERROR) << "clock_gettime() failed";
             return;
         }
         int64_t cost = (end_ts.tv_sec - start_ts.tv_sec) * SEC_TO_USEC +
                        (end_ts.tv_nsec - start_ts.tv_nsec) / USEC_TO_NSEC;
         if (cost > mConfig.event_time_check_usec) {
-            LOG_TO(SYSTEM, ERROR)
-                << "event loop spent " << cost << " usec, threshold "
-                << mConfig.event_time_check_usec << " usec";
+            LOG(ERROR) << "event loop spent " << cost << " usec, threshold "
+                       << mConfig.event_time_check_usec << " usec";
         }
     }
 }
diff --git a/storaged/storaged_diskstats.cpp b/storaged/storaged_diskstats.cpp
index 8b5001d..52bd4e0 100644
--- a/storaged/storaged_diskstats.cpp
+++ b/storaged/storaged_diskstats.cpp
@@ -41,8 +41,8 @@
     // skip if the input structure are all zeros
     if (perf == NULL || perf->is_zero()) return;
 
-    LOG_TO(SYSTEM, INFO) << "disk_perf " << type
-              << " rd: " << perf->read_perf << " kbps, " << perf->read_ios << " iops"
+    LOG(INFO) << "disk_perf " << type << " rd: " << perf->read_perf << " kbps, " << perf->read_ios
+              << " iops"
               << " wr: " << perf->write_perf << " kbps, " << perf->write_ios << " iops"
               << " q: " << perf->queue;
 }
@@ -71,7 +71,7 @@
     // when system is running.
     int ret = clock_gettime(CLOCK_MONOTONIC, ts);
     if (ret < 0) {
-        PLOG_TO(SYSTEM, ERROR) << "clock_gettime() failed";
+        PLOG(ERROR) << "clock_gettime() failed";
         return false;
     }
     return true;
@@ -93,7 +93,7 @@
 
     std::string buffer;
     if (!android::base::ReadFileToString(disk_stats_path, &buffer)) {
-        PLOG_TO(SYSTEM, ERROR) << disk_stats_path << ": ReadFileToString failed.";
+        PLOG(ERROR) << disk_stats_path << ": ReadFileToString failed.";
         return false;
     }
 
@@ -130,12 +130,12 @@
     bool success = false;
     auto ret = service->getDiskStats([&success, stats](auto result, const auto& halStats) {
         if (result == Result::NOT_SUPPORTED) {
-            LOG_TO(SYSTEM, DEBUG) << "getDiskStats is not supported on health HAL.";
+            LOG(DEBUG) << "getDiskStats is not supported on health HAL.";
             return;
         }
         if (result != Result::SUCCESS || halStats.size() == 0) {
-            LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with result " << toString(result)
-                                  << " and size " << halStats.size();
+            LOG(ERROR) << "getDiskStats failed with result " << toString(result) << " and size "
+                       << halStats.size();
             return;
         }
 
@@ -144,7 +144,7 @@
     });
 
     if (!ret.isOk()) {
-        LOG_TO(SYSTEM, ERROR) << "getDiskStats failed with " << ret.description();
+        LOG(ERROR) << "getDiskStats failed with " << ret.description();
         return false;
     }
 
@@ -199,9 +199,9 @@
 void add_disk_stats(struct disk_stats* src, struct disk_stats* dst)
 {
     if (dst->end_time != 0 && dst->end_time != src->start_time) {
-        LOG_TO(SYSTEM, WARNING) << "Two dis-continuous periods of diskstats"
-            << " are added. dst end with " << dst->end_time
-            << ", src start with " << src->start_time;
+        LOG(WARNING) << "Two dis-continuous periods of diskstats"
+                     << " are added. dst end with " << dst->end_time << ", src start with "
+                     << src->start_time;
     }
 
     *dst += *src;
diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp
index 6668cf3..bb21829 100644
--- a/storaged/storaged_info.cpp
+++ b/storaged/storaged_info.cpp
@@ -76,7 +76,7 @@
     if (!perf_history.has_day_start_sec() ||
         perf_history.daily_perf_size() > (int)daily_perf.size() ||
         perf_history.weekly_perf_size() > (int)weekly_perf.size()) {
-        LOG_TO(SYSTEM, ERROR) << "Invalid IOPerfHistory proto";
+        LOG(ERROR) << "Invalid IOPerfHistory proto";
         return;
     }
 
@@ -114,7 +114,7 @@
 {
     struct statvfs buf;
     if (statvfs(userdata_path.c_str(), &buf) != 0) {
-        PLOG_TO(SYSTEM, WARNING) << "Failed to get userdata info";
+        PLOG(WARNING) << "Failed to get userdata info";
         return;
     }
 
@@ -328,12 +328,12 @@
 void health_storage_info_t::report() {
     auto ret = mHealth->getStorageInfo([this](auto result, const auto& halInfos) {
         if (result == Result::NOT_SUPPORTED) {
-            LOG_TO(SYSTEM, DEBUG) << "getStorageInfo is not supported on health HAL.";
+            LOG(DEBUG) << "getStorageInfo is not supported on health HAL.";
             return;
         }
         if (result != Result::SUCCESS || halInfos.size() == 0) {
-            LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with result " << toString(result)
-                                  << " and size " << halInfos.size();
+            LOG(ERROR) << "getStorageInfo failed with result " << toString(result) << " and size "
+                       << halInfos.size();
             return;
         }
         set_values_from_hal_storage_info(halInfos[0]);
@@ -341,7 +341,7 @@
     });
 
     if (!ret.isOk()) {
-        LOG_TO(SYSTEM, ERROR) << "getStorageInfo failed with " << ret.description();
+        LOG(ERROR) << "getStorageInfo failed with " << ret.description();
     }
 }
 
diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp
index 55380ba..f47bf72 100644
--- a/storaged/storaged_uid_monitor.cpp
+++ b/storaged/storaged_uid_monitor.cpp
@@ -71,8 +71,7 @@
         !ParseUint(fields[8],  &io[BACKGROUND].write_bytes) ||
         !ParseUint(fields[9],  &io[FOREGROUND].fsync) ||
         !ParseUint(fields[10], &io[BACKGROUND].fsync)) {
-        LOG_TO(SYSTEM, WARNING) << "Invalid uid I/O stats: \""
-                                << s << "\"";
+        LOG(WARNING) << "Invalid uid I/O stats: \"" << s << "\"";
         return false;
     }
     return true;
@@ -95,8 +94,7 @@
         !ParseUint(fields[size - 3], &io[BACKGROUND].write_bytes) ||
         !ParseUint(fields[size - 2], &io[FOREGROUND].fsync) ||
         !ParseUint(fields[size - 1], &io[BACKGROUND].fsync)) {
-        LOG_TO(SYSTEM, WARNING) << "Invalid task I/O stats: \""
-                                << s << "\"";
+        LOG(WARNING) << "Invalid task I/O stats: \"" << s << "\"";
         return false;
     }
     comm = Join(std::vector<std::string>(
@@ -123,13 +121,13 @@
 {
     sp<IServiceManager> sm = defaultServiceManager();
     if (sm == NULL) {
-        LOG_TO(SYSTEM, ERROR) << "defaultServiceManager failed";
+        LOG(ERROR) << "defaultServiceManager failed";
         return;
     }
 
     sp<IBinder> binder = sm->getService(String16("package_native"));
     if (binder == NULL) {
-        LOG_TO(SYSTEM, ERROR) << "getService package_native failed";
+        LOG(ERROR) << "getService package_native failed";
         return;
     }
 
@@ -137,8 +135,7 @@
     std::vector<std::string> names;
     binder::Status status = package_mgr->getNamesForUids(uids, &names);
     if (!status.isOk()) {
-        LOG_TO(SYSTEM, ERROR) << "package_native::getNamesForUids failed: "
-                              << status.exceptionMessage();
+        LOG(ERROR) << "package_native::getNamesForUids failed: " << status.exceptionMessage();
         return;
     }
 
@@ -158,7 +155,7 @@
     std::unordered_map<uint32_t, uid_info> uid_io_stats;
     std::string buffer;
     if (!ReadFileToString(UID_IO_STATS_PATH, &buffer)) {
-        PLOG_TO(SYSTEM, ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
+        PLOG(ERROR) << UID_IO_STATS_PATH << ": ReadFileToString failed";
         return uid_io_stats;
     }
 
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 5f56408..e230941 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -48,6 +48,8 @@
         return VIRT_RPMB;
     } else if (!strcmp(dev_type_name, "sock")) {
         return SOCK_RPMB;
+    } else if (!strcmp(dev_type_name, "ufs")) {
+        return UFS_RPMB;
     } else {
         return UNKNOWN_RPMB;
     }
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
index 0bd9e68..7dfd0d0 100644
--- a/trusty/storage/proxy/rpmb.c
+++ b/trusty/storage/proxy/rpmb.c
@@ -16,6 +16,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <scsi/sg.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -51,6 +52,50 @@
 
 #define MMC_BLOCK_SIZE 512
 
+/*
+ * There should be no timeout for security protocol ioctl call, so we choose a
+ * large number for timeout.
+ * 20000 millisecs == 20 seconds
+ */
+#define TIMEOUT 20000
+
+/*
+ * The sg device driver that supports new interface has a major version number of "3".
+ * SG_GET_VERSION_NUM ioctl() will yield a number greater than or 30000.
+ */
+#define RPMB_MIN_SG_VERSION_NUM 30000
+
+/*
+ * CDB format of SECURITY PROTOCOL IN/OUT commands
+ * (JEDEC Standard No. 220D, Page 264)
+ */
+struct sec_proto_cdb {
+    /*
+     * OPERATION CODE = A2h for SECURITY PROTOCOL IN command,
+     * OPERATION CODE = B5h for SECURITY PROTOCOL OUT command.
+     */
+    uint8_t opcode;
+    /* SECURITY PROTOCOL = ECh (JEDEC Universal Flash Storage) */
+    uint8_t sec_proto;
+    /*
+     * The SECURITY PROTOCOL SPECIFIC field specifies the RPMB Protocol ID.
+     * CDB Byte 2 = 00h and CDB Byte 3 = 01h for RPMB Region 0.
+     */
+    uint8_t cdb_byte_2;
+    uint8_t cdb_byte_3;
+    /*
+     * Byte 4 and 5 are reserved.
+     */
+    uint8_t cdb_byte_4;
+    uint8_t cdb_byte_5;
+    /* ALLOCATION/TRANSFER LENGTH in big-endian */
+    uint32_t length;
+    /* Byte 9 is reserved. */
+    uint8_t cdb_byte_10;
+    /* CONTROL = 00h. */
+    uint8_t ctrl;
+} __packed;
+
 static int rpmb_fd = -1;
 static uint8_t read_buf[4096];
 static enum dev_type dev_type = UNKNOWN_RPMB;
@@ -71,6 +116,21 @@
 
 #endif
 
+static void set_sg_io_hdr(sg_io_hdr_t* io_hdrp, int dxfer_direction, unsigned char cmd_len,
+                          unsigned char mx_sb_len, unsigned int dxfer_len, void* dxferp,
+                          unsigned char* cmdp, void* sbp) {
+    memset(io_hdrp, 0, sizeof(sg_io_hdr_t));
+    io_hdrp->interface_id = 'S';
+    io_hdrp->dxfer_direction = dxfer_direction;
+    io_hdrp->cmd_len = cmd_len;
+    io_hdrp->mx_sb_len = mx_sb_len;
+    io_hdrp->dxfer_len = dxfer_len;
+    io_hdrp->dxferp = dxferp;
+    io_hdrp->cmdp = cmdp;
+    io_hdrp->sbp = sbp;
+    io_hdrp->timeout = TIMEOUT;
+}
+
 static int send_mmc_rpmb_req(int mmc_fd, const struct storage_rpmb_send_req* req) {
     struct {
         struct mmc_ioc_multi_cmd multi;
@@ -132,6 +192,57 @@
     return rc;
 }
 
+static int send_ufs_rpmb_req(int sg_fd, const struct storage_rpmb_send_req* req) {
+    int rc;
+    const uint8_t* write_buf = req->payload;
+    /*
+     * Meaning of member values are stated on the definition of struct sec_proto_cdb.
+     */
+    struct sec_proto_cdb in_cdb = {0xA2, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
+    struct sec_proto_cdb out_cdb = {0xB5, 0xEC, 0x00, 0x01, 0x00, 0x00, 0, 0x00, 0x00};
+    unsigned char sense_buffer[32];
+
+    if (req->reliable_write_size) {
+        /* Prepare SECURITY PROTOCOL OUT command. */
+        out_cdb.length = __builtin_bswap32(req->reliable_write_size);
+        sg_io_hdr_t io_hdr;
+        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
+                      req->reliable_write_size, (void*)write_buf, (unsigned char*)&out_cdb,
+                      sense_buffer);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+        write_buf += req->reliable_write_size;
+    }
+
+    if (req->write_size) {
+        /* Prepare SECURITY PROTOCOL OUT command. */
+        out_cdb.length = __builtin_bswap32(req->write_size);
+        sg_io_hdr_t io_hdr;
+        set_sg_io_hdr(&io_hdr, SG_DXFER_TO_DEV, sizeof(out_cdb), sizeof(sense_buffer),
+                      req->write_size, (void*)write_buf, (unsigned char*)&out_cdb, sense_buffer);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+        write_buf += req->write_size;
+    }
+
+    if (req->read_size) {
+        /* Prepare SECURITY PROTOCOL IN command. */
+        out_cdb.length = __builtin_bswap32(req->read_size);
+        sg_io_hdr_t io_hdr;
+        set_sg_io_hdr(&io_hdr, SG_DXFER_FROM_DEV, sizeof(in_cdb), sizeof(sense_buffer),
+                      req->read_size, read_buf, (unsigned char*)&in_cdb, sense_buffer);
+        rc = ioctl(sg_fd, SG_IO, &io_hdr);
+        if (rc < 0) {
+            ALOGE("%s: ufs ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+        }
+    }
+    return rc;
+}
+
 static int send_virt_rpmb_req(int rpmb_fd, void* read_buf, size_t read_size, const void* payload,
                               size_t payload_size) {
     int rc;
@@ -194,6 +305,13 @@
             msg->result = STORAGE_ERR_GENERIC;
             goto err_response;
         }
+    } else if (dev_type == UFS_RPMB) {
+        rc = send_ufs_rpmb_req(rpmb_fd, req);
+        if (rc < 0) {
+            ALOGE("send_ufs_rpmb_req failed: %d, %s\n", rc, strerror(errno));
+            msg->result = STORAGE_ERR_GENERIC;
+            goto err_response;
+        }
     } else if ((dev_type == VIRT_RPMB) || (dev_type == SOCK_RPMB)) {
         size_t payload_size = req->reliable_write_size + req->write_size;
         rc = send_virt_rpmb_req(rpmb_fd, read_buf, req->read_size, req->payload, payload_size);
@@ -233,7 +351,7 @@
 }
 
 int rpmb_open(const char* rpmb_devname, enum dev_type open_dev_type) {
-    int rc;
+    int rc, sg_version_num;
     dev_type = open_dev_type;
 
     if (dev_type != SOCK_RPMB) {
@@ -243,6 +361,15 @@
             return rc;
         }
         rpmb_fd = rc;
+
+        /* For UFS, it is prudent to check we have a sg device by calling an ioctl */
+        if (dev_type == UFS_RPMB) {
+            if ((ioctl(rpmb_fd, SG_GET_VERSION_NUM, &sg_version_num) < 0) ||
+                (sg_version_num < RPMB_MIN_SG_VERSION_NUM)) {
+                ALOGE("%s is not a sg device, or old sg driver\n", rpmb_devname);
+                return -1;
+            }
+        }
     } else {
         struct sockaddr_un unaddr;
         struct sockaddr *addr = (struct sockaddr *)&unaddr;
@@ -263,6 +390,7 @@
             return rc;
         }
     }
+
     return 0;
 }
 
diff --git a/trusty/storage/proxy/rpmb.h b/trusty/storage/proxy/rpmb.h
index 09af3c5..f4e1b51 100644
--- a/trusty/storage/proxy/rpmb.h
+++ b/trusty/storage/proxy/rpmb.h
@@ -18,7 +18,7 @@
 #include <stdint.h>
 #include <trusty/interface/storage.h>
 
-enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, SOCK_RPMB };
+enum dev_type { UNKNOWN_RPMB, MMC_RPMB, VIRT_RPMB, UFS_RPMB, SOCK_RPMB };
 
 int rpmb_open(const char* rpmb_devname, enum dev_type dev_type);
 int rpmb_send(struct storage_msg* msg, const void* r, size_t req_len);