Merge "Fix fastdeploy issues when testing Boat Attack Unity3D demo"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index c47230f..f9c3b4a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -2,6 +2,30 @@
   "presubmit": [
     {
       "name": "adbd_test"
+    },
+    {
+      "name": "debuggerd_test"
+    },
+    {
+      "name": "init_tests"
+    },
+    {
+      "name": "libbase_test"
+    },
+    {
+      "name": "libprocinfo_test"
+    },
+    {
+      "name": "memunreachable_test"
+    },
+    {
+      "name": "memunreachable_binder_test"
+    },
+    {
+      "name": "propertyinfoserializer_tests"
+    },
+    {
+      "name": "ziparchive-tests"
     }
   ]
 }
diff --git a/adb/Android.bp b/adb/Android.bp
index 00e98fe..e994075 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -285,6 +285,15 @@
         "deploypatchgenerator",
     ],
 
+    // Archive adb, adb.exe.
+    dist: {
+        targets: [
+            "dist_files",
+            "sdk",
+            "win_sdk",
+        ],
+    },
+
     target: {
         darwin: {
             cflags: [
diff --git a/adb/Android.mk b/adb/Android.mk
deleted file mode 100644
index 8b2d558..0000000
--- a/adb/Android.mk
+++ /dev/null
@@ -1,8 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-# Archive adb, adb.exe.
-$(call dist-for-goals,dist_files sdk win_sdk,$(HOST_OUT_EXECUTABLES)/adb)
-
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_adb.BUILT))
-endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 715e04f..2fc8478 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -36,6 +36,7 @@
 void adb_auth_init();
 
 int adb_auth_keygen(const char* filename);
+int adb_auth_pubkey(const char* filename);
 std::string adb_auth_get_userkey();
 std::deque<std::shared_ptr<RSA>> adb_auth_get_private_keys();
 
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index 71c19b8..bcb829b 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -43,6 +43,7 @@
 
 #include "adb.h"
 #include "adb_auth.h"
+#include "adb_io.h"
 #include "adb_utils.h"
 #include "sysdeps.h"
 #include "transport.h"
@@ -52,30 +53,7 @@
     *new std::map<std::string, std::shared_ptr<RSA>>;
 static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
 
-static std::string get_user_info() {
-    LOG(INFO) << "get_user_info...";
-
-    std::string hostname;
-    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
-    char buf[64];
-    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
-    if (hostname.empty()) hostname = "unknown";
-
-    std::string username;
-    if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
-    if (username.empty() && getlogin()) username = getlogin();
-#endif
-    if (username.empty()) hostname = "unknown";
-
-    return " " + username + "@" + hostname;
-}
-
-static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
-    LOG(INFO) << "write_public_keyfile...";
-
+static bool calculate_public_key(std::string* out, RSA* private_key) {
     uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
     if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
         LOG(ERROR) << "Failed to convert to public key";
@@ -88,20 +66,10 @@
         return false;
     }
 
-    std::string content;
-    content.resize(expected_length);
-    size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+    out->resize(expected_length);
+    size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
                                            sizeof(binary_key_data));
-    content.resize(actual_length);
-
-    content += get_user_info();
-
-    std::string path(private_key_path + ".pub");
-    if (!android::base::WriteStringToFile(content, path)) {
-        PLOG(ERROR) << "Failed to write public key to '" << path << "'";
-        return false;
-    }
-
+    out->resize(actual_length);
     return true;
 }
 
@@ -140,11 +108,6 @@
         goto out;
     }
 
-    if (!write_public_keyfile(rsa, file)) {
-        D("Failed to write public key");
-        goto out;
-    }
-
     ret = 1;
 
 out:
@@ -170,36 +133,41 @@
     return result;
 }
 
-static bool read_key_file(const std::string& file) {
-    LOG(INFO) << "read_key_file '" << file << "'...";
-
+static std::shared_ptr<RSA> read_key_file(const std::string& file) {
     std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file.c_str(), "r"), fclose);
     if (!fp) {
         PLOG(ERROR) << "Failed to open '" << file << "'";
-        return false;
+        return nullptr;
     }
 
     RSA* key = RSA_new();
     if (!PEM_read_RSAPrivateKey(fp.get(), &key, nullptr, nullptr)) {
         LOG(ERROR) << "Failed to read key";
         RSA_free(key);
+        return nullptr;
+    }
+
+    return std::shared_ptr<RSA>(key, RSA_free);
+}
+
+static bool load_key(const std::string& file) {
+    std::shared_ptr<RSA> key = read_key_file(file);
+    if (!key) {
         return false;
     }
 
     std::lock_guard<std::mutex> lock(g_keys_mutex);
-    std::string fingerprint = hash_key(key);
+    std::string fingerprint = hash_key(key.get());
     if (g_keys.find(fingerprint) != g_keys.end()) {
         LOG(INFO) << "ignoring already-loaded key: " << file;
-        RSA_free(key);
     } else {
-        g_keys[fingerprint] = std::shared_ptr<RSA>(key, RSA_free);
+        g_keys[fingerprint] = std::move(key);
     }
-
     return true;
 }
 
-static bool read_keys(const std::string& path, bool allow_dir = true) {
-    LOG(INFO) << "read_keys '" << path << "'...";
+static bool load_keys(const std::string& path, bool allow_dir = true) {
+    LOG(INFO) << "load_keys '" << path << "'...";
 
     struct stat st;
     if (stat(path.c_str(), &st) != 0) {
@@ -208,7 +176,7 @@
     }
 
     if (S_ISREG(st.st_mode)) {
-        return read_key_file(path);
+        return load_key(path);
     } else if (S_ISDIR(st.st_mode)) {
         if (!allow_dir) {
             // inotify isn't recursive. It would break expectations to load keys in nested
@@ -237,7 +205,7 @@
                 continue;
             }
 
-            result |= read_key_file((path + OS_PATH_SEPARATOR + name));
+            result |= load_key((path + OS_PATH_SEPARATOR + name));
         }
         return result;
     }
@@ -250,7 +218,7 @@
     return adb_get_android_dir_path() + OS_PATH_SEPARATOR + "adbkey";
 }
 
-static bool get_user_key() {
+static bool generate_userkey() {
     std::string path = get_user_key_path();
     if (path.empty()) {
         PLOG(ERROR) << "Error getting user key filename";
@@ -266,7 +234,7 @@
         }
     }
 
-    return read_key_file(path);
+    return load_key(path);
 }
 
 static std::set<std::string> get_vendor_keys() {
@@ -320,26 +288,42 @@
     return result;
 }
 
+static bool pubkey_from_privkey(std::string* out, const std::string& path) {
+    std::shared_ptr<RSA> privkey = read_key_file(path);
+    if (!privkey) {
+        return false;
+    }
+    return calculate_public_key(out, privkey.get());
+}
+
 std::string adb_auth_get_userkey() {
     std::string path = get_user_key_path();
     if (path.empty()) {
         PLOG(ERROR) << "Error getting user key filename";
         return "";
     }
-    path += ".pub";
 
-    std::string content;
-    if (!android::base::ReadFileToString(path, &content)) {
-        PLOG(ERROR) << "Can't load '" << path << "'";
+    std::string result;
+    if (!pubkey_from_privkey(&result, path)) {
         return "";
     }
-    return content;
+    return result;
 }
 
 int adb_auth_keygen(const char* filename) {
     return (generate_key(filename) == 0);
 }
 
+int adb_auth_pubkey(const char* filename) {
+    std::string pubkey;
+    if (!pubkey_from_privkey(&pubkey, filename)) {
+        return 1;
+    }
+    pubkey.push_back('\n');
+
+    return WriteFdExactly(STDOUT_FILENO, pubkey.data(), pubkey.size()) ? 0 : 1;
+}
+
 #if defined(__linux__)
 static void adb_auth_inotify_update(int fd, unsigned fd_event, void*) {
     LOG(INFO) << "adb_auth_inotify_update called";
@@ -380,7 +364,7 @@
                     LOG(INFO) << "ignoring new directory at '" << path << "'";
                 } else {
                     LOG(INFO) << "observed new file at '" << path << "'";
-                    read_keys(path, false);
+                    load_keys(path, false);
                 }
             } else {
                 LOG(WARNING) << "unmonitored event for " << path << ": 0x" << std::hex
@@ -420,8 +404,8 @@
 void adb_auth_init() {
     LOG(INFO) << "adb_auth_init...";
 
-    if (!get_user_key()) {
-        LOG(ERROR) << "Failed to get user key";
+    if (!generate_userkey()) {
+        LOG(ERROR) << "Failed to generate user key";
         return;
     }
 
@@ -432,7 +416,7 @@
 #endif
 
     for (const std::string& path : key_paths) {
-        read_keys(path.c_str());
+        load_keys(path.c_str());
     }
 }
 
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index b5bed28..c11052d 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -185,7 +185,6 @@
         " enable-verity            re-enable dm-verity checking on userdebug builds\n"
         " keygen FILE\n"
         "     generate adb public/private key; private key stored in FILE,\n"
-        "     public key stored in FILE.pub (existing files overwritten)\n"
         "\n"
         "scripting:\n"
         " wait-for[-TRANSPORT]-STATE\n"
@@ -1756,14 +1755,14 @@
         // Always print key generation information for keygen command.
         adb_trace_enable(AUTH);
         return adb_auth_keygen(argv[1]);
-    }
-    else if (!strcmp(argv[0], "jdwp")) {
+    } else if (!strcmp(argv[0], "pubkey")) {
+        if (argc != 2) error_exit("pubkey requires an argument");
+        return adb_auth_pubkey(argv[1]);
+    } else if (!strcmp(argv[0], "jdwp")) {
         return adb_connect_command("jdwp");
-    }
-    else if (!strcmp(argv[0], "track-jdwp")) {
+    } else if (!strcmp(argv[0], "track-jdwp")) {
         return adb_connect_command("track-jdwp");
-    }
-    else if (!strcmp(argv[0], "track-devices")) {
+    } else if (!strcmp(argv[0], "track-devices")) {
         return adb_connect_command("host:track-devices");
     } else if (!strcmp(argv[0], "raw")) {
         if (argc != 2) {
@@ -1772,13 +1771,11 @@
         return adb_connect_command(argv[1]);
     }
 
-
     /* "adb /?" is a common idiom under Windows */
     else if (!strcmp(argv[0], "--help") || !strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
         help();
         return 0;
-    }
-    else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
+    } else if (!strcmp(argv[0], "--version") || !strcmp(argv[0], "version")) {
         fprintf(stdout, "%s", adb_version().c_str());
         return 0;
     } else if (!strcmp(argv[0], "features")) {
diff --git a/adb/fastdeploy/OWNERS b/adb/fastdeploy/OWNERS
new file mode 100644
index 0000000..d145834
--- /dev/null
+++ b/adb/fastdeploy/OWNERS
@@ -0,0 +1 @@
+idries@google.com
diff --git a/cpio/Android.bp b/cpio/Android.bp
index 847e0f1..baa0319 100644
--- a/cpio/Android.bp
+++ b/cpio/Android.bp
@@ -5,4 +5,7 @@
     srcs: ["mkbootfs.c"],
     cflags: ["-Werror"],
     shared_libs: ["libcutils"],
+    dist: {
+        targets: ["dist_files"],
+    },
 }
diff --git a/cpio/Android.mk b/cpio/Android.mk
deleted file mode 100644
index fc3551b..0000000
--- a/cpio/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2005 The Android Open Source Project
-
-$(call dist-for-goals,dist_files,$(ALL_MODULES.mkbootfs.BUILT))
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 577e336..d79d20b 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -348,8 +348,16 @@
   return vm_pid;
 }
 
+static void InstallSigPipeHandler() {
+  struct sigaction action = {};
+  action.sa_handler = SIG_IGN;
+  action.sa_flags = SA_RESTART;
+  sigaction(SIGPIPE, &action, nullptr);
+}
+
 int main(int argc, char** argv) {
   DefuseSignalHandlers();
+  InstallSigPipeHandler();
 
   atrace_begin(ATRACE_TAG, "before reparent");
   pid_t target_process = getppid();
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 0b8a936..1179263 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -78,7 +78,7 @@
   _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
 }
 
