Merge "Trusty Keymaster@4.0"
diff --git a/adb/Android.bp b/adb/Android.bp
index eec1335..114eb2a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -26,6 +26,7 @@
         "-Wvla",
         "-DADB_HOST=1",         // overridden by adbd_defaults
         "-DALLOW_ADBD_ROOT=0",  // overridden by adbd_defaults
+        "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
     ],
     cpp_std: "experimental",
 
@@ -509,6 +510,52 @@
 }
 
 cc_binary {
+    name: "static_adbd",
+    defaults: ["adbd_defaults", "host_adbd_supported"],
+
+    recovery_available: false,
+    static_executable: true,
+    host_supported: false,
+
+    srcs: [
+        "daemon/main.cpp",
+    ],
+
+    cflags: [
+        "-D_GNU_SOURCE",
+        "-Wno-deprecated-declarations",
+    ],
+
+    strip: {
+        keep_symbols: true,
+    },
+
+    static_libs: [
+        "libadbd",
+        "libadbd_services",
+        "libasyncio",
+        "libavb_user",
+        "libbase",
+        "libbootloader_message",
+        "libcap",
+        "libcrypto",
+        "libcrypto_utils",
+        "libcutils",
+        "libdiagnose_usb",
+        "libext4_utils",
+        "libfec",
+        "libfec_rs",
+        "libfs_mgr",
+        "liblog",
+        "liblp",
+        "libmdnssd",
+        "libminijail",
+        "libselinux",
+        "libsquashfs_utils",
+    ],
+}
+
+cc_binary {
     name: "abb",
 
     defaults: ["adbd_defaults"],
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 2dd22b3..24d4292 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -1048,9 +1048,9 @@
         // New transport selection protocol:
         // This is essentially identical to the previous version, except it returns the selected
         // transport id to the caller as well.
-        if (ConsumePrefix(&service, "tport:")) {
+        if (android::base::ConsumePrefix(&service, "tport:")) {
             legacy = false;
-            if (ConsumePrefix(&service, "serial:")) {
+            if (android::base::ConsumePrefix(&service, "serial:")) {
                 serial_storage = service;
                 serial = serial_storage.c_str();
             } else if (service == "usb") {
@@ -1064,7 +1064,7 @@
             // Selection by id is unimplemented, since you obviously already know the transport id
             // you're connecting to.
         } else {
-            if (ConsumePrefix(&service, "transport-id:")) {
+            if (android::base::ConsumePrefix(&service, "transport-id:")) {
                 if (!ParseUint(&transport_id, service)) {
                     SendFail(reply_fd, "invalid transport id");
                     return HostRequestResult::Handled;
@@ -1075,7 +1075,7 @@
                 type = kTransportLocal;
             } else if (service == "transport-any") {
                 type = kTransportAny;
-            } else if (ConsumePrefix(&service, "transport:")) {
+            } else if (android::base::ConsumePrefix(&service, "transport:")) {
                 serial_storage = service;
                 serial = serial_storage.c_str();
             }
@@ -1216,7 +1216,7 @@
     }
 
     // Indicates a new emulator instance has started.
-    if (ConsumePrefix(&service, "emulator:")) {
+    if (android::base::ConsumePrefix(&service, "emulator:")) {
         unsigned int port;
         if (!ParseUint(&port, service)) {
           LOG(ERROR) << "received invalid port for emulator: " << service;
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index f5cdcb5..bdb8efa 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -34,7 +34,7 @@
 #include "adb_utils.h"
 #include "sysdeps.h"
 
-bool SendProtocolString(int fd, std::string_view s) {
+bool SendProtocolString(borrowed_fd fd, std::string_view s) {
     unsigned int length = s.size();
     if (length > MAX_PAYLOAD - 4) {
         errno = EMSGSIZE;
@@ -47,7 +47,7 @@
     return WriteFdExactly(fd, str);
 }
 
-bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+bool ReadProtocolString(borrowed_fd fd, std::string* s, std::string* error) {
     char buf[5];
     if (!ReadFdExactly(fd, buf, 4)) {
         *error = perror_str("protocol fault (couldn't read status length)");
@@ -65,57 +65,57 @@
     return true;
 }
 
-bool SendOkay(int fd) {
+bool SendOkay(borrowed_fd fd) {
     return WriteFdExactly(fd, "OKAY", 4);
 }
 
-bool SendFail(int fd, std::string_view reason) {
+bool SendFail(borrowed_fd fd, std::string_view reason) {
     return WriteFdExactly(fd, "FAIL", 4) && SendProtocolString(fd, reason);
 }
 
-bool ReadFdExactly(int fd, void* buf, size_t len) {
+bool ReadFdExactly(borrowed_fd fd, void* buf, size_t len) {
     char* p = reinterpret_cast<char*>(buf);
 
     size_t len0 = len;
 
-    D("readx: fd=%d wanted=%zu", fd, len);
+    D("readx: fd=%d wanted=%zu", fd.get(), len);
     while (len > 0) {
         int r = adb_read(fd, p, len);
         if (r > 0) {
             len -= r;
             p += r;
         } else if (r == -1) {
-            D("readx: fd=%d error %d: %s", fd, errno, strerror(errno));
+            D("readx: fd=%d error %d: %s", fd.get(), errno, strerror(errno));
             return false;
         } else {
-            D("readx: fd=%d disconnected", fd);
+            D("readx: fd=%d disconnected", fd.get());
             errno = 0;
             return false;
         }
     }
 
-    VLOG(RWX) << "readx: fd=" << fd << " wanted=" << len0 << " got=" << (len0 - len)
-              << " " << dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
+    VLOG(RWX) << "readx: fd=" << fd.get() << " wanted=" << len0 << " got=" << (len0 - len) << " "
+              << dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
 
     return true;
 }
 
-bool WriteFdExactly(int fd, const void* buf, size_t len) {
+bool WriteFdExactly(borrowed_fd fd, const void* buf, size_t len) {
     const char* p = reinterpret_cast<const char*>(buf);
     int r;
 
-    VLOG(RWX) << "writex: fd=" << fd << " len=" << len
-              << " " << dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
+    VLOG(RWX) << "writex: fd=" << fd.get() << " len=" << len << " "
+              << dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
 
     while (len > 0) {
         r = adb_write(fd, p, len);
         if (r == -1) {
-            D("writex: fd=%d error %d: %s", fd, errno, strerror(errno));
+            D("writex: fd=%d error %d: %s", fd.get(), errno, strerror(errno));
             if (errno == EAGAIN) {
                 std::this_thread::yield();
                 continue;
             } else if (errno == EPIPE) {
-                D("writex: fd=%d disconnected", fd);
+                D("writex: fd=%d disconnected", fd.get());
                 errno = 0;
                 return false;
             } else {
@@ -129,15 +129,15 @@
     return true;
 }
 
-bool WriteFdExactly(int fd, const char* str) {
+bool WriteFdExactly(borrowed_fd fd, const char* str) {
     return WriteFdExactly(fd, str, strlen(str));
 }
 
-bool WriteFdExactly(int fd, const std::string& str) {
+bool WriteFdExactly(borrowed_fd fd, const std::string& str) {
     return WriteFdExactly(fd, str.c_str(), str.size());
 }
 
-bool WriteFdFmt(int fd, const char* fmt, ...) {
+bool WriteFdFmt(borrowed_fd fd, const char* fmt, ...) {
     std::string str;
 
     va_list ap;
@@ -148,7 +148,7 @@
     return WriteFdExactly(fd, str);
 }
 
-bool ReadOrderlyShutdown(int fd) {
+bool ReadOrderlyShutdown(borrowed_fd fd) {
     char buf[16];
 
     // Only call this function if you're sure that the peer does
@@ -178,7 +178,7 @@
         // data. We don't repeatedly call adb_read() until we get zero because
         // we don't know how long that would take, but we do know that the
         // caller wants to close the socket soon.
-        VLOG(RWX) << "ReadOrderlyShutdown(" << fd << ") unexpectedly read "
+        VLOG(RWX) << "ReadOrderlyShutdown(" << fd.get() << ") unexpectedly read "
                   << dump_hex(buf, result);
         // Shutdown the socket to prevent the caller from reading or writing to
         // it which doesn't make sense if we just read and discarded some data.
diff --git a/adb/adb_io.h b/adb/adb_io.h
index d6e65d8..9628946 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -25,16 +25,16 @@
 #include "adb_unique_fd.h"
 
 // Sends the protocol "OKAY" message.
-bool SendOkay(int fd);
+bool SendOkay(borrowed_fd fd);
 
 // Sends the protocol "FAIL" message, with the given failure reason.
-bool SendFail(int fd, std::string_view reason);
+bool SendFail(borrowed_fd fd, std::string_view reason);
 
 // Writes a protocol-format string; a four hex digit length followed by the string data.
-bool SendProtocolString(int fd, std::string_view s);
+bool SendProtocolString(borrowed_fd fd, std::string_view s);
 
 // Reads a protocol-format string; a four hex digit length followed by the string data.
-bool ReadProtocolString(int fd, std::string* s, std::string* error);
+bool ReadProtocolString(borrowed_fd fd, std::string* s, std::string* error);
 
 // Reads exactly len bytes from fd into buf.
 //
@@ -42,7 +42,7 @@
 // were read. If EOF was found, errno will be set to 0.
 //
 // If this function fails, the contents of buf are undefined.
-bool ReadFdExactly(int fd, void* buf, size_t len);
+bool ReadFdExactly(borrowed_fd fd, void* buf, size_t len);
 
 // Given a client socket, wait for orderly/graceful shutdown. Call this:
 //
@@ -60,19 +60,19 @@
 // connect()s from the client to fail with WSAEADDRINUSE on Windows.
 // Returns true if it is sure that orderly/graceful shutdown has occurred with
 // no additional data read from the server.
-bool ReadOrderlyShutdown(int fd);
+bool ReadOrderlyShutdown(borrowed_fd fd);
 
 // Writes exactly len bytes from buf to fd.
 //
 // Returns false if there is an error or if the fd was closed before the write
 // completed. If the other end of the fd (such as in a socket, pipe, or fifo),
 // is closed, errno will be set to 0.
-bool WriteFdExactly(int fd, const void* buf, size_t len);
+bool WriteFdExactly(borrowed_fd fd, const void* buf, size_t len);
 
 // Same as above, but for strings.
-bool WriteFdExactly(int fd, const char* s);
-bool WriteFdExactly(int fd, const std::string& s);
+bool WriteFdExactly(borrowed_fd fd, const char* s);
+bool WriteFdExactly(borrowed_fd fd, const std::string& s);
 
 // Same as above, but formats the string to send.
-bool WriteFdFmt(int fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
+bool WriteFdFmt(borrowed_fd fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
 #endif /* ADB_IO_H */
diff --git a/adb/adb_unique_fd.h b/adb/adb_unique_fd.h
index d47213d..b6c910a 100644
--- a/adb/adb_unique_fd.h
+++ b/adb/adb_unique_fd.h
@@ -32,6 +32,8 @@
 using unique_fd = android::base::unique_fd;
 #endif
 
+using android::base::borrowed_fd;
+
 template <typename T>
 int adb_close(const android::base::unique_fd_impl<T>&)
         __attribute__((__unavailable__("adb_close called on unique_fd")));
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 9791769..cf5fbc8 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -234,15 +234,15 @@
 
 #if !defined(_WIN32)
 // Windows version provided in sysdeps_win32.cpp
-bool set_file_block_mode(int fd, bool block) {
-    int flags = fcntl(fd, F_GETFL, 0);
+bool set_file_block_mode(borrowed_fd fd, bool block) {
+    int flags = fcntl(fd.get(), F_GETFL, 0);
     if (flags == -1) {
-        PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd;
+        PLOG(ERROR) << "failed to fcntl(F_GETFL) for fd " << fd.get();
         return false;
     }
     flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
-    if (fcntl(fd, F_SETFL, flags) != 0) {
-        PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd << ", flags " << flags;
+    if (fcntl(fd.get(), F_SETFL, flags) != 0) {
+        PLOG(ERROR) << "failed to fcntl(F_SETFL) for fd " << fd.get() << ", flags " << flags;
         return false;
     }
     return true;
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 5800a62..faad03d 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -26,6 +26,7 @@
 #include <android-base/macros.h>
 
 #include "adb.h"
+#include "adb_unique_fd.h"
 
 void close_stdin();
 
@@ -51,7 +52,7 @@
 [[noreturn]] void error_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
 [[noreturn]] void perror_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
 
-bool set_file_block_mode(int fd, bool block);
+bool set_file_block_mode(borrowed_fd fd, bool block);
 
 // Given forward/reverse targets, returns true if they look sane. If an error is found, fills
 // |error| and returns false.
@@ -141,11 +142,3 @@
 
     return true;
 }
-
-inline bool ConsumePrefix(std::string_view* str, std::string_view prefix) {
-  if (str->starts_with(prefix)) {
-    str->remove_prefix(prefix.size());
-    return true;
-  }
-  return false;
-}
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index bd676c2..cdca3aa 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -149,13 +149,13 @@
 TEST(adb_utils, set_file_block_mode) {
     unique_fd fd(adb_open("/dev/null", O_RDWR | O_APPEND));
     ASSERT_GE(fd, 0);
-    int flags = fcntl(fd, F_GETFL, 0);
+    int flags = fcntl(fd.get(), F_GETFL, 0);
     ASSERT_EQ(O_RDWR | O_APPEND, (flags & (O_RDWR | O_APPEND)));
     ASSERT_TRUE(set_file_block_mode(fd, false));
-    int new_flags = fcntl(fd, F_GETFL, 0);
+    int new_flags = fcntl(fd.get(), F_GETFL, 0);
     ASSERT_EQ(flags | O_NONBLOCK, new_flags);
     ASSERT_TRUE(set_file_block_mode(fd, true));
-    new_flags = fcntl(fd, F_GETFL, 0);
+    new_flags = fcntl(fd.get(), F_GETFL, 0);
     ASSERT_EQ(flags, new_flags);
 }
 #endif
diff --git a/adb/client/adb_client.cpp b/adb/client/adb_client.cpp
index 5a7bc8d..7e408a8 100644
--- a/adb/client/adb_client.cpp
+++ b/adb/client/adb_client.cpp
@@ -128,7 +128,7 @@
     return result;
 }
 
-bool adb_status(int fd, std::string* error) {
+bool adb_status(borrowed_fd fd, std::string* error) {
     char buf[5];
     if (!ReadFdExactly(fd, buf, 4)) {
         *error = perror_str("protocol fault (couldn't read status)");
diff --git a/adb/client/adb_client.h b/adb/client/adb_client.h
index 8d32c93..fe1e584 100644
--- a/adb/client/adb_client.h
+++ b/adb/client/adb_client.h
@@ -16,13 +16,14 @@
 
 #pragma once
 
-#include "adb.h"
-#include "sysdeps.h"
-#include "transport.h"
-
 #include <optional>
 #include <string>
 
+#include "adb.h"
+#include "adb_unique_fd.h"
+#include "sysdeps.h"
+#include "transport.h"
+
 // Explicitly check the adb server version.
 // All of the commands below do this implicitly.
 // Only the first invocation of this function will check the server version.
@@ -64,7 +65,7 @@
 
 // Reads a standard adb status response (OKAY|FAIL) and returns true in the
 // event of OKAY, false in the event of FAIL or protocol error.
-bool adb_status(int fd, std::string* _Nonnull error);
+bool adb_status(borrowed_fd fd, std::string* _Nonnull error);
 
 // Create a host command corresponding to selected transport type/serial.
 std::string format_host_command(const char* _Nonnull command);
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index e2a17c5..728e5c1 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -170,9 +170,6 @@
         "     remove this app package from the device\n"
         "     '-k': keep the data and cache directories\n"
         "\n"
-        "backup/restore:\n"
-        "   to show usage run \"adb shell bu help\"\n"
-        "\n"
         "debugging:\n"
         " bugreport [PATH]\n"
         "     write bugreport to given PATH [default=bugreport.zip];\n"
@@ -262,7 +259,7 @@
 // stdout/stderr are routed independently and the remote exit code will be
 // returned.
 // if |callback| is non-null, stdout/stderr output will be handled by it.
-int read_and_dump(int fd, bool use_shell_protocol = false,
+int read_and_dump(borrowed_fd fd, bool use_shell_protocol = false,
                   StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK) {
     int exit_code = 0;
     if (fd < 0) return exit_code;
@@ -305,9 +302,9 @@
             }
             length = protocol->data_length();
         } else {
-            D("read_and_dump(): pre adb_read(fd=%d)", fd);
+            D("read_and_dump(): pre adb_read(fd=%d)", fd.get());
             length = adb_read(fd, raw_buffer, sizeof(raw_buffer));
-            D("read_and_dump(): post adb_read(fd=%d): length=%d", fd, length);
+            D("read_and_dump(): post adb_read(fd=%d): length=%d", fd.get(), length);
             if (length <= 0) {
                 break;
             }
@@ -887,7 +884,7 @@
             return -1;
         }
         fprintf(stderr, "adb: trying pre-KitKat sideload method...\n");
-        return adb_sideload_legacy(filename, package_fd, static_cast<int>(sb.st_size));
+        return adb_sideload_legacy(filename, package_fd.get(), static_cast<int>(sb.st_size));
     }
 
     int opt = SIDELOAD_HOST_BLOCK_SIZE;
@@ -1142,7 +1139,7 @@
     // If we were using a specific transport ID, there's nothing we can wait for.
     if (previous_id == 0) {
         adb_set_transport(previous_type, previous_serial, 0);
-        wait_for_device("wait-for-device", 3000ms);
+        wait_for_device("wait-for-device", 6000ms);
     }
 
     return true;
@@ -1207,14 +1204,14 @@
     return send_shell_command(cmd);
 }
 
-static void write_zeros(int bytes, int fd) {
+static void write_zeros(int bytes, borrowed_fd fd) {
     int old_stdin_mode = -1;
     int old_stdout_mode = -1;
     std::vector<char> buf(bytes);
 
-    D("write_zeros(%d) -> %d", bytes, fd);
+    D("write_zeros(%d) -> %d", bytes, fd.get());
 
-    stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+    stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode);
 
     if (fd == STDOUT_FILENO) {
         fwrite(buf.data(), 1, bytes, stdout);
@@ -1223,12 +1220,14 @@
         adb_write(fd, buf.data(), bytes);
     }
 
-    stdinout_raw_prologue(-1, fd, old_stdin_mode, old_stdout_mode);
+    stdinout_raw_prologue(-1, fd.get(), old_stdin_mode, old_stdout_mode);
 
     D("write_zeros() finished");
 }
 
 static int backup(int argc, const char** argv) {
+    fprintf(stdout, "WARNING: adb backup is deprecated and may be removed in a future release\n");
+
     const char* filename = "backup.ab";
 
     /* find, extract, and use any -f argument */
@@ -1278,6 +1277,8 @@
 }
 
 static int restore(int argc, const char** argv) {
+    fprintf(stdout, "WARNING: adb restore is deprecated and may be removed in a future release\n");
+
     if (argc != 2) error_exit("restore requires an argument");
 
     const char* filename = argv[1];
diff --git a/adb/client/console.cpp b/adb/client/console.cpp
index 1dbb6e2..d10f4de 100644
--- a/adb/client/console.cpp
+++ b/adb/client/console.cpp
@@ -71,7 +71,7 @@
         return -1;
     }
 
-    int port;
+    int port = -1;
     size_t emulator_count = 0;
     for (const auto& device : android::base::Split(devices, "\n")) {
         if (sscanf(device.c_str(), "emulator-%d", &port) == 1) {
diff --git a/adb/daemon/abb.cpp b/adb/daemon/abb.cpp
index eeac41a..425438e 100644
--- a/adb/daemon/abb.cpp
+++ b/adb/daemon/abb.cpp
@@ -17,6 +17,7 @@
 #include <sys/wait.h>
 
 #include <android-base/cmsg.h>
+#include <android-base/strings.h>
 #include <cmd.h>
 
 #include "adb.h"
@@ -28,11 +29,11 @@
 
 class AdbFdTextOutput : public android::TextOutput {
   public:
-    explicit AdbFdTextOutput(int fd) : mFD(fd) {}
+    explicit AdbFdTextOutput(borrowed_fd fd) : fd_(fd) {}
 
   private:
     android::status_t print(const char* txt, size_t len) override {
-        return WriteFdExactly(mFD, txt, len) ? android::OK : -errno;
+        return WriteFdExactly(fd_, txt, len) ? android::OK : -errno;
     }
     void moveIndent(int delta) override { /*not implemented*/
     }
@@ -43,7 +44,7 @@
     }
 
   private:
-    int mFD;
+    borrowed_fd fd_;
 };
 
 std::vector<std::string_view> parseCmdArgs(std::string_view args) {
@@ -67,10 +68,11 @@
 
 }  // namespace
 
-static int execCmd(std::string_view args, int in, int out, int err) {
+static int execCmd(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err) {
     AdbFdTextOutput oin(out);
     AdbFdTextOutput oerr(err);
-    return cmdMain(parseCmdArgs(args), oin, oerr, in, out, err, RunMode::kLibrary);
+    return cmdMain(parseCmdArgs(args), oin, oerr, in.get(), out.get(), err.get(),
+                   RunMode::kLibrary);
 }
 
 int main(int argc, char* const argv[]) {
@@ -87,9 +89,9 @@
 
         std::string_view name = data;
         auto protocol = SubprocessProtocol::kShell;
-        if (ConsumePrefix(&name, "abb:")) {
+        if (android::base::ConsumePrefix(&name, "abb:")) {
             protocol = SubprocessProtocol::kShell;
-        } else if (ConsumePrefix(&name, "abb_exec:")) {
+        } else if (android::base::ConsumePrefix(&name, "abb_exec:")) {
             protocol = SubprocessProtocol::kNone;
         } else {
             LOG(FATAL) << "Unknown command prefix for abb: " << data;
diff --git a/adb/daemon/file_sync_service.cpp b/adb/daemon/file_sync_service.cpp
index e82a51f..0e70d47 100644
--- a/adb/daemon/file_sync_service.cpp
+++ b/adb/daemon/file_sync_service.cpp
@@ -229,17 +229,13 @@
 static bool handle_send_file(int s, const char* path, uint32_t* timestamp, uid_t uid, gid_t gid,
                              uint64_t capabilities, mode_t mode, std::vector<char>& buffer,
                              bool do_unlink) {
+    int rc;
     syncmsg msg;
 
     __android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);
 
     unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));
 
-    if (posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED) <
-        0) {
-        D("[ Failed to fadvise: %d ]", errno);
-    }
-
     if (fd < 0 && errno == ENOENT) {
         if (!secure_mkdirs(Dirname(path))) {
             SendSyncFailErrno(s, "secure_mkdirs failed");
@@ -270,6 +266,12 @@
         fchmod(fd.get(), mode);
     }
 
+    rc = posix_fadvise(fd.get(), 0, 0,
+                       POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED);
+    if (rc != 0) {
+        D("[ Failed to fadvise: %s ]", strerror(rc));
+    }
+
     while (true) {
         if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
 
@@ -464,8 +466,9 @@
         return false;
     }
 
-    if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE) < 0) {
-        D("[ Failed to fadvise: %d ]", errno);
+    int rc = posix_fadvise(fd.get(), 0, 0, POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE);
+    if (rc != 0) {
+        D("[ Failed to fadvise: %s ]", strerror(rc));
     }
 
     syncmsg msg;
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index 66bfc0d..cd9b669 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -325,12 +325,12 @@
 
     addrlen = pathlen + sizeof(addr.sun_family);
 
-    if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
+    if (bind(s.get(), reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
         D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
         return -1;
     }
 
-    if (listen(s, 4) < 0) {
+    if (listen(s.get(), 4) < 0) {
         D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
         return -1;
     }
diff --git a/adb/daemon/reboot_service.cpp b/adb/daemon/reboot_service.cpp
index a5a11b8..13398af 100644
--- a/adb/daemon/reboot_service.cpp
+++ b/adb/daemon/reboot_service.cpp
@@ -58,7 +58,7 @@
 
         sockaddr_un addr = {.sun_family = AF_UNIX};
         strncpy(addr.sun_path, "/dev/socket/recovery", sizeof(addr.sun_path) - 1);
-        if (connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
+        if (connect(sock.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
             WriteFdFmt(fd, "reboot (%s) connect\n", strerror(errno));
             PLOG(ERROR) << "Couldn't connect to recovery socket";
             return;
diff --git a/adb/daemon/services.cpp b/adb/daemon/services.cpp
index b0cc450..e6f4499 100644
--- a/adb/daemon/services.cpp
+++ b/adb/daemon/services.cpp
@@ -223,13 +223,13 @@
         return create_jdwp_service_socket();
     } else if (name == "track-jdwp") {
         return create_jdwp_tracker_service_socket();
-    } else if (ConsumePrefix(&name, "sink:")) {
+    } else if (android::base::ConsumePrefix(&name, "sink:")) {
         uint64_t byte_count = 0;
         if (!ParseUint(&byte_count, name)) {
             return nullptr;
         }
         return new SinkSocket(byte_count);
-    } else if (ConsumePrefix(&name, "source:")) {
+    } else if (android::base::ConsumePrefix(&name, "source:")) {
         uint64_t byte_count = 0;
         if (!ParseUint(&byte_count, name)) {
             return nullptr;
@@ -250,11 +250,11 @@
 #if defined(__ANDROID__)
     if (name.starts_with("framebuffer:")) {
         return create_service_thread("fb", framebuffer_service);
-    } else if (ConsumePrefix(&name, "remount:")) {
+    } else if (android::base::ConsumePrefix(&name, "remount:")) {
         std::string arg(name);
         return create_service_thread("remount",
                                      std::bind(remount_service, std::placeholders::_1, arg));
-    } else if (ConsumePrefix(&name, "reboot:")) {
+    } else if (android::base::ConsumePrefix(&name, "reboot:")) {
         std::string arg(name);
         return create_service_thread("reboot",
                                      std::bind(reboot_service, std::placeholders::_1, arg));
@@ -262,7 +262,7 @@
         return create_service_thread("root", restart_root_service);
     } else if (name.starts_with("unroot:")) {
         return create_service_thread("unroot", restart_unroot_service);
-    } else if (ConsumePrefix(&name, "backup:")) {
+    } else if (android::base::ConsumePrefix(&name, "backup:")) {
         std::string cmd = "/system/bin/bu backup ";
         cmd += name;
         return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);
@@ -275,7 +275,7 @@
     } else if (name.starts_with("enable-verity:")) {
         return create_service_thread("verity-off", std::bind(set_verity_enabled_state_service,
                                                              std::placeholders::_1, true));
-    } else if (ConsumePrefix(&name, "tcpip:")) {
+    } else if (android::base::ConsumePrefix(&name, "tcpip:")) {
         std::string str(name);
 
         int port;
@@ -289,22 +289,22 @@
     }
 #endif
 
-    if (ConsumePrefix(&name, "dev:")) {
+    if (android::base::ConsumePrefix(&name, "dev:")) {
         return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
-    } else if (ConsumePrefix(&name, "jdwp:")) {
+    } else if (android::base::ConsumePrefix(&name, "jdwp:")) {
         pid_t pid;
         if (!ParseUint(&pid, name)) {
             return unique_fd{};
         }
         return create_jdwp_connection_fd(pid);
-    } else if (ConsumePrefix(&name, "shell")) {
+    } else if (android::base::ConsumePrefix(&name, "shell")) {
         return ShellService(name, transport);
-    } else if (ConsumePrefix(&name, "exec:")) {
+    } else if (android::base::ConsumePrefix(&name, "exec:")) {
         return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,
                                SubprocessProtocol::kNone);
     } else if (name.starts_with("sync:")) {
         return create_service_thread("sync", file_sync_service);
-    } else if (ConsumePrefix(&name, "reverse:")) {
+    } else if (android::base::ConsumePrefix(&name, "reverse:")) {
         return reverse_service(name, transport);
     } else if (name == "reconnect") {
         return create_service_thread(
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 889229f..4fbccdb 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -58,7 +58,7 @@
     }
 
     int OFF = 0;
-    bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
+    bool result = (ioctl(fd.get(), BLKROSET, &OFF) != -1);
     return result;
 }
 
@@ -111,8 +111,11 @@
             WriteFdFmt(fd, "%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
         }
     } else if (errno) {
-        WriteFdFmt(fd, "Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
-                   mount_point, strerror(errno));
+        int expected_errno = enable ? EBUSY : ENOENT;
+        if (errno != expected_errno) {
+            WriteFdFmt(fd, "Overlayfs %s for %s failed with error %s\n",
+                       enable ? "teardown" : "setup", mount_point, strerror(errno));
+        }
     }
     WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
     return true;
@@ -194,7 +197,7 @@
         }
 
         if (!android::base::GetBoolProperty("ro.secure", false)) {
-            overlayfs_setup(fd, enable);
+            overlayfs_setup(fd.get(), enable);
             WriteFdExactly(fd.get(), "verity not enabled - ENG build\n");
             return;
         }
@@ -239,7 +242,7 @@
             }
         }
     }
-    if (!any_changed) any_changed = overlayfs_setup(fd, enable);
+    if (!any_changed) any_changed = overlayfs_setup(fd.get(), enable);
 
     if (any_changed) {
         WriteFdExactly(fd.get(), "Now reboot your device for settings to take effect\n");
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index 3c8f393..de97068 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -114,7 +114,7 @@
 namespace {
 
 // Reads from |fd| until close or failure.
-std::string ReadAll(int fd) {
+std::string ReadAll(borrowed_fd fd) {
     char buffer[512];
     std::string received;
 
@@ -317,9 +317,10 @@
             child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
         }
 
-        dup2(child_stdinout_sfd, STDIN_FILENO);
-        dup2(child_stdinout_sfd, STDOUT_FILENO);
-        dup2(child_stderr_sfd != -1 ? child_stderr_sfd : child_stdinout_sfd, STDERR_FILENO);
+        dup2(child_stdinout_sfd.get(), STDIN_FILENO);
+        dup2(child_stdinout_sfd.get(), STDOUT_FILENO);
+        dup2(child_stderr_sfd != -1 ? child_stderr_sfd.get() : child_stdinout_sfd.get(),
+             STDERR_FILENO);
 
         // exec doesn't trigger destructors, close the FDs manually.
         stdinout_sfd_.reset(-1);
@@ -415,7 +416,7 @@
         }
     } else {
         // Raw protocol doesn't support multiple output streams, so combine stdout and stderr.
-        child_stderr_sfd.reset(dup(child_stdinout_sfd));
+        child_stderr_sfd.reset(dup(child_stdinout_sfd.get()));
     }
 
     D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
@@ -537,7 +538,7 @@
     FD_ZERO(&master_write_set);
     for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
         if (*sfd != -1) {
-            FD_SET(*sfd, &master_read_set);
+            FD_SET(sfd->get(), &master_read_set);
         }
     }
 
@@ -547,8 +548,8 @@
         unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
         if (dead_sfd) {
             D("closing FD %d", dead_sfd->get());
-            FD_CLR(*dead_sfd, &master_read_set);
-            FD_CLR(*dead_sfd, &master_write_set);
+            FD_CLR(dead_sfd->get(), &master_read_set);
+            FD_CLR(dead_sfd->get(), &master_write_set);
             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
@@ -573,7 +574,7 @@
 namespace {
 
 inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
-    return sfd != -1 && FD_ISSET(sfd, set);
+    return sfd != -1 && FD_ISSET(sfd.get(), set);
 }
 
 }   // namespace
@@ -581,7 +582,8 @@
 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_, stdinout_sfd_), stderr_sfd_) + 1;
+    int select_n =
+            std::max(std::max(protocol_sfd_.get(), stdinout_sfd_.get()), stderr_sfd_.get()) + 1;
     unique_fd* dead_sfd = nullptr;
 
     // Keep calling select() and passing data until an FD closes/errors.
@@ -614,8 +616,8 @@
             dead_sfd = PassInput();
             // If we didn't finish writing, block on stdin write.
             if (input_bytes_left_) {
-                FD_CLR(protocol_sfd_, master_read_set_ptr);
-                FD_SET(stdinout_sfd_, master_write_set_ptr);
+                FD_CLR(protocol_sfd_.get(), master_read_set_ptr);
+                FD_SET(stdinout_sfd_.get(), master_write_set_ptr);
             }
         }
 
@@ -624,8 +626,8 @@
             dead_sfd = PassInput();
             // If we finished writing, go back to blocking on protocol read.
             if (!input_bytes_left_) {
-                FD_SET(protocol_sfd_, master_read_set_ptr);
-                FD_CLR(stdinout_sfd_, master_write_set_ptr);
+                FD_SET(protocol_sfd_.get(), master_read_set_ptr);
+                FD_CLR(stdinout_sfd_.get(), master_write_set_ptr);
             }
         }
     }  // while (!dead_sfd)
@@ -639,7 +641,7 @@
         if (!input_->Read()) {
             // Read() uses ReadFdExactly() which sets errno to 0 on EOF.
             if (errno != 0) {
-                PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
+                PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get();
             }
             return &protocol_sfd_;
         }
@@ -655,7 +657,7 @@
                         ws.ws_col = cols;
                         ws.ws_xpixel = x_pixels;
                         ws.ws_ypixel = y_pixels;
-                        ioctl(stdinout_sfd_, TIOCSWINSZ, &ws);
+                        ioctl(stdinout_sfd_.get(), TIOCSWINSZ, &ws);
                     }
                     break;
                 case ShellProtocol::kIdStdin:
@@ -666,8 +668,7 @@
                         if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) {
                             return nullptr;
                         }
-                        PLOG(ERROR) << "failed to shutdown writes to FD "
-                                    << stdinout_sfd_;
+                        PLOG(ERROR) << "failed to shutdown writes to FD " << stdinout_sfd_.get();
                         return &stdinout_sfd_;
                     } else {
                         // PTYs can't close just input, so rather than close the
@@ -688,7 +689,7 @@
         int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_);
         if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
             if (bytes < 0) {
-                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_;
+                PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.get();
             }
             // stdin is done, mark this packet as finished and we'll just start
             // dumping any further data received from the protocol FD.
@@ -708,14 +709,14 @@
         // read() returns EIO if a PTY closes; don't report this as an error,
         // it just means the subprocess completed.
         if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) {
-            PLOG(ERROR) << "error reading output FD " << *sfd;
+            PLOG(ERROR) << "error reading output FD " << sfd->get();
         }
         return sfd;
     }
 
     if (bytes > 0 && !output_->Write(id, bytes)) {
         if (errno != 0) {
-            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
+            PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.get();
         }
         return &protocol_sfd_;
     }
diff --git a/adb/daemon/shell_service.h b/adb/daemon/shell_service.h
index 3abd958..030228c 100644
--- a/adb/daemon/shell_service.h
+++ b/adb/daemon/shell_service.h
@@ -48,7 +48,7 @@
 // Sets up in/out and error streams to emulate shell-like behavior.
 //
 // Returns an open FD connected to the thread or -1 on failure.
-using Command = int(std::string_view args, int in, int out, int err);
+using Command = int(std::string_view args, borrowed_fd in, borrowed_fd out, borrowed_fd err);
 unique_fd StartCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
 
 // Create a pipe containing the error.
diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
index dc79d12..cdd8dbe 100644
--- a/adb/daemon/shell_service_test.cpp
+++ b/adb/daemon/shell_service_test.cpp
@@ -77,7 +77,7 @@
 namespace {
 
 // Reads raw data from |fd| until it closes or errors.
-std::string ReadRaw(int fd) {
+std::string ReadRaw(borrowed_fd fd) {
     char buffer[1024];
     char *cur_ptr = buffer, *end_ptr = buffer + sizeof(buffer);
 
@@ -93,12 +93,12 @@
 // Reads shell protocol data from |fd| until it closes or errors. Fills
 // |stdout| and |stderr| with their respective data, and returns the exit code
 // read from the protocol or -1 if an exit code packet was not received.
-int ReadShellProtocol(int fd, std::string* stdout, std::string* stderr) {
+int ReadShellProtocol(borrowed_fd fd, std::string* stdout, std::string* stderr) {
     int exit_code = -1;
     stdout->clear();
     stderr->clear();
 
-    auto protocol = std::make_unique<ShellProtocol>(fd);
+    auto protocol = std::make_unique<ShellProtocol>(fd.get());
     while (protocol->Read()) {
         switch (protocol->id()) {
             case ShellProtocol::kIdStdout:
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 1e37015..96ee6b2 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -119,7 +119,7 @@
 
 struct IoBlock {
     bool pending = false;
-    struct iocb control;
+    struct iocb control = {};
     std::shared_ptr<Block> payload;
 
     TransferId id() const { return TransferId::from_value(control.aio_data); }
@@ -297,9 +297,15 @@
                 }
 
                 struct usb_functionfs_event event;
-                if (TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event))) !=
-                    sizeof(event)) {
+                rc = TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event)));
+                if (rc == -1) {
                     PLOG(FATAL) << "failed to read functionfs event";
+                } else if (rc == 0) {
+                    LOG(WARNING) << "hit EOF on functionfs control fd";
+                    break;
+                } else if (rc != sizeof(event)) {
+                    LOG(FATAL) << "read functionfs event of unexpected size, expected "
+                               << sizeof(event) << ", got " << rc;
                 }
 
                 LOG(INFO) << "USB event: "
@@ -310,11 +316,13 @@
                         if (bound) {
                             LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?";
                             running = false;
+                            break;
                         }
 
                         if (enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?";
                             running = false;
+                            break;
                         }
 
                         bound = true;
@@ -324,11 +332,13 @@
                         if (!bound) {
                             LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?";
                             running = false;
+                            break;
                         }
 
                         if (enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
                             running = false;
+                            break;
                         }
 
                         enabled = true;
diff --git a/adb/fastdeploy/deployagent/deployagent.sh b/adb/fastdeploy/deployagent/deployagent.sh
index 4f17eb7..91576ca 100755
--- a/adb/fastdeploy/deployagent/deployagent.sh
+++ b/adb/fastdeploy/deployagent/deployagent.sh
@@ -1,7 +1,4 @@
-# Script to start "deployagent" on the device, which has a very rudimentary
-# shell.
-#
+#!/system/bin/sh
 base=/data/local/tmp
 export CLASSPATH=$base/deployagent.jar
 exec app_process $base com.android.fastdeploy.DeployAgent "$@"
-
diff --git a/adb/services.cpp b/adb/services.cpp
index 46cab6e..6185aa6 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -202,7 +202,7 @@
         return create_device_tracker(false);
     } else if (name == "track-devices-l") {
         return create_device_tracker(true);
-    } else if (ConsumePrefix(&name, "wait-for-")) {
+    } else if (android::base::ConsumePrefix(&name, "wait-for-")) {
         std::shared_ptr<state_info> sinfo = std::make_shared<state_info>();
         if (sinfo == nullptr) {
             fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
@@ -212,11 +212,11 @@
         sinfo->serial = serial;
         sinfo->transport_id = transport_id;
 
-        if (ConsumePrefix(&name, "local")) {
+        if (android::base::ConsumePrefix(&name, "local")) {
             sinfo->transport_type = kTransportLocal;
-        } else if (ConsumePrefix(&name, "usb")) {
+        } else if (android::base::ConsumePrefix(&name, "usb")) {
             sinfo->transport_type = kTransportUsb;
-        } else if (ConsumePrefix(&name, "any")) {
+        } else if (android::base::ConsumePrefix(&name, "any")) {
             sinfo->transport_type = kTransportAny;
         } else {
             return nullptr;
@@ -243,7 +243,7 @@
         unique_fd fd = create_service_thread(
                 "wait", [sinfo](unique_fd fd) { wait_for_state(std::move(fd), sinfo.get()); });
         return create_local_socket(std::move(fd));
-    } else if (ConsumePrefix(&name, "connect:")) {
+    } else if (android::base::ConsumePrefix(&name, "connect:")) {
         std::string host(name);
         unique_fd fd = create_service_thread(
                 "connect", std::bind(connect_service, std::placeholders::_1, host));
diff --git a/adb/shell_protocol.h b/adb/shell_protocol.h
index 2c82689..4aab813 100644
--- a/adb/shell_protocol.h
+++ b/adb/shell_protocol.h
@@ -21,6 +21,7 @@
 #include <android-base/macros.h>
 
 #include "adb.h"
+#include "adb_unique_fd.h"
 
 // Class to send and receive shell protocol packets.
 //
@@ -60,7 +61,7 @@
     // should be dynamically allocated on the heap instead.
     //
     // |fd| is an open file descriptor to be used to send or receive packets.
-    explicit ShellProtocol(int fd);
+    explicit ShellProtocol(borrowed_fd fd);
     virtual ~ShellProtocol();
 
     // Returns a pointer to the data buffer.
@@ -103,7 +104,7 @@
         kHeaderSize = sizeof(Id) + sizeof(length_t)
     };
 
-    int fd_;
+    borrowed_fd fd_;
     char buffer_[kBufferSize];
     size_t data_length_ = 0, bytes_left_ = 0;
 
diff --git a/adb/shell_service_protocol.cpp b/adb/shell_service_protocol.cpp
index 13b66ec..95afaff 100644
--- a/adb/shell_service_protocol.cpp
+++ b/adb/shell_service_protocol.cpp
@@ -22,7 +22,7 @@
 
 #include "adb_io.h"
 
-ShellProtocol::ShellProtocol(int fd) : fd_(fd) {
+ShellProtocol::ShellProtocol(borrowed_fd fd) : fd_(fd) {
     buffer_[0] = kIdInvalid;
 }
 
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index de4fff9..1333724 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -314,14 +314,14 @@
         addr.svm_port = port == 0 ? VMADDR_PORT_ANY : port;
         addr.svm_cid = VMADDR_CID_ANY;
         socklen_t addr_len = sizeof(addr);
-        if (bind(serverfd, reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
+        if (bind(serverfd.get(), reinterpret_cast<struct sockaddr*>(&addr), addr_len)) {
             return -1;
         }
-        if (listen(serverfd, 4)) {
+        if (listen(serverfd.get(), 4)) {
             return -1;
         }
         if (serverfd >= 0 && resolved_port) {
-            if (getsockname(serverfd, reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
+            if (getsockname(serverfd.get(), reinterpret_cast<sockaddr*>(&addr), &addr_len) == 0) {
                 *resolved_port = addr.svm_port;
             } else {
                 return -1;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 8a2bf9a..75993b3 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -31,6 +31,8 @@
 #include <string>
 #include <vector>
 
+#include <android-base/strings.h>
+
 #if !ADB_HOST
 #include <android-base/properties.h>
 #include <log/log_properties.h>
@@ -755,26 +757,26 @@
 
 #if ADB_HOST
     service = std::string_view(s->smart_socket_data).substr(4);
-    if (ConsumePrefix(&service, "host-serial:")) {
+    if (android::base::ConsumePrefix(&service, "host-serial:")) {
         // serial number should follow "host:" and could be a host:port string.
         if (!internal::parse_host_service(&serial, &service, service)) {
             LOG(ERROR) << "SS(" << s->id << "): failed to parse host service: " << service;
             goto fail;
         }
-    } else if (ConsumePrefix(&service, "host-transport-id:")) {
+    } else if (android::base::ConsumePrefix(&service, "host-transport-id:")) {
         if (!ParseUint(&transport_id, service, &service)) {
             LOG(ERROR) << "SS(" << s->id << "): failed to parse host transport id: " << service;
             return -1;
         }
-        if (!ConsumePrefix(&service, ":")) {
+        if (!android::base::ConsumePrefix(&service, ":")) {
             LOG(ERROR) << "SS(" << s->id << "): host-transport-id without command";
             return -1;
         }
-    } else if (ConsumePrefix(&service, "host-usb:")) {
+    } else if (android::base::ConsumePrefix(&service, "host-usb:")) {
         type = kTransportUsb;
-    } else if (ConsumePrefix(&service, "host-local:")) {
+    } else if (android::base::ConsumePrefix(&service, "host-local:")) {
         type = kTransportLocal;
-    } else if (ConsumePrefix(&service, "host:")) {
+    } else if (android::base::ConsumePrefix(&service, "host:")) {
         type = kTransportAny;
     } else {
         service = std::string_view{};
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 15247e7..78abba5 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -36,6 +36,7 @@
 #include <android-base/unique_fd.h>
 #include <android-base/utf8.h>
 
+#include "adb_unique_fd.h"
 #include "sysdeps/errno.h"
 #include "sysdeps/network.h"
 #include "sysdeps/stat.h"
@@ -76,42 +77,40 @@
 
 extern int adb_thread_setname(const std::string& name);
 
-static __inline__ void  close_on_exec(int  fd)
-{
+static __inline__ void close_on_exec(borrowed_fd fd) {
     /* nothing really */
 }
 
-extern int  adb_unlink(const char*  path);
-#undef  unlink
-#define unlink  ___xxx_unlink
+extern int adb_unlink(const char* path);
+#undef unlink
+#define unlink ___xxx_unlink
 
 extern int adb_mkdir(const std::string& path, int mode);
-#undef   mkdir
-#define  mkdir  ___xxx_mkdir
+#undef mkdir
+#define mkdir ___xxx_mkdir
 
 // See the comments for the !defined(_WIN32) versions of adb_*().
 extern int adb_open(const char* path, int options);
 extern int adb_creat(const char* path, int mode);
-extern int adb_read(int fd, void* buf, int len);
-extern int adb_write(int fd, const void* buf, int len);
-extern int64_t adb_lseek(int fd, int64_t pos, int where);
-extern int adb_shutdown(int fd, int direction = SHUT_RDWR);
+extern int adb_read(borrowed_fd fd, void* buf, int len);
+extern int adb_write(borrowed_fd fd, const void* buf, int len);
+extern int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where);
+extern int adb_shutdown(borrowed_fd fd, int direction = SHUT_RDWR);
 extern int adb_close(int fd);
 extern int adb_register_socket(SOCKET s);
 
 // See the comments for the !defined(_WIN32) version of unix_close().
-static __inline__ int  unix_close(int fd)
-{
+static __inline__ int unix_close(int fd) {
     return close(fd);
 }
-#undef   close
-#define  close   ____xxx_close
+#undef close
+#define close ____xxx_close
 
 // Like unix_read(), but may return EINTR.
-extern int  unix_read_interruptible(int  fd, void*  buf, size_t  len);
+extern int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len);
 
 // See the comments for the !defined(_WIN32) version of unix_read().
-static __inline__ int unix_read(int fd, void* buf, size_t len) {
+static __inline__ int unix_read(borrowed_fd fd, void* buf, size_t len) {
     return TEMP_FAILURE_RETRY(unix_read_interruptible(fd, buf, len));
 }
 
@@ -119,23 +118,21 @@
 #define  read  ___xxx_read
 
 // See the comments for the !defined(_WIN32) version of unix_write().
-static __inline__  int  unix_write(int  fd, const void*  buf, size_t  len)
-{
-    return write(fd, buf, len);
+static __inline__ int unix_write(borrowed_fd fd, const void* buf, size_t len) {
+    return write(fd.get(), buf, len);
 }
 #undef   write
 #define  write  ___xxx_write
 
 // See the comments for the !defined(_WIN32) version of unix_lseek().
-static __inline__ int unix_lseek(int fd, int pos, int where) {
-    return lseek(fd, pos, where);
+static __inline__ int unix_lseek(borrowed_fd fd, int pos, int where) {
+    return lseek(fd.get(), pos, where);
 }
 #undef lseek
 #define lseek ___xxx_lseek
 
 // See the comments for the !defined(_WIN32) version of adb_open_mode().
-static __inline__ int  adb_open_mode(const char* path, int options, int mode)
-{
+static __inline__ int adb_open_mode(const char* path, int options, int mode) {
     return adb_open(path, options);
 }
 
@@ -152,7 +149,7 @@
 // with |fd| must have GENERIC_READ access (which console FDs have by default).
 // Returns 1 if |fd| is a console FD, 0 otherwise. The value of errno after
 // calling this function is unreliable and should not be used.
-int unix_isatty(int fd);
+int unix_isatty(borrowed_fd fd);
 #define  isatty  ___xxx_isatty
 
 int network_inaddr_any_server(int port, int type, std::string* error);
@@ -168,20 +165,21 @@
 int network_connect(const std::string& host, int port, int type, int timeout,
                     std::string* error);
 
-extern int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen);
+extern int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen);
 
 #undef   accept
 #define  accept  ___xxx_accept
 
 // Returns the local port number of a bound socket, or -1 on failure.
-int adb_socket_get_local_port(int fd);
+int adb_socket_get_local_port(borrowed_fd fd);
 
-extern int  adb_setsockopt(int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen);
+extern int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval,
+                          socklen_t optlen);
 
 #undef   setsockopt
 #define  setsockopt  ___xxx_setsockopt
 
-extern int  adb_socketpair( int  sv[2] );
+extern int adb_socketpair(int sv[2]);
 
 struct adb_pollfd {
     int fd;
@@ -214,8 +212,7 @@
 extern int adb_fputc(int ch, FILE* stream);
 extern int adb_putchar(int ch);
 extern int adb_puts(const char* buf);
-extern size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb,
-                         FILE* stream);
+extern size_t adb_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
 
 extern FILE* adb_fopen(const char* f, const char* m);
 
@@ -344,9 +341,8 @@
     return c == '/';
 }
 
-static __inline__ void  close_on_exec(int  fd)
-{
-    fcntl( fd, F_SETFD, FD_CLOEXEC );
+static __inline__ void close_on_exec(borrowed_fd fd) {
+    fcntl(fd.get(), F_SETFD, FD_CLOEXEC);
 }
 
 // Open a file and return a file descriptor that may be used with unix_read(),
@@ -374,12 +370,10 @@
 
 // Similar to the two-argument adb_open(), but takes a mode parameter for file
 // creation. See adb_open() for more info.
-static __inline__ int  adb_open_mode( const char*  pathname, int  options, int  mode )
-{
-    return TEMP_FAILURE_RETRY( open( pathname, options, mode ) );
+static __inline__ int adb_open_mode(const char* pathname, int options, int mode) {
+    return TEMP_FAILURE_RETRY(open(pathname, options, mode));
 }
 
-
 // Open a file and return a file descriptor that may be used with adb_read(),
 // adb_write(), adb_close(), but not unix_read(), unix_write(), unix_close().
 //
@@ -387,23 +381,21 @@
 // sysdeps_win32.cpp) uses Windows native file I/O and bypasses the C Runtime
 // and its CR/LF translation. The returned file descriptor should be used with
 // adb_read(), adb_write(), adb_close(), etc.
-static __inline__ int  adb_open( const char*  pathname, int  options )
-{
-    int  fd = TEMP_FAILURE_RETRY( open( pathname, options ) );
-    if (fd < 0)
-        return -1;
-    close_on_exec( fd );
+static __inline__ int adb_open(const char* pathname, int options) {
+    int fd = TEMP_FAILURE_RETRY(open(pathname, options));
+    if (fd < 0) return -1;
+    close_on_exec(fd);
     return fd;
 }
-#undef   open
-#define  open    ___xxx_open
+#undef open
+#define open ___xxx_open
 
-static __inline__ int adb_shutdown(int fd, int direction = SHUT_RDWR) {
-    return shutdown(fd, direction);
+static __inline__ int adb_shutdown(borrowed_fd fd, int direction = SHUT_RDWR) {
+    return shutdown(fd.get(), direction);
 }
 
-#undef   shutdown
-#define  shutdown   ____xxx_shutdown
+#undef shutdown
+#define shutdown ____xxx_shutdown
 
 // Closes a file descriptor that came from adb_open() or adb_open_mode(), but
 // not designed to take a file descriptor from unix_open(). See the comments
@@ -411,81 +403,76 @@
 __inline__ int adb_close(int fd) {
     return close(fd);
 }
-#undef   close
-#define  close   ____xxx_close
+#undef close
+#define close ____xxx_close
 
 // On Windows, ADB has an indirection layer for file descriptors. If we get a
 // Win32 SOCKET object from an external library, we have to map it in to that
 // indirection layer, which this does.
-__inline__ int  adb_register_socket(int s) {
+__inline__ int adb_register_socket(int s) {
     return s;
 }
 
-static __inline__  int  adb_read(int  fd, void*  buf, size_t  len)
-{
-    return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
+static __inline__ int adb_read(borrowed_fd fd, void* buf, size_t len) {
+    return TEMP_FAILURE_RETRY(read(fd.get(), buf, len));
 }
 
 // Like unix_read(), but does not handle EINTR.
-static __inline__ int unix_read_interruptible(int fd, void* buf, size_t len) {
-    return read(fd, buf, len);
+static __inline__ int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) {
+    return read(fd.get(), buf, len);
 }
 
-#undef   read
-#define  read  ___xxx_read
+#undef read
+#define read ___xxx_read
 
-static __inline__  int  adb_write(int  fd, const void*  buf, size_t  len)
-{
-    return TEMP_FAILURE_RETRY( write( fd, buf, len ) );
+static __inline__ int adb_write(borrowed_fd fd, const void* buf, size_t len) {
+    return TEMP_FAILURE_RETRY(write(fd.get(), buf, len));
 }
 #undef   write
 #define  write  ___xxx_write
 
-static __inline__ int64_t adb_lseek(int fd, int64_t pos, int where) {
+static __inline__ int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) {
 #if defined(__APPLE__)
-    return lseek(fd, pos, where);
+    return lseek(fd.get(), pos, where);
 #else
-    return lseek64(fd, pos, where);
+    return lseek64(fd.get(), pos, where);
 #endif
 }
 #undef lseek
 #define lseek ___xxx_lseek
 
-static __inline__  int    adb_unlink(const char*  path)
-{
-    return  unlink(path);
+static __inline__ int adb_unlink(const char* path) {
+    return unlink(path);
 }
-#undef  unlink
-#define unlink  ___xxx_unlink
+#undef unlink
+#define unlink ___xxx_unlink
 
-static __inline__  int  adb_creat(const char*  path, int  mode)
-{
-    int  fd = TEMP_FAILURE_RETRY( creat( path, mode ) );
+static __inline__ int adb_creat(const char* path, int mode) {
+    int fd = TEMP_FAILURE_RETRY(creat(path, mode));
 
-    if ( fd < 0 )
-        return -1;
+    if (fd < 0) return -1;
 
     close_on_exec(fd);
     return fd;
 }
-#undef   creat
-#define  creat  ___xxx_creat
+#undef creat
+#define creat ___xxx_creat
 
-static __inline__ int unix_isatty(int fd) {
-    return isatty(fd);
+static __inline__ int unix_isatty(borrowed_fd fd) {
+    return isatty(fd.get());
 }
-#define  isatty  ___xxx_isatty
+#define isatty ___xxx_isatty
 
 // Helper for network_* functions.
 inline int _fd_set_error_str(int fd, std::string* error) {
-  if (fd == -1) {
-    *error = strerror(errno);
-  }
-  return fd;
+    if (fd == -1) {
+        *error = strerror(errno);
+    }
+    return fd;
 }
 
 inline int network_inaddr_any_server(int port, int type, std::string* error) {
-  return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
+    return _fd_set_error_str(socket_inaddr_any_server(port, type), error);
 }
 
 inline int network_local_client(const char* name, int namespace_id, int type, std::string* error) {
@@ -498,22 +485,21 @@
 
 int network_connect(const std::string& host, int port, int type, int timeout, std::string* error);
 
-static __inline__ int  adb_socket_accept(int  serverfd, struct sockaddr*  addr, socklen_t  *addrlen)
-{
+static __inline__ int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr,
+                                        socklen_t* addrlen) {
     int fd;
 
-    fd = TEMP_FAILURE_RETRY( accept( serverfd, addr, addrlen ) );
-    if (fd >= 0)
-        close_on_exec(fd);
+    fd = TEMP_FAILURE_RETRY(accept(serverfd.get(), addr, addrlen));
+    if (fd >= 0) close_on_exec(fd);
 
     return fd;
 }
 
-#undef   accept
-#define  accept  ___xxx_accept
+#undef accept
+#define accept ___xxx_accept
 
-inline int adb_socket_get_local_port(int fd) {
-    return socket_get_local_port(fd);
+inline int adb_socket_get_local_port(borrowed_fd fd) {
+    return socket_get_local_port(fd.get());
 }
 
 // Operate on a file descriptor returned from unix_open() or a well-known file
@@ -524,10 +510,10 @@
 // Windows implementations (in the ifdef above and in sysdeps_win32.cpp) call
 // into the C Runtime and its configurable CR/LF translation (which is settable
 // via _setmode()).
-#define  unix_read   adb_read
-#define  unix_write  adb_write
+#define unix_read adb_read
+#define unix_write adb_write
 #define unix_lseek adb_lseek
-#define  unix_close  adb_close
+#define unix_close adb_close
 
 static __inline__ int adb_thread_setname(const std::string& name) {
 #ifdef __APPLE__
@@ -542,34 +528,31 @@
 #endif
 }
 
-static __inline__ int  adb_setsockopt( int  fd, int  level, int  optname, const void*  optval, socklen_t  optlen )
-{
-    return setsockopt( fd, level, optname, optval, optlen );
+static __inline__ int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval,
+                                     socklen_t optlen) {
+    return setsockopt(fd.get(), level, optname, optval, optlen);
 }
 
-#undef   setsockopt
-#define  setsockopt  ___xxx_setsockopt
+#undef setsockopt
+#define setsockopt ___xxx_setsockopt
 
-static __inline__ int  unix_socketpair( int  d, int  type, int  protocol, int sv[2] )
-{
-    return socketpair( d, type, protocol, sv );
+static __inline__ int unix_socketpair(int d, int type, int protocol, int sv[2]) {
+    return socketpair(d, type, protocol, sv);
 }
 
-static __inline__ int  adb_socketpair( int  sv[2] )
-{
-    int  rc;
+static __inline__ int adb_socketpair(int sv[2]) {
+    int rc;
 
-    rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
-    if (rc < 0)
-        return -1;
+    rc = unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
+    if (rc < 0) return -1;
 
-    close_on_exec( sv[0] );
-    close_on_exec( sv[1] );
+    close_on_exec(sv[0]);
+    close_on_exec(sv[1]);
     return 0;
 }
 
-#undef   socketpair
-#define  socketpair   ___xxx_socketpair
+#undef socketpair
+#define socketpair ___xxx_socketpair
 
 typedef struct pollfd adb_pollfd;
 static __inline__ int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) {
@@ -578,13 +561,12 @@
 
 #define poll ___xxx_poll
 
-static __inline__ int  adb_mkdir(const std::string& path, int mode)
-{
+static __inline__ int adb_mkdir(const std::string& path, int mode) {
     return mkdir(path.c_str(), mode);
 }
 
-#undef   mkdir
-#define  mkdir  ___xxx_mkdir
+#undef mkdir
+#define mkdir ___xxx_mkdir
 
 static __inline__ int adb_is_absolute_host_path(const char* path) {
     return path[0] == '/';
@@ -592,15 +574,15 @@
 
 #endif /* !_WIN32 */
 
-static inline void disable_tcp_nagle(int fd) {
+static inline void disable_tcp_nagle(borrowed_fd fd) {
     int off = 1;
-    adb_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
+    adb_setsockopt(fd.get(), IPPROTO_TCP, TCP_NODELAY, &off, sizeof(off));
 }
 
 // Sets TCP socket |fd| to send a keepalive TCP message every |interval_sec| seconds. Set
 // |interval_sec| to 0 to disable keepalives. If keepalives are enabled, the connection will be
 // configured to drop after 10 missed keepalives. Returns true on success.
-bool set_tcp_keepalive(int fd, int interval_sec);
+bool set_tcp_keepalive(borrowed_fd fd, int interval_sec);
 
 #if defined(_WIN32)
 // Win32 defines ERROR, which we don't need, but which conflicts with google3 logging.
diff --git a/adb/sysdeps/posix/network.cpp b/adb/sysdeps/posix/network.cpp
index 4de240e..c5c2275 100644
--- a/adb/sysdeps/posix/network.cpp
+++ b/adb/sysdeps/posix/network.cpp
@@ -104,13 +104,13 @@
     socklen_t addrlen = sizeof(addr_storage);
     sockaddr* addr = (ipv6 ? loopback_addr6 : loopback_addr4)(&addr_storage, &addrlen, port);
 
-    if (bind(s, addr, addrlen) != 0) {
+    if (bind(s.get(), addr, addrlen) != 0) {
         set_error(error);
         return -1;
     }
 
     if (type == SOCK_STREAM || type == SOCK_SEQPACKET) {
-        if (listen(s, SOMAXCONN) != 0) {
+        if (listen(s.get(), SOMAXCONN) != 0) {
             set_error(error);
             return -1;
         }
diff --git a/adb/sysdeps/uio.h b/adb/sysdeps/uio.h
index d06ef89..ced884b 100644
--- a/adb/sysdeps/uio.h
+++ b/adb/sysdeps/uio.h
@@ -18,6 +18,8 @@
 
 #include <sys/types.h>
 
+#include "adb_unique_fd.h"
+
 #if defined(_WIN32)
 
 // Layout of this struct must match struct WSABUF (verified via static assert in sysdeps_win32.cpp)
@@ -26,13 +28,15 @@
     void* iov_base;
 };
 
-ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt);
+ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt);
 
 #else
 
 #include <sys/uio.h>
 using adb_iovec = struct iovec;
-#define adb_writev writev
+inline ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt) {
+    return writev(fd.get(), iov, iovcnt);
+}
 
 #endif
 
diff --git a/adb/sysdeps_unix.cpp b/adb/sysdeps_unix.cpp
index 4445a44..3fdc917 100644
--- a/adb/sysdeps_unix.cpp
+++ b/adb/sysdeps_unix.cpp
@@ -16,7 +16,7 @@
 
 #include "sysdeps.h"
 
-bool set_tcp_keepalive(int fd, int interval_sec) {
+bool set_tcp_keepalive(borrowed_fd fd, int interval_sec) {
     int enable = (interval_sec > 0);
     if (adb_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &enable, sizeof(enable))) {
         return false;
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 4c5d8cb..886ded4 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -145,16 +145,14 @@
 static  FHRec        _win32_fhs[ WIN32_MAX_FHS ];
 static  int          _win32_fh_next;  // where to start search for free FHRec
 
-static FH
-_fh_from_int( int   fd, const char*   func )
-{
-    FH  f;
+static FH _fh_from_int(borrowed_fd bfd, const char* func) {
+    FH f;
 
+    int fd = bfd.get();
     fd -= WIN32_FH_BASE;
 
     if (fd < 0 || fd >= WIN32_MAX_FHS) {
-        D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
-           func );
+        D("_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE, func);
         errno = EBADF;
         return nullptr;
     }
@@ -162,8 +160,7 @@
     f = &_win32_fhs[fd];
 
     if (f->used == 0) {
-        D( "_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE,
-           func );
+        D("_fh_from_int: invalid fd %d passed to %s", fd + WIN32_FH_BASE, func);
         errno = EBADF;
         return nullptr;
     }
@@ -171,20 +168,15 @@
     return f;
 }
 
-
-static int
-_fh_to_int( FH  f )
-{
+static int _fh_to_int(FH f) {
     if (f && f->used && f >= _win32_fhs && f < _win32_fhs + WIN32_MAX_FHS)
         return (int)(f - _win32_fhs) + WIN32_FH_BASE;
 
     return -1;
 }
 
-static FH
-_fh_alloc( FHClass  clazz )
-{
-    FH   f = nullptr;
+static FH _fh_alloc(FHClass clazz) {
+    FH f = nullptr;
 
     std::lock_guard<std::mutex> lock(_win32_lock);
 
@@ -206,10 +198,7 @@
     return nullptr;
 }
 
-
-static int
-_fh_close( FH   f )
-{
+static int _fh_close(FH f) {
     // Use lock so that closing only happens once and so that _fh_alloc can't
     // allocate a FH that we're in the middle of closing.
     std::lock_guard<std::mutex> lock(_win32_lock);
@@ -456,7 +445,7 @@
     return _fh_to_int(f);
 }
 
-int adb_read(int fd, void* buf, int len) {
+int adb_read(borrowed_fd fd, void* buf, int len) {
     FH f = _fh_from_int(fd, __func__);
 
     if (f == nullptr) {
@@ -467,7 +456,7 @@
     return f->clazz->_fh_read(f, buf, len);
 }
 
-int adb_write(int fd, const void* buf, int len) {
+int adb_write(borrowed_fd fd, const void* buf, int len) {
     FH f = _fh_from_int(fd, __func__);
 
     if (f == nullptr) {
@@ -478,7 +467,7 @@
     return f->clazz->_fh_write(f, buf, len);
 }
 
-ssize_t adb_writev(int fd, const adb_iovec* iov, int iovcnt) {
+ssize_t adb_writev(borrowed_fd fd, const adb_iovec* iov, int iovcnt) {
     FH f = _fh_from_int(fd, __func__);
 
     if (f == nullptr) {
@@ -489,7 +478,7 @@
     return f->clazz->_fh_writev(f, iov, iovcnt);
 }
 
-int64_t adb_lseek(int fd, int64_t pos, int where) {
+int64_t adb_lseek(borrowed_fd fd, int64_t pos, int where) {
     FH f = _fh_from_int(fd, __func__);
     if (!f) {
         errno = EBADF;
@@ -973,11 +962,11 @@
 }
 
 #undef accept
-int adb_socket_accept(int serverfd, struct sockaddr* addr, socklen_t* addrlen) {
+int adb_socket_accept(borrowed_fd serverfd, struct sockaddr* addr, socklen_t* addrlen) {
     FH serverfh = _fh_from_int(serverfd, __func__);
 
     if (!serverfh || serverfh->clazz != &_fh_socket_class) {
-        D("adb_socket_accept: invalid fd %d", serverfd);
+        D("adb_socket_accept: invalid fd %d", serverfd.get());
         errno = EBADF;
         return -1;
     }
@@ -992,7 +981,7 @@
     fh->fh_socket = accept(serverfh->fh_socket, addr, addrlen);
     if (fh->fh_socket == INVALID_SOCKET) {
         const DWORD err = WSAGetLastError();
-        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd
+        LOG(ERROR) << "adb_socket_accept: accept on fd " << serverfd.get()
                    << " failed: " + android::base::SystemErrorCodeToString(err);
         _socket_set_errno(err);
         return -1;
@@ -1000,16 +989,16 @@
 
     const int fd = _fh_to_int(fh.get());
     snprintf(fh->name, sizeof(fh->name), "%d(accept:%s)", fd, serverfh->name);
-    D("adb_socket_accept on fd %d returns fd %d", serverfd, fd);
+    D("adb_socket_accept on fd %d returns fd %d", serverfd.get(), fd);
     fh.release();
     return fd;
 }
 
-int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen) {
+int adb_setsockopt(borrowed_fd fd, int level, int optname, const void* optval, socklen_t optlen) {
     FH fh = _fh_from_int(fd, __func__);
 
     if (!fh || fh->clazz != &_fh_socket_class) {
-        D("adb_setsockopt: invalid fd %d", fd);
+        D("adb_setsockopt: invalid fd %d", fd.get());
         errno = EBADF;
         return -1;
     }
@@ -1022,7 +1011,7 @@
         setsockopt(fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
-        D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd, level,
+        D("adb_setsockopt: setsockopt on fd %d level %d optname %d failed: %s\n", fd.get(), level,
           optname, android::base::SystemErrorCodeToString(err).c_str());
         _socket_set_errno(err);
         result = -1;
@@ -1030,11 +1019,11 @@
     return result;
 }
 
-int adb_getsockname(int fd, struct sockaddr* sockaddr, socklen_t* optlen) {
+static int adb_getsockname(borrowed_fd fd, struct sockaddr* sockaddr, socklen_t* optlen) {
     FH fh = _fh_from_int(fd, __func__);
 
     if (!fh || fh->clazz != &_fh_socket_class) {
-        D("adb_getsockname: invalid fd %d", fd);
+        D("adb_getsockname: invalid fd %d", fd.get());
         errno = EBADF;
         return -1;
     }
@@ -1042,7 +1031,7 @@
     int result = getsockname(fh->fh_socket, sockaddr, optlen);
     if (result == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
-        D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd,
+        D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd.get(),
           android::base::SystemErrorCodeToString(err).c_str());
         _socket_set_errno(err);
         result = -1;
@@ -1050,7 +1039,7 @@
     return result;
 }
 
-int adb_socket_get_local_port(int fd) {
+int adb_socket_get_local_port(borrowed_fd fd) {
     sockaddr_storage addr_storage;
     socklen_t addr_len = sizeof(addr_storage);
 
@@ -1068,11 +1057,11 @@
     return ntohs(reinterpret_cast<sockaddr_in*>(&addr_storage)->sin_port);
 }
 
-int adb_shutdown(int fd, int direction) {
+int adb_shutdown(borrowed_fd fd, int direction) {
     FH f = _fh_from_int(fd, __func__);
 
     if (!f || f->clazz != &_fh_socket_class) {
-        D("adb_shutdown: invalid fd %d", fd);
+        D("adb_shutdown: invalid fd %d", fd.get());
         errno = EBADF;
         return -1;
     }
@@ -1080,7 +1069,7 @@
     D("adb_shutdown: %s", f->name);
     if (shutdown(f->fh_socket, direction) == SOCKET_ERROR) {
         const DWORD err = WSAGetLastError();
-        D("socket shutdown fd %d failed: %s", fd,
+        D("socket shutdown fd %d failed: %s", fd.get(),
           android::base::SystemErrorCodeToString(err).c_str());
         _socket_set_errno(err);
         return -1;
@@ -1138,12 +1127,12 @@
     return -1;
 }
 
-bool set_file_block_mode(int fd, bool block) {
+bool set_file_block_mode(borrowed_fd fd, bool block) {
     FH fh = _fh_from_int(fd, __func__);
 
     if (!fh || !fh->used) {
         errno = EBADF;
-        D("Setting nonblocking on bad file descriptor %d", fd);
+        D("Setting nonblocking on bad file descriptor %d", fd.get());
         return false;
     }
 
@@ -1152,22 +1141,22 @@
         if (ioctlsocket(fh->u.socket, FIONBIO, &x) != 0) {
             int error = WSAGetLastError();
             _socket_set_errno(error);
-            D("Setting %d nonblocking failed (%d)", fd, error);
+            D("Setting %d nonblocking failed (%d)", fd.get(), error);
             return false;
         }
         return true;
     } else {
         errno = ENOTSOCK;
-        D("Setting nonblocking on non-socket %d", fd);
+        D("Setting nonblocking on non-socket %d", fd.get());
         return false;
     }
 }
 
-bool set_tcp_keepalive(int fd, int interval_sec) {
+bool set_tcp_keepalive(borrowed_fd fd, int interval_sec) {
     FH fh = _fh_from_int(fd, __func__);
 
     if (!fh || fh->clazz != &_fh_socket_class) {
-        D("set_tcp_keepalive(%d) failed: invalid fd", fd);
+        D("set_tcp_keepalive(%d) failed: invalid fd", fd.get());
         errno = EBADF;
         return false;
     }
@@ -1181,7 +1170,7 @@
     if (WSAIoctl(fh->fh_socket, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), nullptr, 0,
                  &bytes_returned, nullptr, nullptr) != 0) {
         const DWORD err = WSAGetLastError();
-        D("set_tcp_keepalive(%d) failed: %s", fd,
+        D("set_tcp_keepalive(%d) failed: %s", fd.get(),
           android::base::SystemErrorCodeToString(err).c_str());
         _socket_set_errno(err);
         return false;
@@ -1228,12 +1217,12 @@
 // Returns a console HANDLE if |fd| is a console, otherwise returns nullptr.
 // If a valid HANDLE is returned and |mode| is not null, |mode| is also filled
 // with the console mode. Requires GENERIC_READ access to the underlying HANDLE.
-static HANDLE _get_console_handle(int fd, DWORD* mode=nullptr) {
+static HANDLE _get_console_handle(borrowed_fd fd, DWORD* mode = nullptr) {
     // First check isatty(); this is very fast and eliminates most non-console
     // FDs, but returns 1 for both consoles and character devices like NUL.
 #pragma push_macro("isatty")
 #undef isatty
-    if (!isatty(fd)) {
+    if (!isatty(fd.get())) {
         return nullptr;
     }
 #pragma pop_macro("isatty")
@@ -1241,7 +1230,7 @@
     // To differentiate between character devices and consoles we need to get
     // the underlying HANDLE and use GetConsoleMode(), which is what requires
     // GENERIC_READ permissions.
-    const intptr_t intptr_handle = _get_osfhandle(fd);
+    const intptr_t intptr_handle = _get_osfhandle(fd.get());
     if (intptr_handle == -1) {
         return nullptr;
     }
@@ -1265,7 +1254,7 @@
     return _get_console_handle(fd);
 }
 
-int unix_isatty(int fd) {
+int unix_isatty(borrowed_fd fd) {
     return _get_console_handle(fd) ? 1 : 0;
 }
 
@@ -1645,7 +1634,7 @@
 
 // Prefix the len bytes in buf with the escape character, and then return the
 // new buffer length.
-size_t _escape_prefix(char* const buf, const size_t len) {
+static size_t _escape_prefix(char* const buf, const size_t len) {
     // If nothing to prefix, don't do anything. We might be called with
     // len == 0, if alt was held down with a dead key which produced nothing.
     if (len == 0) {
@@ -2073,7 +2062,7 @@
 }
 
 // Called by 'adb shell' and 'adb exec-in' (via unix_read()) to read from stdin.
-int unix_read_interruptible(int fd, void* buf, size_t len) {
+int unix_read_interruptible(borrowed_fd fd, void* buf, size_t len) {
     if ((fd == STDIN_FILENO) && (_console_handle != nullptr)) {
         // If it is a request to read from stdin, and stdin_raw_init() has been
         // called, and it successfully configured the console, then read from
@@ -2093,7 +2082,7 @@
         // plain read() in favor of unix_read() or adb_read().
 #pragma push_macro("read")
 #undef read
-        return read(fd, buf, len);
+        return read(fd.get(), buf, len);
 #pragma pop_macro("read")
     }
 }
diff --git a/base/Android.bp b/base/Android.bp
index 38f301a..340f814 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -29,6 +29,7 @@
     vendor_available: true,
     recovery_available: true,
     host_supported: true,
+    native_bridge_supported: true,
     export_include_dirs: ["include"],
 
     target: {
@@ -45,6 +46,7 @@
     name: "libbase_defaults",
     defaults: ["libbase_cflags_defaults"],
     srcs: [
+        "abi_compatibility.cpp",
         "chrono_utils.cpp",
         "cmsg.cpp",
         "file.cpp",
@@ -100,6 +102,7 @@
     vendor_available: true,
     recovery_available: true,
     host_supported: true,
+    native_bridge_supported: true,
     vndk: {
         enabled: true,
         support_system_process: true,
diff --git a/base/abi_compatibility.cpp b/base/abi_compatibility.cpp
new file mode 100644
index 0000000..06a7801
--- /dev/null
+++ b/base/abi_compatibility.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 <memory>
+
+#include "android-base/cmsg.h"
+#include "android-base/file.h"
+#include "android-base/mapped_file.h"
+#include "android-base/unique_fd.h"
+
+namespace android {
+namespace base {
+
+// These ABI-compatibility shims are in a separate file for two reasons:
+//   1. If they were in the file with the actual functions, it prevents calls to
+//      those functions by other functions in the file, due to ambiguity.
+//   2. We will hopefully be able to delete these quickly.
+
+#if !defined(_WIN32)
+ssize_t SendFileDescriptorVector(int sockfd, const void* data, size_t len,
+                                 const std::vector<int>& fds) {
+  return SendFileDescriptorVector(borrowed_fd(sockfd), data, len, fds);
+}
+
+ssize_t ReceiveFileDescriptorVector(int sockfd, void* data, size_t len, size_t max_fds,
+                                    std::vector<unique_fd>* fds) {
+  return ReceiveFileDescriptorVector(borrowed_fd(sockfd), data, len, max_fds, fds);
+}
+#endif
+
+bool ReadFdToString(int fd, std::string* content) {
+  return ReadFdToString(borrowed_fd(fd), content);
+}
+
+bool WriteStringToFd(const std::string& content, int fd) {
+  return WriteStringToFd(content, borrowed_fd(fd));
+}
+
+bool ReadFully(int fd, void* data, size_t byte_count) {
+  return ReadFully(borrowed_fd(fd), data, byte_count);
+}
+
+bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
+  return ReadFullyAtOffset(borrowed_fd(fd), data, byte_count, offset);
+}
+
+bool WriteFully(int fd, const void* data, size_t byte_count) {
+  return WriteFully(borrowed_fd(fd), data, byte_count);
+}
+
+#if defined(__LP64__)
+#define MAPPEDFILE_FROMFD _ZN10MappedFile6FromFdEilmi
+#else
+#define MAPPEDFILE_FROMFD _ZN10MappedFile6FromFdEixmi
+#endif
+
+#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+extern "C" std::unique_ptr<MappedFile> MAPPEDFILE_FROMFD(int fd, off64_t offset, size_t length,
+                                                         int prot) {
+  return MappedFile::FromFd(fd, offset, length, prot);
+}
+
+}  // namespace base
+}  // namespace android
diff --git a/base/cmsg.cpp b/base/cmsg.cpp
index 42866f8..1fa873c 100644
--- a/base/cmsg.cpp
+++ b/base/cmsg.cpp
@@ -29,7 +29,7 @@
 namespace android {
 namespace base {
 
-ssize_t SendFileDescriptorVector(int sockfd, const void* data, size_t len,
+ssize_t SendFileDescriptorVector(borrowed_fd sockfd, const void* data, size_t len,
                                  const std::vector<int>& fds) {
   size_t cmsg_space = CMSG_SPACE(sizeof(int) * fds.size());
   size_t cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
@@ -67,10 +67,10 @@
   int flags = 0;
 #endif
 
-  return TEMP_FAILURE_RETRY(sendmsg(sockfd, &msg, flags));
+  return TEMP_FAILURE_RETRY(sendmsg(sockfd.get(), &msg, flags));
 }
 
-ssize_t ReceiveFileDescriptorVector(int sockfd, void* data, size_t len, size_t max_fds,
+ssize_t ReceiveFileDescriptorVector(borrowed_fd sockfd, void* data, size_t len, size_t max_fds,
                                     std::vector<unique_fd>* fds) {
   fds->clear();
 
@@ -98,7 +98,7 @@
   flags |= MSG_CMSG_CLOEXEC | MSG_NOSIGNAL;
 #endif
 
-  ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sockfd, &msg, flags));
+  ssize_t rc = TEMP_FAILURE_RETRY(recvmsg(sockfd.get(), &msg, flags));
 
   if (rc == -1) {
     return -1;
diff --git a/base/file.cpp b/base/file.cpp
index adc8984..3dfcfbb 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -176,20 +176,20 @@
 // Versions of standard library APIs that support UTF-8 strings.
 using namespace android::base::utf8;
 
-bool ReadFdToString(int fd, std::string* content) {
+bool ReadFdToString(borrowed_fd fd, std::string* content) {
   content->clear();
 
   // Although original we had small files in mind, this code gets used for
   // very large files too, where the std::string growth heuristics might not
   // be suitable. https://code.google.com/p/android/issues/detail?id=258500.
   struct stat sb;
-  if (fstat(fd, &sb) != -1 && sb.st_size > 0) {
+  if (fstat(fd.get(), &sb) != -1 && sb.st_size > 0) {
     content->reserve(sb.st_size);
   }
 
   char buf[BUFSIZ];
   ssize_t n;
-  while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
+  while ((n = TEMP_FAILURE_RETRY(read(fd.get(), &buf[0], sizeof(buf)))) > 0) {
     content->append(buf, n);
   }
   return (n == 0) ? true : false;
@@ -206,11 +206,11 @@
   return ReadFdToString(fd, content);
 }
 
-bool WriteStringToFd(const std::string& content, int fd) {
+bool WriteStringToFd(const std::string& content, borrowed_fd fd) {
   const char* p = content.data();
   size_t left = content.size();
   while (left > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
+    ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, left));
     if (n == -1) {
       return false;
     }
@@ -269,11 +269,11 @@
   return WriteStringToFd(content, fd) || CleanUpAfterFailedWrite(path);
 }
 
-bool ReadFully(int fd, void* data, size_t byte_count) {
+bool ReadFully(borrowed_fd fd, void* data, size_t byte_count) {
   uint8_t* p = reinterpret_cast<uint8_t*>(data);
   size_t remaining = byte_count;
   while (remaining > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
+    ssize_t n = TEMP_FAILURE_RETRY(read(fd.get(), p, remaining));
     if (n <= 0) return false;
     p += n;
     remaining -= n;
@@ -284,14 +284,14 @@
 #if defined(_WIN32)
 // Windows implementation of pread. Note that this DOES move the file descriptors read position,
 // but it does so atomically.
-static ssize_t pread(int fd, void* data, size_t byte_count, off64_t offset) {
+static ssize_t pread(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
   DWORD bytes_read;
   OVERLAPPED overlapped;
   memset(&overlapped, 0, sizeof(OVERLAPPED));
   overlapped.Offset = static_cast<DWORD>(offset);
   overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
-  if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), data, static_cast<DWORD>(byte_count),
-                &bytes_read, &overlapped)) {
+  if (!ReadFile(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), data,
+                static_cast<DWORD>(byte_count), &bytes_read, &overlapped)) {
     // In case someone tries to read errno (since this is masquerading as a POSIX call)
     errno = EIO;
     return -1;
@@ -300,10 +300,10 @@
 }
 #endif
 
-bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset) {
+bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset) {
   uint8_t* p = reinterpret_cast<uint8_t*>(data);
   while (byte_count > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(pread(fd, p, byte_count, offset));
+    ssize_t n = TEMP_FAILURE_RETRY(pread(fd.get(), p, byte_count, offset));
     if (n <= 0) return false;
     p += n;
     byte_count -= n;
@@ -312,11 +312,11 @@
   return true;
 }
 
-bool WriteFully(int fd, const void* data, size_t byte_count) {
+bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count) {
   const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
   size_t remaining = byte_count;
   while (remaining > 0) {
-    ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
+    ssize_t n = TEMP_FAILURE_RETRY(write(fd.get(), p, remaining));
     if (n == -1) return false;
     p += n;
     remaining -= n;
diff --git a/base/include/android-base/cmsg.h b/base/include/android-base/cmsg.h
index 7f93ddc..e4197b1 100644
--- a/base/include/android-base/cmsg.h
+++ b/base/include/android-base/cmsg.h
@@ -51,20 +51,20 @@
 // Note that the write can return short if the socket type is SOCK_STREAM. When
 // this happens, file descriptors are still sent to the other end, but with
 // truncated data. For this reason, using SOCK_SEQPACKET or SOCK_DGRAM is recommended.
-ssize_t SendFileDescriptorVector(int sock, const void* data, size_t len,
+ssize_t SendFileDescriptorVector(borrowed_fd sock, const void* data, size_t len,
                                  const std::vector<int>& fds);
 
 // Receive file descriptors from a Unix domain socket.
 //
 // If more FDs (or bytes, for datagram sockets) are received than expected,
 // -1 is returned with errno set to EMSGSIZE, and all received FDs are thrown away.
-ssize_t ReceiveFileDescriptorVector(int sock, void* data, size_t len, size_t max_fds,
+ssize_t ReceiveFileDescriptorVector(borrowed_fd sock, void* data, size_t len, size_t max_fds,
                                     std::vector<android::base::unique_fd>* fds);
 
 // Helper for SendFileDescriptorVector that constructs a std::vector for you, e.g.:
 //   SendFileDescriptors(sock, "foo", 3, std::move(fd1), std::move(fd2))
 template <typename... Args>
-ssize_t SendFileDescriptors(int sock, const void* data, size_t len, Args&&... sent_fds) {
+ssize_t SendFileDescriptors(borrowed_fd sock, const void* data, size_t len, Args&&... sent_fds) {
   // Do not allow implicit conversion to int: people might try to do something along the lines of:
   //   SendFileDescriptors(..., std::move(a_unique_fd))
   // and be surprised when the unique_fd isn't closed afterwards.
@@ -79,7 +79,7 @@
 // If fewer file descriptors are received than requested, -1 is returned with errno set to ENOMSG.
 // In both cases, all arguments are cleared and any received FDs are thrown away.
 template <typename... Args>
-ssize_t ReceiveFileDescriptors(int sock, void* data, size_t len, Args&&... received_fds) {
+ssize_t ReceiveFileDescriptors(borrowed_fd sock, void* data, size_t len, Args&&... received_fds) {
   std::vector<unique_fd*> fds;
   Append(fds, std::forward<Args>(received_fds)...);
 
diff --git a/base/include/android-base/file.h b/base/include/android-base/file.h
index f8748b5..c622562 100644
--- a/base/include/android-base/file.h
+++ b/base/include/android-base/file.h
@@ -21,8 +21,9 @@
 
 #include <string>
 
-#include <android-base/macros.h>
+#include "android-base/macros.h"
 #include "android-base/off64_t.h"
+#include "android-base/unique_fd.h"
 
 #if !defined(_WIN32) && !defined(O_BINARY)
 /** Windows needs O_BINARY, but Unix never mangles line endings. */
@@ -77,13 +78,13 @@
 namespace android {
 namespace base {
 
-bool ReadFdToString(int fd, std::string* content);
+bool ReadFdToString(borrowed_fd fd, std::string* content);
 bool ReadFileToString(const std::string& path, std::string* content,
                       bool follow_symlinks = false);
 
 bool WriteStringToFile(const std::string& content, const std::string& path,
                        bool follow_symlinks = false);
-bool WriteStringToFd(const std::string& content, int fd);
+bool WriteStringToFd(const std::string& content, borrowed_fd fd);
 
 #if !defined(_WIN32)
 bool WriteStringToFile(const std::string& content, const std::string& path,
@@ -91,7 +92,7 @@
                        bool follow_symlinks = false);
 #endif
 
-bool ReadFully(int fd, void* data, size_t byte_count);
+bool ReadFully(borrowed_fd fd, void* data, size_t byte_count);
 
 // Reads `byte_count` bytes from the file descriptor at the specified offset.
 // Returns false if there was an IO error or EOF was reached before reading `byte_count` bytes.
@@ -101,9 +102,9 @@
 // get modified. This means that ReadFullyAtOffset can be used concurrently with other calls to the
 // same function, but concurrently seeking or reading incrementally can lead to unexpected
 // behavior.
-bool ReadFullyAtOffset(int fd, void* data, size_t byte_count, off64_t offset);
+bool ReadFullyAtOffset(borrowed_fd fd, void* data, size_t byte_count, off64_t offset);
 
-bool WriteFully(int fd, const void* data, size_t byte_count);
+bool WriteFully(borrowed_fd fd, const void* data, size_t byte_count);
 
 bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
 
diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h
index 80513b1..b719646 100644
--- a/base/include/android-base/mapped_file.h
+++ b/base/include/android-base/mapped_file.h
@@ -16,13 +16,14 @@
 
 #pragma once
 
-#include "android-base/macros.h"
-#include "android-base/off64_t.h"
-
 #include <sys/types.h>
 
 #include <memory>
 
+#include "android-base/macros.h"
+#include "android-base/off64_t.h"
+#include "android-base/unique_fd.h"
+
 #if defined(_WIN32)
 #include <windows.h>
 #define PROT_READ 1
@@ -44,7 +45,8 @@
    * `offset` does not need to be page-aligned. If `PROT_WRITE` is set in `prot`, the mapping
    * will be writable, otherwise it will be read-only. Mappings are always `MAP_SHARED`.
    */
-  static std::unique_ptr<MappedFile> FromFd(int fd, off64_t offset, size_t length, int prot);
+  static std::unique_ptr<MappedFile> FromFd(borrowed_fd fd, off64_t offset, size_t length,
+                                            int prot);
 
   /**
    * Removes the mapping.
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 8e9716f..b1c22c9 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -18,6 +18,7 @@
 
 #include <sstream>
 #include <string>
+#include <string_view>
 #include <vector>
 
 namespace android {
@@ -68,5 +69,21 @@
 // Tests whether 'lhs' equals 'rhs', ignoring case.
 bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs);
 
+// Removes `prefix` from the start of the given string and returns true (if
+// it was present), false otherwise.
+inline bool ConsumePrefix(std::string_view* s, std::string_view prefix) {
+  if (!StartsWith(*s, prefix)) return false;
+  s->remove_prefix(prefix.size());
+  return true;
+}
+
+// Removes `suffix` from the end of the given string and returns true (if
+// it was present), false otherwise.
+inline bool ConsumeSuffix(std::string_view* s, std::string_view suffix) {
+  if (!EndsWith(*s, suffix)) return false;
+  s->remove_suffix(suffix.size());
+  return true;
+}
+
 }  // namespace base
 }  // namespace android
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 3fa3bea..3a02cff 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -103,7 +103,17 @@
   void reset(int new_value = -1) { reset(new_value, nullptr); }
 
   int get() const { return fd_; }
+
+#if !defined(ANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION)
+  // unique_fd's operator int is dangerous, but we have way too much code that
+  // depends on it, so make this opt-in at first.
   operator int() const { return get(); }  // NOLINT
+#endif
+
+  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!=(int rhs) const { return get() != rhs; }
 
   // Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
   bool operator!() const = delete;
@@ -246,6 +256,22 @@
 
 #endif  // !defined(_WIN32)
 
+// A wrapper type that can be implicitly constructed from either int or unique_fd.
+struct borrowed_fd {
+  /* implicit */ borrowed_fd(int fd) : fd_(fd) {}
+  template <typename T>
+  /* implicit */ borrowed_fd(const unique_fd_impl<T>& ufd) : fd_(ufd.get()) {}
+
+  int get() const { return fd_; }
+
+  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!=(int rhs) const { return get() != rhs; }
+
+ private:
+  int fd_ = -1;
+};
 }  // namespace base
 }  // namespace android
 
diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp
index 7c65dc3..f689bfa 100644
--- a/base/mapped_file.cpp
+++ b/base/mapped_file.cpp
@@ -18,6 +18,8 @@
 
 #include <errno.h>
 
+#include "android-base/unique_fd.h"
+
 namespace android {
 namespace base {
 
@@ -31,7 +33,8 @@
 #endif
 }
 
-std::unique_ptr<MappedFile> MappedFile::FromFd(int fd, off64_t offset, size_t length, int prot) {
+std::unique_ptr<MappedFile> MappedFile::FromFd(borrowed_fd fd, off64_t offset, size_t length,
+                                               int prot) {
   static off64_t page_size = InitPageSize();
   size_t slop = offset % page_size;
   off64_t file_offset = offset - slop;
@@ -39,7 +42,7 @@
 
 #if defined(_WIN32)
   HANDLE handle =
-      CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr,
+      CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd.get())), nullptr,
                         (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
   if (handle == nullptr) {
     // http://b/119818070 "app crashes when reading asset of zero length".
@@ -58,7 +61,7 @@
   return std::unique_ptr<MappedFile>(
       new MappedFile{static_cast<char*>(base), length, slop, handle});
 #else
-  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd, file_offset);
+  void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd.get(), 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.
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 9d74094..ca3c0b8 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -295,3 +295,19 @@
 TEST(strings, ubsan_28729303) {
   android::base::Split("/dev/null", ":");
 }
+
+TEST(strings, ConsumePrefix) {
+  std::string_view s{"foo.bar"};
+  ASSERT_FALSE(android::base::ConsumePrefix(&s, "bar."));
+  ASSERT_EQ("foo.bar", s);
+  ASSERT_TRUE(android::base::ConsumePrefix(&s, "foo."));
+  ASSERT_EQ("bar", s);
+}
+
+TEST(strings, ConsumeSuffix) {
+  std::string_view s{"foo.bar"};
+  ASSERT_FALSE(android::base::ConsumeSuffix(&s, ".foo"));
+  ASSERT_EQ("foo.bar", s);
+  ASSERT_TRUE(android::base::ConsumeSuffix(&s, ".bar"));
+  ASSERT_EQ("foo", s);
+}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 558e6c4..c091ff7 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -1183,6 +1183,7 @@
   boot_event_store.AddBootEventWithValue(boot_complete_prefix, uptime_s.count());
 
   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init");
+  RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.first_stage");
   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.selinux");
   RecordInitBootTimeProp(&boot_event_store, "ro.boottime.init.cold_boot_wait");
 
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index c608a8c..cb55745 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -463,6 +463,7 @@
       ThreadInfo info;
       info.pid = target_process;
       info.tid = thread;
+      info.uid = getuid();
       info.process_name = process_name;
       info.thread_name = get_thread_name(thread);
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index f8f7eb3..25df451 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -502,9 +502,8 @@
 
 static bool UnzipToMemory(ZipArchiveHandle zip, const std::string& entry_name,
                           std::vector<char>* out) {
-    ZipString zip_entry_name(entry_name.c_str());
     ZipEntry zip_entry;
-    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+    if (FindEntry(zip, entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name.c_str());
         return false;
     }
@@ -614,9 +613,8 @@
 static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
     unique_fd fd(make_temporary_fd(entry_name));
 
-    ZipString zip_entry_name(entry_name);
     ZipEntry zip_entry;
-    if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
+    if (FindEntry(zip, entry_name, &zip_entry) != 0) {
         fprintf(stderr, "archive does not contain '%s'\n", entry_name);
         errno = ENOENT;
         return -1;
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index ff918a7..a1d69d2 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -244,16 +244,29 @@
 // Testing creation/resize/delete of logical partitions
 TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) {
     ASSERT_TRUE(UserSpaceFastboot());
+    std::string test_partition_name = "test_partition";
+    std::string slot_count;
+    // Add suffix to test_partition_name if device is slotted.
+    EXPECT_EQ(fb->GetVar("slot-count", &slot_count), SUCCESS) << "getvar slot-count failed";
+    int32_t num_slots = strtol(slot_count.c_str(), nullptr, 10);
+    if (num_slots > 0) {
+        std::string current_slot;
+        EXPECT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
+                << "getvar current-slot failed";
+        std::string slot_suffix = "_" + current_slot;
+        test_partition_name += slot_suffix;
+    }
+
     GTEST_LOG_(INFO) << "Testing 'fastboot create-logical-partition' command";
-    EXPECT_EQ(fb->CreatePartition("test_partition_a", "0"), SUCCESS)
+    EXPECT_EQ(fb->CreatePartition(test_partition_name, "0"), SUCCESS)
             << "create-logical-partition failed";
     GTEST_LOG_(INFO) << "Testing 'fastboot resize-logical-partition' command";
-    EXPECT_EQ(fb->ResizePartition("test_partition_a", "4096"), SUCCESS)
+    EXPECT_EQ(fb->ResizePartition(test_partition_name, "4096"), SUCCESS)
             << "resize-logical-partition failed";
     std::vector<char> buf(4096);
 
     GTEST_LOG_(INFO) << "Flashing a logical partition..";
-    EXPECT_EQ(fb->FlashPartition("test_partition_a", buf), SUCCESS)
+    EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS)
             << "flash logical -partition failed";
     GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
     // Reboot to bootloader mode and attempt to flash the logical partitions
@@ -262,7 +275,7 @@
     ReconnectFastbootDevice();
     ASSERT_FALSE(UserSpaceFastboot());
     GTEST_LOG_(INFO) << "Attempt to flash a logical partition..";
-    EXPECT_EQ(fb->FlashPartition("test_partition", buf), DEVICE_FAIL)
+    EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), DEVICE_FAIL)
             << "flash logical partition must fail in bootloader";
     GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
     fb->RebootTo("fastboot");
@@ -270,7 +283,7 @@
     ReconnectFastbootDevice();
     ASSERT_TRUE(UserSpaceFastboot());
     GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
-    EXPECT_EQ(fb->DeletePartition("test_partition_a"), SUCCESS)
+    EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS)
             << "delete logical-partition failed";
 }
 
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index f597f50..8a3c213 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -106,7 +106,7 @@
     kr = (*dev)->CreateInterfaceIterator(dev, &request, &iterator);
 
     if (kr != 0) {
-        ERR("Couldn't create a device interface iterator: (%08x)\n", kr);
+        WARN("Couldn't create a device interface iterator: (%08x)\n", kr);
         return -1;
     }
 
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 4ee9624..ffde114 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -121,9 +121,14 @@
     shared_libs: [
         "libbootloader_message",
         "libbase",
+        "libcutils",
         "libcrypto",
+        "libext4_utils",
         "libfec",
         "libfs_mgr",
+        "liblog",
+        "liblp",
+        "libselinux",
     ],
     header_libs: [
         "libcutils_headers",
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index f89e598..d204bfd 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -117,3 +117,25 @@
   be used to clear scratch storage to permit the flash.
   Then reinstate the overrides and continue.
 - File bugs or submit fixes for review.
+- There are other subtle caveats requiring complex logic to solve.
+  Have evaluated them as too complex or not worth the trouble, please
+  File a bug if a use case needs to be covered.
+  - The backing storage is treated fragile, if anything else has
+    issue with the space taken, the backing storage will be cleared
+    out and we reserve the right to not inform, if the layering
+    does not prevent any messaging.
+  - Space remaining threshold is hard coded.  If 1% or more space
+    still remains, overlayfs will not be used, yet that amount of
+    space remaining is problematic.
+  - Flashing a partition via bootloader fastboot, as opposed to user
+    space fastbootd, is not detected, thus a partition may have
+    override content remaining.  adb enable-verity to wipe.
+  - Space is limited, there is near unlimited space on userdata,
+    we have made an architectural decision to not utilize
+    /data/overlay/ at this time.  Acquiring space to use for
+    backing remains an ongoing battle.
+  - First stage init, or ramdisk, can not be overriden.
+  - Backing storage will be discarded or ignored on errors, leading
+    to confusion.  When debugging using **adb remount** it is
+    currently advised to confirm update is present after a reboot
+    to develop confidence.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index c1aafda..56ea92c 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -390,7 +390,7 @@
 // Set the number of reserved filesystem blocks if needed.
 static void tune_reserved_size(const std::string& blk_device, const FstabEntry& entry,
                                const struct ext4_super_block* sb, int* fs_stat) {
-    if (entry.reserved_size != 0) {
+    if (entry.reserved_size == 0) {
         return;
     }
 
@@ -1610,38 +1610,6 @@
     return ret;
 }
 
-bool fs_mgr_load_verity_state(int* mode) {
-    /* return the default mode, unless any of the verified partitions are in
-     * logging mode, in which case return that */
-    *mode = VERITY_MODE_DEFAULT;
-
-    Fstab fstab;
-    if (!ReadDefaultFstab(&fstab)) {
-        LERROR << "Failed to read default fstab";
-        return false;
-    }
-
-    for (const auto& entry : fstab) {
-        if (entry.fs_mgr_flags.avb) {
-            *mode = VERITY_MODE_RESTART;  // avb only supports restart mode.
-            break;
-        } else if (!entry.fs_mgr_flags.verify) {
-            continue;
-        }
-
-        int current;
-        if (load_verity_state(entry, &current) < 0) {
-            continue;
-        }
-        if (current != VERITY_MODE_DEFAULT) {
-            *mode = current;
-            break;
-        }
-    }
-
-    return true;
-}
-
 bool fs_mgr_is_verity_enabled(const FstabEntry& entry) {
     if (!entry.fs_mgr_flags.verify && !entry.fs_mgr_flags.avb) {
         return false;
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index da049ef..0cbdcce 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -261,10 +261,6 @@
                     LWARNING << "Warning: zramsize= flag malformed: " << arg;
                 }
             }
-        } else if (StartsWith(flag, "verify=")) {
-            // If the verify flag is followed by an = and the location for the verity state.
-            entry->fs_mgr_flags.verify = true;
-            entry->verity_loc = arg;
         } else if (StartsWith(flag, "forceencrypt=")) {
             // The forceencrypt flag is followed by an = and the location of the keys.
             entry->fs_mgr_flags.force_crypt = true;
@@ -704,7 +700,9 @@
     constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg";
 
     std::string skip_config;
+    auto save_errno = errno;
     if (!ReadFileToString(kSkipMountConfig, &skip_config)) {
+        errno = save_errno;  // missing file is expected
         return true;
     }
 
@@ -805,8 +803,11 @@
 std::string GetVerityDeviceName(const FstabEntry& entry) {
     std::string base_device;
     if (entry.mount_point == "/") {
-        // In AVB, the dm device name is vroot instead of system.
-        base_device = entry.fs_mgr_flags.avb ? "vroot" : "system";
+        // When using system-as-root, the device name is fixed as "vroot".
+        if (entry.fs_mgr_flags.avb) {
+            return "vroot";
+        }
+        base_device = "system";
     } else {
         base_device = android::base::Basename(entry.mount_point);
     }
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index e46e497..a649975 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -139,7 +139,11 @@
     // If we have access issues to find out space remaining, return true
     // to prevent us trying to override with overlayfs.
     struct statvfs vst;
-    if (statvfs(mount_point.c_str(), &vst)) return true;
+    auto save_errno = errno;
+    if (statvfs(mount_point.c_str(), &vst)) {
+        errno = save_errno;
+        return true;
+    }
 
     static constexpr int kPercentThreshold = 1;  // 1%
 
@@ -265,9 +269,11 @@
 
 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
     Fstab fstab;
+    auto save_errno = errno;
     if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
         return false;
     }
+    errno = save_errno;
     const auto lowerdir = kLowerdirOption + mount_point;
     for (const auto& entry : fstab) {
         if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
@@ -646,6 +652,25 @@
     return true;
 }
 
+static void TruncatePartitionsWithSuffix(MetadataBuilder* builder, const std::string& suffix) {
+    auto& dm = DeviceMapper::Instance();
+
+    // Remove <other> partitions
+    for (const auto& group : builder->ListGroups()) {
+        for (const auto& part : builder->ListPartitionsInGroup(group)) {
+            const auto& name = part->name();
+            if (!android::base::EndsWith(name, suffix)) {
+                continue;
+            }
+            if (dm.GetState(name) != DmDeviceState::INVALID && !DestroyLogicalPartition(name, 2s)) {
+                continue;
+            }
+            builder->ResizePartition(builder->FindPartition(name), 0);
+        }
+    }
+}
+
+// This is where we find and steal backing storage from the system.
 bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_device,
                                      bool* partition_exists, bool* change) {
     *scratch_device = fs_mgr_overlayfs_scratch_device();
@@ -692,15 +717,24 @@
             // the adb remount overrides :-( .
             auto margin_size = uint64_t(3 * 256 * 1024);
             BlockDeviceInfo info;
-            if (builder->GetBlockDeviceInfo(partition_name, &info)) {
+            if (builder->GetBlockDeviceInfo(fs_mgr_get_super_partition_name(slot_number), &info)) {
                 margin_size = 3 * info.logical_block_size;
             }
             partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
                                       partition_size / 2);
             if (partition_size > partition->size()) {
                 if (!builder->ResizePartition(partition, partition_size)) {
-                    LERROR << "resize " << partition_name;
-                    return false;
+                    // Try to free up space by deallocating partitions in the other slot.
+                    TruncatePartitionsWithSuffix(builder.get(), fs_mgr_get_other_slot_suffix());
+
+                    partition_size =
+                            builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+                    partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
+                                              partition_size / 2);
+                    if (!builder->ResizePartition(partition, partition_size)) {
+                        LERROR << "resize " << partition_name;
+                        return false;
+                    }
                 }
                 if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
                 changed = true;
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 70abf5b..c36fd3d 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -99,7 +99,6 @@
 bool fs_mgr_is_device_unlocked();
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
-int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
 
 bool fs_mgr_is_ext4(const std::string& blk_device);
 bool fs_mgr_is_f2fs(const std::string& blk_device);
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index cbe2008..6482ed3 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -249,20 +249,21 @@
 
     // Check verity and optionally setup overlayfs backing.
     auto reboot_later = false;
+    auto user_please_reboot_later = false;
     auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported;
     for (auto it = partitions.begin(); it != partitions.end();) {
         auto& entry = *it;
         auto& mount_point = entry.mount_point;
         if (fs_mgr_is_verity_enabled(entry)) {
             retval = VERITY_PARTITION;
-            if (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked") {
+            if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") != "locked") {
                 if (AvbOps* ops = avb_ops_user_new()) {
                     auto ret = avb_user_verity_set(
                             ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(),
                             false);
                     avb_ops_user_free(ops);
                     if (ret) {
-                        LOG(WARNING) << "Disable verity for " << mount_point;
+                        LOG(WARNING) << "Disabling verity for " << mount_point;
                         reboot_later = can_reboot;
                         if (reboot_later) {
                             // w/o overlayfs available, also check for dedupe
@@ -272,20 +273,22 @@
                             }
                             reboot(false);
                         }
+                        user_please_reboot_later = true;
                     } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) {
                         fec::io fh(entry.blk_device.c_str(), O_RDWR);
                         if (fh && fh.set_verity_status(false)) {
-                            LOG(WARNING) << "Disable verity for " << mount_point;
+                            LOG(WARNING) << "Disabling verity for " << mount_point;
                             reboot_later = can_reboot;
                             if (reboot_later && !uses_overlayfs) {
                                 ++it;
                                 continue;
                             }
+                            user_please_reboot_later = true;
                         }
                     }
                 }
             }
-            LOG(ERROR) << "Skipping " << mount_point;
+            LOG(ERROR) << "Skipping " << mount_point << " for remount";
             it = partitions.erase(it);
             continue;
         }
@@ -307,6 +310,10 @@
 
     if (partitions.empty()) {
         if (reboot_later) reboot(false);
+        if (user_please_reboot_later) {
+            LOG(INFO) << "Now reboot your device for settings to take effect";
+            return 0;
+        }
         LOG(WARNING) << "No partitions to remount";
         return retval;
     }
@@ -383,6 +390,10 @@
     }
 
     if (reboot_later) reboot(false);
+    if (user_please_reboot_later) {
+        LOG(INFO) << "Now reboot your device for settings to take effect";
+        return 0;
+    }
 
     return retval;
 }
diff --git a/fs_mgr/fs_mgr_roots.cpp b/fs_mgr/fs_mgr_roots.cpp
index 58ef9b6..1e65587 100644
--- a/fs_mgr/fs_mgr_roots.cpp
+++ b/fs_mgr/fs_mgr_roots.cpp
@@ -101,7 +101,9 @@
         }
     }
 
-    auto mounted = GetMountState(rec->mount_point);
+    const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
+
+    auto mounted = GetMountState(mount_point);
     if (mounted == MountState::ERROR) {
         return false;
     }
@@ -109,8 +111,6 @@
         return true;
     }
 
-    const std::string mount_point = mount_pt.empty() ? rec->mount_point : mount_pt;
-
     static const std::vector<std::string> supported_fs{"ext4", "squashfs", "vfat", "f2fs", "none"};
     if (std::find(supported_fs.begin(), supported_fs.end(), rec->fs_type) == supported_fs.end()) {
         LERROR << "unknown fs_type \"" << rec->fs_type << "\" for " << mount_point;
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 3f09157..1deb1ac 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -275,248 +275,6 @@
     return 0;
 }
 
-static int check_verity_restart(const char *fname)
-{
-    char buffer[VERITY_KMSG_BUFSIZE + 1];
-    int fd;
-    int rc = 0;
-    ssize_t size;
-    struct stat s;
-
-    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
-
-    if (fd == -1) {
-        if (errno != ENOENT) {
-            PERROR << "Failed to open " << fname;
-        }
-        goto out;
-    }
-
-    if (fstat(fd, &s) == -1) {
-        PERROR << "Failed to fstat " << fname;
-        goto out;
-    }
-
-    size = VERITY_KMSG_BUFSIZE;
-
-    if (size > s.st_size) {
-        size = s.st_size;
-    }
-
-    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
-        PERROR << "Failed to lseek " << (intmax_t)(s.st_size - size) << " " << fname;
-        goto out;
-    }
-
-    if (!android::base::ReadFully(fd, buffer, size)) {
-        PERROR << "Failed to read " << size << " bytes from " << fname;
-        goto out;
-    }
-
-    buffer[size] = '\0';
-
-    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
-        rc = 1;
-    }
-
-out:
-    if (fd != -1) {
-        close(fd);
-    }
-
-    return rc;
-}
-
-static int was_verity_restart()
-{
-    static const char* files[] = {
-        // clang-format off
-        "/sys/fs/pstore/console-ramoops-0",
-        "/sys/fs/pstore/console-ramoops",
-        "/proc/last_kmsg",
-        NULL
-        // clang-format on
-    };
-    int i;
-
-    for (i = 0; files[i]; ++i) {
-        if (check_verity_restart(files[i])) {
-            return 1;
-        }
-    }
-
-    return 0;
-}
-
-static int metadata_add(FILE *fp, long start, const char *tag,
-        unsigned int length, off64_t *offset)
-{
-    if (fseek(fp, start, SEEK_SET) < 0 ||
-        fprintf(fp, "%s %u\n", tag, length) < 0) {
-        return -1;
-    }
-
-    *offset = ftell(fp);
-
-    if (fseek(fp, length, SEEK_CUR) < 0 ||
-        fprintf(fp, METADATA_EOD " 0\n") < 0) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static int metadata_find(const char *fname, const char *stag,
-        unsigned int slength, off64_t *offset)
-{
-    char tag[METADATA_TAG_MAX_LENGTH + 1];
-    int rc = -1;
-    int n;
-    long start = 0x4000; /* skip cryptfs metadata area */
-    uint32_t magic;
-    unsigned int length = 0;
-
-    if (!fname) {
-        return -1;
-    }
-
-    auto fp = std::unique_ptr<FILE, decltype(&fclose)>{fopen(fname, "re+"), fclose};
-
-    if (!fp) {
-        PERROR << "Failed to open " << fname;
-        return -1;
-    }
-
-    /* check magic */
-    if (fseek(fp.get(), start, SEEK_SET) < 0 || fread(&magic, sizeof(magic), 1, fp.get()) != 1) {
-        PERROR << "Failed to read magic from " << fname;
-        return -1;
-    }
-
-    if (magic != METADATA_MAGIC) {
-        magic = METADATA_MAGIC;
-
-        if (fseek(fp.get(), start, SEEK_SET) < 0 ||
-            fwrite(&magic, sizeof(magic), 1, fp.get()) != 1) {
-            PERROR << "Failed to write magic to " << fname;
-            return -1;
-        }
-
-        rc = metadata_add(fp.get(), start + sizeof(magic), stag, slength, offset);
-        if (rc < 0) {
-            PERROR << "Failed to add metadata to " << fname;
-        }
-
-        return rc;
-    }
-
-    start += sizeof(magic);
-
-    while (1) {
-        n = fscanf(fp.get(), "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n", tag, &length);
-
-        if (n == 2 && strcmp(tag, METADATA_EOD)) {
-            /* found a tag */
-            start = ftell(fp.get());
-
-            if (!strcmp(tag, stag) && length == slength) {
-                *offset = start;
-                return 0;
-            }
-
-            start += length;
-
-            if (fseek(fp.get(), length, SEEK_CUR) < 0) {
-                PERROR << "Failed to seek " << fname;
-                return -1;
-            }
-        } else {
-            rc = metadata_add(fp.get(), start, stag, slength, offset);
-            if (rc < 0) {
-                PERROR << "Failed to write metadata to " << fname;
-            }
-            return rc;
-        }
-    }
-}
-
-static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
-{
-    int fd;
-    int rc = -1;
-    struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
-
-    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
-
-    if (fd == -1) {
-        PERROR << "Failed to open " << fname;
-        goto out;
-    }
-
-    if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
-        PERROR << "Failed to write " << sizeof(s) << " bytes to " << fname
-               << " to offset " << offset;
-        goto out;
-    }
-
-    rc = 0;
-
-out:
-    if (fd != -1) {
-        close(fd);
-    }
-
-    return rc;
-}
-
-static int read_verity_state(const char *fname, off64_t offset, int *mode)
-{
-    int fd = -1;
-    int rc = -1;
-    struct verity_state s;
-
-    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
-
-    if (fd == -1) {
-        PERROR << "Failed to open " << fname;
-        goto out;
-    }
-
-    if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
-        PERROR << "Failed to read " <<  sizeof(s) << " bytes from " << fname
-               << " offset " << offset;
-        goto out;
-    }
-
-    if (s.header != VERITY_STATE_HEADER) {
-        /* space allocated, but no state written. write default state */
-        *mode = VERITY_MODE_DEFAULT;
-        rc = write_verity_state(fname, offset, *mode);
-        goto out;
-    }
-
-    if (s.version != VERITY_STATE_VERSION) {
-        LERROR << "Unsupported verity state version (" << s.version << ")";
-        goto out;
-    }
-
-    if (s.mode < VERITY_MODE_EIO ||
-        s.mode > VERITY_MODE_LAST) {
-        LERROR << "Unsupported verity mode (" << s.mode << ")";
-        goto out;
-    }
-
-    *mode = s.mode;
-    rc = 0;
-
-out:
-    if (fd != -1) {
-        close(fd);
-    }
-
-    return rc;
-}
-
 static int read_partition(const char *path, uint64_t size)
 {
     char buf[READ_BUF_SIZE];
@@ -540,119 +298,23 @@
     return 0;
 }
 
-static int compare_last_signature(const FstabEntry& entry, int* match) {
-    char tag[METADATA_TAG_MAX_LENGTH + 1];
-    int fd = -1;
-    int rc = -1;
-    off64_t offset = 0;
-    struct fec_handle *f = NULL;
-    struct fec_verity_metadata verity;
-    uint8_t curr[SHA256_DIGEST_LENGTH];
-    uint8_t prev[SHA256_DIGEST_LENGTH];
-
-    *match = 1;
-
-    if (fec_open(&f, entry.blk_device.c_str(), O_RDONLY, FEC_VERITY_DISABLE, FEC_DEFAULT_ROOTS) ==
-        -1) {
-        PERROR << "Failed to open '" << entry.blk_device << "'";
-        return rc;
-    }
-
-    // read verity metadata
-    if (fec_verity_get_metadata(f, &verity) == -1) {
-        PERROR << "Failed to get verity metadata '" << entry.blk_device << "'";
-        goto out;
-    }
-
-    SHA256(verity.signature, sizeof(verity.signature), curr);
-
-    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s", basename(entry.mount_point.c_str())) >=
-        (int)sizeof(tag)) {
-        LERROR << "Metadata tag name too long for " << entry.mount_point;
-        goto out;
-    }
-
-    if (metadata_find(entry.verity_loc.c_str(), tag, SHA256_DIGEST_LENGTH, &offset) < 0) {
-        goto out;
-    }
-
-    fd = TEMP_FAILURE_RETRY(open(entry.verity_loc.c_str(), O_RDWR | O_SYNC | O_CLOEXEC));
-
-    if (fd == -1) {
-        PERROR << "Failed to open " << entry.verity_loc;
-        goto out;
-    }
-
-    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev), offset)) != sizeof(prev)) {
-        PERROR << "Failed to read " << sizeof(prev) << " bytes from " << entry.verity_loc
-               << " offset " << offset;
-        goto out;
-    }
-
-    *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
-
-    if (!*match) {
-        /* update current signature hash */
-        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
-                offset)) != sizeof(curr)) {
-            PERROR << "Failed to write " << sizeof(curr) << " bytes to " << entry.verity_loc
-                   << " offset " << offset;
-            goto out;
-        }
-    }
-
-    rc = 0;
-
-out:
-    fec_close(f);
-    return rc;
-}
-
-static int get_verity_state_offset(const FstabEntry& entry, off64_t* offset) {
-    char tag[METADATA_TAG_MAX_LENGTH + 1];
-
-    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s", basename(entry.mount_point.c_str())) >=
-        (int)sizeof(tag)) {
-        LERROR << "Metadata tag name too long for " << entry.mount_point;
-        return -1;
-    }
-
-    return metadata_find(entry.verity_loc.c_str(), tag, sizeof(struct verity_state), offset);
-}
-
-int load_verity_state(const FstabEntry& entry, int* mode) {
+bool fs_mgr_load_verity_state(int* mode) {
     // unless otherwise specified, use EIO mode.
     *mode = VERITY_MODE_EIO;
 
-    // use the kernel parameter if set.
-    std::string veritymode;
-    if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
-        if (veritymode == "enforcing") {
-            *mode = VERITY_MODE_DEFAULT;
-        }
-        return 0;
+    // The bootloader communicates verity mode via the kernel commandline
+    std::string verity_mode;
+    if (!fs_mgr_get_boot_config("veritymode", &verity_mode)) {
+        return false;
     }
 
-    off64_t offset = 0;
-    if (get_verity_state_offset(entry, &offset) < 0) {
-        /* fall back to stateless behavior */
-        return 0;
-    }
-
-    if (was_verity_restart()) {
-        /* device was restarted after dm-verity detected a corrupted
-         * block, so use EIO mode */
-        return write_verity_state(entry.verity_loc.c_str(), offset, *mode);
-    }
-
-    int match = 0;
-    if (!compare_last_signature(entry, &match) && !match) {
-        /* partition has been reflashed, reset dm-verity state */
+    if (verity_mode == "enforcing") {
         *mode = VERITY_MODE_DEFAULT;
-        return write_verity_state(entry.verity_loc.c_str(), offset, *mode);
+    } else if (verity_mode == "logging") {
+        *mode = VERITY_MODE_LOGGING;
     }
 
-    return read_verity_state(entry.verity_loc.c_str(), offset, mode);
+    return true;
 }
 
 // Update the verity table using the actual block device path.
@@ -759,7 +421,7 @@
 
     params.ecc_dev = entry->blk_device.c_str();
 
-    if (load_verity_state(*entry, &params.mode) < 0) {
+    if (!fs_mgr_load_verity_state(&params.mode)) {
         /* if accessing or updating the state failed, switch to the default
          * safe mode. This makes sure the device won't end up in an endless
          * restart loop, and no corrupted data will be exposed to userspace
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index d7afed6..c7193ab 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -38,7 +38,6 @@
     std::string fs_options;
     std::string key_loc;
     std::string key_dir;
-    std::string verity_loc;
     off64_t length = 0;
     std::string label;
     int partnum = -1;
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index a4614d0..c2917a4 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -210,6 +210,20 @@
     return true;
 }
 
+bool DeviceMapper::GetTargetByName(const std::string& name, DmTargetTypeInfo* info) {
+    std::vector<DmTargetTypeInfo> targets;
+    if (!GetAvailableTargets(&targets)) {
+        return false;
+    }
+    for (const auto& target : targets) {
+        if (target.name() == name) {
+            if (info) *info = target;
+            return true;
+        }
+    }
+    return false;
+}
+
 bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
     devices->clear();
 
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index cb33eea..da1013e 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -16,8 +16,12 @@
 
 #include "libdm/dm_target.h"
 
+#include <stdio.h>
+#include <sys/types.h>
+
 #include <android-base/logging.h>
 #include <android-base/macros.h>
+#include <android-base/parseint.h>
 #include <android-base/strings.h>
 
 #include <libdm/dm.h>
@@ -115,5 +119,107 @@
     return keyid_ + " " + block_device_;
 }
 
+std::string DmTargetSnapshot::name() const {
+    if (mode_ == SnapshotStorageMode::Merge) {
+        return "snapshot-merge";
+    }
+    return "snapshot";
+}
+
+std::string DmTargetSnapshot::GetParameterString() const {
+    std::string mode;
+    switch (mode_) {
+        case SnapshotStorageMode::Persistent:
+        case SnapshotStorageMode::Merge:
+            // Note: "O" lets us query for overflow in the status message. This
+            // is only supported on kernels 4.4+. On earlier kernels, an overflow
+            // will be reported as "Invalid" in the status string.
+            mode = "P";
+            if (ReportsOverflow(name())) {
+                mode += "O";
+            }
+            break;
+        case SnapshotStorageMode::Transient:
+            mode = "N";
+            break;
+        default:
+            LOG(ERROR) << "DmTargetSnapshot unknown mode";
+            break;
+    }
+    return base_device_ + " " + cow_device_ + " " + mode + " " + std::to_string(chunk_size_);
+}
+
+bool DmTargetSnapshot::ReportsOverflow(const std::string& target_type) {
+    DeviceMapper& dm = DeviceMapper::Instance();
+    DmTargetTypeInfo info;
+    if (!dm.GetTargetByName(target_type, &info)) {
+        return false;
+    }
+    if (target_type == "snapshot") {
+        return info.IsAtLeast(1, 15, 0);
+    }
+    if (target_type == "snapshot-merge") {
+        return info.IsAtLeast(1, 4, 0);
+    }
+    return false;
+}
+
+bool DmTargetSnapshot::ParseStatusText(const std::string& text, Status* status) {
+    auto sections = android::base::Split(text, " ");
+    if (sections.size() == 1) {
+        // This is probably an error code, "Invalid" is possible as is "Overflow"
+        // on 4.4+.
+        status->error = text;
+        return true;
+    }
+    if (sections.size() != 2) {
+        LOG(ERROR) << "snapshot status should have two components";
+        return false;
+    }
+    auto sector_info = android::base::Split(sections[0], "/");
+    if (sector_info.size() != 2) {
+        LOG(ERROR) << "snapshot sector info should have two components";
+        return false;
+    }
+    if (!android::base::ParseUint(sections[1], &status->metadata_sectors)) {
+        LOG(ERROR) << "could not parse metadata sectors";
+        return false;
+    }
+    if (!android::base::ParseUint(sector_info[0], &status->sectors_allocated)) {
+        LOG(ERROR) << "could not parse sectors allocated";
+        return false;
+    }
+    if (!android::base::ParseUint(sector_info[1], &status->total_sectors)) {
+        LOG(ERROR) << "could not parse total sectors";
+        return false;
+    }
+    return true;
+}
+
+std::string DmTargetCrypt::GetParameterString() const {
+    std::vector<std::string> argv = {
+            cipher_,
+            key_,
+            std::to_string(iv_sector_offset_),
+            device_,
+            std::to_string(device_sector_),
+    };
+
+    std::vector<std::string> extra_argv;
+    if (allow_discards_) extra_argv.emplace_back("allow_discards");
+    if (allow_encrypt_override_) extra_argv.emplace_back("allow_encrypt_override");
+    if (iv_large_sectors_) extra_argv.emplace_back("iv_large_sectors");
+    if (sector_size_) extra_argv.emplace_back("sector_size:" + std::to_string(sector_size_));
+
+    if (!extra_argv.empty()) argv.emplace_back(std::to_string(extra_argv.size()));
+
+    argv.insert(argv.end(), extra_argv.begin(), extra_argv.end());
+    return android::base::Join(argv, " ");
+}
+
+std::string DmTargetDefaultKey::GetParameterString() const {
+    return cipher_ + " " + key_ + " " + blockdev_ + " " + std::to_string(start_sector_);
+}
+
 }  // namespace dm
 }  // namespace android
diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp
index 70823c6..dc47c33 100644
--- a/fs_mgr/libdm/dm_test.cpp
+++ b/fs_mgr/libdm/dm_test.cpp
@@ -24,6 +24,7 @@
 
 #include <chrono>
 #include <ctime>
+#include <iostream>
 #include <map>
 #include <thread>
 
@@ -35,21 +36,15 @@
 #include "test_util.h"
 
 using namespace std;
+using namespace std::chrono_literals;
 using namespace android::dm;
 using unique_fd = android::base::unique_fd;
 
 TEST(libdm, HasMinimumTargets) {
+    DmTargetTypeInfo info;
+
     DeviceMapper& dm = DeviceMapper::Instance();
-    vector<DmTargetTypeInfo> targets;
-    ASSERT_TRUE(dm.GetAvailableTargets(&targets));
-
-    map<string, DmTargetTypeInfo> by_name;
-    for (const auto& target : targets) {
-        by_name[target.name()] = target;
-    }
-
-    auto iter = by_name.find("linear");
-    EXPECT_NE(iter, by_name.end());
+    ASSERT_TRUE(dm.GetTargetByName("linear", &info));
 }
 
 // Helper to ensure that device mapper devices are released.
@@ -201,3 +196,268 @@
             "2 fec_blocks 126955 fec_start 126955 restart_on_corruption ignore_zero_blocks";
     EXPECT_EQ(target.GetParameterString(), expected);
 }
+
+TEST(libdm, DmSnapshotArgs) {
+    DmTargetSnapshot target1(0, 512, "base", "cow", SnapshotStorageMode::Persistent, 8);
+    if (DmTargetSnapshot::ReportsOverflow("snapshot")) {
+        EXPECT_EQ(target1.GetParameterString(), "base cow PO 8");
+    } else {
+        EXPECT_EQ(target1.GetParameterString(), "base cow P 8");
+    }
+    EXPECT_EQ(target1.name(), "snapshot");
+
+    DmTargetSnapshot target2(0, 512, "base", "cow", SnapshotStorageMode::Transient, 8);
+    EXPECT_EQ(target2.GetParameterString(), "base cow N 8");
+    EXPECT_EQ(target2.name(), "snapshot");
+
+    DmTargetSnapshot target3(0, 512, "base", "cow", SnapshotStorageMode::Merge, 8);
+    if (DmTargetSnapshot::ReportsOverflow("snapshot-merge")) {
+        EXPECT_EQ(target3.GetParameterString(), "base cow PO 8");
+    } else {
+        EXPECT_EQ(target3.GetParameterString(), "base cow P 8");
+    }
+    EXPECT_EQ(target3.name(), "snapshot-merge");
+}
+
+TEST(libdm, DmSnapshotOriginArgs) {
+    DmTargetSnapshotOrigin target(0, 512, "base");
+    EXPECT_EQ(target.GetParameterString(), "base");
+    EXPECT_EQ(target.name(), "snapshot-origin");
+}
+
+class SnapshotTestHarness final {
+  public:
+    bool Setup();
+    bool Merge();
+
+    std::string origin_dev() const { return origin_dev_->path(); }
+    std::string snapshot_dev() const { return snapshot_dev_->path(); }
+
+    int base_fd() const { return base_fd_; }
+
+    static const uint64_t kBaseDeviceSize = 1024 * 1024;
+    static const uint64_t kCowDeviceSize = 1024 * 64;
+    static const uint64_t kSectorSize = 512;
+
+  private:
+    void SetupImpl();
+    void MergeImpl();
+
+    unique_fd base_fd_;
+    unique_fd cow_fd_;
+    unique_ptr<LoopDevice> base_loop_;
+    unique_ptr<LoopDevice> cow_loop_;
+    unique_ptr<TempDevice> origin_dev_;
+    unique_ptr<TempDevice> snapshot_dev_;
+    bool setup_ok_ = false;
+    bool merge_ok_ = false;
+};
+
+bool SnapshotTestHarness::Setup() {
+    SetupImpl();
+    return setup_ok_;
+}
+
+void SnapshotTestHarness::SetupImpl() {
+    base_fd_ = CreateTempFile("base_device", kBaseDeviceSize);
+    ASSERT_GE(base_fd_, 0);
+    cow_fd_ = CreateTempFile("cow_device", kCowDeviceSize);
+    ASSERT_GE(cow_fd_, 0);
+
+    base_loop_ = std::make_unique<LoopDevice>(base_fd_);
+    ASSERT_TRUE(base_loop_->valid());
+    cow_loop_ = std::make_unique<LoopDevice>(cow_fd_);
+    ASSERT_TRUE(cow_loop_->valid());
+
+    DmTable origin_table;
+    ASSERT_TRUE(origin_table.AddTarget(make_unique<DmTargetSnapshotOrigin>(
+            0, kBaseDeviceSize / kSectorSize, base_loop_->device())));
+    ASSERT_TRUE(origin_table.valid());
+
+    origin_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot-origin", origin_table);
+    ASSERT_TRUE(origin_dev_->valid());
+    ASSERT_FALSE(origin_dev_->path().empty());
+    ASSERT_TRUE(origin_dev_->WaitForUdev());
+
+    // chunk size = 4K blocks.
+    DmTable snap_table;
+    ASSERT_TRUE(snap_table.AddTarget(make_unique<DmTargetSnapshot>(
+            0, kBaseDeviceSize / kSectorSize, base_loop_->device(), cow_loop_->device(),
+            SnapshotStorageMode::Persistent, 8)));
+    ASSERT_TRUE(snap_table.valid());
+
+    snapshot_dev_ = std::make_unique<TempDevice>("libdm-test-dm-snapshot", snap_table);
+    ASSERT_TRUE(snapshot_dev_->valid());
+    ASSERT_FALSE(snapshot_dev_->path().empty());
+    ASSERT_TRUE(snapshot_dev_->WaitForUdev());
+
+    setup_ok_ = true;
+}
+
+bool SnapshotTestHarness::Merge() {
+    MergeImpl();
+    return merge_ok_;
+}
+
+void SnapshotTestHarness::MergeImpl() {
+    DmTable merge_table;
+    ASSERT_TRUE(merge_table.AddTarget(
+            make_unique<DmTargetSnapshot>(0, kBaseDeviceSize / kSectorSize, base_loop_->device(),
+                                          cow_loop_->device(), SnapshotStorageMode::Merge, 8)));
+    ASSERT_TRUE(merge_table.valid());
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    ASSERT_TRUE(dm.LoadTableAndActivate("libdm-test-dm-snapshot", merge_table));
+
+    while (true) {
+        vector<DeviceMapper::TargetInfo> status;
+        ASSERT_TRUE(dm.GetTableStatus("libdm-test-dm-snapshot", &status));
+        ASSERT_EQ(status.size(), 1);
+        ASSERT_EQ(strncmp(status[0].spec.target_type, "snapshot-merge", strlen("snapshot-merge")),
+                  0);
+
+        DmTargetSnapshot::Status merge_status;
+        ASSERT_TRUE(DmTargetSnapshot::ParseStatusText(status[0].data, &merge_status));
+        ASSERT_TRUE(merge_status.error.empty());
+        if (merge_status.sectors_allocated == merge_status.metadata_sectors) {
+            break;
+        }
+
+        std::this_thread::sleep_for(250ms);
+    }
+
+    merge_ok_ = true;
+}
+
+bool CheckSnapshotAvailability() {
+    DmTargetTypeInfo info;
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    if (!dm.GetTargetByName("snapshot", &info)) {
+        cout << "snapshot module not enabled; skipping test" << std::endl;
+        return false;
+    }
+    if (!dm.GetTargetByName("snapshot-merge", &info)) {
+        cout << "snapshot-merge module not enabled; skipping test" << std::endl;
+        return false;
+    }
+    if (!dm.GetTargetByName("snapshot-origin", &info)) {
+        cout << "snapshot-origin module not enabled; skipping test" << std::endl;
+        return false;
+    }
+    return true;
+}
+
+TEST(libdm, DmSnapshot) {
+    if (!CheckSnapshotAvailability()) {
+        return;
+    }
+
+    SnapshotTestHarness harness;
+    ASSERT_TRUE(harness.Setup());
+
+    // Open the dm devices.
+    unique_fd origin_fd(open(harness.origin_dev().c_str(), O_RDONLY | O_CLOEXEC));
+    ASSERT_GE(origin_fd, 0);
+    unique_fd snapshot_fd(open(harness.snapshot_dev().c_str(), O_RDWR | O_CLOEXEC | O_SYNC));
+    ASSERT_GE(snapshot_fd, 0);
+
+    // Write to the first block of the snapshot device.
+    std::string data("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
+    ASSERT_TRUE(android::base::WriteFully(snapshot_fd, data.data(), data.size()));
+    ASSERT_EQ(lseek(snapshot_fd, 0, SEEK_SET), 0);
+
+    // We should get the same data back from the snapshot device.
+    std::string read(data.size(), '\0');
+    ASSERT_TRUE(android::base::ReadFully(snapshot_fd, read.data(), read.size()));
+    ASSERT_EQ(read, data);
+
+    // We should see the original data from the origin device.
+    std::string zeroes(data.size(), '\0');
+    ASSERT_TRUE(android::base::ReadFully(origin_fd, read.data(), read.size()));
+    ASSERT_EQ(lseek(snapshot_fd, 0, SEEK_SET), 0);
+    ASSERT_EQ(read, zeroes);
+
+    // We should also see the original data from the base device.
+    ASSERT_TRUE(android::base::ReadFully(harness.base_fd(), read.data(), read.size()));
+    ASSERT_EQ(lseek(harness.base_fd(), 0, SEEK_SET), 0);
+    ASSERT_EQ(read, zeroes);
+
+    // Now, perform the merge and wait.
+    ASSERT_TRUE(harness.Merge());
+
+    // Reading from the base device should give us the modified data.
+    ASSERT_TRUE(android::base::ReadFully(harness.base_fd(), read.data(), read.size()));
+    ASSERT_EQ(lseek(harness.base_fd(), 0, SEEK_SET), 0);
+    ASSERT_EQ(read, data);
+}
+
+TEST(libdm, DmSnapshotOverflow) {
+    if (!CheckSnapshotAvailability()) {
+        return;
+    }
+
+    SnapshotTestHarness harness;
+    ASSERT_TRUE(harness.Setup());
+
+    // Open the dm devices.
+    unique_fd snapshot_fd(open(harness.snapshot_dev().c_str(), O_RDWR | O_CLOEXEC));
+    ASSERT_GE(snapshot_fd, 0);
+
+    // Fill the copy-on-write device until it overflows.
+    uint64_t bytes_remaining = SnapshotTestHarness::kCowDeviceSize;
+    uint8_t byte = 1;
+    while (bytes_remaining) {
+        std::string data(4096, char(byte));
+        if (!android::base::WriteFully(snapshot_fd, data.data(), data.size())) {
+            ASSERT_EQ(errno, EIO);
+            break;
+        }
+        bytes_remaining -= data.size();
+    }
+
+    // If writes succeed (because they are buffered), then we should expect an
+    // fsync to fail with EIO.
+    if (!bytes_remaining) {
+        ASSERT_EQ(fsync(snapshot_fd), -1);
+        ASSERT_EQ(errno, EIO);
+    }
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+
+    vector<DeviceMapper::TargetInfo> target_status;
+    ASSERT_TRUE(dm.GetTableStatus("libdm-test-dm-snapshot", &target_status));
+    ASSERT_EQ(target_status.size(), 1);
+    ASSERT_EQ(strncmp(target_status[0].spec.target_type, "snapshot", strlen("snapshot")), 0);
+
+    DmTargetSnapshot::Status status;
+    ASSERT_TRUE(DmTargetSnapshot::ParseStatusText(target_status[0].data, &status));
+    if (DmTargetSnapshot::ReportsOverflow("snapshot")) {
+        ASSERT_EQ(status.error, "Overflow");
+    } else {
+        ASSERT_EQ(status.error, "Invalid");
+    }
+}
+
+TEST(libdm, CryptArgs) {
+    DmTargetCrypt target1(0, 512, "sha1", "abcdefgh", 50, "/dev/loop0", 100);
+    ASSERT_EQ(target1.name(), "crypt");
+    ASSERT_TRUE(target1.Valid());
+    ASSERT_EQ(target1.GetParameterString(), "sha1 abcdefgh 50 /dev/loop0 100");
+
+    DmTargetCrypt target2(0, 512, "sha1", "abcdefgh", 50, "/dev/loop0", 100);
+    target2.SetSectorSize(64);
+    target2.AllowDiscards();
+    target2.SetIvLargeSectors();
+    target2.AllowEncryptOverride();
+    ASSERT_EQ(target2.GetParameterString(),
+              "sha1 abcdefgh 50 /dev/loop0 100 4 allow_discards allow_encrypt_override "
+              "iv_large_sectors sector_size:64");
+}
+
+TEST(libdm, DefaultKeyArgs) {
+    DmTargetDefaultKey target(0, 4096, "AES-256-XTS", "abcdef0123456789", "/dev/loop0", 0);
+    ASSERT_EQ(target.name(), "default-key");
+    ASSERT_TRUE(target.Valid());
+    ASSERT_EQ(target.GetParameterString(), "AES-256-XTS abcdef0123456789 /dev/loop0 0");
+}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index 28e6e01..d7e8aa9 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -96,6 +96,10 @@
     // successfully read and stored in 'targets'. Returns 'false' otherwise.
     bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets);
 
+    // Finds a target by name and returns its information if found. |info| may
+    // be null to check for the existence of a target.
+    bool GetTargetByName(const std::string& name, DmTargetTypeInfo* info);
+
     // Return 'true' if it can successfully read the list of device mapper block devices
     // currently created. 'devices' will be empty if the kernel interactions
     // were successful and there are no block devices at the moment. Returns
diff --git a/fs_mgr/libdm/include/libdm/dm_table.h b/fs_mgr/libdm/include/libdm/dm_table.h
index 5c639be..ee66653 100644
--- a/fs_mgr/libdm/include/libdm/dm_table.h
+++ b/fs_mgr/libdm/include/libdm/dm_table.h
@@ -43,12 +43,20 @@
     // successfully removed.
     bool RemoveTarget(std::unique_ptr<DmTarget>&& target);
 
+    // Adds a target, constructing it in-place for convenience. For example,
+    //
+    //   table.Emplace<DmTargetZero>(0, num_sectors);
+    template <typename T, typename... Args>
+    bool Emplace(Args&&... args) {
+        return AddTarget(std::make_unique<T>(std::forward<Args>(args)...));
+    }
+
     // Checks the table to make sure it is valid. i.e. Checks for range overlaps, range gaps
     // and returns 'true' if the table is ready to be loaded into kernel. Returns 'false' if the
     // table is malformed.
     bool valid() const;
 
-    // Returns the toatl number of targets.
+    // Returns the total number of targets.
     size_t num_targets() const { return targets_.size(); }
 
     // Returns the total size represented by the table in terms of number of 512-byte sectors.
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 175b0f0..722922d 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -40,6 +40,18 @@
         return std::to_string(major_) + "." + std::to_string(minor_) + "." + std::to_string(patch_);
     }
 
+    uint32_t major_version() const { return major_; }
+    uint32_t minor_version() const { return minor_; }
+    uint32_t patch_level() const { return patch_; }
+
+    bool IsAtLeast(uint32_t major, uint32_t minor, uint32_t patch) const {
+        if (major_ > major) return true;
+        if (major_ < major) return false;
+        if (minor_ > minor) return true;
+        if (minor_ < minor) return false;
+        return patch_ >= patch;
+    }
+
   private:
     std::string name_;
     uint32_t major_;
@@ -170,6 +182,119 @@
     std::string target_string_;
 };
 
+enum class SnapshotStorageMode {
+    // The snapshot will be persisted to the COW device.
+    Persistent,
+    // The snapshot will be lost on reboot.
+    Transient,
+    // The snapshot will be merged from the COW device into the base device,
+    // in the background.
+    Merge
+};
+
+// Writes to a snapshot device will be written to the given COW device. Reads
+// will read from the COW device or base device. The chunk size is specified
+// in sectors.
+class DmTargetSnapshot final : public DmTarget {
+  public:
+    DmTargetSnapshot(uint64_t start, uint64_t length, const std::string& base_device,
+                     const std::string& cow_device, SnapshotStorageMode mode, uint64_t chunk_size)
+        : DmTarget(start, length),
+          base_device_(base_device),
+          cow_device_(cow_device),
+          mode_(mode),
+          chunk_size_(chunk_size) {}
+
+    std::string name() const override;
+    std::string GetParameterString() const override;
+    bool Valid() const override { return true; }
+
+    struct Status {
+        uint64_t sectors_allocated;
+        uint64_t total_sectors;
+        uint64_t metadata_sectors;
+        std::string error;
+    };
+
+    static bool ParseStatusText(const std::string& text, Status* status);
+    static bool ReportsOverflow(const std::string& target_type);
+
+  private:
+    std::string base_device_;
+    std::string cow_device_;
+    SnapshotStorageMode mode_;
+    uint64_t chunk_size_;
+};
+
+// snapshot-origin will read/write directly to the backing device, updating any
+// snapshot devices with a matching origin.
+class DmTargetSnapshotOrigin final : public DmTarget {
+  public:
+    DmTargetSnapshotOrigin(uint64_t start, uint64_t length, const std::string& device)
+        : DmTarget(start, length), device_(device) {}
+
+    std::string name() const override { return "snapshot-origin"; }
+    std::string GetParameterString() const override { return device_; }
+    bool Valid() const override { return true; }
+
+  private:
+    std::string device_;
+};
+
+class DmTargetCrypt final : public DmTarget {
+  public:
+    DmTargetCrypt(uint64_t start, uint64_t length, const std::string& cipher,
+                  const std::string& key, uint64_t iv_sector_offset, const std::string& device,
+                  uint64_t device_sector)
+        : DmTarget(start, length),
+          cipher_(cipher),
+          key_(key),
+          iv_sector_offset_(iv_sector_offset),
+          device_(device),
+          device_sector_(device_sector) {}
+
+    void AllowDiscards() { allow_discards_ = true; }
+    void AllowEncryptOverride() { allow_encrypt_override_ = true; }
+    void SetIvLargeSectors() { iv_large_sectors_ = true; }
+    void SetSectorSize(uint32_t sector_size) { sector_size_ = sector_size; }
+
+    std::string name() const override { return "crypt"; }
+    bool Valid() const override { return true; }
+    std::string GetParameterString() const override;
+
+  private:
+    std::string cipher_;
+    std::string key_;
+    uint64_t iv_sector_offset_;
+    std::string device_;
+    uint64_t device_sector_;
+    bool allow_discards_ = false;
+    bool allow_encrypt_override_ = false;
+    bool iv_large_sectors_ = false;
+    uint32_t sector_size_ = 0;
+};
+
+class DmTargetDefaultKey final : public DmTarget {
+  public:
+    DmTargetDefaultKey(uint64_t start, uint64_t length, const std::string& cipher,
+                       const std::string& key, const std::string& blockdev, uint64_t start_sector)
+        : DmTarget(start, length),
+          cipher_(cipher),
+          key_(key),
+          blockdev_(blockdev),
+          start_sector_(start_sector) {}
+
+    std::string name() const override { return "default-key"; }
+    bool Valid() const override { return true; }
+    std::string GetParameterString() const override;
+
+  private:
+    std::string cipher_;
+    std::string key_;
+    std::string blockdev_;
+    uint64_t start_sector_;
+};
+
 }  // namespace dm
 }  // namespace android
 
diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
index 04776ed..c4d7511 100644
--- a/fs_mgr/libfs_avb/fs_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -338,6 +338,7 @@
                                nullptr /* custom_device_path */);
 }
 
+// TODO(b/128807537): removes this function.
 AvbUniquePtr AvbHandle::Open() {
     bool is_device_unlocked = IsDeviceUnlocked();
 
@@ -353,25 +354,28 @@
     AvbSlotVerifyResult verify_result =
             avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_);
 
-    // Only allow two verify results:
+    // Only allow the following verify results:
     //   - AVB_SLOT_VERIFY_RESULT_OK.
-    //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state).
-    //     If the device is UNLOCKED, i.e., |allow_verification_error| is true for
-    //     AvbSlotVerify(), then the following return values are all non-fatal:
-    //       * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION
-    //       * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED
-    //       * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
-    //     The latter two results were checked by bootloader prior to start fs_mgr so
-    //     we just need to handle the first result here. See *dummy* operations in
-    //     FsManagerAvbOps and the comments in external/avb/libavb/avb_slot_verify.h
-    //     for more details.
+    //   - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (UNLOCKED only).
+    //     Might occur in either the top-level vbmeta or a chained vbmeta.
+    //   - AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED (UNLOCKED only).
+    //     Could only occur in a chained vbmeta. Because we have *dummy* operations in
+    //     FsManagerAvbOps such that avb_ops->validate_vbmeta_public_key() used to validate
+    //     the public key of the top-level vbmeta always pass in userspace here.
+    //
+    // The following verify result won't happen, because the *dummy* operation
+    // avb_ops->read_rollback_index() always returns the minimum value zero. So rollbacked
+    // vbmeta images, which should be caught in the bootloader stage, won't be detected here.
+    //   - AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX
     switch (verify_result) {
         case AVB_SLOT_VERIFY_RESULT_OK:
             avb_handle->status_ = AvbHandleStatus::kSuccess;
             break;
         case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
+        case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
             if (!is_device_unlocked) {
-                LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED";
+                LERROR << "ERROR_VERIFICATION / PUBLIC_KEY_REJECTED isn't allowed "
+                       << "if the device is LOCKED";
                 return nullptr;
             }
             avb_handle->status_ = AvbHandleStatus::kVerificationError;
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 8fc02cb..fcef1f0 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -21,6 +21,8 @@
 
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
+#include <fs_mgr.h>
+#include <fstab/fstab.h>
 #include <gtest/gtest.h>
 #include <liblp/builder.h>
 
@@ -702,3 +704,19 @@
     ASSERT_EQ(updated->block_devices.size(), static_cast<size_t>(1));
     EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super");
 }
+
+TEST(liblp, ReadSuperPartition) {
+    auto slot_suffix = fs_mgr_get_slot_suffix();
+    auto slot_number = SlotNumberForSlotSuffix(slot_suffix);
+    auto super_name = fs_mgr_get_super_partition_name(slot_number);
+    auto metadata = ReadMetadata(super_name, slot_number);
+    ASSERT_NE(metadata, nullptr);
+
+    if (!slot_suffix.empty()) {
+        auto other_slot_suffix = fs_mgr_get_other_slot_suffix();
+        auto other_slot_number = SlotNumberForSlotSuffix(other_slot_suffix);
+        auto other_super_name = fs_mgr_get_super_partition_name(other_slot_number);
+        auto other_metadata = ReadMetadata(other_super_name, other_slot_number);
+        ASSERT_NE(other_metadata, nullptr);
+    }
+}
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 72afa69..6d87594 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -394,7 +394,7 @@
     std::string fstab_contents = R"fs(
 source none0       swap   defaults      encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_loopback_path,zram_loopback_size,zram_backing_dev_path
 
-source none1       swap   defaults      encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,verify=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_loopback_path=,zram_loopback_size=,zram_backing_dev_path=
+source none1       swap   defaults      encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_loopback_path=,zram_loopback_size=,zram_backing_dev_path=
 
 source none2       swap   defaults      forcefdeorfbe=
 
@@ -413,7 +413,6 @@
     }
     EXPECT_EQ("", entry->key_loc);
     EXPECT_EQ("", entry->key_dir);
-    EXPECT_EQ("", entry->verity_loc);
     EXPECT_EQ(0, entry->length);
     EXPECT_EQ("", entry->label);
     EXPECT_EQ(-1, entry->partnum);
@@ -437,13 +436,11 @@
         flags.crypt = true;
         flags.force_crypt = true;
         flags.file_encryption = true;
-        flags.verify = true;
         flags.avb = true;
         EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
     }
     EXPECT_EQ("", entry->key_loc);
     EXPECT_EQ("", entry->key_dir);
-    EXPECT_EQ("", entry->verity_loc);
     EXPECT_EQ(0, entry->length);
     EXPECT_EQ("", entry->label);
     EXPECT_EQ(-1, entry->partnum);
@@ -639,29 +636,6 @@
     EXPECT_EQ(0, entry->zram_size);
 }
 
-TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_Verify) {
-    TemporaryFile tf;
-    ASSERT_TRUE(tf.fd != -1);
-    std::string fstab_contents = R"fs(
-source none0       swap   defaults      verify=/dir/key
-)fs";
-
-    ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path));
-
-    Fstab fstab;
-    EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
-    ASSERT_EQ(1U, fstab.size());
-
-    auto entry = fstab.begin();
-    EXPECT_EQ("none0", entry->mount_point);
-
-    FstabEntry::FsMgrFlags flags = {};
-    flags.verify = true;
-    EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags));
-
-    EXPECT_EQ("/dir/key", entry->verity_loc);
-}
-
 TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_ForceEncrypt) {
     TemporaryFile tf;
     ASSERT_TRUE(tf.fd != -1);
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 9309aad..7e6ad5b 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -38,15 +38,7 @@
 #include <vector>
 
 using namespace std::literals::string_literals;
-
-using DeviceMapper = ::android::dm::DeviceMapper;
-using DmTable = ::android::dm::DmTable;
-using DmTarget = ::android::dm::DmTarget;
-using DmTargetLinear = ::android::dm::DmTargetLinear;
-using DmTargetZero = ::android::dm::DmTargetZero;
-using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
-using DmTargetBow = ::android::dm::DmTargetBow;
-using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
+using namespace android::dm;
 using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
 
 static int Usage(void) {
@@ -57,6 +49,7 @@
     std::cerr << "  delete <dm-name>" << std::endl;
     std::cerr << "  list <devices | targets> [-v]" << std::endl;
     std::cerr << "  getpath <dm-name>" << std::endl;
+    std::cerr << "  status <dm-name>" << std::endl;
     std::cerr << "  table <dm-name>" << std::endl;
     std::cerr << "  help" << std::endl;
     std::cerr << std::endl;
@@ -122,6 +115,62 @@
             }
             std::string block_device = NextArg();
             return std::make_unique<DmTargetBow>(start_sector, num_sectors, block_device);
+        } else if (target_type == "snapshot-origin") {
+            if (!HasArgs(1)) {
+                std::cerr << "Expected \"snapshot-origin\" <block_device>" << std::endl;
+                return nullptr;
+            }
+            std::string block_device = NextArg();
+            return std::make_unique<DmTargetSnapshotOrigin>(start_sector, num_sectors,
+                                                            block_device);
+        } else if (target_type == "snapshot") {
+            if (!HasArgs(4)) {
+                std::cerr
+                        << "Expected \"snapshot\" <block_device> <block_device> <mode> <chunk_size>"
+                        << std::endl;
+                return nullptr;
+            }
+            std::string base_device = NextArg();
+            std::string cow_device = NextArg();
+            std::string mode_str = NextArg();
+            std::string chunk_size_str = NextArg();
+
+            SnapshotStorageMode mode;
+            if (mode_str == "P") {
+                mode = SnapshotStorageMode::Persistent;
+            } else if (mode_str == "N") {
+                mode = SnapshotStorageMode::Transient;
+            } else {
+                std::cerr << "Unrecognized mode: " << mode_str << "\n";
+                return nullptr;
+            }
+
+            uint32_t chunk_size;
+            if (!android::base::ParseUint(chunk_size_str, &chunk_size)) {
+                std::cerr << "Chunk size must be an unsigned integer.\n";
+                return nullptr;
+            }
+            return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
+                                                      cow_device, mode, chunk_size);
+        } else if (target_type == "snapshot-merge") {
+            if (!HasArgs(3)) {
+                std::cerr
+                        << "Expected \"snapshot-merge\" <block_device> <block_device> <chunk_size>"
+                        << std::endl;
+                return nullptr;
+            }
+            std::string base_device = NextArg();
+            std::string cow_device = NextArg();
+            std::string chunk_size_str = NextArg();
+            SnapshotStorageMode mode = SnapshotStorageMode::Merge;
+
+            uint32_t chunk_size;
+            if (!android::base::ParseUint(chunk_size_str, &chunk_size)) {
+                std::cerr << "Chunk size must be an unsigned integer.\n";
+                return nullptr;
+            }
+            return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
+                                                      cow_device, mode, chunk_size);
         } else {
             std::cerr << "Unrecognized target type: " << target_type << std::endl;
             return nullptr;
@@ -308,7 +357,7 @@
     return 0;
 }
 
-static int TableCmdHandler(int argc, char** argv) {
+static int DumpTable(const std::string& mode, int argc, char** argv) {
     if (argc != 1) {
         std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
         return -EINVAL;
@@ -316,9 +365,18 @@
 
     DeviceMapper& dm = DeviceMapper::Instance();
     std::vector<DeviceMapper::TargetInfo> table;
-    if (!dm.GetTableInfo(argv[0], &table)) {
-        std::cerr << "Could not query table status of device \"" << argv[0] << "\"." << std::endl;
-        return -EINVAL;
+    if (mode == "status") {
+        if (!dm.GetTableStatus(argv[0], &table)) {
+            std::cerr << "Could not query table status of device \"" << argv[0] << "\"."
+                      << std::endl;
+            return -EINVAL;
+        }
+    } else if (mode == "table") {
+        if (!dm.GetTableInfo(argv[0], &table)) {
+            std::cerr << "Could not query table status of device \"" << argv[0] << "\"."
+                      << std::endl;
+            return -EINVAL;
+        }
     }
     std::cout << "Targets in the device-mapper table for " << argv[0] << ":" << std::endl;
     for (const auto& target : table) {
@@ -333,6 +391,14 @@
     return 0;
 }
 
+static int TableCmdHandler(int argc, char** argv) {
+    return DumpTable("table", argc, argv);
+}
+
+static int StatusCmdHandler(int argc, char** argv) {
+    return DumpTable("status", argc, argv);
+}
+
 static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
         // clang-format off
         {"create", DmCreateCmdHandler},
@@ -341,6 +407,7 @@
         {"help", HelpCmdHandler},
         {"getpath", GetPathCmdHandler},
         {"table", TableCmdHandler},
+        {"status", StatusCmdHandler},
         // clang-format on
 };
 
diff --git a/init/README.md b/init/README.md
index 28a106a..806bfa7 100644
--- a/init/README.md
+++ b/init/README.md
@@ -412,6 +412,11 @@
   not already running.  See the start entry for more information on
   starting services.
 
+`class_start_post_data <serviceclass>`
+> Like `class_start`, but only considers services that were started
+  after /data was mounted, and that were running at the time
+ `class_reset_post_data` was called. Only used for FDE devices.
+
 `class_stop <serviceclass>`
 > Stop and disable all services of the specified class if they are
   currently running.
@@ -421,6 +426,10 @@
   currently running, without disabling them. They can be restarted
   later using `class_start`.
 
+`class_reset_post_data <serviceclass>`
+> Like `class_reset`, but only considers services that were started
+  after /data was mounted. Only used for FDE devices.
+
 `class_restart <serviceclass>`
 > Restarts all services of the specified class.
 
@@ -494,6 +503,10 @@
   `write` command to write to `/proc/sys/kernel/printk` to change that.
   Properties are expanded within _level_.
 
+`mark_post_data`
+> Used to mark the point right after /data is mounted. Used to implement the
+  `class_reset_post_data` and `class_start_post_data` commands.
+
 `mkdir <path> [mode] [owner] [group]`
 > Create a directory at _path_, optionally with the given mode, owner, and
   group. If not provided, the directory is created with permissions 755 and
@@ -586,9 +599,6 @@
 `umount <path>`
 > Unmount the filesystem mounted at that path.
 
-`verity_load_state`
-> Internal implementation detail used to load dm-verity state.
-
 `verity_update_state <mount-point>`
 > Internal implementation detail used to update dm-verity state and
   set the partition._mount-point_.verified properties used by adb remount
@@ -686,8 +696,11 @@
 > Time after boot in ns (via the CLOCK\_BOOTTIME clock) at which the first
   stage of init started.
 
+`ro.boottime.init.first_stage`
+> How long in ns it took to run first stage.
+
 `ro.boottime.init.selinux`
-> How long it took the first stage to initialize SELinux.
+> How long in ns it took to run SELinux stage.
 
 `ro.boottime.init.cold_boot_wait`
 > How long init waited for ueventd's coldboot phase to end.
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 06da4be..6ce7736 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -121,6 +121,21 @@
     return Success();
 }
 
+static Result<Success> do_class_start_post_data(const BuiltinArguments& args) {
+    if (args.context != kInitContext) {
+        return Error() << "command 'class_start_post_data' only available in init context";
+    }
+    for (const auto& service : ServiceList::GetInstance()) {
+        if (service->classnames().count(args[1])) {
+            if (auto result = service->StartIfPostData(); !result) {
+                LOG(ERROR) << "Could not start service '" << service->name()
+                           << "' as part of class '" << args[1] << "': " << result.error();
+            }
+        }
+    }
+    return Success();
+}
+
 static Result<Success> do_class_stop(const BuiltinArguments& args) {
     ForEachServiceInClass(args[1], &Service::Stop);
     return Success();
@@ -131,6 +146,14 @@
     return Success();
 }
 
+static Result<Success> do_class_reset_post_data(const BuiltinArguments& args) {
+    if (args.context != kInitContext) {
+        return Error() << "command 'class_reset_post_data' only available in init context";
+    }
+    ForEachServiceInClass(args[1], &Service::ResetIfPostData);
+    return Success();
+}
+
 static Result<Success> do_class_restart(const BuiltinArguments& args) {
     // Do not restart a class if it has a property persist.dont_start_class.CLASS set to 1.
     if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
@@ -707,17 +730,6 @@
     return Success();
 }
 
-static Result<Success> do_verity_load_state(const BuiltinArguments& args) {
-    int mode = -1;
-    bool loaded = fs_mgr_load_verity_state(&mode);
-    if (loaded && mode != VERITY_MODE_DEFAULT) {
-        ActionManager::GetInstance().QueueEventTrigger("verity-logging");
-    }
-    if (!loaded) return Error() << "Could not load verity state";
-
-    return Success();
-}
-
 static Result<Success> do_verity_update_state(const BuiltinArguments& args) {
     int mode;
     if (!fs_mgr_load_verity_state(&mode)) {
@@ -1053,6 +1065,12 @@
         {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context});
 }
 
+static Result<Success> do_mark_post_data(const BuiltinArguments& args) {
+    ServiceList::GetInstance().MarkPostData();
+
+    return Success();
+}
+
 static Result<Success> do_parse_apex_configs(const BuiltinArguments& args) {
     glob_t glob_result;
     // @ is added to filter out the later paths, which are bind mounts of the places
@@ -1104,8 +1122,10 @@
         {"chmod",                   {2,     2,    {true,   do_chmod}}},
         {"chown",                   {2,     3,    {true,   do_chown}}},
         {"class_reset",             {1,     1,    {false,  do_class_reset}}},
+        {"class_reset_post_data",   {1,     1,    {false,  do_class_reset_post_data}}},
         {"class_restart",           {1,     1,    {false,  do_class_restart}}},
         {"class_start",             {1,     1,    {false,  do_class_start}}},
+        {"class_start_post_data",   {1,     1,    {false,  do_class_start_post_data}}},
         {"class_stop",              {1,     1,    {false,  do_class_stop}}},
         {"copy",                    {2,     2,    {true,   do_copy}}},
         {"domainname",              {1,     1,    {true,   do_domainname}}},
@@ -1125,6 +1145,7 @@
         {"load_persist_props",      {0,     0,    {false,  do_load_persist_props}}},
         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
+        {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
         {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
         // TODO: Do mount operations in vendor_init.
         // mount_all is currently too complex to run in vendor_init as it queues action triggers,
@@ -1150,7 +1171,6 @@
         {"symlink",                 {2,     2,    {true,   do_symlink}}},
         {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
         {"trigger",                 {1,     1,    {false,  do_trigger}}},
-        {"verity_load_state",       {0,     0,    {false,  do_verity_load_state}}},
         {"verity_update_state",     {0,     0,    {false,  do_verity_update_state}}},
         {"wait",                    {1,     2,    {true,   do_wait}}},
         {"wait_for_prop",           {2,     2,    {false,  do_wait_for_prop}}},
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 8b95e38..7dd3ad4 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -235,9 +235,8 @@
 
     SetInitAvbVersionInRecovery();
 
-    static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
-    uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
-    setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
+    setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(),
+           1);
 
     const char* path = "/system/bin/init";
     const char* args[] = {path, "selinux_setup", nullptr};
diff --git a/init/first_stage_init.h b/init/first_stage_init.h
index 0476e44..7de816f 100644
--- a/init/first_stage_init.h
+++ b/init/first_stage_init.h
@@ -21,5 +21,7 @@
 
 int FirstStageMain(int argc, char** argv);
 
+static constexpr char kEnvFirstStageStartedAt[] = "FIRST_STAGE_STARTED_AT";
+
 }  // namespace init
 }  // namespace android
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 3e76556..1a5ed28 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -276,14 +276,12 @@
 // required_devices_partition_names_. Found partitions will then be removed from it
 // for the subsequent member function to check which devices are NOT created.
 bool FirstStageMount::InitRequiredDevices() {
-    if (required_devices_partition_names_.empty()) {
-        return true;
+    if (!InitDeviceMapper()) {
+        return false;
     }
 
-    if (IsDmLinearEnabled() || need_dm_verity_) {
-        if (!InitDeviceMapper()) {
-            return false;
-        }
+    if (required_devices_partition_names_.empty()) {
+        return true;
     }
 
     auto uevent_callback = [this](const Uevent& uevent) { return UeventCallback(uevent); };
@@ -604,12 +602,6 @@
         return;
     }
 
-    // Device-mapper might not be ready if the device doesn't use DAP or verity
-    // (for example, hikey).
-    if (access("/dev/device-mapper", F_OK) && !InitDeviceMapper()) {
-        return;
-    }
-
     // Find the name of the super partition for the GSI. It will either be
     // "userdata", or a block device such as an sdcard. There are no by-name
     // partitions other than userdata that we support installing GSIs to.
@@ -644,7 +636,6 @@
 }
 
 bool FirstStageMountVBootV1::GetDmVerityDevices() {
-    std::string verity_loc_device;
     need_dm_verity_ = false;
 
     for (const auto& fstab_entry : fstab_) {
@@ -657,21 +648,9 @@
         if (fstab_entry.fs_mgr_flags.verify) {
             need_dm_verity_ = true;
         }
-        // Checks if verity metadata is on a separate partition. Note that it is
-        // not partition specific, so there must be only one additional partition
-        // that carries verity state.
-        if (!fstab_entry.verity_loc.empty()) {
-            if (verity_loc_device.empty()) {
-                verity_loc_device = fstab_entry.verity_loc;
-            } else if (verity_loc_device != fstab_entry.verity_loc) {
-                LOG(ERROR) << "More than one verity_loc found: " << verity_loc_device << ", "
-                           << fstab_entry.verity_loc;
-                return false;
-            }
-        }
     }
 
-    // Includes the partition names of fstab records and verity_loc_device (if any).
+    // Includes the partition names of fstab records.
     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
     for (const auto& fstab_entry : fstab_) {
         if (!fstab_entry.fs_mgr_flags.logical) {
@@ -679,10 +658,6 @@
         }
     }
 
-    if (!verity_loc_device.empty()) {
-        required_devices_partition_names_.emplace(basename(verity_loc_device.c_str()));
-    }
-
     return true;
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index c79e459..1f3c2fc 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -35,6 +35,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -55,6 +56,7 @@
 #include "action_parser.h"
 #include "boringssl_self_test.h"
 #include "epoll.h"
+#include "first_stage_init.h"
 #include "first_stage_mount.h"
 #include "import_parser.h"
 #include "keychords.h"
@@ -627,11 +629,38 @@
     }
 }
 
+static void RecordStageBoottimes(const boot_clock::time_point& second_stage_start_time) {
+    int64_t first_stage_start_time_ns = -1;
+    if (auto first_stage_start_time_str = getenv(kEnvFirstStageStartedAt);
+        first_stage_start_time_str) {
+        property_set("ro.boottime.init", first_stage_start_time_str);
+        android::base::ParseInt(first_stage_start_time_str, &first_stage_start_time_ns);
+    }
+    unsetenv(kEnvFirstStageStartedAt);
+
+    int64_t selinux_start_time_ns = -1;
+    if (auto selinux_start_time_str = getenv(kEnvSelinuxStartedAt); selinux_start_time_str) {
+        android::base::ParseInt(selinux_start_time_str, &selinux_start_time_ns);
+    }
+    unsetenv(kEnvSelinuxStartedAt);
+
+    if (selinux_start_time_ns == -1) return;
+    if (first_stage_start_time_ns == -1) return;
+
+    property_set("ro.boottime.init.first_stage",
+                 std::to_string(selinux_start_time_ns - first_stage_start_time_ns));
+    property_set("ro.boottime.init.selinux",
+                 std::to_string(second_stage_start_time.time_since_epoch().count() -
+                                selinux_start_time_ns));
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
     }
 
+    boot_clock::time_point start_time = boot_clock::now();
+
     // We need to set up stdin/stdout/stderr again now that we're running in init's context.
     InitKernelLogging(argv, InitAborter);
     LOG(INFO) << "init second stage started!";
@@ -663,9 +692,8 @@
     // used by init as well as the current required properties.
     export_kernel_boot_props();
 
-    // Make the time that init started available for bootstat to log.
-    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
-    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
+    // Make the time that init stages started available for bootstat to log.
+    RecordStageBoottimes(start_time);
 
     // Set libavb version for Framework-only OTA match in Treble build.
     const char* avb_version = getenv("INIT_AVB_VERSION");
@@ -678,8 +706,6 @@
     }
 
     // Clean up our environment.
-    unsetenv("INIT_STARTED_AT");
-    unsetenv("INIT_SELINUX_TOOK");
     unsetenv("INIT_AVB_VERSION");
     unsetenv("INIT_FORCE_DEBUGGABLE");
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 132fc13..8a63363 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -331,6 +331,12 @@
     }
     std::string plat_mapping_file("/system/etc/selinux/mapping/" + vend_plat_vers + ".cil");
 
+    std::string plat_compat_cil_file("/system/etc/selinux/mapping/" + vend_plat_vers +
+                                     ".compat.cil");
+    if (access(plat_compat_cil_file.c_str(), F_OK) == -1) {
+        plat_compat_cil_file.clear();
+    }
+
     std::string product_policy_cil_file("/product/etc/selinux/product_sepolicy.cil");
     if (access(product_policy_cil_file.c_str(), F_OK) == -1) {
         product_policy_cil_file.clear();
@@ -376,6 +382,9 @@
     };
     // clang-format on
 
+    if (!plat_compat_cil_file.empty()) {
+        compile_args.push_back(plat_compat_cil_file.c_str());
+    }
     if (!product_policy_cil_file.empty()) {
         compile_args.push_back(product_policy_cil_file.c_str());
     }
@@ -422,8 +431,6 @@
 }
 
 void SelinuxInitialize() {
-    Timer t;
-
     LOG(INFO) << "Loading SELinux policy";
     if (!LoadPolicy()) {
         LOG(FATAL) << "Unable to load SELinux policy";
@@ -440,9 +447,6 @@
     if (auto result = WriteFile("/sys/fs/selinux/checkreqprot", "0"); !result) {
         LOG(FATAL) << "Unable to write to /sys/fs/selinux/checkreqprot: " << result.error();
     }
-
-    // init's first stage can't set properties, so pass the time to the second stage.
-    setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
 }
 
 }  // namespace
@@ -526,6 +530,8 @@
         InstallRebootSignalHandlers();
     }
 
+    boot_clock::time_point start_time = boot_clock::now();
+
     // Set up SELinux, loading the SELinux policy.
     SelinuxSetupKernelLogging();
     SelinuxInitialize();
@@ -538,6 +544,8 @@
         PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
     }
 
+    setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1);
+
     const char* path = "/system/bin/init";
     const char* args[] = {path, "second_stage", nullptr};
     execv(path, const_cast<char**>(args));
diff --git a/init/selinux.h b/init/selinux.h
index 3aa9406..c7d6647 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -35,6 +35,8 @@
                                        const std::vector<std::string>& aliases, int type,
                                        std::string* result);
 
+static constexpr char kEnvSelinuxStartedAt[] = "SELINUX_STARTED_AT";
+
 }  // namespace init
 }  // namespace android
 
diff --git a/init/service.cpp b/init/service.cpp
index 276c2aa..ccc37b7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -362,7 +362,7 @@
 
     // Oneshot processes go into the disabled state on exit,
     // except when manually restarted.
-    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) {
+    if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART) && !(flags_ & SVC_RESET)) {
         flags_ |= SVC_DISABLED;
     }
 
@@ -951,6 +951,8 @@
         pre_apexd_ = true;
     }
 
+    post_data_ = ServiceList::GetInstance().IsPostData();
+
     LOG(INFO) << "starting service '" << name_ << "'...";
 
     pid_t pid = -1;
@@ -1150,6 +1152,25 @@
     StopOrReset(SVC_RESET);
 }
 
+void Service::ResetIfPostData() {
+    if (post_data_) {
+        if (flags_ & SVC_RUNNING) {
+            running_at_post_data_reset_ = true;
+        }
+        StopOrReset(SVC_RESET);
+    }
+}
+
+Result<Success> Service::StartIfPostData() {
+    // Start the service, but only if it was started after /data was mounted,
+    // and it was still running when we reset the post-data services.
+    if (running_at_post_data_reset_) {
+        return Start();
+    }
+
+    return Success();
+}
+
 void Service::Stop() {
     StopOrReset(SVC_DISABLED);
 }
@@ -1343,6 +1364,14 @@
     }
 }
 
+void ServiceList::MarkPostData() {
+    post_data_ = true;
+}
+
+bool ServiceList::IsPostData() {
+    return post_data_;
+}
+
 void ServiceList::MarkServicesUpdate() {
     services_update_finished_ = true;
 
diff --git a/init/service.h b/init/service.h
index c42a5a3..ae29f28 100644
--- a/init/service.h
+++ b/init/service.h
@@ -79,8 +79,10 @@
     Result<Success> ExecStart();
     Result<Success> Start();
     Result<Success> StartIfNotDisabled();
+    Result<Success> StartIfPostData();
     Result<Success> Enable();
     void Reset();
+    void ResetIfPostData();
     void Stop();
     void Terminate();
     void Timeout();
@@ -124,6 +126,7 @@
     std::optional<std::chrono::seconds> timeout_period() const { return timeout_period_; }
     const std::vector<std::string>& args() const { return args_; }
     bool is_updatable() const { return updatable_; }
+    bool is_post_data() const { return post_data_; }
 
   private:
     using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
@@ -244,6 +247,10 @@
     std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_;
 
     bool pre_apexd_ = false;
+
+    bool post_data_ = false;
+
+    bool running_at_post_data_reset_ = false;
 };
 
 class ServiceList {
@@ -285,6 +292,8 @@
     const std::vector<std::unique_ptr<Service>>& services() const { return services_; }
     const std::vector<Service*> services_in_shutdown_order() const;
 
+    void MarkPostData();
+    bool IsPostData();
     void MarkServicesUpdate();
     bool IsServicesUpdated() const { return services_update_finished_; }
     void DelayService(const Service& service);
@@ -292,6 +301,7 @@
   private:
     std::vector<std::unique_ptr<Service>> services_;
 
+    bool post_data_ = false;
     bool services_update_finished_ = false;
     std::vector<std::string> delayed_service_names_;
 };
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 6217bc8..494a06f 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -88,7 +88,6 @@
     { 00771, AID_SYSTEM,       AID_SYSTEM,       0, "data" },
     { 00755, AID_ROOT,         AID_SYSTEM,       0, "mnt" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "product/bin" },
-    { 00750, AID_ROOT,         AID_SHELL,        0, "sbin" },
     { 00777, AID_ROOT,         AID_ROOT,         0, "sdcard" },
     { 00751, AID_ROOT,         AID_SDCARD_R,     0, "storage" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/bin" },
@@ -171,7 +170,6 @@
     { 00600, AID_ROOT,      AID_ROOT,      0, "product_services/build.prop" },
     { 00444, AID_ROOT,      AID_ROOT,      0, product_services_conf_dir + 1 },
     { 00444, AID_ROOT,      AID_ROOT,      0, product_services_conf_file + 1 },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/fs_mgr" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump32" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/crash_dump64" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/debuggerd" },
@@ -216,8 +214,8 @@
     { 00755, AID_ROOT,      AID_ROOT,      0, "bin/*" },
     { 00640, AID_ROOT,      AID_SHELL,     0, "fstab.*" },
     { 00750, AID_ROOT,      AID_SHELL,     0, "init*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "odm/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "product/bin/*" },
-    { 00750, AID_ROOT,      AID_SHELL,     0, "sbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/*/bin/*" },
@@ -295,20 +293,21 @@
     const int fnm_flags = FNM_NOESCAPE;
     if (fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0) return true;
 
-    static constexpr const char* kSystem = "system/";
-    if (StartsWith(input, kSystem)) {
-        input.erase(0, strlen(kSystem));
-    } else if (input.size() <= strlen(kSystem)) {
-        return false;
-    } else if (StartsWith(pattern, kSystem)) {
-        pattern.erase(0, strlen(kSystem));
-    } else {
-        return false;
+    // Check match between logical partition's files and patterns.
+    static constexpr const char* kLogicalPartitions[] = {"system/product/",
+                                                         "system/product_services/",
+                                                         "system/vendor/",
+                                                         "vendor/odm/"};
+    for (auto& logical_partition : kLogicalPartitions) {
+        if (StartsWith(input, logical_partition)) {
+            std::string input_in_partition = input.substr(input.find('/') + 1);
+            if (!is_partition(input_in_partition)) continue;
+            if (fnmatch(pattern.c_str(), input_in_partition.c_str(), fnm_flags) == 0) {
+                return true;
+            }
+        }
     }
-
-    if (!is_partition(pattern)) return false;
-    if (!is_partition(input)) return false;
-    return fnmatch(pattern.c_str(), input.c_str(), fnm_flags) == 0;
+    return false;
 }
 #ifndef __ANDROID_VNDK__
 auto __for_testing_only__fs_config_cmp = fs_config_cmp;
diff --git a/liblog/Android.bp b/liblog/Android.bp
index da475cb..53d3ab3 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -45,6 +45,7 @@
     host_supported: true,
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
     export_include_dirs: ["include"],
     system_shared_libs: [],
     stl: "none",
@@ -67,6 +68,7 @@
     name: "liblog",
     host_supported: true,
     recovery_available: true,
+    native_bridge_supported: true,
     srcs: liblog_sources,
 
     target: {
@@ -138,6 +140,7 @@
 
 llndk_library {
     name: "liblog",
+    native_bridge_supported: true,
     symbol_file: "liblog.map.txt",
     export_include_dirs: ["include_vndk"],
 }
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index b2f0ed9..935590d 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -122,9 +122,10 @@
  *
  * Most callers should use
  * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
- * `<assert.h>` instead, or the `__assert` and `__assert2` functions provided by
- * bionic if more control is needed. They support automatically including the
- * source filename and line number more conveniently than this function.
+ * `&lt;assert.h&gt;` instead, or the `__assert` and `__assert2` functions
+ * provided by bionic if more control is needed. They support automatically
+ * including the source filename and line number more conveniently than this
+ * function.
  */
 void __android_log_assert(const char* cond, const char* tag, const char* fmt,
                           ...)
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index 66cb49f..debc43f 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -17,7 +17,9 @@
     name: "libnativeloader",
     defaults: ["libnativeloader-defaults"],
     host_supported: true,
-    srcs: ["native_loader.cpp"],
+    srcs: [
+        "native_loader.cpp",
+    ],
     shared_libs: [
         "libnativehelper",
         "liblog",
@@ -26,6 +28,11 @@
     ],
     target: {
         android: {
+            srcs: [
+                "library_namespaces.cpp",
+                "native_loader_namespace.cpp",
+                "public_libraries.cpp",
+            ],
             shared_libs: [
                 "libdl_android",
             ],
diff --git a/libnativeloader/README.md b/libnativeloader/README.md
new file mode 100644
index 0000000..46f6fdd
--- /dev/null
+++ b/libnativeloader/README.md
@@ -0,0 +1,84 @@
+libnativeloader
+===============================================================================
+
+Overview
+-------------------------------------------------------------------------------
+libnativeloader is responsible for loading native shared libraries (`*.so`
+files) inside the Android Runtime (ART). The native shared libraries could be
+app-provided JNI libraries or public native libraries like `libc.so` provided
+by the platform.
+
+The most typical use case of this library is calling `System.loadLibrary(name)`.
+When the method is called, the ART runtime delegates the call to this library
+along with the reference to the classloader where the call was made.  Then this
+library finds the linker namespace (named `classloader-namespace`) that is
+associated with the given classloader, and tries to load the requested library
+from the namespace. The actual searching, loading, and linking of the library
+is performed by the dynamic linker.
+
+The linker namespace is created when an APK is loaded into the process, and is
+associated with the classloader that loaded the APK. The linker namespace is
+configured so that only the JNI libraries embedded in the APK is accessible
+from the namespace, thus preventing an APK from loading JNI libraries of other
+APKs.
+
+The linker namespace is also configured differently depending on other
+characteristics of the APK such as whether or not the APK is bundled with the
+platform. In case of the unbundled, i.e., downloaded or updated APK, only the
+public native libraries that is listed in `/system/etc/public.libraries.txt`
+are available from the platform, whereas in case of the bundled, all libraries
+under `/system/lib` are available (i.e. shared). In case when the unbundled
+app is from `/vendor` or `/product` partition, the app is additionally provided
+with the [VNDK-SP](https://source.android.com/devices/architecture/vndk#sp-hal)
+libraries. As the platform is getting modularized with
+[APEX](https://android.googlesource.com/platform/system/apex/+/refs/heads/master/docs/README.md),
+some libraries are no longer provided from platform, but from the APEXes which
+have their own linker namespaces. For example, ICU libraries `libicuuc.so` and
+`libicui18n.so` are from the runtime APEX.
+
+The list of public native libraries is not static. The default set of libraries
+are defined in AOSP, but partners can extend it to include their own libraries.
+Currently, following extensions are available:
+
+- `/vendor/etc/public.libraries.txt`: libraries in `/vendor/lib` that are
+specific to the underlying SoC, e.g. GPU, DSP, etc.
+- `/{system|product}/etc/public.libraries-<companyname>.txt`: libraries in
+`/{system|system}/lib` that a device manufacturer has newly added. The
+libraries should be named as `lib<name>.<companyname>.so` as in
+`libFoo.acme.so`.
+
+Note that, due to the naming constraint requiring `.<companyname>.so` suffix, it
+is prohibited for a device manufacturer to expose an AOSP-defined private
+library, e.g. libgui.so, libart.so, etc., to APKs.
+
+Lastly, libnativeloader is responsible for abstracting the two types of the
+dynamic linker interface: `libdl.so` and `libnativebridge.so`. The former is
+for non-translated, e.g. ARM-on-ARM, libraries, while the latter is for
+loading libraries in a translated environment such as ARM-on-x86.
+
+Implementation
+-------------------------------------------------------------------------------
+Implementation wise, libnativeloader consists of four parts:
+
+- `native_loader.cpp`
+- `library_namespaces.cpp`
+- `native_loader_namespace.cpp`
+- `public_libraries.cpp`
+
+`native_loader.cpp` implements the public interface of this library. It is just
+a thin wrapper around `library_namespaces.cpp` and `native_loader_namespace.cpp`.
+
+`library_namespaces.cpp` implements the singleton class `LibraryNamespaces` which
+is a manager-like entity that is responsible for creating and configuring
+linker namespaces and finding an already created linker namespace for a given
+classloader.
+
+`native_loader_namesapces.cpp` implements the class `NativeLoaderNamespace` that
+models a linker namespace. It's main job is to abstract the two types of the
+dynamic linker interface so that other parts of this library do not have to know
+the differences of the interfaces.
+
+`public_libraries.cpp` is responsible for reading `*.txt` files for the public
+native libraries from the various partitions. It can be considered as a part of
+`LibraryNamespaces` but is separated from it to hide the details of the parsing
+routines.
diff --git a/libnativeloader/library_namespaces.cpp b/libnativeloader/library_namespaces.cpp
new file mode 100644
index 0000000..f7f972f
--- /dev/null
+++ b/libnativeloader/library_namespaces.cpp
@@ -0,0 +1,322 @@
+/*
+ * 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 "library_namespaces.h"
+
+#include <dirent.h>
+#include <dlfcn.h>
+
+#include <regex>
+#include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <nativehelper/ScopedUtfChars.h>
+
+#include "nativeloader/dlext_namespaces.h"
+#include "public_libraries.h"
+#include "utils.h"
+
+namespace android::nativeloader {
+
+namespace {
+// The device may be configured to have the vendor libraries loaded to a separate namespace.
+// For historical reasons this namespace was named sphal but effectively it is intended
+// to use to load vendor libraries to separate namespace with controlled interface between
+// vendor and system namespaces.
+constexpr const char* kVendorNamespaceName = "sphal";
+constexpr const char* kVndkNamespaceName = "vndk";
+constexpr const char* kRuntimeNamespaceName = "runtime";
+
+// classloader-namespace is a linker namespace that is created for the loaded
+// app. To be specific, it is created for the app classloader. When
+// System.load() is called from a Java class that is loaded from the
+// classloader, the classloader-namespace namespace associated with that
+// classloader is selected for dlopen. The namespace is configured so that its
+// search path is set to the app-local JNI directory and it is linked to the
+// platform namespace with the names of libs listed in the public.libraries.txt.
+// This way an app can only load its own JNI libraries along with the public libs.
+constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
+// Same thing for vendor APKs.
+constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
+
+// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
+// System.load() with an absolute path which is outside of the classloader library search path.
+// This list includes all directories app is allowed to access this way.
+constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
+
+constexpr const char* kVendorLibPath = "/vendor/" LIB;
+constexpr const char* kProductLibPath = "/product/" LIB ":/system/product/" LIB;
+
+const std::regex kVendorDexPathRegex("(^|:)/vendor/");
+const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
+
+// Define origin of APK if it is from vendor partition or product partition
+typedef enum {
+  APK_ORIGIN_DEFAULT = 0,
+  APK_ORIGIN_VENDOR = 1,
+  APK_ORIGIN_PRODUCT = 2,
+} ApkOrigin;
+
+jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
+  jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
+  jmethodID get_parent =
+      env->GetMethodID(class_loader_class, "getParent", "()Ljava/lang/ClassLoader;");
+
+  return env->CallObjectMethod(class_loader, get_parent);
+}
+
+ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
+  ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
+
+  if (dex_path != nullptr) {
+    ScopedUtfChars dex_path_utf_chars(env, dex_path);
+
+    if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
+      apk_origin = APK_ORIGIN_VENDOR;
+    }
+
+    if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
+      LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
+                          "Dex path contains both vendor and product partition : %s",
+                          dex_path_utf_chars.c_str());
+
+      apk_origin = APK_ORIGIN_PRODUCT;
+    }
+  }
+  return apk_origin;
+}
+
+}  // namespace
+
+void LibraryNamespaces::Initialize() {
+  // Once public namespace is initialized there is no
+  // point in running this code - it will have no effect
+  // on the current list of public libraries.
+  if (initialized_) {
+    return;
+  }
+
+  // android_init_namespaces() expects all the public libraries
+  // to be loaded so that they can be found by soname alone.
+  //
+  // TODO(dimitry): this is a bit misleading since we do not know
+  // if the vendor public library is going to be opened from /vendor/lib
+  // we might as well end up loading them from /system/lib or /product/lib
+  // For now we rely on CTS test to catch things like this but
+  // it should probably be addressed in the future.
+  for (const auto& soname : android::base::Split(default_public_libraries(), ":")) {
+    LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
+                        "Error preloading public library %s: %s", soname.c_str(), dlerror());
+  }
+}
+
+NativeLoaderNamespace* LibraryNamespaces::Create(JNIEnv* env, uint32_t target_sdk_version,
+                                                 jobject class_loader, bool is_shared,
+                                                 jstring dex_path, jstring java_library_path,
+                                                 jstring java_permitted_path,
+                                                 std::string* error_msg) {
+  std::string library_path;  // empty string by default.
+
+  if (java_library_path != nullptr) {
+    ScopedUtfChars library_path_utf_chars(env, java_library_path);
+    library_path = library_path_utf_chars.c_str();
+  }
+
+  ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
+
+  // (http://b/27588281) This is a workaround for apps using custom
+  // classloaders and calling System.load() with an absolute path which
+  // is outside of the classloader library search path.
+  //
+  // This part effectively allows such a classloader to access anything
+  // under /data and /mnt/expand
+  std::string permitted_path = kWhitelistedDirectories;
+
+  if (java_permitted_path != nullptr) {
+    ScopedUtfChars path(env, java_permitted_path);
+    if (path.c_str() != nullptr && path.size() > 0) {
+      permitted_path = permitted_path + ":" + path.c_str();
+    }
+  }
+
+  // Initialize the anonymous namespace with the first non-empty library path.
+  if (!library_path.empty() && !initialized_ &&
+      !InitPublicNamespace(library_path.c_str(), error_msg)) {
+    return nullptr;
+  }
+
+  bool found = FindNamespaceByClassLoader(env, class_loader);
+
+  LOG_ALWAYS_FATAL_IF(found, "There is already a namespace associated with this classloader");
+
+  std::string system_exposed_libraries = default_public_libraries();
+  const char* namespace_name = kClassloaderNamespaceName;
+  bool unbundled_vendor_or_product_app = false;
+  if ((apk_origin == APK_ORIGIN_VENDOR ||
+       (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
+      !is_shared) {
+    unbundled_vendor_or_product_app = true;
+    // For vendor / product apks, give access to the vendor / product lib even though
+    // they are treated as unbundled; the libs and apks are still bundled
+    // together in the vendor / product partition.
+    const char* origin_partition;
+    const char* origin_lib_path;
+
+    switch (apk_origin) {
+      case APK_ORIGIN_VENDOR:
+        origin_partition = "vendor";
+        origin_lib_path = kVendorLibPath;
+        break;
+      case APK_ORIGIN_PRODUCT:
+        origin_partition = "product";
+        origin_lib_path = kProductLibPath;
+        break;
+      default:
+        origin_partition = "unknown";
+        origin_lib_path = "";
+    }
+    library_path = library_path + ":" + origin_lib_path;
+    permitted_path = permitted_path + ":" + origin_lib_path;
+
+    // Also give access to LLNDK libraries since they are available to vendors
+    system_exposed_libraries = system_exposed_libraries + ":" + llndk_libraries().c_str();
+
+    // Different name is useful for debugging
+    namespace_name = kVendorClassloaderNamespaceName;
+    ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
+          origin_partition, library_path.c_str());
+  } else {
+    // extended public libraries are NOT available to vendor apks, otherwise it
+    // would be system->vendor violation.
+    if (!extended_public_libraries().empty()) {
+      system_exposed_libraries = system_exposed_libraries + ':' + extended_public_libraries();
+    }
+  }
+
+  // Create the app namespace
+  NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
+  auto app_ns =
+      NativeLoaderNamespace::Create(namespace_name, library_path, permitted_path, parent_ns,
+                                    is_shared, target_sdk_version < 24 /* is_greylist_enabled */);
+  if (app_ns.IsNil()) {
+    *error_msg = app_ns.GetError();
+    return nullptr;
+  }
+
+  // ... and link to other namespaces to allow access to some public libraries
+  bool is_bridged = app_ns.IsBridged();
+
+  auto platform_ns = NativeLoaderNamespace::GetPlatformNamespace(is_bridged);
+  if (!app_ns.Link(platform_ns, system_exposed_libraries)) {
+    *error_msg = app_ns.GetError();
+    return nullptr;
+  }
+
+  auto runtime_ns = NativeLoaderNamespace::GetExportedNamespace(kRuntimeNamespaceName, is_bridged);
+  // Runtime apex does not exist in host, and under certain build conditions.
+  if (!runtime_ns.IsNil()) {
+    if (!app_ns.Link(runtime_ns, runtime_public_libraries())) {
+      *error_msg = app_ns.GetError();
+      return nullptr;
+    }
+  }
+
+  // Give access to VNDK-SP libraries from the 'vndk' namespace.
+  if (unbundled_vendor_or_product_app && !vndksp_libraries().empty()) {
+    auto vndk_ns = NativeLoaderNamespace::GetExportedNamespace(kVndkNamespaceName, is_bridged);
+    if (!vndk_ns.IsNil() && !app_ns.Link(vndk_ns, vndksp_libraries())) {
+      *error_msg = app_ns.GetError();
+      return nullptr;
+    }
+  }
+
+  // Note that when vendor_ns is not configured, vendor_ns.IsNil() will be true
+  // and it will result in linking to the default namespace which is expected
+  // behavior in this case.
+  if (!vendor_public_libraries().empty()) {
+    auto vendor_ns = NativeLoaderNamespace::GetExportedNamespace(kVendorNamespaceName, is_bridged);
+    if (!app_ns.Link(vendor_ns, vendor_public_libraries())) {
+      *error_msg = dlerror();
+      return nullptr;
+    }
+  }
+
+  namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), app_ns));
+
+  return &(namespaces_.back().second);
+}
+
+NativeLoaderNamespace* LibraryNamespaces::FindNamespaceByClassLoader(JNIEnv* env,
+                                                                     jobject class_loader) {
+  auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
+                         [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
+                           return env->IsSameObject(value.first, class_loader);
+                         });
+  if (it != namespaces_.end()) {
+    return &it->second;
+  }
+
+  return nullptr;
+}
+
+bool LibraryNamespaces::InitPublicNamespace(const char* library_path, std::string* error_msg) {
+  // Ask native bride if this apps library path should be handled by it
+  bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
+
+  // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
+  // code is one example) unknown to linker in which  case linker uses anonymous
+  // namespace. The second argument specifies the search path for the anonymous
+  // namespace which is the library_path of the classloader.
+  initialized_ = android_init_anonymous_namespace(default_public_libraries().c_str(),
+                                                  is_native_bridge ? nullptr : library_path);
+  if (!initialized_) {
+    *error_msg = dlerror();
+    return false;
+  }
+
+  // and now initialize native bridge namespaces if necessary.
+  if (NativeBridgeInitialized()) {
+    initialized_ = NativeBridgeInitAnonymousNamespace(default_public_libraries().c_str(),
+                                                      is_native_bridge ? library_path : nullptr);
+    if (!initialized_) {
+      *error_msg = NativeBridgeGetError();
+    }
+  }
+
+  return initialized_;
+}
+
+NativeLoaderNamespace* LibraryNamespaces::FindParentNamespaceByClassLoader(JNIEnv* env,
+                                                                           jobject class_loader) {
+  jobject parent_class_loader = GetParentClassLoader(env, class_loader);
+
+  while (parent_class_loader != nullptr) {
+    NativeLoaderNamespace* ns;
+    if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
+      return ns;
+    }
+
+    parent_class_loader = GetParentClassLoader(env, parent_class_loader);
+  }
+
+  return nullptr;
+}
+
+}  // namespace android::nativeloader
diff --git a/libnativeloader/library_namespaces.h b/libnativeloader/library_namespaces.h
new file mode 100644
index 0000000..fd46cdc
--- /dev/null
+++ b/libnativeloader/library_namespaces.h
@@ -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.
+ */
+#pragma once
+#if !defined(__ANDROID__)
+#error "Not available for host"
+#endif
+
+#define LOG_TAG "nativeloader"
+
+#include "native_loader_namespace.h"
+
+#include <list>
+#include <string>
+
+#include <jni.h>
+
+namespace android::nativeloader {
+
+// LibraryNamespaces is a singleton object that manages NativeLoaderNamespace
+// objects for an app process. Its main job is to create (and configure) a new
+// NativeLoaderNamespace object for a Java ClassLoader, and to find an existing
+// object for a given ClassLoader.
+class LibraryNamespaces {
+ public:
+  LibraryNamespaces() : initialized_(false) {}
+
+  LibraryNamespaces(LibraryNamespaces&&) = default;
+  LibraryNamespaces(const LibraryNamespaces&) = delete;
+  LibraryNamespaces& operator=(const LibraryNamespaces&) = delete;
+
+  void Initialize();
+  void Reset() { namespaces_.clear(); }
+  NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
+                                bool is_shared, jstring dex_path, jstring java_library_path,
+                                jstring java_permitted_path, std::string* error_msg);
+  NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+
+ private:
+  bool InitPublicNamespace(const char* library_path, std::string* error_msg);
+  NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+
+  bool initialized_;
+  std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
+};
+
+}  // namespace android::nativeloader
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index e460b1a..0c29324 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -14,728 +14,64 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "nativeloader"
+
 #include "nativeloader/native_loader.h"
-#include <nativehelper/ScopedUtfChars.h>
 
 #include <dlfcn.h>
-#ifdef __ANDROID__
-#define LOG_TAG "libnativeloader"
-#include "nativeloader/dlext_namespaces.h"
-#include "log/log.h"
-#endif
-#include <dirent.h>
 #include <sys/types.h>
-#include "nativebridge/native_bridge.h"
 
-#include <algorithm>
-#include <list>
 #include <memory>
 #include <mutex>
-#include <regex>
 #include <string>
 #include <vector>
 
 #include <android-base/file.h>
 #include <android-base/macros.h>
 #include <android-base/strings.h>
+#include <nativebridge/native_bridge.h>
+#include <nativehelper/ScopedUtfChars.h>
 
-#ifdef __BIONIC__
-#include <android-base/properties.h>
+#ifdef __ANDROID__
+#include <log/log.h>
+#include "library_namespaces.h"
+#include "nativeloader/dlext_namespaces.h"
 #endif
 
-#define CHECK(predicate) LOG_ALWAYS_FATAL_IF(!(predicate),\
-                                             "%s:%d: %s CHECK '" #predicate "' failed.",\
-                                             __FILE__, __LINE__, __FUNCTION__)
-
-using namespace std::string_literals;
-
 namespace android {
 
+namespace {
 #if defined(__ANDROID__)
-struct NativeLoaderNamespace {
- public:
-  NativeLoaderNamespace()
-      : android_ns_(nullptr), native_bridge_ns_(nullptr) { }
+using android::nativeloader::LibraryNamespaces;
 
-  explicit NativeLoaderNamespace(android_namespace_t* ns)
-      : android_ns_(ns), native_bridge_ns_(nullptr) { }
+constexpr const char* kApexPath = "/apex/";
 
-  explicit NativeLoaderNamespace(native_bridge_namespace_t* ns)
-      : android_ns_(nullptr), native_bridge_ns_(ns) { }
+std::mutex g_namespaces_mutex;
+LibraryNamespaces* g_namespaces = new LibraryNamespaces;
 
-  NativeLoaderNamespace(NativeLoaderNamespace&& that) = default;
-  NativeLoaderNamespace(const NativeLoaderNamespace& that) = default;
-
-  NativeLoaderNamespace& operator=(const NativeLoaderNamespace& that) = default;
-
-  android_namespace_t* get_android_ns() const {
-    CHECK(native_bridge_ns_ == nullptr);
-    return android_ns_;
+android_namespace_t* FindExportedNamespace(const char* caller_location) {
+  std::string location = caller_location;
+  // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
+  // /apex/com.android...modulename/...
+  //
+  // And we extract from it 'modulename', which is the name of the linker namespace.
+  if (android::base::StartsWith(location, kApexPath)) {
+    size_t slash_index = location.find_first_of('/', strlen(kApexPath));
+    LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
+                        "Error finding namespace of apex: no slash in path %s", caller_location);
+    size_t dot_index = location.find_last_of('.', slash_index);
+    LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
+                        "Error finding namespace of apex: no dot in apex name %s", caller_location);
+    std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
+    android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
+    LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
+                        "Error finding namespace of apex: no namespace called %s", name.c_str());
+    return boot_namespace;
   }
-
-  native_bridge_namespace_t* get_native_bridge_ns() const {
-    CHECK(android_ns_ == nullptr);
-    return native_bridge_ns_;
-  }
-
-  bool is_android_namespace() const {
-    return native_bridge_ns_ == nullptr;
-  }
-
- private:
-  // Only one of them can be not null
-  android_namespace_t* android_ns_;
-  native_bridge_namespace_t* native_bridge_ns_;
-};
-
-static constexpr const char kPublicNativeLibrariesSystemConfigPathFromRoot[] =
-    "/etc/public.libraries.txt";
-static constexpr const char kPublicNativeLibrariesExtensionConfigPrefix[] = "public.libraries-";
-static constexpr const size_t kPublicNativeLibrariesExtensionConfigPrefixLen =
-    sizeof(kPublicNativeLibrariesExtensionConfigPrefix) - 1;
-static constexpr const char kPublicNativeLibrariesExtensionConfigSuffix[] = ".txt";
-static constexpr const size_t kPublicNativeLibrariesExtensionConfigSuffixLen =
-    sizeof(kPublicNativeLibrariesExtensionConfigSuffix) - 1;
-static constexpr const char kPublicNativeLibrariesVendorConfig[] =
-    "/vendor/etc/public.libraries.txt";
-static constexpr const char kLlndkNativeLibrariesSystemConfigPathFromRoot[] =
-    "/etc/llndk.libraries.txt";
-static constexpr const char kVndkspNativeLibrariesSystemConfigPathFromRoot[] =
-    "/etc/vndksp.libraries.txt";
-
-static const std::vector<const std::string> kRuntimePublicLibraries = {
-    "libicuuc.so",
-    "libicui18n.so",
-};
-
-// The device may be configured to have the vendor libraries loaded to a separate namespace.
-// For historical reasons this namespace was named sphal but effectively it is intended
-// to use to load vendor libraries to separate namespace with controlled interface between
-// vendor and system namespaces.
-static constexpr const char* kVendorNamespaceName = "sphal";
-
-static constexpr const char* kVndkNamespaceName = "vndk";
-
-static constexpr const char* kDefaultNamespaceName = "default";
-static constexpr const char* kPlatformNamespaceName = "platform";
-static constexpr const char* kRuntimeNamespaceName = "runtime";
-
-// classloader-namespace is a linker namespace that is created for the loaded
-// app. To be specific, it is created for the app classloader. When
-// System.load() is called from a Java class that is loaded from the
-// classloader, the classloader-namespace namespace associated with that
-// classloader is selected for dlopen. The namespace is configured so that its
-// search path is set to the app-local JNI directory and it is linked to the
-// default namespace with the names of libs listed in the public.libraries.txt.
-// This way an app can only load its own JNI libraries along with the public libs.
-static constexpr const char* kClassloaderNamespaceName = "classloader-namespace";
-// Same thing for vendor APKs.
-static constexpr const char* kVendorClassloaderNamespaceName = "vendor-classloader-namespace";
-
-// (http://b/27588281) This is a workaround for apps using custom classloaders and calling
-// System.load() with an absolute path which is outside of the classloader library search path.
-// This list includes all directories app is allowed to access this way.
-static constexpr const char* kWhitelistedDirectories = "/data:/mnt/expand";
-
-static constexpr const char* kApexPath = "/apex/";
-
-#if defined(__LP64__)
-static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64";
-static constexpr const char* kVendorLibPath = "/vendor/lib64";
-static constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64";
-#else
-static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib";
-static constexpr const char* kVendorLibPath = "/vendor/lib";
-static constexpr const char* kProductLibPath = "/product/lib:/system/product/lib";
-#endif
-
-static const std::regex kVendorDexPathRegex("(^|:)/vendor/");
-static const std::regex kProductDexPathRegex("(^|:)(/system)?/product/");
-
-// Define origin of APK if it is from vendor partition or product partition
-typedef enum {
-  APK_ORIGIN_DEFAULT = 0,
-  APK_ORIGIN_VENDOR = 1,
-  APK_ORIGIN_PRODUCT = 2,
-} ApkOrigin;
-
-static bool is_debuggable() {
-  bool debuggable = false;
-#ifdef __BIONIC__
-  debuggable = android::base::GetBoolProperty("ro.debuggable", false);
-#endif
-  return debuggable;
+  return nullptr;
 }
-
-static std::string vndk_version_str() {
-#ifdef __BIONIC__
-  std::string version = android::base::GetProperty("ro.vndk.version", "");
-  if (version != "" && version != "current") {
-    return "." + version;
-  }
-#endif
-  return "";
-}
-
-static void insert_vndk_version_str(std::string* file_name) {
-  CHECK(file_name != nullptr);
-  size_t insert_pos = file_name->find_last_of(".");
-  if (insert_pos == std::string::npos) {
-    insert_pos = file_name->length();
-  }
-  file_name->insert(insert_pos, vndk_version_str());
-}
-
-static const std::function<bool(const std::string&, std::string*)> always_true =
-    [](const std::string&, std::string*) { return true; };
-
-class LibraryNamespaces {
- public:
-  LibraryNamespaces() : initialized_(false) { }
-
-  NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader,
-                                bool is_shared, jstring dex_path, jstring java_library_path,
-                                jstring java_permitted_path, std::string* error_msg) {
-    std::string library_path; // empty string by default.
-
-    if (java_library_path != nullptr) {
-      ScopedUtfChars library_path_utf_chars(env, java_library_path);
-      library_path = library_path_utf_chars.c_str();
-    }
-
-    ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path);
-
-    // (http://b/27588281) This is a workaround for apps using custom
-    // classloaders and calling System.load() with an absolute path which
-    // is outside of the classloader library search path.
-    //
-    // This part effectively allows such a classloader to access anything
-    // under /data and /mnt/expand
-    std::string permitted_path = kWhitelistedDirectories;
-
-    if (java_permitted_path != nullptr) {
-      ScopedUtfChars path(env, java_permitted_path);
-      if (path.c_str() != nullptr && path.size() > 0) {
-        permitted_path = permitted_path + ":" + path.c_str();
-      }
-    }
-
-    // Initialize the anonymous namespace with the first non-empty library path.
-    if (!library_path.empty() && !initialized_ &&
-        !InitPublicNamespace(library_path.c_str(), error_msg)) {
-      return nullptr;
-    }
-
-    bool found = FindNamespaceByClassLoader(env, class_loader);
-
-    LOG_ALWAYS_FATAL_IF(found,
-                        "There is already a namespace associated with this classloader");
-
-    uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
-    if (is_shared) {
-      namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
-    }
-
-    if (target_sdk_version < 24) {
-      namespace_type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
-    }
-
-    NativeLoaderNamespace* parent_ns = FindParentNamespaceByClassLoader(env, class_loader);
-
-    bool is_native_bridge = false;
-
-    if (parent_ns != nullptr) {
-      is_native_bridge = !parent_ns->is_android_namespace();
-    } else if (!library_path.empty()) {
-      is_native_bridge = NativeBridgeIsPathSupported(library_path.c_str());
-    }
-
-    std::string system_exposed_libraries = system_public_libraries_;
-    const char* namespace_name = kClassloaderNamespaceName;
-    android_namespace_t* vndk_ns = nullptr;
-    if ((apk_origin == APK_ORIGIN_VENDOR ||
-         (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) &&
-        !is_shared) {
-      LOG_FATAL_IF(is_native_bridge,
-                   "Unbundled vendor / product apk must not use translated architecture");
-
-      // For vendor / product apks, give access to the vendor / product lib even though
-      // they are treated as unbundled; the libs and apks are still bundled
-      // together in the vendor / product partition.
-      const char* origin_partition;
-      const char* origin_lib_path;
-
-      switch (apk_origin) {
-        case APK_ORIGIN_VENDOR:
-          origin_partition = "vendor";
-          origin_lib_path = kVendorLibPath;
-          break;
-        case APK_ORIGIN_PRODUCT:
-          origin_partition = "product";
-          origin_lib_path = kProductLibPath;
-          break;
-        default:
-          origin_partition = "unknown";
-          origin_lib_path = "";
-      }
-
-      LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture",
-                   origin_partition);
-
-      library_path = library_path + ":" + origin_lib_path;
-      permitted_path = permitted_path + ":" + origin_lib_path;
-
-      // Also give access to LLNDK libraries since they are available to vendors
-      system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str();
-
-      // Give access to VNDK-SP libraries from the 'vndk' namespace.
-      vndk_ns = android_get_exported_namespace(kVndkNamespaceName);
-      if (vndk_ns == nullptr) {
-        ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition);
-      }
-
-      // Different name is useful for debugging
-      namespace_name = kVendorClassloaderNamespaceName;
-      ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s",
-            origin_partition, library_path.c_str());
-    } else {
-      // oem and product public libraries are NOT available to vendor apks, otherwise it
-      // would be system->vendor violation.
-      if (!oem_public_libraries_.empty()) {
-        system_exposed_libraries = system_exposed_libraries + ':' + oem_public_libraries_;
-      }
-      if (!product_public_libraries_.empty()) {
-        system_exposed_libraries = system_exposed_libraries + ':' + product_public_libraries_;
-      }
-    }
-
-    std::string runtime_exposed_libraries = base::Join(kRuntimePublicLibraries, ":");
-
-    NativeLoaderNamespace native_loader_ns;
-    if (!is_native_bridge) {
-      android_namespace_t* android_parent_ns;
-      if (parent_ns != nullptr) {
-        android_parent_ns = parent_ns->get_android_ns();
-      } else {
-        // Fall back to the platform namespace if no parent is found. It is
-        // called "default" for binaries in /system and "platform" for those in
-        // the Runtime APEX. Try "platform" first since "default" always exists.
-        android_parent_ns = android_get_exported_namespace(kPlatformNamespaceName);
-        if (android_parent_ns == nullptr) {
-          android_parent_ns = android_get_exported_namespace(kDefaultNamespaceName);
-        }
-      }
-
-      android_namespace_t* ns = android_create_namespace(namespace_name,
-                                                         nullptr,
-                                                         library_path.c_str(),
-                                                         namespace_type,
-                                                         permitted_path.c_str(),
-                                                         android_parent_ns);
-      if (ns == nullptr) {
-        *error_msg = dlerror();
-        return nullptr;
-      }
-
-      // Note that when vendor_ns is not configured this function will return nullptr
-      // and it will result in linking vendor_public_libraries_ to the default namespace
-      // which is expected behavior in this case.
-      android_namespace_t* vendor_ns = android_get_exported_namespace(kVendorNamespaceName);
-
-      android_namespace_t* runtime_ns = android_get_exported_namespace(kRuntimeNamespaceName);
-
-      if (!android_link_namespaces(ns, nullptr, system_exposed_libraries.c_str())) {
-        *error_msg = dlerror();
-        return nullptr;
-      }
-
-      // Runtime apex does not exist in host, and under certain build conditions.
-      if (runtime_ns != nullptr) {
-        if (!android_link_namespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
-          *error_msg = dlerror();
-          return nullptr;
-        }
-      }
-
-      if (vndk_ns != nullptr && !system_vndksp_libraries_.empty()) {
-        // vendor apks are allowed to use VNDK-SP libraries.
-        if (!android_link_namespaces(ns, vndk_ns, system_vndksp_libraries_.c_str())) {
-          *error_msg = dlerror();
-          return nullptr;
-        }
-      }
-
-      if (!vendor_public_libraries_.empty()) {
-        if (!android_link_namespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
-          *error_msg = dlerror();
-          return nullptr;
-        }
-      }
-
-      native_loader_ns = NativeLoaderNamespace(ns);
-    } else {
-      native_bridge_namespace_t* native_bridge_parent_namespace;
-      if (parent_ns != nullptr) {
-        native_bridge_parent_namespace = parent_ns->get_native_bridge_ns();
-      } else {
-        native_bridge_parent_namespace = NativeBridgeGetExportedNamespace(kPlatformNamespaceName);
-        if (native_bridge_parent_namespace == nullptr) {
-          native_bridge_parent_namespace = NativeBridgeGetExportedNamespace(kDefaultNamespaceName);
-        }
-      }
-
-      native_bridge_namespace_t* ns = NativeBridgeCreateNamespace(namespace_name,
-                                                                  nullptr,
-                                                                  library_path.c_str(),
-                                                                  namespace_type,
-                                                                  permitted_path.c_str(),
-                                                                  native_bridge_parent_namespace);
-      if (ns == nullptr) {
-        *error_msg = NativeBridgeGetError();
-        return nullptr;
-      }
-
-      native_bridge_namespace_t* vendor_ns = NativeBridgeGetExportedNamespace(kVendorNamespaceName);
-      native_bridge_namespace_t* runtime_ns =
-          NativeBridgeGetExportedNamespace(kRuntimeNamespaceName);
-
-      if (!NativeBridgeLinkNamespaces(ns, nullptr, system_exposed_libraries.c_str())) {
-        *error_msg = NativeBridgeGetError();
-        return nullptr;
-      }
-
-      // Runtime apex does not exist in host, and under certain build conditions.
-      if (runtime_ns != nullptr) {
-        if (!NativeBridgeLinkNamespaces(ns, runtime_ns, runtime_exposed_libraries.c_str())) {
-          *error_msg = NativeBridgeGetError();
-          return nullptr;
-        }
-      }
-      if (!vendor_public_libraries_.empty()) {
-        if (!NativeBridgeLinkNamespaces(ns, vendor_ns, vendor_public_libraries_.c_str())) {
-          *error_msg = NativeBridgeGetError();
-          return nullptr;
-        }
-      }
-
-      native_loader_ns = NativeLoaderNamespace(ns);
-    }
-
-    namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), native_loader_ns));
-
-    return &(namespaces_.back().second);
-  }
-
-  NativeLoaderNamespace* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
-    auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
-                [&](const std::pair<jweak, NativeLoaderNamespace>& value) {
-                  return env->IsSameObject(value.first, class_loader);
-                });
-    if (it != namespaces_.end()) {
-      return &it->second;
-    }
-
-    return nullptr;
-  }
-
-  void Initialize() {
-    // Once public namespace is initialized there is no
-    // point in running this code - it will have no effect
-    // on the current list of public libraries.
-    if (initialized_) {
-      return;
-    }
-
-    std::vector<std::string> sonames;
-    const char* android_root_env = getenv("ANDROID_ROOT");
-    std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
-    std::string public_native_libraries_system_config =
-            root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
-    std::string llndk_native_libraries_system_config =
-            root_dir + kLlndkNativeLibrariesSystemConfigPathFromRoot;
-    std::string vndksp_native_libraries_system_config =
-            root_dir + kVndkspNativeLibrariesSystemConfigPathFromRoot;
-
-    std::string product_public_native_libraries_dir = "/product/etc";
-
-    std::string error_msg;
-    LOG_ALWAYS_FATAL_IF(
-        !ReadConfig(public_native_libraries_system_config, &sonames, always_true, &error_msg),
-        "Error reading public native library list from \"%s\": %s",
-        public_native_libraries_system_config.c_str(), error_msg.c_str());
-
-    // For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
-    // variable to add libraries to the list. This is intended for platform tests only.
-    if (is_debuggable()) {
-      const char* additional_libs = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
-      if (additional_libs != nullptr && additional_libs[0] != '\0') {
-        std::vector<std::string> additional_libs_vector = base::Split(additional_libs, ":");
-        std::copy(additional_libs_vector.begin(), additional_libs_vector.end(),
-                  std::back_inserter(sonames));
-      }
-    }
-
-    // Remove the public libs in the runtime namespace.
-    // These libs are listed in public.android.txt, but we don't want the rest of android
-    // in default namespace to dlopen the libs.
-    // For example, libicuuc.so is exposed to classloader namespace from runtime namespace.
-    // Unfortunately, it does not have stable C symbols, and default namespace should only use
-    // stable symbols in libandroidicu.so. http://b/120786417
-    removePublicLibsIfExistsInRuntimeApex(sonames);
-
-    // android_init_namespaces() expects all the public libraries
-    // to be loaded so that they can be found by soname alone.
-    //
-    // TODO(dimitry): this is a bit misleading since we do not know
-    // if the vendor public library is going to be opened from /vendor/lib
-    // we might as well end up loading them from /system/lib or /product/lib
-    // For now we rely on CTS test to catch things like this but
-    // it should probably be addressed in the future.
-    for (const auto& soname : sonames) {
-      LOG_ALWAYS_FATAL_IF(dlopen(soname.c_str(), RTLD_NOW | RTLD_NODELETE) == nullptr,
-                          "Error preloading public library %s: %s", soname.c_str(), dlerror());
-    }
-
-    system_public_libraries_ = base::Join(sonames, ':');
-
-    // read /system/etc/public.libraries-<companyname>.txt which contain partner defined
-    // system libs that are exposed to apps. The libs in the txt files must be
-    // named as lib<name>.<companyname>.so.
-    sonames.clear();
-    ReadExtensionLibraries(base::Dirname(public_native_libraries_system_config).c_str(), &sonames);
-    oem_public_libraries_ = base::Join(sonames, ':');
-
-    // read /product/etc/public.libraries-<companyname>.txt which contain partner defined
-    // product libs that are exposed to apps.
-    sonames.clear();
-    ReadExtensionLibraries(product_public_native_libraries_dir.c_str(), &sonames);
-    product_public_libraries_ = base::Join(sonames, ':');
-
-    // Insert VNDK version to llndk and vndksp config file names.
-    insert_vndk_version_str(&llndk_native_libraries_system_config);
-    insert_vndk_version_str(&vndksp_native_libraries_system_config);
-
-    sonames.clear();
-    ReadConfig(llndk_native_libraries_system_config, &sonames, always_true);
-    system_llndk_libraries_ = base::Join(sonames, ':');
-
-    sonames.clear();
-    ReadConfig(vndksp_native_libraries_system_config, &sonames, always_true);
-    system_vndksp_libraries_ = base::Join(sonames, ':');
-
-    sonames.clear();
-    // This file is optional, quietly ignore if the file does not exist.
-    ReadConfig(kPublicNativeLibrariesVendorConfig, &sonames, always_true, nullptr);
-
-    vendor_public_libraries_ = base::Join(sonames, ':');
-  }
-
-  void Reset() { namespaces_.clear(); }
-
- private:
-  void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
-    std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
-    if (dir != nullptr) {
-      // Failing to opening the dir is not an error, which can happen in
-      // webview_zygote.
-      while (struct dirent* ent = readdir(dir.get())) {
-        if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
-          continue;
-        }
-        const std::string filename(ent->d_name);
-        if (android::base::StartsWith(filename, kPublicNativeLibrariesExtensionConfigPrefix) &&
-            android::base::EndsWith(filename, kPublicNativeLibrariesExtensionConfigSuffix)) {
-          const size_t start = kPublicNativeLibrariesExtensionConfigPrefixLen;
-          const size_t end = filename.size() - kPublicNativeLibrariesExtensionConfigSuffixLen;
-          const std::string company_name = filename.substr(start, end - start);
-          const std::string config_file_path = dirname + "/"s + filename;
-          LOG_ALWAYS_FATAL_IF(
-              company_name.empty(),
-              "Error extracting company name from public native library list file path \"%s\"",
-              config_file_path.c_str());
-
-          std::string error_msg;
-
-          LOG_ALWAYS_FATAL_IF(
-              !ReadConfig(
-                  config_file_path, sonames,
-                  [&company_name](const std::string& soname, std::string* error_msg) {
-                    if (android::base::StartsWith(soname, "lib") &&
-                        android::base::EndsWith(soname, "." + company_name + ".so")) {
-                      return true;
-                    } else {
-                      *error_msg = "Library name \"" + soname +
-                                   "\" does not end with the company name: " + company_name + ".";
-                      return false;
-                    }
-                  },
-                  &error_msg),
-              "Error reading public native library list from \"%s\": %s", config_file_path.c_str(),
-              error_msg.c_str());
-        }
-      }
-    }
-  }
-
-  /**
-   * Remove the public libs in runtime namespace
-   */
-  void removePublicLibsIfExistsInRuntimeApex(std::vector<std::string>& sonames) {
-    for (const std::string& lib_name : kRuntimePublicLibraries) {
-      std::string path(kRuntimeApexLibPath);
-      path.append("/").append(lib_name);
-
-      struct stat s;
-      // Do nothing if the path in /apex does not exist.
-      // Runtime APEX must be mounted since libnativeloader is in the same APEX
-      if (stat(path.c_str(), &s) != 0) {
-        continue;
-      }
-
-      auto it = std::find(sonames.begin(), sonames.end(), lib_name);
-      if (it != sonames.end()) {
-        sonames.erase(it);
-      }
-    }
-  }
-
-  bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
-                  const std::function<bool(const std::string& /* soname */,
-                                           std::string* /* error_msg */)>& check_soname,
-                  std::string* error_msg = nullptr) {
-    // Read list of public native libraries from the config file.
-    std::string file_content;
-    if(!base::ReadFileToString(configFile, &file_content)) {
-      if (error_msg) *error_msg = strerror(errno);
-      return false;
-    }
-
-    std::vector<std::string> lines = base::Split(file_content, "\n");
-
-    for (auto& line : lines) {
-      auto trimmed_line = base::Trim(line);
-      if (trimmed_line[0] == '#' || trimmed_line.empty()) {
-        continue;
-      }
-      size_t space_pos = trimmed_line.rfind(' ');
-      if (space_pos != std::string::npos) {
-        std::string type = trimmed_line.substr(space_pos + 1);
-        if (type != "32" && type != "64") {
-          if (error_msg) *error_msg = "Malformed line: " + line;
-          return false;
-        }
-#if defined(__LP64__)
-        // Skip 32 bit public library.
-        if (type == "32") {
-          continue;
-        }
-#else
-        // Skip 64 bit public library.
-        if (type == "64") {
-          continue;
-        }
-#endif
-        trimmed_line.resize(space_pos);
-      }
-
-      if (check_soname(trimmed_line, error_msg)) {
-        sonames->push_back(trimmed_line);
-      } else {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  bool InitPublicNamespace(const char* library_path, std::string* error_msg) {
-    // Ask native bride if this apps library path should be handled by it
-    bool is_native_bridge = NativeBridgeIsPathSupported(library_path);
-
-    // (http://b/25844435) - Some apps call dlopen from generated code (mono jited
-    // code is one example) unknown to linker in which  case linker uses anonymous
-    // namespace. The second argument specifies the search path for the anonymous
-    // namespace which is the library_path of the classloader.
-    initialized_ = android_init_anonymous_namespace(system_public_libraries_.c_str(),
-                                                    is_native_bridge ? nullptr : library_path);
-    if (!initialized_) {
-      *error_msg = dlerror();
-      return false;
-    }
-
-    // and now initialize native bridge namespaces if necessary.
-    if (NativeBridgeInitialized()) {
-      initialized_ = NativeBridgeInitAnonymousNamespace(system_public_libraries_.c_str(),
-                                                        is_native_bridge ? library_path : nullptr);
-      if (!initialized_) {
-        *error_msg = NativeBridgeGetError();
-      }
-    }
-
-    return initialized_;
-  }
-
-  jobject GetParentClassLoader(JNIEnv* env, jobject class_loader) {
-    jclass class_loader_class = env->FindClass("java/lang/ClassLoader");
-    jmethodID get_parent = env->GetMethodID(class_loader_class,
-                                            "getParent",
-                                            "()Ljava/lang/ClassLoader;");
-
-    return env->CallObjectMethod(class_loader, get_parent);
-  }
-
-  NativeLoaderNamespace* FindParentNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
-    jobject parent_class_loader = GetParentClassLoader(env, class_loader);
-
-    while (parent_class_loader != nullptr) {
-      NativeLoaderNamespace* ns;
-      if ((ns = FindNamespaceByClassLoader(env, parent_class_loader)) != nullptr) {
-        return ns;
-      }
-
-      parent_class_loader = GetParentClassLoader(env, parent_class_loader);
-    }
-
-    return nullptr;
-  }
-
-  ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) {
-    ApkOrigin apk_origin = APK_ORIGIN_DEFAULT;
-
-    if (dex_path != nullptr) {
-      ScopedUtfChars dex_path_utf_chars(env, dex_path);
-
-      if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) {
-        apk_origin = APK_ORIGIN_VENDOR;
-      }
-
-      if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) {
-        LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR,
-                            "Dex path contains both vendor and product partition : %s",
-                            dex_path_utf_chars.c_str());
-
-        apk_origin = APK_ORIGIN_PRODUCT;
-      }
-    }
-
-    return apk_origin;
-  }
-
-  bool initialized_;
-  std::list<std::pair<jweak, NativeLoaderNamespace>> namespaces_;
-  std::string system_public_libraries_;
-  std::string vendor_public_libraries_;
-  std::string oem_public_libraries_;
-  std::string product_public_libraries_;
-  std::string system_llndk_libraries_;
-  std::string system_vndksp_libraries_;
-
-  DISALLOW_COPY_AND_ASSIGN(LibraryNamespaces);
-};
-
-static std::mutex g_namespaces_mutex;
-static LibraryNamespaces* g_namespaces = new LibraryNamespaces;
-#endif
+#endif  // #if defined(__ANDROID__)
+}  // namespace
 
 void InitializeNativeLoader() {
 #if defined(__ANDROID__)
@@ -769,30 +105,6 @@
   return nullptr;
 }
 
-#if defined(__ANDROID__)
-static android_namespace_t* FindExportedNamespace(const char* caller_location) {
-  std::string location = caller_location;
-  // Lots of implicit assumptions here: we expect `caller_location` to be of the form:
-  // /apex/com.android...modulename/...
-  //
-  // And we extract from it 'modulename', which is the name of the linker namespace.
-  if (android::base::StartsWith(location, kApexPath)) {
-    size_t slash_index = location.find_first_of('/', strlen(kApexPath));
-    LOG_ALWAYS_FATAL_IF((slash_index == std::string::npos),
-                        "Error finding namespace of apex: no slash in path %s", caller_location);
-    size_t dot_index = location.find_last_of('.', slash_index);
-    LOG_ALWAYS_FATAL_IF((dot_index == std::string::npos),
-                        "Error finding namespace of apex: no dot in apex name %s", caller_location);
-    std::string name = location.substr(dot_index + 1, slash_index - dot_index - 1);
-    android_namespace_t* boot_namespace = android_get_exported_namespace(name.c_str());
-    LOG_ALWAYS_FATAL_IF((boot_namespace == nullptr),
-                        "Error finding namespace of apex: no namespace called %s", name.c_str());
-    return boot_namespace;
-  }
-  return nullptr;
-}
-#endif
-
 void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path,
                         jobject class_loader, const char* caller_location, jstring library_path,
                         bool* needs_native_bridge, char** error_msg) {
@@ -910,25 +222,12 @@
 #if defined(__ANDROID__)
 void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path,
                                    bool* needs_native_bridge, char** error_msg) {
-  if (ns->is_android_namespace()) {
-    android_dlextinfo extinfo;
-    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
-    extinfo.library_namespace = ns->get_android_ns();
-
-    void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
-    if (handle == nullptr) {
-      *error_msg = strdup(dlerror());
-    }
-    *needs_native_bridge = false;
-    return handle;
-  } else {
-    void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns());
-    if (handle == nullptr) {
-      *error_msg = strdup(NativeBridgeGetError());
-    }
-    *needs_native_bridge = true;
-    return handle;
+  void* handle = ns->Load(path);
+  if (handle == nullptr) {
+    *error_msg = ns->GetError();
   }
+  *needs_native_bridge = ns->IsBridged();
+  return handle;
 }
 
 // native_bridge_namespaces are not supported for callers of this function.
@@ -937,16 +236,16 @@
 android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
   NativeLoaderNamespace* ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader);
-  if (ns != nullptr) {
-    return ns->is_android_namespace() ? ns->get_android_ns() : nullptr;
+  if (ns != nullptr && !ns->IsBridged()) {
+    return ns->ToRawAndroidNamespace();
   }
-
   return nullptr;
 }
+
 NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
   std::lock_guard<std::mutex> guard(g_namespaces_mutex);
   return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
 }
 #endif
 
-}; //  android namespace
+};  // namespace android
diff --git a/libnativeloader/native_loader_namespace.cpp b/libnativeloader/native_loader_namespace.cpp
new file mode 100644
index 0000000..90f730c
--- /dev/null
+++ b/libnativeloader/native_loader_namespace.cpp
@@ -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.
+ */
+
+#define LOG_TAG "nativeloader"
+
+#include "native_loader_namespace.h"
+
+#include <dlfcn.h>
+
+#include <functional>
+
+#include <android-base/strings.h>
+#include <log/log.h>
+#include <nativebridge/native_bridge.h>
+
+#include "nativeloader/dlext_namespaces.h"
+
+namespace android {
+
+namespace {
+
+constexpr const char* kDefaultNamespaceName = "default";
+constexpr const char* kPlatformNamespaceName = "platform";
+
+}  // namespace
+
+NativeLoaderNamespace NativeLoaderNamespace::GetExportedNamespace(const std::string& name,
+                                                                  bool is_bridged) {
+  if (!is_bridged) {
+    return NativeLoaderNamespace(name, android_get_exported_namespace(name.c_str()));
+  } else {
+    return NativeLoaderNamespace(name, NativeBridgeGetExportedNamespace(name.c_str()));
+  }
+}
+
+char* NativeLoaderNamespace::GetError() const {
+  if (!IsBridged()) {
+    return strdup(dlerror());
+  } else {
+    return strdup(NativeBridgeGetError());
+  }
+}
+
+// The platform namespace is called "default" for binaries in /system and
+// "platform" for those in the Runtime APEX. Try "platform" first since
+// "default" always exists.
+NativeLoaderNamespace NativeLoaderNamespace::GetPlatformNamespace(bool is_bridged) {
+  NativeLoaderNamespace ns = GetExportedNamespace(kPlatformNamespaceName, is_bridged);
+  if (ns.IsNil()) {
+    ns = GetExportedNamespace(kDefaultNamespaceName, is_bridged);
+  }
+  return ns;
+}
+
+NativeLoaderNamespace NativeLoaderNamespace::Create(const std::string& name,
+                                                    const std::string& search_paths,
+                                                    const std::string& permitted_paths,
+                                                    const NativeLoaderNamespace* parent,
+                                                    bool is_shared, bool is_greylist_enabled) {
+  bool is_bridged = false;
+  if (parent != nullptr) {
+    is_bridged = parent->IsBridged();
+  } else if (!search_paths.empty()) {
+    is_bridged = NativeBridgeIsPathSupported(search_paths.c_str());
+  }
+
+  // Fall back to the platform namespace if no parent is set.
+  const NativeLoaderNamespace& effective_parent =
+      parent != nullptr ? *parent : GetPlatformNamespace(is_bridged);
+
+  uint64_t type = ANDROID_NAMESPACE_TYPE_ISOLATED;
+  if (is_shared) {
+    type |= ANDROID_NAMESPACE_TYPE_SHARED;
+  }
+  if (is_greylist_enabled) {
+    type |= ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED;
+  }
+
+  if (!is_bridged) {
+    android_namespace_t* raw =
+        android_create_namespace(name.c_str(), nullptr, search_paths.c_str(), type,
+                                 permitted_paths.c_str(), effective_parent.ToRawAndroidNamespace());
+    return NativeLoaderNamespace(name, raw);
+  } else {
+    native_bridge_namespace_t* raw = NativeBridgeCreateNamespace(
+        name.c_str(), nullptr, search_paths.c_str(), type, permitted_paths.c_str(),
+        effective_parent.ToRawNativeBridgeNamespace());
+    return NativeLoaderNamespace(name, raw);
+  }
+}
+
+bool NativeLoaderNamespace::Link(const NativeLoaderNamespace& target,
+                                 const std::string& shared_libs) const {
+  LOG_ALWAYS_FATAL_IF(shared_libs.empty(), "empty share lib when linking %s to %s",
+                      this->name().c_str(), target.name().c_str());
+  if (!IsBridged()) {
+    return android_link_namespaces(this->ToRawAndroidNamespace(), target.ToRawAndroidNamespace(),
+                                   shared_libs.c_str());
+  } else {
+    return NativeBridgeLinkNamespaces(this->ToRawNativeBridgeNamespace(),
+                                      target.ToRawNativeBridgeNamespace(), shared_libs.c_str());
+  }
+}
+
+void* NativeLoaderNamespace::Load(const std::string& lib_name) const {
+  if (!IsBridged()) {
+    android_dlextinfo extinfo;
+    extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+    extinfo.library_namespace = this->ToRawAndroidNamespace();
+    return android_dlopen_ext(lib_name.c_str(), RTLD_NOW, &extinfo);
+  } else {
+    return NativeBridgeLoadLibraryExt(lib_name.c_str(), RTLD_NOW,
+                                      this->ToRawNativeBridgeNamespace());
+  }
+}
+
+}  // namespace android
diff --git a/libnativeloader/native_loader_namespace.h b/libnativeloader/native_loader_namespace.h
new file mode 100644
index 0000000..1575f8c
--- /dev/null
+++ b/libnativeloader/native_loader_namespace.h
@@ -0,0 +1,72 @@
+/*
+ * 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
+#if defined(__ANDROID__)
+
+#include <string>
+#include <variant>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android/dlext.h>
+#include <log/log.h>
+#include <nativebridge/native_bridge.h>
+
+namespace android {
+
+// NativeLoaderNamespace abstracts a linker namespace for the native
+// architecture (ex: arm on arm) or the translated architecture (ex: arm on
+// x86). Instances of this class are managed by LibraryNamespaces object.
+struct NativeLoaderNamespace {
+ public:
+  // TODO(return with errors)
+  static NativeLoaderNamespace Create(const std::string& name, const std::string& search_paths,
+                                      const std::string& permitted_paths,
+                                      const NativeLoaderNamespace* parent, bool is_shared,
+                                      bool is_greylist_enabled);
+
+  NativeLoaderNamespace(NativeLoaderNamespace&&) = default;
+  NativeLoaderNamespace(const NativeLoaderNamespace&) = default;
+  NativeLoaderNamespace& operator=(const NativeLoaderNamespace&) = default;
+
+  android_namespace_t* ToRawAndroidNamespace() const { return std::get<0>(raw_); }
+  native_bridge_namespace_t* ToRawNativeBridgeNamespace() const { return std::get<1>(raw_); }
+
+  std::string name() const { return name_; }
+  bool IsBridged() const { return raw_.index() == 1; }
+  bool IsNil() const {
+    return IsBridged() ? std::get<1>(raw_) == nullptr : std::get<0>(raw_) == nullptr;
+  }
+
+  bool Link(const NativeLoaderNamespace& target, const std::string& shared_libs) const;
+  void* Load(const std::string& lib_name) const;
+  char* GetError() const;
+
+  static NativeLoaderNamespace GetExportedNamespace(const std::string& name, bool is_bridged);
+  static NativeLoaderNamespace GetPlatformNamespace(bool is_bridged);
+
+ private:
+  explicit NativeLoaderNamespace(const std::string& name, android_namespace_t* ns)
+      : name_(name), raw_(ns) {}
+  explicit NativeLoaderNamespace(const std::string& name, native_bridge_namespace_t* ns)
+      : name_(name), raw_(ns) {}
+
+  std::string name_;
+  std::variant<android_namespace_t*, native_bridge_namespace_t*> raw_;
+};
+
+}  // namespace android
+#endif  // #if defined(__ANDROID__)
diff --git a/libnativeloader/public_libraries.cpp b/libnativeloader/public_libraries.cpp
new file mode 100644
index 0000000..c205eb1
--- /dev/null
+++ b/libnativeloader/public_libraries.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "nativeloader"
+
+#include "public_libraries.h"
+
+#include <dirent.h>
+
+#include <algorithm>
+#include <memory>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <log/log.h>
+
+#include "utils.h"
+
+namespace android::nativeloader {
+
+using namespace std::string_literals;
+
+namespace {
+
+constexpr const char* kDefaultPublicLibrariesFile = "/etc/public.libraries.txt";
+constexpr const char* kExtendedPublicLibrariesFilePrefix = "public.libraries-";
+constexpr const char* kExtendedPublicLibrariesFileSuffix = ".txt";
+constexpr const char* kVendorPublicLibrariesFile = "/vendor/etc/public.libraries.txt";
+constexpr const char* kLlndkLibrariesFile = "/system/etc/llndk.libraries.txt";
+constexpr const char* kVndkLibrariesFile = "/system/etc/vndksp.libraries.txt";
+
+const std::vector<const std::string> kRuntimePublicLibraries = {
+    "libicuuc.so",
+    "libicui18n.so",
+};
+
+constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/" LIB;
+
+// TODO(b/130388701): do we need this?
+std::string root_dir() {
+  static const char* android_root_env = getenv("ANDROID_ROOT");
+  return android_root_env != nullptr ? android_root_env : "/system";
+}
+
+bool debuggable() {
+  static bool debuggable = android::base::GetBoolProperty("ro.debuggable", false);
+  return debuggable;
+}
+
+std::string vndk_version_str() {
+  static std::string version = android::base::GetProperty("ro.vndk.version", "");
+  if (version != "" && version != "current") {
+    return "." + version;
+  }
+  return "";
+}
+
+// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
+// variable to add libraries to the list. This is intended for platform tests only.
+std::string additional_public_libraries() {
+  if (debuggable()) {
+    const char* val = getenv("ANDROID_ADDITIONAL_PUBLIC_LIBRARIES");
+    return val ? val : "";
+  }
+  return "";
+}
+
+void InsertVndkVersionStr(std::string* file_name) {
+  CHECK(file_name != nullptr);
+  size_t insert_pos = file_name->find_last_of(".");
+  if (insert_pos == std::string::npos) {
+    insert_pos = file_name->length();
+  }
+  file_name->insert(insert_pos, vndk_version_str());
+}
+
+const std::function<bool(const std::string&, std::string*)> always_true =
+    [](const std::string&, std::string*) { return true; };
+
+bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
+                const std::function<bool(const std::string& /* soname */,
+                                         std::string* /* error_msg */)>& check_soname,
+                std::string* error_msg = nullptr) {
+  // Read list of public native libraries from the config file.
+  std::string file_content;
+  if (!base::ReadFileToString(configFile, &file_content)) {
+    if (error_msg) *error_msg = strerror(errno);
+    return false;
+  }
+
+  std::vector<std::string> lines = base::Split(file_content, "\n");
+
+  for (auto& line : lines) {
+    auto trimmed_line = base::Trim(line);
+    if (trimmed_line[0] == '#' || trimmed_line.empty()) {
+      continue;
+    }
+    size_t space_pos = trimmed_line.rfind(' ');
+    if (space_pos != std::string::npos) {
+      std::string type = trimmed_line.substr(space_pos + 1);
+      if (type != "32" && type != "64") {
+        if (error_msg) *error_msg = "Malformed line: " + line;
+        return false;
+      }
+#if defined(__LP64__)
+      // Skip 32 bit public library.
+      if (type == "32") {
+        continue;
+      }
+#else
+      // Skip 64 bit public library.
+      if (type == "64") {
+        continue;
+      }
+#endif
+      trimmed_line.resize(space_pos);
+    }
+
+    if (check_soname(trimmed_line, error_msg)) {
+      sonames->push_back(trimmed_line);
+    } else {
+      return false;
+    }
+  }
+  return true;
+}
+
+void ReadExtensionLibraries(const char* dirname, std::vector<std::string>* sonames) {
+  std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
+  if (dir != nullptr) {
+    // Failing to opening the dir is not an error, which can happen in
+    // webview_zygote.
+    while (struct dirent* ent = readdir(dir.get())) {
+      if (ent->d_type != DT_REG && ent->d_type != DT_LNK) {
+        continue;
+      }
+      const std::string filename(ent->d_name);
+      std::string_view fn = filename;
+      if (android::base::ConsumePrefix(&fn, kExtendedPublicLibrariesFilePrefix) &&
+          android::base::ConsumeSuffix(&fn, kExtendedPublicLibrariesFileSuffix)) {
+        const std::string company_name(fn);
+        const std::string config_file_path = dirname + "/"s + filename;
+        LOG_ALWAYS_FATAL_IF(
+            company_name.empty(),
+            "Error extracting company name from public native library list file path \"%s\"",
+            config_file_path.c_str());
+
+        std::string error_msg;
+
+        LOG_ALWAYS_FATAL_IF(
+            !ReadConfig(config_file_path, sonames,
+                        [&company_name](const std::string& soname, std::string* error_msg) {
+                          if (android::base::StartsWith(soname, "lib") &&
+                              android::base::EndsWith(soname, "." + company_name + ".so")) {
+                            return true;
+                          } else {
+                            *error_msg = "Library name \"" + soname +
+                                         "\" does not end with the company name: " + company_name +
+                                         ".";
+                            return false;
+                          }
+                        },
+                        &error_msg),
+            "Error reading public native library list from \"%s\": %s", config_file_path.c_str(),
+            error_msg.c_str());
+      }
+    }
+  }
+}
+
+static std::string InitDefaultPublicLibraries() {
+  std::string config_file = root_dir() + kDefaultPublicLibrariesFile;
+  std::vector<std::string> sonames;
+  std::string error_msg;
+  LOG_ALWAYS_FATAL_IF(!ReadConfig(config_file, &sonames, always_true, &error_msg),
+                      "Error reading public native library list from \"%s\": %s",
+                      config_file.c_str(), error_msg.c_str());
+
+  std::string additional_libs = additional_public_libraries();
+  if (!additional_libs.empty()) {
+    auto vec = base::Split(additional_libs, ":");
+    std::copy(vec.begin(), vec.end(), std::back_inserter(sonames));
+  }
+
+  // Remove the public libs in the runtime namespace.
+  // These libs are listed in public.android.txt, but we don't want the rest of android
+  // in default namespace to dlopen the libs.
+  // For example, libicuuc.so is exposed to classloader namespace from runtime namespace.
+  // Unfortunately, it does not have stable C symbols, and default namespace should only use
+  // stable symbols in libandroidicu.so. http://b/120786417
+  for (const std::string& lib_name : kRuntimePublicLibraries) {
+    std::string path(kRuntimeApexLibPath);
+    path.append("/").append(lib_name);
+
+    struct stat s;
+    // Do nothing if the path in /apex does not exist.
+    // Runtime APEX must be mounted since libnativeloader is in the same APEX
+    if (stat(path.c_str(), &s) != 0) {
+      continue;
+    }
+
+    auto it = std::find(sonames.begin(), sonames.end(), lib_name);
+    if (it != sonames.end()) {
+      sonames.erase(it);
+    }
+  }
+  return android::base::Join(sonames, ':');
+}
+
+static std::string InitRuntimePublicLibraries() {
+  CHECK(sizeof(kRuntimePublicLibraries) > 0);
+  std::string list = android::base::Join(kRuntimePublicLibraries, ":");
+
+  std::string additional_libs = additional_public_libraries();
+  if (!additional_libs.empty()) {
+    list = list + ':' + additional_libs;
+  }
+  return list;
+}
+
+static std::string InitVendorPublicLibraries() {
+  // This file is optional, quietly ignore if the file does not exist.
+  std::vector<std::string> sonames;
+  ReadConfig(kVendorPublicLibrariesFile, &sonames, always_true, nullptr);
+  return android::base::Join(sonames, ':');
+}
+
+// read /system/etc/public.libraries-<companyname>.txt and
+// /product/etc/public.libraries-<companyname>.txt which contain partner defined
+// system libs that are exposed to apps. The libs in the txt files must be
+// named as lib<name>.<companyname>.so.
+static std::string InitExtendedPublicLibraries() {
+  std::vector<std::string> sonames;
+  ReadExtensionLibraries("/system/etc", &sonames);
+  ReadExtensionLibraries("/product/etc", &sonames);
+  return android::base::Join(sonames, ':');
+}
+
+static std::string InitLlndkLibraries() {
+  std::string config_file = kLlndkLibrariesFile;
+  InsertVndkVersionStr(&config_file);
+  std::vector<std::string> sonames;
+  ReadConfig(config_file, &sonames, always_true, nullptr);
+  return android::base::Join(sonames, ':');
+}
+
+static std::string InitVndkspLibraries() {
+  std::string config_file = kVndkLibrariesFile;
+  InsertVndkVersionStr(&config_file);
+  std::vector<std::string> sonames;
+  ReadConfig(config_file, &sonames, always_true, nullptr);
+  return android::base::Join(sonames, ':');
+}
+
+}  // namespace
+
+const std::string& default_public_libraries() {
+  static std::string list = InitDefaultPublicLibraries();
+  return list;
+}
+
+const std::string& runtime_public_libraries() {
+  static std::string list = InitRuntimePublicLibraries();
+  return list;
+}
+
+const std::string& vendor_public_libraries() {
+  static std::string list = InitVendorPublicLibraries();
+  return list;
+}
+
+const std::string& extended_public_libraries() {
+  static std::string list = InitExtendedPublicLibraries();
+  return list;
+}
+
+const std::string& llndk_libraries() {
+  static std::string list = InitLlndkLibraries();
+  return list;
+}
+
+const std::string& vndksp_libraries() {
+  static std::string list = InitVndkspLibraries();
+  return list;
+}
+
+}  // namespace android::nativeloader
diff --git a/libnativeloader/public_libraries.h b/libnativeloader/public_libraries.h
new file mode 100644
index 0000000..9b6dea8
--- /dev/null
+++ b/libnativeloader/public_libraries.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <string>
+
+namespace android::nativeloader {
+
+// These provide the list of libraries that are available to the namespace for apps.
+// Not all of the libraries are available to apps. Depending on the context,
+// e.g., if it is a vendor app or not, different set of libraries are made available.
+const std::string& default_public_libraries();
+const std::string& runtime_public_libraries();
+const std::string& vendor_public_libraries();
+const std::string& extended_public_libraries();
+const std::string& llndk_libraries();
+const std::string& vndksp_libraries();
+
+};  // namespace android::nativeloader
diff --git a/libnativeloader/utils.h b/libnativeloader/utils.h
new file mode 100644
index 0000000..a1c2be5
--- /dev/null
+++ b/libnativeloader/utils.h
@@ -0,0 +1,26 @@
+/*
+ * 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
+
+namespace android::nativeloader {
+
+#if defined(__LP64__)
+#define LIB "lib64"
+#else
+#define LIB "lib"
+#endif
+
+}  // namespace android::nativeloader
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 78a02e5..0207a75 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -32,6 +32,8 @@
     shared_libs: [
         "libbase",
         "libcgrouprc",
+    ],
+    static_libs: [
         "libjsoncpp",
     ],
     // for cutils/android_filesystem_config.h
diff --git a/libsparse/sparse.cpp b/libsparse/sparse.cpp
index cb288c5..24c6379 100644
--- a/libsparse/sparse.cpp
+++ b/libsparse/sparse.cpp
@@ -188,7 +188,7 @@
                               int (*write)(void* priv, const void* data, size_t len,
                                            unsigned int block, unsigned int nr_blocks),
                               void* priv) {
-  int ret;
+  int ret = 0;
   int chunks;
   struct chunk_data chk;
   struct output_file* out;
diff --git a/libsync/Android.bp b/libsync/Android.bp
index e56f8ba..c996e1b 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -23,6 +23,7 @@
 cc_library {
     name: "libsync",
     recovery_available: true,
+    native_bridge_supported: true,
     defaults: ["libsync_defaults"],
 }
 
diff --git a/libsysutils/Android.bp b/libsysutils/Android.bp
index da5d86c..ccda5d1 100644
--- a/libsysutils/Android.bp
+++ b/libsysutils/Android.bp
@@ -26,6 +26,19 @@
     ],
 
     export_include_dirs: ["include"],
+
+    tidy: true,
+    tidy_checks: [
+        "-*",
+        "cert-*",
+        "clang-analyzer-security*",
+        "android-*",
+    ],
+    tidy_checks_as_errors: [
+        "cert-*",
+        "clang-analyzer-security*",
+        "android-*",
+    ],
 }
 
 cc_test {
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 9dc2699..8fe7854 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -39,9 +39,12 @@
 const int LOCAL_QLOG_NL_EVENT = 112;
 const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
 
+#include <android-base/parseint.h>
 #include <log/log.h>
 #include <sysutils/NetlinkEvent.h>
 
+using android::base::ParseInt;
+
 NetlinkEvent::NetlinkEvent() {
     mAction = Action::kUnknown;
     memset(mParams, 0, sizeof(mParams));
@@ -301,8 +304,9 @@
         raw = (char*)nlAttrData(payload);
     }
 
-    char* hex = (char*) calloc(1, 5 + (len * 2));
-    strcpy(hex, "HEX=");
+    size_t hexSize = 5 + (len * 2);
+    char* hex = (char*)calloc(1, hexSize);
+    strlcpy(hex, "HEX=", hexSize);
     for (int i = 0; i < len; i++) {
         hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf];
         hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf];
@@ -474,23 +478,20 @@
         struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
         const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
 
-        // Construct "SERVERS=<comma-separated string of DNS addresses>".
-        static const char kServerTag[] = "SERVERS=";
-        static const size_t kTagLength = strlen(kServerTag);
+        // Construct a comma-separated string of DNS addresses.
         // Reserve sufficient space for an IPv6 link-local address: all but the
         // last address are followed by ','; the last is followed by '\0'.
         static const size_t kMaxSingleAddressLength =
                 INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(",");
-        const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength;
+        const size_t bufsize = numaddrs * kMaxSingleAddressLength;
         char *buf = (char *) malloc(bufsize);
         if (!buf) {
             SLOGE("RDNSS option: out of memory\n");
             return false;
         }
-        strcpy(buf, kServerTag);
-        size_t pos = kTagLength;
 
         struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
+        size_t pos = 0;
         for (int i = 0; i < numaddrs; i++) {
             if (i > 0) {
                 buf[pos++] = ',';
@@ -508,7 +509,8 @@
         mSubsystem = strdup("net");
         asprintf(&mParams[0], "INTERFACE=%s", ifname);
         asprintf(&mParams[1], "LIFETIME=%u", lifetime);
-        mParams[2] = buf;
+        asprintf(&mParams[2], "SERVERS=%s", buf);
+        free(buf);
     } else if (opthdr->nd_opt_type == ND_OPT_DNSSL) {
         // TODO: support DNSSL.
     } else {
@@ -634,7 +636,9 @@
                 else if (!strcmp(a, "change"))
                     mAction = Action::kChange;
             } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != nullptr) {
-                mSeq = atoi(a);
+                if (!ParseInt(a, &mSeq)) {
+                    SLOGE("NetlinkEvent::parseAsciiNetlinkMessage: failed to parse SEQNUM=%s", a);
+                }
             } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != nullptr) {
                 mSubsystem = strdup(a);
             } else if (param_idx < NL_PARAMS_MAX) {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 26626b5..37323dc 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -25,6 +25,7 @@
 #include <algorithm>
 
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include <demangle.h>
 
@@ -168,7 +169,7 @@
       // If this elf is memory backed, and there is a valid file, then set
       // an indicator that we couldn't open the file.
       if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
-          map_info->name[0] != '[') {
+          map_info->name[0] != '[' && !android::base::StartsWith(map_info->name, "/memfd:")) {
         elf_from_memory_not_file_ = true;
       }
       step_pc = regs_->pc();
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index f635021..30e57a1 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -126,6 +126,12 @@
     const auto& info5 = *--maps_->end();
     info5->memory_backed_elf = true;
 
+    elf = new ElfFake(new MemoryFake);
+    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+    AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf);
+    const auto& info6 = *--maps_->end();
+    info6->memory_backed_elf = true;
+
     process_memory_.reset(new MemoryFake);
   }
 
@@ -1234,6 +1240,36 @@
   EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
 }
 
+TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) {
+  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+  regs_.set_pc(0xc3050);
+  regs_.set_sp(0x10000);
+  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
+  unwinder.Unwind();
+  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+  EXPECT_FALSE(unwinder.elf_from_memory_not_file());
+
+  ASSERT_EQ(1U, unwinder.NumFrames());
+
+  auto* frame = &unwinder.frames()[0];
+  EXPECT_EQ(0U, frame->num);
+  EXPECT_EQ(0x50U, frame->rel_pc);
+  EXPECT_EQ(0xc3050U, frame->pc);
+  EXPECT_EQ(0x10000U, frame->sp);
+  EXPECT_EQ("Frame0", frame->function_name);
+  EXPECT_EQ(0U, frame->function_offset);
+  EXPECT_EQ("/memfd:/jit-cache", frame->map_name);
+  EXPECT_EQ(0U, frame->map_elf_start_offset);
+  EXPECT_EQ(0U, frame->map_exact_offset);
+  EXPECT_EQ(0xc3000U, frame->map_start);
+  EXPECT_EQ(0xc4000U, frame->map_end);
+  EXPECT_EQ(0U, frame->map_load_bias);
+  EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
+}
+
 // Verify format frame code.
 TEST_F(UnwinderTest, format_frame) {
   RegsFake regs_arm(10);
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 2d696eb..14e3e35 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -14,7 +14,9 @@
 #define DEBUG_CALLBACKS 0
 
 #include <utils/Looper.h>
+
 #include <sys/eventfd.h>
+#include <cinttypes>
 
 namespace android {
 
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 858c0bb..3843252 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -84,6 +84,7 @@
     host_supported: true,
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
     vndk: {
         enabled: true,
     },
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index ab38dfd..7eead7e 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -25,6 +25,8 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+#include <string_view>
+
 #include "android-base/off64_t.h"
 
 /* Zip compression methods we support */
@@ -39,10 +41,7 @@
 
   ZipString() {}
 
-  /*
-   * entry_name has to be an c-style string with only ASCII characters.
-   */
-  explicit ZipString(const char* entry_name);
+  explicit ZipString(std::string_view entry_name);
 
   bool operator==(const ZipString& rhs) const {
     return name && (name_length == rhs.name_length) && (memcmp(name, rhs.name, name_length) == 0);
@@ -149,8 +148,7 @@
 void CloseArchive(ZipArchiveHandle archive);
 
 /*
- * Find an entry in the Zip archive, by name. |entryName| must be a null
- * terminated string, and |data| must point to a writeable memory location.
+ * Find an entry in the Zip archive, by name. |data| must be non-null.
  *
  * Returns 0 if an entry is found, and populates |data| with information
  * about this entry. Returns negative values otherwise.
@@ -164,7 +162,7 @@
  * On non-Windows platforms this method does not modify internal state and
  * can be called concurrently.
  */
-int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data);
+int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName, ZipEntry* data);
 
 /*
  * Start iterating over all entries of a zip file. The order of iteration
@@ -180,6 +178,10 @@
  * Returns 0 on success and negative values on failure.
  */
 int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       const std::string_view optional_prefix = "",
+                       const std::string_view optional_suffix = "");
+// TODO: remove this.
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
                        const ZipString* optional_prefix, const ZipString* optional_suffix);
 
 /*
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index c6def73..3a3a694 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -249,7 +249,7 @@
   // libziparchive iteration order doesn't match the central directory.
   // We could sort, but that would cost extra and wouldn't match either.
   void* cookie;
-  int err = StartIteration(zah, &cookie, nullptr, nullptr);
+  int err = StartIteration(zah, &cookie);
   if (err != 0) {
     error(1, 0, "couldn't iterate %s: %s", archive_name, ErrorCodeString(err));
   }
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 596786a..ac3e236 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -689,72 +689,77 @@
 }
 
 struct IterationHandle {
-  uint32_t position;
-  // We're not using vector here because this code is used in the Windows SDK
-  // where the STL is not available.
-  ZipString prefix;
-  ZipString suffix;
   ZipArchive* archive;
 
-  IterationHandle(const ZipString* in_prefix, const ZipString* in_suffix) {
-    if (in_prefix) {
-      uint8_t* name_copy = new uint8_t[in_prefix->name_length];
-      memcpy(name_copy, in_prefix->name, in_prefix->name_length);
-      prefix.name = name_copy;
-      prefix.name_length = in_prefix->name_length;
-    } else {
-      prefix.name = NULL;
-      prefix.name_length = 0;
-    }
-    if (in_suffix) {
-      uint8_t* name_copy = new uint8_t[in_suffix->name_length];
-      memcpy(name_copy, in_suffix->name, in_suffix->name_length);
-      suffix.name = name_copy;
-      suffix.name_length = in_suffix->name_length;
-    } else {
-      suffix.name = NULL;
-      suffix.name_length = 0;
-    }
-  }
+  std::string prefix_holder;
+  ZipString prefix;
 
-  ~IterationHandle() {
-    delete[] prefix.name;
-    delete[] suffix.name;
-  }
+  std::string suffix_holder;
+  ZipString suffix;
+
+  uint32_t position = 0;
+
+  IterationHandle(ZipArchive* archive, const std::string_view in_prefix,
+                  const std::string_view in_suffix)
+      : archive(archive),
+        prefix_holder(in_prefix),
+        prefix(prefix_holder),
+        suffix_holder(in_suffix),
+        suffix(suffix_holder) {}
 };
 
 int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
-                       const ZipString* optional_prefix, const ZipString* optional_suffix) {
+                       const std::string_view optional_prefix,
+                       const std::string_view optional_suffix) {
   if (archive == NULL || archive->hash_table == NULL) {
     ALOGW("Zip: Invalid ZipArchiveHandle");
     return kInvalidHandle;
   }
 
-  IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix);
-  cookie->position = 0;
-  cookie->archive = archive;
+  if (optional_prefix.size() > static_cast<size_t>(UINT16_MAX) ||
+      optional_suffix.size() > static_cast<size_t>(UINT16_MAX)) {
+    ALOGW("Zip: prefix/suffix too long");
+    return kInvalidEntryName;
+  }
 
-  *cookie_ptr = cookie;
+  *cookie_ptr = new IterationHandle(archive, optional_prefix, optional_suffix);
   return 0;
 }
 
+// TODO: remove this.
+int32_t StartIteration(ZipArchiveHandle archive, void** cookie_ptr,
+                       const ZipString* optional_prefix, const ZipString* optional_suffix) {
+  std::string prefix;
+  if (optional_prefix) {
+    prefix = std::string(reinterpret_cast<const char*>(optional_prefix->name),
+                         optional_prefix->name_length);
+  }
+  std::string suffix;
+  if (optional_suffix) {
+    suffix = std::string(reinterpret_cast<const char*>(optional_suffix->name),
+                         optional_suffix->name_length);
+  }
+  return StartIteration(archive, cookie_ptr, prefix.c_str(), suffix.c_str());
+}
+
 void EndIteration(void* cookie) {
   delete reinterpret_cast<IterationHandle*>(cookie);
 }
 
-int32_t FindEntry(const ZipArchiveHandle archive, const ZipString& entryName, ZipEntry* data) {
-  if (entryName.name_length == 0) {
-    ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
+int32_t FindEntry(const ZipArchiveHandle archive, const std::string_view entryName,
+                  ZipEntry* data) {
+  if (entryName.empty() || entryName.size() > static_cast<size_t>(UINT16_MAX)) {
+    ALOGW("Zip: Invalid filename of length %zu", entryName.size());
     return kInvalidEntryName;
   }
 
-  const int64_t ent = EntryToIndex(archive->hash_table, archive->hash_table_size, entryName,
-                                   archive->central_directory.GetBasePtr());
+  const int64_t ent = EntryToIndex(archive->hash_table, archive->hash_table_size,
+                                   ZipString(entryName), archive->central_directory.GetBasePtr());
   if (ent < 0) {
-    ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
+    ALOGV("Zip: Could not find entry %.*s", static_cast<int>(entryName.size()), entryName.data());
     return static_cast<int32_t>(ent);  // kEntryNotFound is safe to truncate.
   }
-  // We know there are at most hast_table_size entries, safe to truncate.
+  // We know there are at most hash_table_size entries, safe to truncate.
   return FindEntry(archive, static_cast<uint32_t>(ent), data);
 }
 
@@ -1152,8 +1157,9 @@
   return archive->mapped_zip.GetFileDescriptor();
 }
 
-ZipString::ZipString(const char* entry_name) : name(reinterpret_cast<const uint8_t*>(entry_name)) {
-  size_t len = strlen(entry_name);
+ZipString::ZipString(std::string_view entry_name)
+    : name(reinterpret_cast<const uint8_t*>(entry_name.data())) {
+  size_t len = entry_name.size();
   CHECK_LE(len, static_cast<size_t>(UINT16_MAX));
   name_length = static_cast<uint16_t>(len);
 }
diff --git a/libziparchive/zip_archive_benchmark.cpp b/libziparchive/zip_archive_benchmark.cpp
index 46aa5a6..434f2e1 100644
--- a/libziparchive/zip_archive_benchmark.cpp
+++ b/libziparchive/zip_archive_benchmark.cpp
@@ -55,7 +55,7 @@
 
   // In order to walk through all file names in the archive, look for a name
   // that does not exist in the archive.
-  ZipString name("thisFileNameDoesNotExist");
+  std::string_view name("thisFileNameDoesNotExist");
 
   // Start the benchmark.
   while (state.KeepRunning()) {
@@ -75,7 +75,7 @@
 
   while (state.KeepRunning()) {
     OpenArchive(temp_file->path, &handle);
-    StartIteration(handle, &iteration_cookie, nullptr, nullptr);
+    StartIteration(handle, &iteration_cookie);
     while (Next(iteration_cookie, &data, &name) == 0) {
     }
     EndIteration(iteration_cookie);
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index e471d5e..993c975 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -64,12 +64,6 @@
   return OpenArchive(abs_path.c_str(), handle);
 }
 
-static void SetZipString(ZipString* zip_str, const std::string& str) {
-  zip_str->name = reinterpret_cast<const uint8_t*>(str.c_str());
-  CHECK_LE(str.size(), std::numeric_limits<uint16_t>::max());
-  zip_str->name_length = static_cast<uint16_t>(str.size());
-}
-
 TEST(ziparchive, Open) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -113,7 +107,7 @@
   close(fd);
 }
 
-static void AssertIterationOrder(const ZipString* prefix, const ZipString* suffix,
+static void AssertIterationOrder(const std::string_view prefix, const std::string_view suffix,
                                  const std::vector<std::string>& expected_names_sorted) {
   ZipArchiveHandle handle;
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -143,30 +137,26 @@
   static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/", "b/c.txt",
                                                                   "b/d.txt"};
 
-  AssertIterationOrder(nullptr, nullptr, kExpectedMatchesSorted);
+  AssertIterationOrder("", "", kExpectedMatchesSorted);
 }
 
 TEST(ziparchive, IterationWithPrefix) {
-  ZipString prefix("b/");
   static const std::vector<std::string> kExpectedMatchesSorted = {"b/", "b/c.txt", "b/d.txt"};
 
-  AssertIterationOrder(&prefix, nullptr, kExpectedMatchesSorted);
+  AssertIterationOrder("b/", "", kExpectedMatchesSorted);
 }
 
 TEST(ziparchive, IterationWithSuffix) {
-  ZipString suffix(".txt");
   static const std::vector<std::string> kExpectedMatchesSorted = {"a.txt", "b.txt", "b/c.txt",
                                                                   "b/d.txt"};
 
-  AssertIterationOrder(nullptr, &suffix, kExpectedMatchesSorted);
+  AssertIterationOrder("", ".txt", kExpectedMatchesSorted);
 }
 
 TEST(ziparchive, IterationWithPrefixAndSuffix) {
-  ZipString prefix("b");
-  ZipString suffix(".txt");
   static const std::vector<std::string> kExpectedMatchesSorted = {"b.txt", "b/c.txt", "b/d.txt"};
 
-  AssertIterationOrder(&prefix, &suffix, kExpectedMatchesSorted);
+  AssertIterationOrder("b", ".txt", kExpectedMatchesSorted);
 }
 
 TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
@@ -174,9 +164,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   void* iteration_cookie;
-  ZipString prefix("x");
-  ZipString suffix("y");
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, "x", "y"));
 
   ZipEntry data;
   ZipString name;
@@ -192,9 +180,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry data;
-  ZipString name;
-  SetZipString(&name, kATxtName);
-  ASSERT_EQ(0, FindEntry(handle, name, &data));
+  ASSERT_EQ(0, FindEntry(handle, kATxtName, &data));
 
   // Known facts about a.txt, from zipinfo -v.
   ASSERT_EQ(63, data.offset);
@@ -205,9 +191,28 @@
   ASSERT_EQ(static_cast<uint32_t>(0x438a8005), data.mod_time);
 
   // An entry that doesn't exist. Should be a negative return code.
-  ZipString absent_name;
-  SetZipString(&absent_name, kNonexistentTxtName);
-  ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
+  ASSERT_LT(FindEntry(handle, kNonexistentTxtName, &data), 0);
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, FindEntry_empty) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  ZipEntry data;
+  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, "", &data));
+
+  CloseArchive(handle);
+}
+
+TEST(ziparchive, FindEntry_too_long) {
+  ZipArchiveHandle handle;
+  ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+  std::string very_long_name(65536, 'x');
+  ZipEntry data;
+  ASSERT_EQ(kInvalidEntryName, FindEntry(handle, very_long_name, &data));
 
   CloseArchive(handle);
 }
@@ -217,7 +222,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
 
   void* iteration_cookie;
-  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, nullptr, nullptr));
+  ASSERT_EQ(0, StartIteration(handle, &iteration_cookie));
 
   ZipString name;
   ZipEntry data;
@@ -234,9 +239,7 @@
 
   // An entry that's deflated.
   ZipEntry data;
-  ZipString a_name;
-  SetZipString(&a_name, kATxtName);
-  ASSERT_EQ(0, FindEntry(handle, a_name, &data));
+  ASSERT_EQ(0, FindEntry(handle, kATxtName, &data));
   const uint32_t a_size = data.uncompressed_length;
   ASSERT_EQ(a_size, kATxtContents.size());
   uint8_t* buffer = new uint8_t[a_size];
@@ -245,9 +248,7 @@
   delete[] buffer;
 
   // An entry that's stored.
-  ZipString b_name;
-  SetZipString(&b_name, kBTxtName);
-  ASSERT_EQ(0, FindEntry(handle, b_name, &data));
+  ASSERT_EQ(0, FindEntry(handle, kBTxtName, &data));
   const uint32_t b_size = data.uncompressed_length;
   ASSERT_EQ(b_size, kBTxtContents.size());
   buffer = new uint8_t[b_size];
@@ -302,9 +303,7 @@
   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EmptyEntriesTest", &handle, false));
 
   ZipEntry entry;
-  ZipString empty_name;
-  SetZipString(&empty_name, kEmptyTxtName);
-  ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
+  ASSERT_EQ(0, FindEntry(handle, kEmptyTxtName, &entry));
   ASSERT_EQ(static_cast<uint32_t>(0), entry.uncompressed_length);
   uint8_t buffer[1];
   ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1));
@@ -327,9 +326,7 @@
   ASSERT_EQ(0, OpenArchiveFd(tmp_file.fd, "EntryLargerThan32KTest", &handle, false));
 
   ZipEntry entry;
-  ZipString ab_name;
-  SetZipString(&ab_name, kAbTxtName);
-  ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
+  ASSERT_EQ(0, FindEntry(handle, kAbTxtName, &entry));
   ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
 
   // Extract the entry to memory.
@@ -386,9 +383,7 @@
   ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
 
   ZipEntry entry;
-  ZipString name;
-  SetZipString(&name, kATxtName);
-  ASSERT_EQ(0, FindEntry(handle, name, &entry));
+  ASSERT_EQ(0, FindEntry(handle, kATxtName, &entry));
   ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, tmp_file.fd));
 
   // Assert that the first 8 bytes of the file haven't been clobbered.
@@ -424,10 +419,8 @@
             OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));
 
   // Assert one entry can be found and extracted correctly.
-  std::string BINARY_PATH("META-INF/com/google/android/update-binary");
-  ZipString binary_path(BINARY_PATH.c_str());
   ZipEntry binary_entry;
-  ASSERT_EQ(0, FindEntry(handle, binary_path, &binary_entry));
+  ASSERT_EQ(0, FindEntry(handle, "META-INF/com/google/android/update-binary", &binary_entry));
   TemporaryFile tmp_binary;
   ASSERT_NE(-1, tmp_binary.fd);
   ASSERT_EQ(0, ExtractEntryToFile(handle, &binary_entry, tmp_binary.fd));
@@ -436,9 +429,7 @@
 
 static void ZipArchiveStreamTest(ZipArchiveHandle& handle, const std::string& entry_name, bool raw,
                                  bool verified, ZipEntry* entry, std::vector<uint8_t>* read_data) {
-  ZipString name;
-  SetZipString(&name, entry_name);
-  ASSERT_EQ(0, FindEntry(handle, name, entry));
+  ASSERT_EQ(0, FindEntry(handle, entry_name, entry));
   std::unique_ptr<ZipArchiveStreamEntry> stream;
   if (raw) {
     stream.reset(ZipArchiveStreamEntry::CreateRaw(handle, *entry));
@@ -589,11 +580,7 @@
   // an entry whose name is "name" and whose size is 12 (contents =
   // "abdcdefghijk").
   ZipEntry entry;
-  ZipString name;
-  std::string name_str = "name";
-  SetZipString(&name, name_str);
-
-  ASSERT_EQ(0, FindEntry(handle, name, &entry));
+  ASSERT_EQ(0, FindEntry(handle, "name", &entry));
   ASSERT_EQ(static_cast<uint32_t>(12), entry.uncompressed_length);
 
   entry_out->resize(12);
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 63adbbc..c3da23c 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -62,7 +62,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
   EXPECT_EQ(kCompressStored, data.method);
   EXPECT_EQ(0u, data.has_data_descriptor);
   EXPECT_EQ(strlen(expected), data.compressed_length);
@@ -95,19 +95,19 @@
 
   ZipEntry data;
 
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
   EXPECT_EQ(kCompressStored, data.method);
   EXPECT_EQ(2u, data.compressed_length);
   ASSERT_EQ(2u, data.uncompressed_length);
   ASSERT_TRUE(AssertFileEntryContentsEq("he", handle, &data));
 
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file/file.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file/file.txt", &data));
   EXPECT_EQ(kCompressStored, data.method);
   EXPECT_EQ(3u, data.compressed_length);
   ASSERT_EQ(3u, data.uncompressed_length);
   ASSERT_TRUE(AssertFileEntryContentsEq("llo", handle, &data));
 
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file/file2.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file/file2.txt", &data));
   EXPECT_EQ(kCompressStored, data.method);
   EXPECT_EQ(0u, data.compressed_length);
   EXPECT_EQ(0u, data.uncompressed_length);
@@ -129,7 +129,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "align.txt", &data));
   EXPECT_EQ(0, data.offset & 0x03);
 
   CloseArchive(handle);
@@ -163,7 +163,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "align.txt", &data));
   EXPECT_EQ(0, data.offset & 0x03);
 
   struct tm mod = data.GetModificationTime();
@@ -191,7 +191,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "align.txt", &data));
   EXPECT_EQ(0, data.offset & 0xfff);
 
   CloseArchive(handle);
@@ -213,7 +213,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("align.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "align.txt", &data));
   EXPECT_EQ(0, data.offset & 0xfff);
 
   struct tm mod = data.GetModificationTime();
@@ -241,7 +241,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
   EXPECT_EQ(kCompressDeflated, data.method);
   ASSERT_EQ(4u, data.uncompressed_length);
   ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
@@ -273,7 +273,7 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "file.txt", &data));
   EXPECT_EQ(kCompressDeflated, data.method);
   EXPECT_EQ(kBufSize, data.uncompressed_length);
 
@@ -340,12 +340,12 @@
   ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
 
   ZipEntry data;
-  ASSERT_EQ(0, FindEntry(handle, ZipString("keep.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "keep.txt", &data));
   ASSERT_TRUE(AssertFileEntryContentsEq(kKeepThis, handle, &data));
 
-  ASSERT_NE(0, FindEntry(handle, ZipString("drop.txt"), &data));
+  ASSERT_NE(0, FindEntry(handle, "drop.txt", &data));
 
-  ASSERT_EQ(0, FindEntry(handle, ZipString("replace.txt"), &data));
+  ASSERT_EQ(0, FindEntry(handle, "replace.txt", &data));
   ASSERT_TRUE(AssertFileEntryContentsEq(kReplaceWithThis, handle, &data));
 
   CloseArchive(handle);
diff --git a/logd/tests/Android.bp b/logd/tests/Android.bp
index 83a194f..d39da8a 100644
--- a/logd/tests/Android.bp
+++ b/logd/tests/Android.bp
@@ -35,12 +35,12 @@
 
     srcs: ["logd_test.cpp"],
 
-    shared_libs: [
+    static_libs: [
         "libbase",
         "libcutils",
         "libselinux",
+        "liblog",
     ],
-    static_libs: ["liblog"],
 }
 
 // Build tests for the logger. Run with:
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
index 5c57d69..ac802b5 100644
--- a/property_service/libpropertyinfoparser/Android.bp
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -3,6 +3,7 @@
     host_supported: true,
     vendor_available: true,
     recovery_available: true,
+    native_bridge_supported: true,
     srcs: ["property_info_parser.cpp"],
 
     cpp_std: "experimental",
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
index f484550..33da1f1 100644
--- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -585,6 +585,7 @@
       {"ro.boottime.imsdatadaemon", "u:object_r:boottime_prop:s0"},
       {"ro.boottime.imsqmidaemon", "u:object_r:boottime_prop:s0"},
       {"ro.boottime.init", "u:object_r:boottime_prop:s0"},
+      {"ro.boottime.init.first_stage", "u:object_r:boottime_prop:s0"},
       {"ro.boottime.init.cold_boot_wait", "u:object_r:boottime_prop:s0"},
       {"ro.boottime.init.mount_all.default", "u:object_r:boottime_prop:s0"},
       {"ro.boottime.init.selinux", "u:object_r:boottime_prop:s0"},
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index 485bc75..4b07478 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -20,6 +20,9 @@
 
 [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}
@@ -41,7 +44,7 @@
 
 additional.namespaces = runtime,conscrypt,media,resolv
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# 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 runtime namespace. And then, if the
@@ -50,9 +53,6 @@
 # Finally, if all attempts fail, the dynamic linker returns an error.
 namespace.default.links = runtime,resolv
 namespace.default.asan.links = runtime,resolv
-# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
-# libart.
-namespace.default.visible = true
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -72,11 +72,13 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
+# Visible to allow links to be created at runtime, e.g. through
+# android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -120,11 +122,11 @@
 # "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
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 264fbf4..f4710d8 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -43,6 +43,9 @@
 # can't be loaded in this namespace.
 ###############################################################################
 namespace.default.isolated = true
+# 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}
@@ -121,7 +124,7 @@
 namespace.default.asan.permitted.paths += /apex/com.android.runtime/${LIB}/bionic
 namespace.default.asan.permitted.paths += /system/${LIB}/bootstrap
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# 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 runtime namespace. And then, if the
@@ -129,9 +132,6 @@
 # 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 = runtime,resolv
-# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
-# libart.
-namespace.default.visible = true
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -151,11 +151,13 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
+# Visible to allow links to be created at runtime, e.g. through
+# android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -188,11 +190,11 @@
 # "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
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
@@ -235,6 +237,8 @@
 # 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}
@@ -324,6 +328,8 @@
 # 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
@@ -431,10 +437,10 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = system
@@ -566,6 +572,10 @@
 [unrestricted]
 additional.namespaces = runtime,media,conscrypt,resolv
 
+# 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}
@@ -577,10 +587,8 @@
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
 namespace.default.links = runtime,resolv
-namespace.default.visible = true
-
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -597,11 +605,13 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
+# Visible to allow links to be created at runtime, e.g. through
+# android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -632,11 +642,11 @@
 # "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
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 02b1bfa..4ce7f52 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -43,6 +43,9 @@
 # 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 += /odm/${LIB}
@@ -61,8 +64,7 @@
 namespace.default.asan.search.paths += /data/asan/%PRODUCT_SERVICES%/${LIB}
 namespace.default.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
 
-# Keep in sync with the platform namespace in the com.android.runtime APEX
-# ld.config.txt.
+# 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 runtime namespace. And then, if the
@@ -70,9 +72,6 @@
 # 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 = runtime,resolv
-# Visible because some libraries are dlopen'ed, e.g. libopenjdk is dlopen'ed by
-# libart.
-namespace.default.visible = true
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -92,12 +91,13 @@
 # "runtime" APEX namespace
 #
 # This namespace pulls in externally accessible libs from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
+# Visible to allow links to be created at runtime, e.g. through
+# android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# Keep in sync with the default namespace in the com.android.runtime APEX
-# ld.config.txt.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -130,11 +130,11 @@
 # "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
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
@@ -177,6 +177,8 @@
 # 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}
@@ -266,6 +268,8 @@
 # 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
@@ -369,10 +373,10 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -389,6 +393,10 @@
 [unrestricted]
 additional.namespaces = runtime,media,conscrypt,resolv
 
+# 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}
@@ -400,10 +408,8 @@
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
+# Keep in sync with the "platform" namespace in art/build/apex/ld.config.txt.
 namespace.default.links = runtime,resolv
-namespace.default.visible = true
-
 namespace.default.link.runtime.shared_libs  = libandroidicu.so
 namespace.default.link.runtime.shared_libs += libdexfile_external.so
 namespace.default.link.runtime.shared_libs += libdexfiled_external.so
@@ -420,11 +426,13 @@
 # "runtime" APEX namespace
 #
 # This namespace exposes externally accessible libraries from the Runtime APEX.
+# Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
 namespace.runtime.isolated = true
+# Visible to allow links to be created at runtime, e.g. through
+# android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.runtime.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.asan.search.paths = /apex/com.android.runtime/${LIB}
 namespace.runtime.links = default
@@ -455,11 +463,11 @@
 # "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
 
-# Keep in sync with ld.config.txt in the com.android.runtime APEX.
 namespace.conscrypt.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.asan.search.paths = /apex/com.android.conscrypt/${LIB}
 namespace.conscrypt.links = runtime,default
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 295e704..84fa46e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -80,7 +80,9 @@
     chmod 0664 /dev/stune/top-app/tasks
     chmod 0664 /dev/stune/rt/tasks
 
-    # Create blkio tuning nodes
+    # Create blkio group and apply initial settings.
+    # This feature needs kernel to support it, and the
+    # device's init.rc must actually set the correct values.
     mkdir /dev/blkio/background
     chown system system /dev/blkio
     chown system system /dev/blkio/background
@@ -88,6 +90,10 @@
     chown system system /dev/blkio/background/tasks
     chmod 0664 /dev/blkio/tasks
     chmod 0664 /dev/blkio/background/tasks
+    write /dev/blkio/blkio.weight 1000
+    write /dev/blkio/background/blkio.weight 500
+    write /dev/blkio/blkio.group_idle 0
+    write /dev/blkio/background/blkio.group_idle 0
 
     restorecon_recursive /mnt
 
@@ -405,6 +411,8 @@
     class_start early_hal
 
 on post-fs-data
+    mark_post_data
+
     # Start checkpoint before we touch data
     start vold
     exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint
@@ -747,9 +755,6 @@
 on charger
     class_start charger
 
-on property:vold.decrypt=trigger_reset_main
-    class_reset main
-
 on property:vold.decrypt=trigger_load_persist_props
     load_persist_props
     start logd
@@ -767,6 +772,8 @@
 on property:vold.decrypt=trigger_restart_framework
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier
+    class_start_post_data hal
+    class_start_post_data core
     class_start main
     class_start late_start
     setprop service.bootanim.exit 0
@@ -775,6 +782,8 @@
 on property:vold.decrypt=trigger_shutdown_framework
     class_reset late_start
     class_reset main
+    class_reset_post_data core
+    class_reset_post_data hal
 
 on property:sys.boot_completed=1
     bootchart stop
diff --git a/usbd/usbd.cpp b/usbd/usbd.cpp
index 41cd8dd..191fb92 100644
--- a/usbd/usbd.cpp
+++ b/usbd/usbd.cpp
@@ -22,15 +22,20 @@
 #include <android-base/properties.h>
 #include <android/hardware/usb/gadget/1.0/IUsbGadget.h>
 
+#include <hidl/HidlTransportSupport.h>
+
 #define PERSISTENT_USB_CONFIG "persist.sys.usb.config"
 
 using android::base::GetProperty;
 using android::base::SetProperty;
+using android::hardware::configureRpcThreadpool;
 using android::hardware::usb::gadget::V1_0::GadgetFunction;
 using android::hardware::usb::gadget::V1_0::IUsbGadget;
 using android::hardware::Return;
 
 int main(int /*argc*/, char** /*argv*/) {
+    configureRpcThreadpool(1, true /*callerWillJoin*/);
+
     android::sp<IUsbGadget> gadget = IUsbGadget::getService();
     Return<void> ret;