-static void dump_probable_cause(log_t* log, const siginfo_t* si) {
+static void dump_probable_cause(log_t* log, const siginfo_t* si, BacktraceMap* map) {
   std::string cause;
   if (si->si_signo == SIGSEGV && si->si_code == SEGV_MAPERR) {
     if (si->si_addr < reinterpret_cast<void*>(4096)) {
@@ -94,6 +94,14 @@
     } else if (si->si_addr == reinterpret_cast<void*>(0xffff0f60)) {
       cause = "call to kuser_cmpxchg64";
     }
+  } else if (si->si_signo == SIGSEGV && si->si_code == SEGV_ACCERR) {
+    for (auto it = map->begin(); it != map->end(); ++it) {
+      const backtrace_map_t* entry = *it;
+      if (si->si_addr >= reinterpret_cast<void*>(entry->start) &&
+          si->si_addr < reinterpret_cast<void*>(entry->end) && entry->flags == PROT_EXEC) {
+        cause = "execute-only (no-read) memory access error; likely due to data in .text.";
+      }
+    }
   } else if (si->si_signo == SIGSYS && si->si_code == SYS_SECCOMP) {
     cause = StringPrintf("seccomp prevented call to disallowed %s system call %d", ABI_STRING,
                          si->si_syscall);
@@ -125,8 +133,6 @@
   _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s%s), fault addr %s\n",
        thread_info.siginfo->si_signo, get_signame(thread_info.siginfo),
        thread_info.siginfo->si_code, get_sigcode(thread_info.siginfo), sender_desc, addr_desc);
-
-  dump_probable_cause(log, thread_info.siginfo);
 }
 
 static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) {
@@ -426,6 +432,7 @@
 
   if (thread_info.siginfo) {
     dump_signal_info(log, thread_info, process_memory);
+    dump_probable_cause(log, thread_info.siginfo, map);
   }
 
   if (primary_thread) {
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index faed376..8006c41 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -260,6 +260,13 @@
         "mke2fs",
         "make_f2fs",
     ],
+    dist: {
+        targets: [
+            "dist_files",
+            "sdk",
+            "win_sdk",
+        ],
+    },
 
     target: {
         not_windows: {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index e4c1317..17ec392 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,13 +18,9 @@
 # Package fastboot-related executables.
 #
 
-my_dist_files := $(HOST_OUT_EXECUTABLES)/fastboot
-my_dist_files += $(HOST_OUT_EXECUTABLES)/mke2fs
+my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
 my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
 my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
 my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk win_sdk,$(my_dist_files))
-ifdef HOST_CROSS_OS
-$(call dist-for-goals,dist_files sdk win_sdk,$(ALL_MODULES.host_cross_fastboot.BUILT))
-endif
 my_dist_files :=
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e066bff..fee0857 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -46,6 +46,7 @@
 #include <chrono>
 #include <functional>
 #include <regex>
+#include <string>
 #include <thread>
 #include <utility>
 #include <vector>
@@ -78,6 +79,7 @@
 using android::base::Split;
 using android::base::Trim;
 using android::base::unique_fd;
+using namespace std::string_literals;
 
 static const char* serial = nullptr;
 
@@ -162,9 +164,17 @@
         // clang-format on
 };
 
-static std::string find_item_given_name(const std::string& img_name) {
+static char* get_android_product_out() {
     char* dir = getenv("ANDROID_PRODUCT_OUT");
     if (dir == nullptr || dir[0] == '\0') {
+        return nullptr;
+    }
+    return dir;
+}
+
+static std::string find_item_given_name(const std::string& img_name) {
+    char* dir = get_android_product_out();
+    if (!dir) {
         die("ANDROID_PRODUCT_OUT not set");
     }
     return std::string(dir) + "/" + img_name;
@@ -1098,6 +1108,14 @@
     return fb->GetVar("is-logical:" + partition, &value) == fastboot::SUCCESS && value == "yes";
 }
 
+static bool is_retrofit_device() {
+    std::string value;
+    if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
+        return false;
+    }
+    return android::base::StartsWith(value, "system_");
+}
+
 static void do_flash(const char* pname, const char* fname) {
     struct fastboot_buffer buf;
 
@@ -1311,6 +1329,19 @@
         command += ":wipe";
     }
     fb->RawCommand(command, "Updating super partition");
+
+    // Retrofit devices have two super partitions, named super_a and super_b.
+    // On these devices, secondary slots must be flashed as physical
+    // partitions (otherwise they would not mount on first boot). To enforce
+    // this, we delete any logical partitions for the "other" slot.
+    if (is_retrofit_device()) {
+        for (const auto& [image, slot] : os_images_) {
+            std::string partition_name = image->part_name + "_"s + slot;
+            if (image->IsSecondary() && is_logical(partition_name)) {
+                fb->DeletePartition(partition_name);
+            }
+        }
+    }
 }
 
 class ZipImageSource final : public ImageSource {
@@ -1466,15 +1497,13 @@
             fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str());
             return;
         }
-        fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n",
-                partition_type.c_str());
-        return;
+        die("Formatting is not supported for file system with type '%s'.",
+            partition_type.c_str());
     }
 
     int64_t size;
     if (!android::base::ParseInt(partition_size, &size)) {
-        fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str());
-        return;
+        die("Couldn't parse partition size '%s'.", partition_size.c_str());
     }
 
     unsigned eraseBlkSize, logicalBlkSize;
@@ -1484,17 +1513,14 @@
     if (fs_generator_generate(gen, output.path, size, initial_dir,
             eraseBlkSize, logicalBlkSize)) {
         die("Cannot generate image for %s", partition.c_str());
-        return;
     }
 
     fd.reset(open(output.path, O_RDONLY));
     if (fd == -1) {
-        fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno));
-        return;
+        die("Cannot open generated image: %s", strerror(errno));
     }
     if (!load_buf_fd(fd.release(), &buf)) {
-        fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
-        return;
+        die("Cannot read image: %s", strerror(errno));
     }
     flash_buf(partition, &buf);
     return;
@@ -1505,9 +1531,15 @@
         if (errMsg) fprintf(stderr, "%s", errMsg);
     }
     fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str());
+    if (!skip_if_not_supported) {
+        die("Command failed");
+    }
 }
 
 static bool should_flash_in_userspace(const std::string& partition_name) {
+    if (!get_android_product_out()) {
+        return false;
+    }
     auto path = find_item_given_name("super_empty.img");
     if (path.empty()) {
         return false;
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index fc6a16b..8c0aa6b 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -172,13 +172,8 @@
     mkf2fs_args.push_back("-S");
     std::string size_str = std::to_string(partSize);
     mkf2fs_args.push_back(size_str.c_str());
-    mkf2fs_args.push_back("-f");
-    mkf2fs_args.push_back("-O");
-    mkf2fs_args.push_back("encrypt");
-    mkf2fs_args.push_back("-O");
-    mkf2fs_args.push_back("quota");
-    mkf2fs_args.push_back("-O");
-    mkf2fs_args.push_back("verity");
+    mkf2fs_args.push_back("-g");
+    mkf2fs_args.push_back("android");
     mkf2fs_args.push_back(fileName);
     mkf2fs_args.push_back(nullptr);
 
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 6c8a943..f150af3 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -42,8 +42,6 @@
         "fs_mgr.cpp",
         "fs_mgr_format.cpp",
         "fs_mgr_verity.cpp",
-        "fs_mgr_avb.cpp",
-        "fs_mgr_avb_ops.cpp",
         "fs_mgr_dm_linear.cpp",
         "fs_mgr_overlayfs.cpp",
         "fs_mgr_vendor_overlay.cpp",
@@ -61,10 +59,12 @@
     ],
     static_libs: [
         "libavb",
+        "libfs_avb",
         "libfstab",
         "libdm",
     ],
     export_static_lib_headers: [
+        "libfs_avb",
         "libfstab",
         "libdm",
     ],
@@ -104,3 +104,28 @@
     export_include_dirs: ["include_fstab"],
     header_libs: ["libbase_headers"],
 }
+
+cc_library_static {
+    name: "libfs_avb",
+    defaults: ["fs_mgr_defaults"],
+    recovery_available: true,
+    export_include_dirs: ["libfs_avb/include"],
+    srcs: [
+        "libfs_avb/avb_ops.cpp",
+        "libfs_avb/fs_avb.cpp",
+    ],
+    static_libs: [
+        "libavb",
+        "libfstab",
+        "libdm",
+    ],
+    export_static_lib_headers: [
+        "libfstab",
+    ],
+    shared_libs: [
+        "libcrypto",
+    ],
+    header_libs: [
+        "libbase_headers",
+    ],
+}
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
new file mode 100644
index 0000000..d715d7b
--- /dev/null
+++ b/fs_mgr/README.overlayfs.md
@@ -0,0 +1,92 @@
+Android Overlayfs integration with adb remount
+==============================================
+
+Introduction
+------------
+
+Users working with userdebug or eng builds expect to be able to
+remount the system partition as read-write and then add or modify
+any number of files without reflashing the system image, which is
+understandably efficient for a development cycle.
+Limited memory systems that chose to use readonly filesystems like
+*squashfs*, or *Logical Resizable Android Partitions* which land
+system partition images right-sized, and with filesystem that have
+been deduped on the block level to compress the content; means that
+either a remount is not possible directly, or when done offers
+little or no utility because of remaining space limitations or
+support logistics.
+
+*Overlayfs* comes to the rescue for these debug scenarios, and logic
+will _automatically_ setup backing storage for a writable filesystem
+as an upper reference, and mount overtop the lower.  These actions
+will be performed in the **adb disable-verity** and **adb remount**
+requests.
+
+Operations
+----------
+
+### Cookbook
+
+The typical action to utilize the remount facility is:
+
+    $ adb root
+    $ adb disable-verity
+    $ adb reboot
+    $ adb wait-for-device
+    $ adb root
+    $ adb remount
+
+Followed by one of the following:
+
+    $ adb stop
+    $ adb sync
+    $ adb start
+    $ adb reboot
+
+*or*
+
+    $ adb push <source> <destination>
+    $ adb reboot
+
+Note that the sequence above:
+
+    $ adb disable-verity
+    $ adb reboot
+
+can be replaced with:
+
+    $ adb reboot -R
+
+which will not reboot if everything is already prepared and ready
+to go.
+
+None of this changes if *overlayfs* needs to be engaged.
+The decisions whether to use traditional direct filesystem remount,
+or one wrapped by *overlayfs* is automatically determined based on
+a probe of the filesystem types and space remaining.
+
+### Backing Storage
+
+When *overlayfs* logic is feasible, it will use either the
+**/cache/overlay/** directory for non-A/B devices, or the
+**/mnt/scratch/overlay** directory for A/B devices that have
+access to *Logical Resizeable Android Partitions*.
+The backing store is used as soon as possible in the boot
+process and can occur at first stage init, or at the
+mount_all init rc commands.
+
+This early as possible attachment of *overlayfs* means that
+*sepolicy* or *init* itself can also be pushed and used after
+the exec phases that accompany each stage.
+
+Caveats
+-------
+
+- Space used in the backing storage is on a file by file basis
+  and will require more space than if updated in place.
+- Kernel must have CONFIG_OVERLAY_FS=y and will need to be patched
+  with "*overlayfs: override_creds=off option bypass creator_cred*"
+  if higher than 4.6.
+- *adb enable-verity* will free up overlayfs and as a bonus the
+  device will be reverted pristine to before any content was updated.
+- File bugs or submit fixes for review.
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 8e57e1e..1ba956d 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -34,6 +34,7 @@
 #include <unistd.h>
 
 #include <functional>
+#include <map>
 #include <memory>
 #include <string>
 #include <thread>
@@ -53,6 +54,7 @@
 #include <ext4_utils/ext4_sb.h>
 #include <ext4_utils/ext4_utils.h>
 #include <ext4_utils/wipe.h>
+#include <fs_avb/fs_avb.h>
 #include <fs_mgr_overlayfs.h>
 #include <libdm/dm.h>
 #include <liblp/metadata_format.h>
@@ -62,7 +64,6 @@
 #include <log/log_properties.h>
 #include <logwrap/logwrap.h>
 
-#include "fs_mgr_avb.h"
 #include "fs_mgr_priv.h"
 
 #define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
@@ -82,6 +83,9 @@
 
 using android::dm::DeviceMapper;
 using android::dm::DmDeviceState;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
 
 // record fs stat
 enum FsStatFlags {
@@ -973,7 +977,7 @@
     int mount_errno = 0;
     int attempted_idx = -1;
     CheckpointManager checkpoint_manager;
-    FsManagerAvbUniquePtr avb_handle(nullptr);
+    AvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
         return FS_MGR_MNTALL_FAIL;
@@ -1031,14 +1035,14 @@
 
         if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
             if (!avb_handle) {
-                avb_handle = FsManagerAvbHandle::Open();
+                avb_handle = AvbHandle::Open();
                 if (!avb_handle) {
-                    LERROR << "Failed to open FsManagerAvbHandle";
+                    LERROR << "Failed to open AvbHandle";
                     return FS_MGR_MNTALL_FAIL;
                 }
             }
             if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
-                SetUpAvbHashtreeResult::kFail) {
+                AvbHashtreeResult::kFail) {
                 LERROR << "Failed to set up AVB on partition: "
                        << fstab->recs[i].mount_point << ", skipping!";
                 /* Skips mounting the device. */
@@ -1232,7 +1236,7 @@
     int first_mount_errno = 0;
     char* mount_point;
     CheckpointManager checkpoint_manager(needs_checkpoint);
-    FsManagerAvbUniquePtr avb_handle(nullptr);
+    AvbUniquePtr avb_handle(nullptr);
 
     if (!fstab) {
         return FS_MGR_DOMNT_FAILED;
@@ -1275,14 +1279,14 @@
 
         if (fstab->recs[i].fs_mgr_flags & MF_AVB) {
             if (!avb_handle) {
-                avb_handle = FsManagerAvbHandle::Open();
+                avb_handle = AvbHandle::Open();
                 if (!avb_handle) {
-                    LERROR << "Failed to open FsManagerAvbHandle";
+                    LERROR << "Failed to open AvbHandle";
                     return FS_MGR_DOMNT_FAILED;
                 }
             }
             if (avb_handle->SetUpAvbHashtree(&fstab->recs[i], true /* wait_for_verity_dev */) ==
-                SetUpAvbHashtreeResult::kFail) {
+                AvbHashtreeResult::kFail) {
                 LERROR << "Failed to set up AVB on partition: "
                        << fstab->recs[i].mount_point << ", skipping!";
                 /* Skips mounting the device. */
@@ -1603,9 +1607,6 @@
         } else if (slot == -1) {
             suffix = fs_mgr_get_slot_suffix();
         }
-        if (suffix.empty()) {
-            LFATAL << "Super partition name can only be overridden on A/B devices.";
-        }
         return super_partition + suffix;
     }
     return LP_METADATA_DEFAULT_PARTITION_NAME;
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 845cca9..0983663 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -117,12 +117,7 @@
     // clang-format off
     const char* const args[] = {
         "/system/bin/make_f2fs",
-        "-d1",
-        "-f",
-        "-O", "encrypt",
-        "-O", "quota",
-        "-O", "verity",
-        "-w", "4096",
+        "-g", "android",
         fs_blkdev,
         size_str.c_str(),
         nullptr
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index a1de005..bef46e1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -432,7 +432,7 @@
         if (change) *change = true;
         if (!DestroyLogicalPartition(partition_name, 0s)) return false;
     } else {
-        PERROR << "delete partition " << overlay;
+        LERROR << "delete partition " << overlay;
         return false;
     }
     errno = save_errno;
@@ -647,49 +647,65 @@
     if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
     auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
     auto scratch_device = fs_mgr_overlayfs_scratch_device();
-    auto partition_exists = fs_mgr_rw_access(scratch_device);
+    auto partition_create = !fs_mgr_rw_access(scratch_device);
+    auto slot_number = fs_mgr_overlayfs_slot_number();
+    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    if (!fs_mgr_rw_access(super_device)) return false;
+    if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
+    auto builder = MetadataBuilder::New(super_device, slot_number);
+    if (!builder) {
+        LERROR << "open " << super_device << " metadata";
+        return false;
+    }
+    const auto partition_name = android::base::Basename(kScratchMountPoint);
+    auto partition = builder->FindPartition(partition_name);
+    auto partition_exists = partition != nullptr;
+    auto changed = false;
     if (!partition_exists) {
-        auto slot_number = fs_mgr_overlayfs_slot_number();
-        auto super_device = fs_mgr_overlayfs_super_device(slot_number);
-        if (!fs_mgr_rw_access(super_device)) return false;
-        if (!fs_mgr_overlayfs_has_logical(fstab)) return false;
-        auto builder = MetadataBuilder::New(super_device, slot_number);
-        if (!builder) {
-            PERROR << "open " << super_device << " metadata";
+        partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
+        if (!partition) {
+            LERROR << "create " << partition_name;
             return false;
         }
-        const auto partition_name = android::base::Basename(kScratchMountPoint);
-        partition_exists = builder->FindPartition(partition_name) != nullptr;
-        if (!partition_exists) {
-            auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
-            if (!partition) {
-                PERROR << "create " << partition_name;
-                return false;
+        changed = true;
+    }
+    // Take half of free space, minimum 512MB or free space - 256KB margin.
+    static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
+    static constexpr auto kMarginSize = uint64_t(256 * 1024);
+    if (partition->size() < kMinimumSize) {
+        auto partition_size =
+                builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
+        if ((partition_size > kMinimumSize) || !partition->size()) {
+            partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
+                                      partition_size / 2);
+            if (partition_size > partition->size()) {
+                if (!builder->ResizePartition(partition, partition_size)) {
+                    LERROR << "resize " << partition_name;
+                    return false;
+                }
+                if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
+                changed = true;
+                partition_exists = false;
             }
-            auto partition_size = builder->AllocatableSpace() - builder->UsedSpace();
-            // 512MB or half the remaining available space, whichever is greater.
-            partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2);
-            if (!builder->ResizePartition(partition, partition_size)) {
-                PERROR << "resize " << partition_name;
-                return false;
-            }
-
-            auto metadata = builder->Export();
-            if (!metadata) {
-                LERROR << "generate new metadata " << partition_name;
-                return false;
-            }
-            if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
-                LERROR << "update " << partition_name;
-                return false;
-            }
-
-            if (change) *change = true;
+        }
+    }
+    // land the update back on to the partition
+    if (changed) {
+        auto metadata = builder->Export();
+        if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
+            LERROR << "add partition " << partition_name;
+            return false;
         }
 
+        if (change) *change = true;
+    }
+
+    if (changed || partition_create) {
         if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
                                     &scratch_device))
             return false;
+
+        if (change) *change = true;
     }
 
     if (partition_exists) {
@@ -709,6 +725,7 @@
     } else if (mnt_type == "ext4") {
         command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
     } else {
+        errno = ESRCH;
         LERROR << mnt_type << " has no mkfs cookbook";
         return false;
     }
@@ -773,6 +790,8 @@
 }
 
 std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return {};
+
     if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
         return {};
     }
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 23a92d3..87c971a 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -21,8 +21,8 @@
 #include <string>
 
 #include <android-base/logging.h>
+#include <fs_mgr.h>
 
-#include "fs_mgr.h"
 #include "fs_mgr_priv_boot_config.h"
 
 /* The CHECK() in logging.h will use program invocation name as the tag.
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index e1815ff..830f0dd 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -35,43 +35,42 @@
 
 namespace {
 
-const auto kVendorOverlaySourceDir = "/system/vendor_overlay/"s;
+// The order of the list means the priority to show the files in the directory.
+// The last one has the highest priority.
+const std::vector<const std::string> kVendorOverlaySourceDirs = {
+        "/system/vendor_overlay/",
+        "/product/vendor_overlay/",
+};
 const auto kVndkVersionPropertyName = "ro.vndk.version"s;
 const auto kVendorTopDir = "/vendor/"s;
 const auto kLowerdirOption = "lowerdir="s;
 
-std::string fs_mgr_get_vendor_overlay_top_dir() {
-    // VNDK version is provided by the /vendor/default.prop
-    // To read the property, it must be called at the second init stage after the default
-    // properties are loaded.
-    std::string vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
-    if (vndk_version.empty()) {
-        return "";
-    }
-    return kVendorOverlaySourceDir + vndk_version;
-}
+std::vector<std::pair<std::string, std::string>> fs_mgr_get_vendor_overlay_dirs(
+        const std::string& vndk_version) {
+    std::vector<std::pair<std::string, std::string>> vendor_overlay_dirs;
+    for (const auto& vendor_overlay_source : kVendorOverlaySourceDirs) {
+        const auto overlay_top = vendor_overlay_source + vndk_version;
+        std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
+                                                                     closedir);
+        if (!vendor_overlay_top) continue;
 
-std::vector<std::string> fs_mgr_get_vendor_overlay_dirs(const std::string& overlay_top) {
-    std::vector<std::string> vendor_overlay_dirs;
-    std::unique_ptr<DIR, decltype(&closedir)> vendor_overlay_top(opendir(overlay_top.c_str()),
-                                                                 closedir);
-    if (!vendor_overlay_top) return vendor_overlay_dirs;
+        // Vendor overlay root for current vendor version found!
+        LINFO << "vendor overlay root: " << overlay_top;
 
-    // Vendor overlay root for current vendor version found!
-    LINFO << "vendor overlay root: " << overlay_top;
-    struct dirent* dp;
-    while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
-        if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
-            continue;
+        struct dirent* dp;
+        while ((dp = readdir(vendor_overlay_top.get())) != nullptr) {
+            if (dp->d_type != DT_DIR || dp->d_name[0] == '.') {
+                continue;
+            }
+            vendor_overlay_dirs.emplace_back(overlay_top, dp->d_name);
         }
-        vendor_overlay_dirs.push_back(dp->d_name);
     }
-
     return vendor_overlay_dirs;
 }
 
-bool fs_mgr_vendor_overlay_mount(const std::string& overlay_top, const std::string& mount_point) {
-    const auto vendor_mount_point = kVendorTopDir + mount_point;
+bool fs_mgr_vendor_overlay_mount(const std::pair<std::string, std::string>& mount_point) {
+    const auto [overlay_top, mount_dir] = mount_point;
+    const auto vendor_mount_point = kVendorTopDir + mount_dir;
     LINFO << "vendor overlay mount on " << vendor_mount_point;
 
     const auto target_context = fs_mgr_get_context(vendor_mount_point);
@@ -79,7 +78,7 @@
         PERROR << " failed: cannot find the target vendor mount point";
         return false;
     }
-    const auto source_directory = overlay_top + "/" + mount_point;
+    const auto source_directory = overlay_top + "/" + mount_dir;
     const auto source_context = fs_mgr_get_context(source_directory);
     if (target_context != source_context) {
         LERROR << " failed: source and target contexts do not match (source:" << source_context
@@ -112,22 +111,25 @@
 // To read the properties, vendor overlay must be mounted at the second stage, right
 // after "property_load_boot_defaults()" is called.
 bool fs_mgr_vendor_overlay_mount_all() {
-    const auto overlay_top = fs_mgr_get_vendor_overlay_top_dir();
-    if (overlay_top.empty()) {
+    // To read the property, it must be called at the second init stage after the default
+    // properties are loaded.
+    static const auto vndk_version = android::base::GetProperty(kVndkVersionPropertyName, "");
+    if (vndk_version.empty()) {
         LINFO << "vendor overlay: vndk version not defined";
         return false;
     }
-    const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(overlay_top);
+
+    const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
     if (vendor_overlay_dirs.empty()) return true;
     if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
         LINFO << "vendor overlay: kernel does not support overlayfs";
         return false;
     }
 
-    // Mount each directory in /system/vendor_overlay/<ver> on /vendor
+    // Mount each directory in /(system|product)/vendor_overlay/<ver> on /vendor
     auto ret = true;
     for (const auto& vendor_overlay_dir : vendor_overlay_dirs) {
-        if (!fs_mgr_vendor_overlay_mount(overlay_top, vendor_overlay_dir)) {
+        if (!fs_mgr_vendor_overlay_mount(vendor_overlay_dir)) {
             ret = false;
         }
     }
diff --git a/fs_mgr/fs_mgr_avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp
similarity index 93%
rename from fs_mgr/fs_mgr_avb_ops.cpp
rename to fs_mgr/libfs_avb/avb_ops.cpp
index 18efa22..f56a517 100644
--- a/fs_mgr/fs_mgr_avb_ops.cpp
+++ b/fs_mgr/libfs_avb/avb_ops.cpp
@@ -22,7 +22,7 @@
  * SOFTWARE.
  */
 
-#include "fs_mgr_priv_avb_ops.h"
+#include "avb_ops.h"
 
 #include <errno.h>
 #include <fcntl.h>
@@ -37,15 +37,17 @@
 #include <libavb/libavb.h>
 #include <utils/Compat.h>
 
-#include "fs_mgr.h"
 #include "fs_mgr_priv.h"
 
 using namespace std::literals;
 
+namespace android {
+namespace fs_mgr {
+
 static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
                                        size_t num_bytes, void* buffer, size_t* out_num_read) {
     return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
-        partition, offset, num_bytes, buffer, out_num_read);
+            partition, offset, num_bytes, buffer, out_num_read);
 }
 
 static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
@@ -58,9 +60,10 @@
 }
 
 static AvbIOResult dummy_validate_vbmeta_public_key(
-    AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
-    size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
-    size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
+        AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
+        size_t public_key_length ATTRIBUTE_UNUSED,
+        const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
+        size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
     // vbmeta public key has been checked in bootloader phase.
     // In user-space, returns true to pass the check.
     //
@@ -178,3 +181,6 @@
     return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
                            AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data);
 }
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_priv_avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h
similarity index 89%
rename from fs_mgr/fs_mgr_priv_avb_ops.h
rename to fs_mgr/libfs_avb/avb_ops.h
index 44eb1da..e6b33c2 100644
--- a/fs_mgr/fs_mgr_priv_avb_ops.h
+++ b/fs_mgr/libfs_avb/avb_ops.h
@@ -22,15 +22,14 @@
  * SOFTWARE.
  */
 
-#ifndef __CORE_FS_MGR_PRIV_AVB_OPS_H
-#define __CORE_FS_MGR_PRIV_AVB_OPS_H
+#pragma once
 
-#include <map>
 #include <string>
 
 #include <libavb/libavb.h>
 
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
 
 // This class provides C++ bindings to interact with libavb, a small
 // self-contained piece of code that's intended to be used in bootloaders.
@@ -42,7 +41,7 @@
 //     read and verify the metadata and store it into the out_data parameter.
 //     The caller MUST check the integrity of metadata against the
 //     androidboot.vbmeta.{hash_alg, size, digest} values from /proc/cmdline.
-//     e.g., see class FsManagerAvbVerifier for more details.
+//     e.g., see class AvbVerifier for more details.
 //
 class FsManagerAvbOps {
   public:
@@ -60,6 +59,7 @@
 
   private:
     AvbOps avb_ops_;
-    std::map<std::string, std::string> by_name_symlink_map_;
 };
-#endif /* __CORE_FS_MGR_PRIV_AVB_OPS_H */
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp
similarity index 86%
rename from fs_mgr/fs_mgr_avb.cpp
rename to fs_mgr/libfs_avb/fs_avb.cpp
index 6f94d45..c4accad 100644
--- a/fs_mgr/fs_mgr_avb.cpp
+++ b/fs_mgr/libfs_avb/fs_avb.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "fs_mgr_avb.h"
+#include "fs_avb/fs_avb.h"
 
 #include <fcntl.h>
 #include <libgen.h>
@@ -35,10 +35,12 @@
 #include <libavb/libavb.h>
 #include <libdm/dm.h>
 
-#include "fs_mgr.h"
+#include "avb_ops.h"
 #include "fs_mgr_priv.h"
-#include "fs_mgr_priv_avb_ops.h"
-#include "fs_mgr_priv_sha.h"
+#include "sha.h"
+
+namespace android {
+namespace fs_mgr {
 
 static inline bool nibble_value(const char& c, uint8_t* value) {
     FS_MGR_CHECK(value != nullptr);
@@ -117,14 +119,14 @@
 //   - androidboot.vbmeta.hash_alg
 //   - androidboot.vbmeta.size
 //   - androidboot.vbmeta.digest
-class FsManagerAvbVerifier {
+class AvbVerifier {
   public:
-    // The factory method to return a unique_ptr<FsManagerAvbVerifier>
-    static std::unique_ptr<FsManagerAvbVerifier> Create();
+    // The factory method to return a unique_ptr<AvbVerifier>
+    static std::unique_ptr<AvbVerifier> Create();
     bool VerifyVbmetaImages(const AvbSlotVerifyData& verify_data);
 
   protected:
-    FsManagerAvbVerifier() = default;
+    AvbVerifier() = default;
 
   private:
     enum HashAlgorithm {
@@ -138,10 +140,10 @@
     size_t vbmeta_size_;
 };
 
-std::unique_ptr<FsManagerAvbVerifier> FsManagerAvbVerifier::Create() {
-    std::unique_ptr<FsManagerAvbVerifier> avb_verifier(new FsManagerAvbVerifier());
+std::unique_ptr<AvbVerifier> AvbVerifier::Create() {
+    std::unique_ptr<AvbVerifier> avb_verifier(new AvbVerifier());
     if (!avb_verifier) {
-        LERROR << "Failed to create unique_ptr<FsManagerAvbVerifier>";
+        LERROR << "Failed to create unique_ptr<AvbVerifier>";
         return nullptr;
     }
 
@@ -184,7 +186,7 @@
     return avb_verifier;
 }
 
-bool FsManagerAvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
+bool AvbVerifier::VerifyVbmetaImages(const AvbSlotVerifyData& verify_data) {
     if (verify_data.num_vbmeta_images == 0) {
         LERROR << "No vbmeta images";
         return false;
@@ -195,10 +197,10 @@
 
     if (hash_alg_ == kSHA256) {
         std::tie(total_size, digest_matched) =
-            verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
+                verify_vbmeta_digest<SHA256Hasher>(verify_data, digest_);
     } else if (hash_alg_ == kSHA512) {
         std::tie(total_size, digest_matched) =
-            verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
+                verify_vbmeta_digest<SHA512Hasher>(verify_data, digest_);
     }
 
     if (total_size != vbmeta_size_) {
@@ -268,7 +270,8 @@
                                      const std::string& salt, const std::string& root_digest,
                                      bool wait_for_verity_dev) {
     android::dm::DmTable table;
-    if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device, &table) ||
+    if (!construct_verity_table(hashtree_desc, salt, root_digest, fstab_entry->blk_device,
+                                &table) ||
         !table.valid()) {
         LERROR << "Failed to construct verity table.";
         return false;
@@ -314,9 +317,9 @@
         // Get descriptors from vbmeta_images[i].
         size_t num_descriptors;
         std::unique_ptr<const AvbDescriptor* [], decltype(&avb_free)> descriptors(
-            avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
-                                   verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
-            avb_free);
+                avb_descriptor_get_all(verify_data.vbmeta_images[i].vbmeta_data,
+                                       verify_data.vbmeta_images[i].vbmeta_size, &num_descriptors),
+                avb_free);
 
         if (!descriptors || num_descriptors < 1) {
             continue;
@@ -329,9 +332,10 @@
                 continue;
             }
             if (desc.tag == AVB_DESCRIPTOR_TAG_HASHTREE) {
-                desc_partition_name = (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
+                desc_partition_name =
+                        (const uint8_t*)descriptors[j] + sizeof(AvbHashtreeDescriptor);
                 if (!avb_hashtree_descriptor_validate_and_byteswap(
-                        (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
+                            (AvbHashtreeDescriptor*)descriptors[j], out_hashtree_desc)) {
                     continue;
                 }
                 if (out_hashtree_desc->partition_name_len != partition_name.length()) {
@@ -361,12 +365,12 @@
     return true;
 }
 
-FsManagerAvbUniquePtr FsManagerAvbHandle::Open() {
+AvbUniquePtr AvbHandle::Open() {
     bool is_device_unlocked = fs_mgr_is_device_unlocked();
 
-    FsManagerAvbUniquePtr avb_handle(new FsManagerAvbHandle());
+    AvbUniquePtr avb_handle(new AvbHandle());
     if (!avb_handle) {
-        LERROR << "Failed to allocate FsManagerAvbHandle";
+        LERROR << "Failed to allocate AvbHandle";
         return nullptr;
     }
 
@@ -406,7 +410,7 @@
 
     // Sets the MAJOR.MINOR for init to set it into "ro.boot.avb_version".
     avb_handle->avb_version_ =
-        android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
+            android::base::StringPrintf("%d.%d", AVB_VERSION_MAJOR, AVB_VERSION_MINOR);
 
     // Checks whether FLAGS_VERIFICATION_DISABLED is set:
     //   - Only the top-level vbmeta struct is read.
@@ -414,18 +418,18 @@
     //     and AVB HASHTREE descriptor(s).
     AvbVBMetaImageHeader vbmeta_header;
     avb_vbmeta_image_header_to_host_byte_order(
-        (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
-        &vbmeta_header);
-    bool verification_disabled =
-        ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
+            (AvbVBMetaImageHeader*)avb_handle->avb_slot_data_->vbmeta_images[0].vbmeta_data,
+            &vbmeta_header);
+    bool verification_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+                                  AVB_VBMETA_IMAGE_FLAGS_VERIFICATION_DISABLED);
 
     if (verification_disabled) {
         avb_handle->status_ = kAvbHandleVerificationDisabled;
     } else {
         // Verifies vbmeta structs against the digest passed from bootloader in kernel cmdline.
-        std::unique_ptr<FsManagerAvbVerifier> avb_verifier = FsManagerAvbVerifier::Create();
+        std::unique_ptr<AvbVerifier> avb_verifier = AvbVerifier::Create();
         if (!avb_verifier) {
-            LERROR << "Failed to create FsManagerAvbVerifier";
+            LERROR << "Failed to create AvbVerifier";
             return nullptr;
         }
         if (!avb_verifier->VerifyVbmetaImages(*avb_handle->avb_slot_data_)) {
@@ -434,8 +438,8 @@
         }
 
         // Checks whether FLAGS_HASHTREE_DISABLED is set.
-        bool hashtree_disabled =
-            ((AvbVBMetaImageFlags)vbmeta_header.flags & AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
+        bool hashtree_disabled = ((AvbVBMetaImageFlags)vbmeta_header.flags &
+                                  AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED);
         if (hashtree_disabled) {
             avb_handle->status_ = kAvbHandleHashtreeDisabled;
         }
@@ -445,16 +449,16 @@
     return avb_handle;
 }
 
-SetUpAvbHashtreeResult FsManagerAvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
-                                                            bool wait_for_verity_dev) {
+AvbHashtreeResult AvbHandle::SetUpAvbHashtree(struct fstab_rec* fstab_entry,
+                                              bool wait_for_verity_dev) {
     if (!fstab_entry || status_ == kAvbHandleUninitialized || !avb_slot_data_ ||
         avb_slot_data_->num_vbmeta_images < 1) {
-        return SetUpAvbHashtreeResult::kFail;
+        return AvbHashtreeResult::kFail;
     }
 
     if (status_ == kAvbHandleHashtreeDisabled || status_ == kAvbHandleVerificationDisabled) {
         LINFO << "AVB HASHTREE disabled on: " << fstab_entry->mount_point;
-        return SetUpAvbHashtreeResult::kDisabled;
+        return AvbHashtreeResult::kDisabled;
     }
 
     // Derives partition_name from blk_device to query the corresponding AVB HASHTREE descriptor
@@ -478,14 +482,17 @@
     std::string root_digest;
     if (!get_hashtree_descriptor(partition_name, *avb_slot_data_, &hashtree_descriptor, &salt,
                                  &root_digest)) {
-        return SetUpAvbHashtreeResult::kFail;
+        return AvbHashtreeResult::kFail;
     }
 
     // Converts HASHTREE descriptor to verity_table_params.
     if (!hashtree_dm_verity_setup(fstab_entry, hashtree_descriptor, salt, root_digest,
                                   wait_for_verity_dev)) {
-        return SetUpAvbHashtreeResult::kFail;
+        return AvbHashtreeResult::kFail;
     }
 
-    return SetUpAvbHashtreeResult::kSuccess;
+    return AvbHashtreeResult::kSuccess;
 }
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/include/fs_mgr_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
similarity index 75%
rename from fs_mgr/include/fs_mgr_avb.h
rename to fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
index bb55a14..9adab3d 100644
--- a/fs_mgr/include/fs_mgr_avb.h
+++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef __CORE_FS_MGR_AVB_H
-#define __CORE_FS_MGR_AVB_H
+#pragma once
 
-#include <map>
 #include <memory>
 #include <string>
 
+#include <fstab/fstab.h>
 #include <libavb/libavb.h>
 
-#include "fs_mgr.h"
+namespace android {
+namespace fs_mgr {
 
-enum class SetUpAvbHashtreeResult {
+enum class AvbHashtreeResult {
     kSuccess = 0,
     kFail,
     kDisabled,
@@ -33,17 +33,15 @@
 
 class FsManagerAvbOps;
 
-class FsManagerAvbHandle;
-using FsManagerAvbUniquePtr = std::unique_ptr<FsManagerAvbHandle>;
-
-using ByNameSymlinkMap = std::map<std::string, std::string>;
+class AvbHandle;
+using AvbUniquePtr = std::unique_ptr<AvbHandle>;
 
 // Provides a factory method to return a unique_ptr pointing to itself and the
 // SetUpAvbHashtree() function to extract dm-verity parameters from AVB HASHTREE
 // descriptors to load verity table into kernel through ioctl.
-class FsManagerAvbHandle {
+class AvbHandle {
   public:
-    // The factory method to return a FsManagerAvbUniquePtr that holds
+    // The factory method to return a AvbUniquePtr that holds
     // the verified AVB (external/avb) metadata of all verified partitions
     // in avb_slot_data_.vbmeta_images[].
     //
@@ -51,7 +49,7 @@
     //   - androidboot.vbmeta.{hash_alg, size, digest}.
     //
     // A typical usage will be:
-    //   - FsManagerAvbUniquePtr handle = FsManagerAvbHandle::Open();
+    //   - AvbUniquePtr handle = AvbHandle::Open();
     //
     // Possible return values:
     //   - nullptr: any error when reading and verifying the metadata,
@@ -75,7 +73,7 @@
     //   - a valid unique_ptr with status kAvbHandleSuccess: the metadata
     //     is verified and can be trusted.
     //
-    static FsManagerAvbUniquePtr Open();
+    static AvbUniquePtr Open();
 
     // Sets up dm-verity on the given fstab entry.
     // The 'wait_for_verity_dev' parameter makes this function wait for the
@@ -87,17 +85,17 @@
     //     failed to get the HASHTREE descriptor, runtime error when set up
     //     device-mapper, etc.
     //   - kDisabled: hashtree is disabled.
-    SetUpAvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
+    AvbHashtreeResult SetUpAvbHashtree(fstab_rec* fstab_entry, bool wait_for_verity_dev);
 
     const std::string& avb_version() const { return avb_version_; }
 
-    FsManagerAvbHandle(const FsManagerAvbHandle&) = delete;             // no copy
-    FsManagerAvbHandle& operator=(const FsManagerAvbHandle&) = delete;  // no assignment
+    AvbHandle(const AvbHandle&) = delete;             // no copy
+    AvbHandle& operator=(const AvbHandle&) = delete;  // no assignment
 
-    FsManagerAvbHandle(FsManagerAvbHandle&&) noexcept = delete;             // no move
-    FsManagerAvbHandle& operator=(FsManagerAvbHandle&&) noexcept = delete;  // no move assignment
+    AvbHandle(AvbHandle&&) noexcept = delete;             // no move
+    AvbHandle& operator=(AvbHandle&&) noexcept = delete;  // no move assignment
 
-    ~FsManagerAvbHandle() {
+    ~AvbHandle() {
         if (avb_slot_data_) {
             avb_slot_verify_data_free(avb_slot_data_);
         }
@@ -112,11 +110,12 @@
         kAvbHandleVerificationError,
     };
 
-    FsManagerAvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
+    AvbHandle() : avb_slot_data_(nullptr), status_(kAvbHandleUninitialized) {}
 
     AvbSlotVerifyData* avb_slot_data_;
     AvbHandleStatus status_;
     std::string avb_version_;
 };
 
-#endif /* __CORE_FS_MGR_AVB_H */
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_priv_sha.h b/fs_mgr/libfs_avb/sha.h
similarity index 92%
rename from fs_mgr/fs_mgr_priv_sha.h
rename to fs_mgr/libfs_avb/sha.h
index 5b53eea..2d3ca6d 100644
--- a/fs_mgr/fs_mgr_priv_sha.h
+++ b/fs_mgr/libfs_avb/sha.h
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef __CORE_FS_MGR_PRIV_SHA_H
-#define __CORE_FS_MGR_PRIV_SHA_H
+#pragma once
 
 #include <openssl/sha.h>
 
+namespace android {
+namespace fs_mgr {
+
 class SHA256Hasher {
   private:
     SHA256_CTX sha256_ctx;
@@ -59,4 +61,5 @@
     }
 };
 
-#endif /* __CORE_FS_MGR_PRIV_SHA_H */
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 7a00194..d9e017c 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -63,6 +63,7 @@
 
 Returns: the logcat output" ]
 adb_logcat() {
+  echo "${RED}[     INFO ]${NORMAL} logcat ${@}" >&2 &&
   adb logcat "${@}" </dev/null |
     grep -v 'logd    : logdr: UID=' |
     sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
@@ -106,12 +107,13 @@
 
 Returns: true if the reboot command succeeded" ]
 adb_reboot() {
-  adb reboot remount-test
+  adb reboot remount-test &&
+  sleep 2
 }
 
 [ "USAGE: adb_wait [timeout]
 
-Returns: waits until the device has returned or the optional timeout" ]
+Returns: waits until the device has returned for adb or optional timeout" ]
 adb_wait() {
   if [ -n "${1}" ]; then
     timeout --preserve-status --signal=KILL ${1} adb wait-for-device
@@ -120,14 +122,49 @@
   fi
 }
 
+[ "USAGE: fastboot_wait [timeout]
+
+Returns: waits until the device has returned for fastboot or optional timeout" ]
+fastboot_wait() {
+  # fastboot has no wait-for-device, but it does an automatic
+  # wait and requires (even a nonsensical) command to do so.
+  if [ -n "${1}" ]; then
+    timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
+  else
+    fastboot wait-for-device >/dev/null
+  fi >/dev/null 2>/dev/null ||
+    inFastboot
+}
+
 [ "USAGE: adb_root
 
 Returns: true if device in root state" ]
 adb_root() {
-  adb root >/dev/null </dev/null 2>/dev/null &&
-  sleep 1 &&
-  adb_wait &&
-  sleep 1
+  adb root >/dev/null </dev/null 2>/dev/null
+  sleep 2
+  adb_wait 2m &&
+    [ `adb_sh echo '${USER}'` = root ]
+}
+
+[ "USAGE: fastboot_getvar var expected
+
+Returns: true if var output matches expected" ]
+fastboot_getvar() {
+  O=`fastboot getvar ${1} 2>&1`
+  err=${?}
+  O="${O#< waiting for * >?}"
+  O="${O%%?Finished. Total time: *}"
+  if [ 0 -ne ${err} ]; then
+    echo ${O} >&2
+    false
+    return
+  fi
+  if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
+    echo "${2} != ${O}" >&2
+    false
+    return
+  fi
+  echo ${O} >&2
 }
 
 [ "USAGE: die [-t <epoch>] [message] >/dev/stderr
@@ -233,8 +270,7 @@
 adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
   echo "${GREEN}[       OK ]${NORMAL} overlay module supports override_creds" >&2 ||
   die "overlay module can not be used on ANDROID"
-adb_root &&
-  adb_wait ||
+adb_root ||
   die "initial setup"
 reboot=false
 OVERLAYFS_BACKING="cache mnt/scratch"
@@ -250,8 +286,7 @@
   echo "${ORANGE}[  WARNING ]${NORMAL} rebooting before test" >&2
   adb_reboot &&
     adb_wait 2m &&
-    adb_root &&
-    adb_wait ||
+    adb_root ||
     die "reboot after wipe"
 fi
 D=`adb_sh df -k </dev/null` &&
@@ -288,7 +323,6 @@
 
 T=`adb_date`
 adb_root &&
-  adb_wait &&
   adb remount &&
   D=`adb_sh df -k </dev/null` ||
   die -t ${T} "can not collect filesystem data"
@@ -340,19 +374,31 @@
   die "re-read vendor hello after reboot w/o root"
 check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
 adb_root &&
-  adb_wait &&
   B="`adb_cat /vendor/hello`" ||
   die "re-read vendor hello after reboot"
 check_eq "${A}" "${B}" vendor after reboot
 
 adb reboot-fastboot &&
-  fastboot flash vendor &&
-  fastboot reboot ||
+  fastboot_wait 2m &&
+  fastboot flash vendor ||
   die "fastbootd flash vendor"
+# check scratch via fastboot
+fastboot_getvar partition-type:scratch raw &&
+  fastboot_getvar has-slot:scratch no &&
+  fastboot_getvar is-logical:scratch yes ||
+  die "fastboot can not see scratch parameters"
+echo "${ORANGE}[     INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
+fastboot erase scratch &&
+  die "fastbootd can erase scratch"
+echo "${ORANGE}[     INFO ]${NORMAL} expect fastboot format scratch to fail" >&2
+fastboot format scratch &&
+  die "fastbootd can format scratch"
+fastboot reboot ||
+  die "can not reboot out of fastbootd"
+echo "${ORANGE}[  WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
 adb_wait 2m ||
   die "did not reboot after flash"
 adb_root &&
-  adb_wait &&
   D=`adb_sh df -k </dev/null` &&
   H=`echo "${D}" | head -1` &&
   D=`echo "${D}" | grep "^overlay "` &&
@@ -365,8 +411,7 @@
 B="`adb_cat /system/hello`" ||
   die "re-read system hello after flash vendor"
 check_eq "${A}" "${B}" system after flash vendor
-adb_root &&
-  adb_wait ||
+adb_root ||
   die "adb root"
 B="`adb_cat /vendor/hello`" &&
   die "re-read vendor hello after flash vendor"
@@ -384,4 +429,27 @@
   die "re-read vendor hello after rm"
 check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
 
+adb reboot-fastboot &&
+  dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
+  fastboot_wait 2m ||
+  die "reboot into fastbootd"
+fastboot flash scratch adb-remount-test.img
+err=${?}
+rm adb-remount-test.img
+[ 0 -eq ${err} ] ||
+  die "fastbootd flash scratch"
+fastboot reboot ||
+  die "can not reboot out of fastbootd"
+adb_wait 2m &&
+  adb_root ||
+  die "did not reboot after flash"
+T=`adb_date`
+D=`adb disable-verity 2>&1`
+err=${?}
+echo "${D}"
+[ ${err} = 0 ] &&
+  [ X"${D}" = X"${D##*setup failed}" ] &&
+  [ X"${D}" != X"${D##*using overlayfs}" ] ||
+  die -t ${T} "setup for overlayfs"
+
 echo "${GREEN}[  PASSED  ]${NORMAL} adb remount" >&2
diff --git a/init/Android.bp b/init/Android.bp
index ff3b61f..ea66ac6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -71,6 +71,7 @@
         "libbinder",
         "libbootloader_message",
         "libcutils",
+        "libcrypto",
         "libdl",
         "libext4_utils",
         "libfs_mgr",
@@ -79,6 +80,7 @@
         "libkeyutils",
         "liblog",
         "liblogwrap",
+        "liblp",
         "libselinux",
         "libutils",
     ],
@@ -92,6 +94,7 @@
         "action.cpp",
         "action_manager.cpp",
         "action_parser.cpp",
+        "boringssl_self_test.cpp",
         "bootchart.cpp",
         "builtins.cpp",
         "capabilities.cpp",
@@ -99,6 +102,7 @@
         "devices.cpp",
         "epoll.cpp",
         "firmware_handler.cpp",
+        "first_stage_init.cpp",
         "first_stage_mount.cpp",
         "import_parser.cpp",
         "init.cpp",
@@ -117,6 +121,7 @@
         "sigchld_handler.cpp",
         "subcontext.cpp",
         "subcontext.proto",
+        "switch_root.cpp",
         "rlimit_parser.cpp",
         "tokenizer.cpp",
         "uevent_listener.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index dc46d21..69f1d87 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -39,12 +39,15 @@
 
 # --
 
+# Do not build this even with mmma if we're system-as-root, otherwise it will overwrite the symlink.
+ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
 include $(CLEAR_VARS)
 LOCAL_CPPFLAGS := $(init_cflags)
 LOCAL_SRC_FILES := \
     devices.cpp \
+    first_stage_init.cpp \
+    first_stage_main.cpp \
     first_stage_mount.cpp \
-    init_first_stage.cpp \
     reboot_utils.cpp \
     selinux.cpp \
     switch_root.cpp \
@@ -67,6 +70,7 @@
     $(TARGET_RAMDISK_OUT)/sys \
 
 LOCAL_STATIC_LIBRARIES := \
+    libfs_avb \
     libfs_mgr \
     libfec \
     libfec_rs \
@@ -93,20 +97,15 @@
 # First stage init is weird: it may start without stdout/stderr, and no /proc.
 LOCAL_NOSANITIZE := hwaddress
 include $(BUILD_EXECUTABLE)
+endif
 
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := init_system
-ifeq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
-LOCAL_REQUIRED_MODULES := \
-   init_first_stage \
-   init_second_stage \
-
-else
 LOCAL_REQUIRED_MODULES := \
    init_second_stage \
 
-endif
+LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init
 include $(BUILD_PHONY_PACKAGE)
 
 include $(CLEAR_VARS)
@@ -118,5 +117,3 @@
 
 endif
 include $(BUILD_PHONY_PACKAGE)
-
-
diff --git a/init/boringssl_self_test.cpp b/init/boringssl_self_test.cpp
new file mode 100644
index 0000000..0408d30
--- /dev/null
+++ b/init/boringssl_self_test.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "boringssl_self_test.h"
+
+#include <android-base/logging.h>
+#include <cutils/android_reboot.h>
+#include <openssl/crypto.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&) {
+    pid_t id = fork();
+
+    if (id == 0) {
+        if (BORINGSSL_self_test() != 1) {
+            LOG(INFO) << "BoringSSL crypto self tests failed";
+
+            // This check has failed, so the device should refuse
+            // to boot. Rebooting to bootloader to wait for
+            // further action from the user.
+
+            int result = android_reboot(ANDROID_RB_RESTART2, 0,
+                                        "bootloader,boringssl-self-check-failed");
+            if (result != 0) {
+                LOG(ERROR) << "Failed to reboot into bootloader";
+            }
+        }
+
+        _exit(0);
+    } else if (id == -1) {
+        // Failed to fork, so cannot run the test. Refuse to continue.
+        PLOG(FATAL) << "Failed to fork for BoringSSL self test";
+    }
+
+    return Success();
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/boringssl_self_test.h b/init/boringssl_self_test.h
new file mode 100644
index 0000000..b21fc78
--- /dev/null
+++ b/init/boringssl_self_test.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "builtin_arguments.h"
+#include "result.h"
+
+namespace android {
+namespace init {
+
+Result<Success> StartBoringSslSelfTest(const BuiltinArguments&);
+
+}  // namespace init
+}  // namespace android
diff --git a/init/init_first_stage.cpp b/init/first_stage_init.cpp
similarity index 97%
rename from init/init_first_stage.cpp
rename to init/first_stage_init.cpp
index c2c6868..e11d897 100644
--- a/init/init_first_stage.cpp
+++ b/init/first_stage_init.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "first_stage_init.h"
+
 #include <dirent.h>
 #include <fcntl.h>
 #include <paths.h>
@@ -94,7 +96,7 @@
 
 }  // namespace
 
-int main(int argc, char** argv) {
+int FirstStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
     }
@@ -214,7 +216,7 @@
     setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
 
     const char* path = "/system/bin/init";
-    const char* args[] = {path, nullptr};
+    const char* args[] = {path, "selinux_setup", nullptr};
     execv(path, const_cast<char**>(args));
 
     // execv() only returns if an error happened, in which case we
@@ -226,7 +228,3 @@
 
 }  // namespace init
 }  // namespace android
-
-int main(int argc, char** argv) {
-    return android::init::main(argc, argv);
-}
diff --git a/init/first_stage_init.h b/init/first_stage_init.h
new file mode 100644
index 0000000..0476e44
--- /dev/null
+++ b/init/first_stage_init.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+namespace init {
+
+int FirstStageMain(int argc, char** argv);
+
+}  // namespace init
+}  // namespace android
diff --git a/init/first_stage_main.cpp b/init/first_stage_main.cpp
new file mode 100644
index 0000000..7bae84c
--- /dev/null
+++ b/init/first_stage_main.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "first_stage_init.h"
+
+int main(int argc, char** argv) {
+    return android::init::FirstStageMain(argc, argv);
+}
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 43b2ebf..8644dae 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -30,8 +30,8 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <fs_avb/fs_avb.h>
 #include <fs_mgr.h>
-#include <fs_mgr_avb.h>
 #include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
 #include <liblp/liblp.h>
@@ -43,6 +43,9 @@
 #include "util.h"
 
 using android::base::Timer;
+using android::fs_mgr::AvbHandle;
+using android::fs_mgr::AvbHashtreeResult;
+using android::fs_mgr::AvbUniquePtr;
 
 using namespace std::literals;
 
@@ -113,7 +116,7 @@
     bool InitAvbHandle();
 
     std::string device_tree_vbmeta_parts_;
-    FsManagerAvbUniquePtr avb_handle_;
+    AvbUniquePtr avb_handle_;
 };
 
 // Static Functions
@@ -449,7 +452,9 @@
     // Includes the partition names of fstab records and verity_loc_device (if any).
     // Notes that fstab_rec->blk_device has A/B suffix updated by fs_mgr when A/B is used.
     for (auto fstab_rec : mount_fstab_recs_) {
-        required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        if (!fs_mgr_is_logical(fstab_rec)) {
+            required_devices_partition_names_.emplace(basename(fstab_rec->blk_device));
+        }
     }
 
     if (!verity_loc_device.empty()) {
@@ -545,12 +550,12 @@
 bool FirstStageMountVBootV2::SetUpDmVerity(fstab_rec* fstab_rec) {
     if (fs_mgr_is_avb(fstab_rec)) {
         if (!InitAvbHandle()) return false;
-        SetUpAvbHashtreeResult hashtree_result =
+        AvbHashtreeResult hashtree_result =
                 avb_handle_->SetUpAvbHashtree(fstab_rec, false /* wait_for_verity_dev */);
         switch (hashtree_result) {
-            case SetUpAvbHashtreeResult::kDisabled:
+            case AvbHashtreeResult::kDisabled:
                 return true;  // Returns true to mount the partition.
-            case SetUpAvbHashtreeResult::kSuccess:
+            case AvbHashtreeResult::kSuccess:
                 // The exact block device name (fstab_rec->blk_device) is changed to
                 // "/dev/block/dm-XX". Needs to create it because ueventd isn't started in init
                 // first stage.
@@ -565,10 +570,10 @@
 bool FirstStageMountVBootV2::InitAvbHandle() {
     if (avb_handle_) return true;  // Returns true if the handle is already initialized.
 
-    avb_handle_ = FsManagerAvbHandle::Open();
+    avb_handle_ = AvbHandle::Open();
 
     if (!avb_handle_) {
-        PLOG(ERROR) << "Failed to open FsManagerAvbHandle";
+        PLOG(ERROR) << "Failed to open AvbHandle";
         return false;
     }
     // Sets INIT_AVB_VERSION here for init to set ro.boot.avb_version in the second stage.
@@ -605,7 +610,7 @@
         return;
     }
 
-    // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
+    // Initializes required devices for the subsequent AvbHandle::Open()
     // to verify AVB metadata on all partitions in the verified chain.
     // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
     // Open() function returns a valid handle.
@@ -616,9 +621,9 @@
         return;
     }
 
-    FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open();
+    AvbUniquePtr avb_handle = AvbHandle::Open();
     if (!avb_handle) {
-        PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
+        PLOG(ERROR) << "Failed to open AvbHandle for INIT_AVB_VERSION";
         return;
     }
     setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
diff --git a/init/init.cpp b/init/init.cpp
index e7dbc11..dc46a82 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -49,6 +49,7 @@
 #endif
 
 #include "action_parser.h"
+#include "boringssl_self_test.h"
 #include "epoll.h"
 #include "first_stage_mount.h"
 #include "import_parser.h"
@@ -59,13 +60,8 @@
 #include "security.h"
 #include "selinux.h"
 #include "sigchld_handler.h"
-#include "ueventd.h"
 #include "util.h"
 
-#if __has_feature(address_sanitizer)
-#include <sanitizer/asan_interface.h>
-#endif
-
 using namespace std::chrono_literals;
 using namespace std::string_literals;
 
@@ -79,25 +75,6 @@
 namespace android {
 namespace init {
 
-#if __has_feature(address_sanitizer)
-// Load asan.options if it exists since these are not yet in the environment.
-// Always ensure detect_container_overflow=0 as there are false positives with this check.
-// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
-extern "C" const char* __asan_default_options() {
-    return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
-__sanitizer_report_error_summary(const char* summary) {
-    LOG(ERROR) << "Main stage (error summary): " << summary;
-}
-
-__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
-AsanReportCallback(const char* str) {
-    LOG(ERROR) << "Main stage: " << str;
-}
-#endif
-
 static int property_triggers_enabled = 0;
 
 static char qemu[32];
@@ -622,57 +599,11 @@
     });
 }
 
-static void SetupSelinux(char** argv) {
-    android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
-        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
-    });
-
-    // Set up SELinux, loading the SELinux policy.
-    SelinuxSetupKernelLogging();
-    SelinuxInitialize();
-
-    // We're in the kernel domain and want to transition to the init domain.  File systems that
-    // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
-    // but other file systems do.  In particular, this is needed for ramdisks such as the
-    // recovery image for A/B devices.
-    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
-        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
-    }
-
-    setenv("SELINUX_INITIALIZED", "true", 1);
-
-    const char* path = "/system/bin/init";
-    const char* args[] = {path, nullptr};
-    execv(path, const_cast<char**>(args));
-
-    // execv() only returns if an error happened, in which case we
-    // panic and never return from this function.
-    PLOG(FATAL) << "execv(\"" << path << "\") failed";
-}
-
-int main(int argc, char** argv) {
-#if __has_feature(address_sanitizer)
-    __asan_set_error_report_callback(AsanReportCallback);
-#endif
-
-    if (!strcmp(basename(argv[0]), "ueventd")) {
-        return ueventd_main(argc, argv);
-    }
-
-    if (argc > 1 && !strcmp(argv[1], "subcontext")) {
-        android::base::InitLogging(argv, &android::base::KernelLogger);
-        const BuiltinFunctionMap function_map;
-        return SubcontextMain(argc, argv, &function_map);
-    }
-
+int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
     }
 
-    if (getenv("SELINUX_INITIALIZED") == nullptr) {
-        SetupSelinux(argv);
-    }
-
     // 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!";
@@ -708,7 +639,6 @@
     if (avb_version) property_set("ro.boot.avb_version", avb_version);
 
     // Clean up our environment.
-    unsetenv("SELINUX_INITIALIZED");
     unsetenv("INIT_STARTED_AT");
     unsetenv("INIT_SELINUX_TOOK");
     unsetenv("INIT_AVB_VERSION");
@@ -768,6 +698,9 @@
     // Trigger all the boot actions to get us started.
     am.QueueEventTrigger("init");
 
+    // Starting the BoringSSL self test, for NIAP certification compliance.
+    am.QueueBuiltinAction(StartBoringSslSelfTest, "StartBoringSslSelfTest");
+
     // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
     // wasn't ready immediately after wait_for_coldboot_done
     am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
diff --git a/init/init.h b/init/init.h
index 65405aa..a76da20 100644
--- a/init/init.h
+++ b/init/init.h
@@ -50,7 +50,7 @@
 
 void ResetWaitForProp();
 
-int main(int argc, char** argv);
+int SecondStageMain(int argc, char** argv);
 
 }  // namespace init
 }  // namespace android
diff --git a/init/main.cpp b/init/main.cpp
index 9ed451b..868c409 100644
--- a/init/main.cpp
+++ b/init/main.cpp
@@ -14,8 +14,70 @@
  * limitations under the License.
  */
 
+#include "builtins.h"
+#include "first_stage_init.h"
 #include "init.h"
+#include "selinux.h"
+#include "subcontext.h"
+#include "ueventd.h"
+
+#include <android-base/logging.h>
+
+#if __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+#endif
+
+#if __has_feature(address_sanitizer)
+// Load asan.options if it exists since these are not yet in the environment.
+// Always ensure detect_container_overflow=0 as there are false positives with this check.
+// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
+extern "C" const char* __asan_default_options() {
+    return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
+__sanitizer_report_error_summary(const char* summary) {
+    LOG(ERROR) << "Init (error summary): " << summary;
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
+AsanReportCallback(const char* str) {
+    LOG(ERROR) << "Init: " << str;
+}
+#endif
+
+using namespace android::init;
 
 int main(int argc, char** argv) {
-    android::init::main(argc, argv);
+#if __has_feature(address_sanitizer)
+    __asan_set_error_report_callback(AsanReportCallback);
+#endif
+
+    if (!strcmp(basename(argv[0]), "ueventd")) {
+        return ueventd_main(argc, argv);
+    }
+
+    if (argc < 2) {
+        return FirstStageMain(argc, argv);
+    }
+
+    if (!strcmp(argv[1], "subcontext")) {
+        android::base::InitLogging(argv, &android::base::KernelLogger);
+        const BuiltinFunctionMap function_map;
+
+        return SubcontextMain(argc, argv, &function_map);
+    }
+
+    if (!strcmp(argv[1], "selinux_setup")) {
+        return SetupSelinux(argv);
+    }
+
+    if (!strcmp(argv[1], "second_stage")) {
+        return SecondStageMain(argc, argv);
+    }
+
+    android::base::InitLogging(argv, &android::base::KernelLogger);
+
+    LOG(ERROR) << "Unknown argument passed to init '" << argv[1] << "'";
+    return 1;
 }
diff --git a/init/selinux.cpp b/init/selinux.cpp
index fd7e86f..3a09096 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -18,8 +18,8 @@
 // for SELinux operation for init.
 
 // When the system boots, there is no SEPolicy present and init is running in the kernel domain.
-// Init loads the SEPolicy from the file system, restores the context of /init based on this
-// SEPolicy, and finally exec()'s itself to run in the proper domain.
+// Init loads the SEPolicy from the file system, restores the context of /system/bin/init based on
+// this SEPolicy, and finally exec()'s itself to run in the proper domain.
 
 // The SEPolicy on Android comes in two variants: monolithic and split.
 
@@ -58,8 +58,10 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/unique_fd.h>
+#include <cutils/android_reboot.h>
 #include <selinux/android.h>
 
+#include "reboot_utils.h"
 #include "util.h"
 
 using android::base::ParseInt;
@@ -379,8 +381,6 @@
     return IsSplitPolicyDevice() ? LoadSplitPolicy() : LoadMonolithicPolicy();
 }
 
-}  // namespace
-
 void SelinuxInitialize() {
     Timer t;
 
@@ -405,6 +405,8 @@
     setenv("INIT_SELINUX_TOOK", std::to_string(t.duration().count()).c_str(), 1);
 }
 
+}  // namespace
+
 // The files and directories that were created before initial sepolicy load or
 // files on ramdisk need to have their security context restored to the proper
 // value. This must happen before /dev is populated by ueventd.
@@ -496,6 +498,39 @@
     return major_version;
 }
 
+// This function initializes SELinux then execs init to run in the init SELinux context.
+int SetupSelinux(char** argv) {
+    android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) {
+        RebootSystem(ANDROID_RB_RESTART2, "bootloader");
+    });
+
+    if (REBOOT_BOOTLOADER_ON_PANIC) {
+        InstallRebootSignalHandlers();
+    }
+
+    // Set up SELinux, loading the SELinux policy.
+    SelinuxSetupKernelLogging();
+    SelinuxInitialize();
+
+    // We're in the kernel domain and want to transition to the init domain.  File systems that
+    // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here,
+    // but other file systems do.  In particular, this is needed for ramdisks such as the
+    // recovery image for A/B devices.
+    if (selinux_android_restorecon("/system/bin/init", 0) == -1) {
+        PLOG(FATAL) << "restorecon failed of /system/bin/init failed";
+    }
+
+    const char* path = "/system/bin/init";
+    const char* args[] = {path, "second_stage", nullptr};
+    execv(path, const_cast<char**>(args));
+
+    // execv() only returns if an error happened, in which case we
+    // panic and never return from this function.
+    PLOG(FATAL) << "execv(\"" << path << "\") failed";
+
+    return 1;
+}
+
 // selinux_android_file_context_handle() takes on the order of 10+ms to run, so we want to cache
 // its value.  selinux_android_restorecon() also needs an sehandle for file context look up.  It
 // will create and store its own copy, but selinux_android_set_sehandle() can be used to provide
diff --git a/init/selinux.h b/init/selinux.h
index c41d7f0..3aa9406 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace init {
 
-void SelinuxInitialize();
+int SetupSelinux(char** argv);
 void SelinuxRestoreContext();
 
 void SelinuxSetupKernelLogging();
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 2403ad0..89837f7 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -35,6 +35,13 @@
     end = begin + 1;
   }
   Range range{begin, end};
+  if (valid_mappings_range_.end != 0 &&
+      (begin < valid_mappings_range_.begin || end > valid_mappings_range_.end)) {
+    MEM_LOG_ALWAYS_FATAL("allocation %p-%p is outside mapping range %p-%p",
+                         reinterpret_cast<void*>(begin), reinterpret_cast<void*>(end),
+                         reinterpret_cast<void*>(valid_mappings_range_.begin),
+                         reinterpret_cast<void*>(valid_mappings_range_.end));
+  }
   auto inserted = allocations_.insert(std::pair<Range, AllocationInfo>(range, AllocationInfo{}));
   if (inserted.second) {
     valid_allocations_range_.begin = std::min(valid_allocations_range_.begin, begin);
@@ -76,15 +83,22 @@
     Range range = to_do.back();
     to_do.pop_back();
 
+    walking_range_ = range;
     ForEachPtrInRange(range, [&](Range& ref_range, AllocationInfo* ref_info) {
       if (!ref_info->referenced_from_root) {
         ref_info->referenced_from_root = true;
         to_do.push_back(ref_range);
       }
     });
+    walking_range_ = Range{0, 0};
   }
 }
 
+void HeapWalker::Mapping(uintptr_t begin, uintptr_t end) {
+  valid_mappings_range_.begin = std::min(valid_mappings_range_.begin, begin);
+  valid_mappings_range_.end = std::max(valid_mappings_range_.end, end);
+}
+
 void HeapWalker::Root(uintptr_t begin, uintptr_t end) {
   roots_.push_back(Range{begin, end});
 }
@@ -113,6 +127,10 @@
 
   RecurseRoot(vals);
 
+  if (segv_page_count_ > 0) {
+    MEM_ALOGE("%zu pages skipped due to segfaults", segv_page_count_);
+  }
+
   return true;
 }
 
@@ -168,7 +186,15 @@
     handler.reset();
     return;
   }
-  MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+  if (!segv_logged_) {
+    MEM_ALOGW("failed to read page at %p, signal %d", si->si_addr, signal);
+    if (walking_range_.begin != 0U) {
+      MEM_ALOGW("while walking range %p-%p", reinterpret_cast<void*>(walking_range_.begin),
+                reinterpret_cast<void*>(walking_range_.end));
+    }
+    segv_logged_ = true;
+  }
+  segv_page_count_++;
   if (!MapOverPage(si->si_addr)) {
     handler.reset();
   }
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 92a8325..9e3db08 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -53,9 +53,14 @@
         roots_(allocator),
         root_vals_(allocator),
         segv_handler_(),
-        walking_ptr_(0) {
+        walking_ptr_(0),
+        walking_range_{0, 0},
+        segv_logged_(false),
+        segv_page_count_(0) {
     valid_allocations_range_.end = 0;
     valid_allocations_range_.begin = ~valid_allocations_range_.end;
+    valid_mappings_range_.end = 0;
+    valid_mappings_range_.begin = ~valid_allocations_range_.end;
 
     segv_handler_.install(
         SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
@@ -65,6 +70,7 @@
 
   ~HeapWalker() {}
   bool Allocation(uintptr_t begin, uintptr_t end);
+  void Mapping(uintptr_t begin, uintptr_t end);
   void Root(uintptr_t begin, uintptr_t end);
   void Root(const allocator::vector<uintptr_t>& vals);
 
@@ -95,12 +101,16 @@
   AllocationMap allocations_;
   size_t allocation_bytes_;
   Range valid_allocations_range_;
+  Range valid_mappings_range_;
 
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
 
   ScopedSignalHandler segv_handler_;
-  uintptr_t walking_ptr_;
+  volatile uintptr_t walking_ptr_;
+  Range walking_range_;
+  bool segv_logged_;
+  size_t segv_page_count_;
 };
 
 template <class F>
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index b160de9..3d7b8a8 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -87,6 +87,11 @@
                                         const allocator::vector<Mapping>& mappings,
                                         const allocator::vector<uintptr_t>& refs) {
   MEM_ALOGI("searching process %d for allocations", pid_);
+
+  for (auto it = mappings.begin(); it != mappings.end(); it++) {
+    heap_walker_.Mapping(it->begin, it->end);
+  }
+
   allocator::vector<Mapping> heap_mappings{mappings};
   allocator::vector<Mapping> anon_mappings{mappings};
   allocator::vector<Mapping> globals_mappings{mappings};
diff --git a/libmemunreachable/tests/HeapWalker_test.cpp b/libmemunreachable/tests/HeapWalker_test.cpp
index 84a0ec6..9610cd6 100644
--- a/libmemunreachable/tests/HeapWalker_test.cpp
+++ b/libmemunreachable/tests/HeapWalker_test.cpp
@@ -73,6 +73,24 @@
   ASSERT_FALSE(heap_walker.Allocation(2, 3));
 }
 
+TEST_F(HeapWalkerTest, mapping) {
+  HeapWalker heap_walker(heap_);
+  heap_walker.Mapping(2, 3);
+  heap_walker.Mapping(4, 5);
+  ASSERT_TRUE(heap_walker.Allocation(2, 3));
+  ASSERT_TRUE(heap_walker.Allocation(4, 5));
+  // space between mappings is not checked, but could be in the future
+  ASSERT_TRUE(heap_walker.Allocation(3, 4));
+
+  // re-enable malloc, ASSERT_DEATH may allocate
+  disable_malloc_.Enable();
+  ASSERT_DEATH({ heap_walker.Allocation(1, 2); }, "0x1-0x2.*outside.*0x2-0x5");
+  ASSERT_DEATH({ heap_walker.Allocation(1, 3); }, "0x1-0x3.*outside.*0x2-0x5");
+  ASSERT_DEATH({ heap_walker.Allocation(4, 6); }, "0x4-0x6.*outside.*0x2-0x5");
+  ASSERT_DEATH({ heap_walker.Allocation(5, 6); }, "0x5-0x6.*outside.*0x2-0x5");
+  ASSERT_DEATH({ heap_walker.Allocation(1, 6); }, "0x1-0x6.*outside.*0x2-0x5");
+}
+
 #define buffer_begin(buffer) reinterpret_cast<uintptr_t>(buffer)
 #define buffer_end(buffer) (reinterpret_cast<uintptr_t>(buffer) + sizeof(buffer))
 
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 14f82c7..a5e0dc9 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -184,6 +184,7 @@
         "tests/MapInfoGetLoadBiasTest.cpp",
         "tests/MapsTest.cpp",
         "tests/MemoryBufferTest.cpp",
+        "tests/MemoryCacheTest.cpp",
         "tests/MemoryFake.cpp",
         "tests/MemoryFileTest.cpp",
         "tests/MemoryLocalTest.cpp",
@@ -310,6 +311,28 @@
     ],
 }
 
+//-------------------------------------------------------------------------
+// Benchmarks
+//-------------------------------------------------------------------------
+cc_benchmark {
+    name: "unwind_benchmarks",
+    host_supported: true,
+    defaults: ["libunwindstack_flags"],
+
+    // Disable optimizations so that all of the calls are not optimized away.
+    cflags: [
+        "-O0",
+    ],
+
+    srcs: [
+        "benchmarks/unwind_benchmarks.cpp",
+    ],
+
+    shared_libs: [
+        "libunwindstack",
+    ],
+}
+
 // Generates the elf data for use in the tests for .gnu_debugdata frames.
 // Once these files are generated, use the xz command to compress the data.
 cc_binary_host {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index cfa8c6d..a30d65e 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -174,6 +174,13 @@
   return std::shared_ptr<Memory>(new MemoryRemote(pid));
 }
 
+std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
+  if (pid == getpid()) {
+    return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
+  }
+  return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
+}
+
 size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
   if (addr >= raw_.size()) {
     return 0;
@@ -398,4 +405,50 @@
   return 0;
 }
 
+size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
+  // Only bother caching and looking at the cache if this is a small read for now.
+  if (size > 64) {
+    return impl_->Read(addr, dst, size);
+  }
+
+  uint64_t addr_page = addr >> kCacheBits;
+  auto entry = cache_.find(addr_page);
+  uint8_t* cache_dst;
+  if (entry != cache_.end()) {
+    cache_dst = entry->second;
+  } else {
+    cache_dst = cache_[addr_page];
+    if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+      // Erase the entry.
+      cache_.erase(addr_page);
+      return impl_->Read(addr, dst, size);
+    }
+  }
+  size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
+  if (size <= max_read) {
+    memcpy(dst, &cache_dst[addr & kCacheMask], size);
+    return size;
+  }
+
+  // The read crossed into another cached entry, since a read can only cross
+  // into one extra cached page, duplicate the code rather than looping.
+  memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
+  dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
+  addr_page++;
+
+  entry = cache_.find(addr_page);
+  if (entry != cache_.end()) {
+    cache_dst = entry->second;
+  } else {
+    cache_dst = cache_[addr_page];
+    if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
+      // Erase the entry.
+      cache_.erase(addr_page);
+      return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
+    }
+  }
+  memcpy(dst, cache_dst, size - max_read);
+  return size;
+}
+
 }  // namespace unwindstack
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
new file mode 100644
index 0000000..db0fb54
--- /dev/null
+++ b/libunwindstack/benchmarks/unwind_benchmarks.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <memory>
+
+#include <benchmark/benchmark.h>
+
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+#include <unwindstack/Regs.h>
+#include <unwindstack/RegsGetLocal.h>
+#include <unwindstack/Unwinder.h>
+
+size_t Call6(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
+  unwindstack::RegsGetLocal(regs.get());
+  unwindstack::Unwinder unwinder(32, maps, regs.get(), process_memory);
+  unwinder.Unwind();
+  return unwinder.NumFrames();
+}
+
+size_t Call5(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  return Call6(process_memory, maps);
+}
+
+size_t Call4(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  return Call5(process_memory, maps);
+}
+
+size_t Call3(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  return Call4(process_memory, maps);
+}
+
+size_t Call2(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  return Call3(process_memory, maps);
+}
+
+size_t Call1(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
+  return Call2(process_memory, maps);
+}
+
+static void BM_uncached_unwind(benchmark::State& state) {
+  auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
+  unwindstack::LocalMaps maps;
+  if (!maps.Parse()) {
+    state.SkipWithError("Failed to parse local maps.");
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(Call1(process_memory, &maps));
+  }
+}
+BENCHMARK(BM_uncached_unwind);
+
+static void BM_cached_unwind(benchmark::State& state) {
+  auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
+  unwindstack::LocalMaps maps;
+  if (!maps.Parse()) {
+    state.SkipWithError("Failed to parse local maps.");
+  }
+
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(Call1(process_memory, &maps));
+  }
+}
+BENCHMARK(BM_cached_unwind);
+
+BENCHMARK_MAIN();
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
index 9c425cb..dba41d1 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -25,6 +25,7 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 namespace unwindstack {
@@ -35,9 +36,12 @@
   virtual ~Memory() = default;
 
   static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
+  static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
 
   virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX);
 
+  virtual void Clear() {}
+
   virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
 
   bool ReadFully(uint64_t addr, void* dst, size_t size);
@@ -51,6 +55,24 @@
   }
 };
 
+class MemoryCache : public Memory {
+ public:
+  MemoryCache(Memory* memory) : impl_(memory) {}
+  virtual ~MemoryCache() = default;
+
+  size_t Read(uint64_t addr, void* dst, size_t size) override;
+
+  void Clear() override { cache_.clear(); }
+
+ private:
+  constexpr static size_t kCacheBits = 12;
+  constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
+  constexpr static size_t kCacheSize = 1 << kCacheBits;
+  std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
+
+  std::unique_ptr<Memory> impl_;
+};
+
 class MemoryBuffer : public Memory {
  public:
   MemoryBuffer() = default;
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
new file mode 100644
index 0000000..a3def20
--- /dev/null
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <unwindstack/Memory.h>
+
+#include "MemoryFake.h"
+
+namespace unwindstack {
+
+class MemoryCacheTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    memory_ = new MemoryFake;
+    memory_cache_.reset(new MemoryCache(memory_));
+
+    memory_->SetMemoryBlock(0x8000, 4096, 0xab);
+    memory_->SetMemoryBlock(0x9000, 4096, 0xde);
+    memory_->SetMemoryBlock(0xa000, 3000, 0x50);
+  }
+
+  MemoryFake* memory_;
+  std::unique_ptr<MemoryCache> memory_cache_;
+
+  constexpr static size_t kMaxCachedSize = 64;
+};
+
+TEST_F(MemoryCacheTest, cached_read) {
+  for (size_t i = 1; i <= kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+  }
+
+  // Verify the cached data is used.
+  memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+  for (size_t i = 1; i <= kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+  }
+}
+
+TEST_F(MemoryCacheTest, no_cached_read_after_clear) {
+  for (size_t i = 1; i <= kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+  }
+
+  // Verify the cached data is not used after a reset.
+  memory_cache_->Clear();
+  memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+  for (size_t i = 1; i <= kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+  }
+}
+
+TEST_F(MemoryCacheTest, cached_read_across_caches) {
+  std::vector<uint8_t> expect(16, 0xab);
+  expect.resize(32, 0xde);
+
+  std::vector<uint8_t> buffer(32);
+  ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+  ASSERT_EQ(expect, buffer);
+
+  // Verify the cached data is used.
+  memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+  memory_->SetMemoryBlock(0x9000, 4096, 0xff);
+  ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
+  ASSERT_EQ(expect, buffer);
+}
+
+TEST_F(MemoryCacheTest, no_cache_read) {
+  for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
+  }
+
+  // Verify the cached data is not used.
+  memory_->SetMemoryBlock(0x8000, 4096, 0xff);
+  for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
+    std::vector<uint8_t> buffer(i);
+    ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
+        << "Read failed at size " << i;
+    ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
+  }
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail) {
+  std::vector<uint8_t> buffer(kMaxCachedSize);
+  ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+  ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
+
+  // Verify the cached data is not used.
+  memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+  ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
+  ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
+}
+
+TEST_F(MemoryCacheTest, read_for_cache_fail_cross) {
+  std::vector<uint8_t> expect(16, 0xde);
+  expect.resize(32, 0x50);
+
+  std::vector<uint8_t> buffer(32);
+  ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+  ASSERT_EQ(expect, buffer);
+
+  // Verify the cached data is not used for the second half but for the first.
+  memory_->SetMemoryBlock(0xa000, 3000, 0xff);
+  ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
+  expect.resize(16);
+  expect.resize(32, 0xff);
+  ASSERT_EQ(expect, buffer);
+}
+
+}  // namespace unwindstack
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2095189..9538bba 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -125,6 +125,7 @@
             enabled: true,
         },
     },
+    test_suites: ["device-tests"],
 }
 
 // Performance benchmarks.
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index fc8c960..18d5287 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -165,9 +165,14 @@
         bug_num->assign("");
     }
 
+    // Ensure the uid name is not null before passing it to the bug string.
     if (uid >= AID_APP_START && uid <= AID_APP_END) {
-        bug_num->append(" app=");
-        bug_num->append(android::uidToName(uid));
+        char* uidname = android::uidToName(uid);
+        if (uidname) {
+            bug_num->append(" app=");
+            bug_num->append(uidname);
+            free(uidname);
+        }
     }
 }
 
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index ca6aafe..461184a 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -6,35 +6,40 @@
 
 # All binaries gets the same configuration 'legacy'
 dir.legacy = /system
+dir.legacy = /product
 dir.legacy = /vendor
 dir.legacy = /odm
 dir.legacy = /sbin
 
-# Except for /postinstall, where only /system is searched
+# Except for /postinstall, where only /system and /product are searched
 dir.postinstall = /postinstall
 
 [legacy]
 namespace.default.isolated = false
 
 namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
 namespace.default.search.paths += /vendor/${LIB}
 namespace.default.search.paths += /odm/${LIB}
 
 namespace.default.asan.search.paths  = /data/asan/system/${LIB}
 namespace.default.asan.search.paths +=           /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths +=           /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/product/${LIB}
+namespace.default.asan.search.paths +=           /product/${LIB}
 namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
 namespace.default.asan.search.paths +=           /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths +=           /odm/${LIB}
 
 ###############################################################################
 # Namespace config for binaries under /postinstall.
 # Only one default namespace is defined and it has no directories other than
-# /system/lib in the search paths. This is because linker calls realpath on the
-# search paths and this causes selinux denial if the paths (/vendor, /odm) are
-# not allowed to the poinstall binaries. There is no reason to allow the
-# binaries to access the paths.
+# /system/lib and /product/lib in the search paths. This is because linker
+# calls realpath on the search paths and this causes selinux denial if the
+# paths (/vendor, /odm) are not allowed to the poinstall binaries.
+# There is no reason to allow the binaries to access the paths.
 ###############################################################################
 [postinstall]
 namespace.default.isolated = false
-namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths  = /system/${LIB}
+namespace.default.search.paths += /product/${LIB}
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 2f85dec..d47506c 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -72,7 +72,7 @@
 /dev/diag_arm9            0660   radio      radio
 /dev/ttyMSM0              0600   bluetooth  bluetooth
 /dev/uhid                 0660   uhid       uhid
-/dev/uinput               0660   system     bluetooth
+/dev/uinput               0660   uhid       uhid
 /dev/alarm                0664   system     radio
 /dev/rtc0                 0640   system     system
 /dev/tty0                 0660   root       system