Merge "Add more filesystem support to libfiemap_writer."
diff --git a/adb/Android.bp b/adb/Android.bp
index 3813578..1e085a7 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -402,6 +402,14 @@
         "liblog",
     ],
 
+    product_variables: {
+        debuggable: {
+            required: [
+                "remount",
+            ],
+        },
+    },
+
     target: {
         android: {
             srcs: [
diff --git a/adb/daemon/remount_service.cpp b/adb/daemon/remount_service.cpp
index 5e6d416..7999ddc 100644
--- a/adb/daemon/remount_service.cpp
+++ b/adb/daemon/remount_service.cpp
@@ -14,339 +14,81 @@
  * limitations under the License.
  */
 
-#define TRACE_TAG ADB
-
-#include "sysdeps.h"
-
 #include <errno.h>
 #include <fcntl.h>
-#include <mntent.h>
-#include <spawn.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <sys/mount.h>
-#include <sys/statvfs.h>
-#include <sys/vfs.h>
+#include <sys/types.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
-#include <memory>
-#include <set>
 #include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <bootloader_message/bootloader_message.h>
-#include <cutils/android_reboot.h>
-#include <fs_mgr.h>
-#include <fs_mgr_overlayfs.h>
 
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_unique_fd.h"
-#include "adb_utils.h"
-#include "set_verity_enable_state_service.h"
-
-using android::base::Realpath;
-using android::fs_mgr::Fstab;
-using android::fs_mgr::ReadDefaultFstab;
-
-// Returns the last device used to mount a directory in /proc/mounts.
-// This will find overlayfs entry where upperdir=lowerdir, to make sure
-// remount is associated with the correct directory.
-static std::string find_proc_mount(const char* dir) {
-    std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
-    std::string mnt_fsname;
-    if (!fp) return mnt_fsname;
-
-    // dir might be a symlink, e.g., /product -> /system/product in GSI.
-    std::string canonical_path;
-    if (!Realpath(dir, &canonical_path)) {
-        PLOG(ERROR) << "Realpath failed: " << dir;
-    }
-
-    mntent* e;
-    while ((e = getmntent(fp.get())) != nullptr) {
-        if (canonical_path == e->mnt_dir) {
-            mnt_fsname = e->mnt_fsname;
-        }
-    }
-    return mnt_fsname;
-}
-
-// Returns the device used to mount a directory in the fstab.
-static std::string find_fstab_mount(const char* dir) {
-    Fstab fstab;
-    if (!ReadDefaultFstab(&fstab)) {
-        return "";
-    }
-
-    auto entry = std::find_if(fstab.begin(), fstab.end(),
-                              [&dir](const auto& entry) { return entry.mount_point == dir; });
-    if (entry == fstab.end()) {
-        return "";
-    }
-    if (entry->fs_mgr_flags.logical) {
-        fs_mgr_update_logical_partition(&(*entry));
-    }
-    return entry->blk_device;
-}
-
-// The proc entry for / is full of lies, so check fstab instead.
-// /proc/mounts lists rootfs and /dev/root, neither of which is what we want.
-static std::string find_mount(const char* dir, bool is_root) {
-    if (is_root) {
-        return find_fstab_mount(dir);
-    } else {
-        return find_proc_mount(dir);
-    }
-}
-
-bool dev_is_overlayfs(const std::string& dev) {
-    return (dev == "overlay") || (dev == "overlayfs");
-}
-
-bool make_block_device_writable(const std::string& dev) {
-    if (dev_is_overlayfs(dev)) return true;
-    int fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
-    if (fd == -1) {
-        return false;
-    }
-
-    int OFF = 0;
-    bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
-    unix_close(fd);
-    return result;
-}
-
-static bool can_unshare_blocks(int fd, const char* dev) {
-    const char* E2FSCK_BIN = "/system/bin/e2fsck";
-    if (access(E2FSCK_BIN, X_OK)) {
-        WriteFdFmt(fd, "e2fsck is not available, cannot undo deduplication on %s\n", dev);
-        return false;
-    }
-
-    pid_t child;
-    char* env[] = {nullptr};
-    const char* argv[] = {E2FSCK_BIN, "-n", "-E", "unshare_blocks", dev, nullptr};
-    if (posix_spawn(&child, E2FSCK_BIN, nullptr, nullptr, const_cast<char**>(argv), env)) {
-        WriteFdFmt(fd, "failed to e2fsck to check deduplication: %s\n", strerror(errno));
-        return false;
-    }
-    int status = 0;
-    int ret = TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
-    if (ret < 0) {
-        WriteFdFmt(fd, "failed to get e2fsck status: %s\n", strerror(errno));
-        return false;
-    }
-    if (!WIFEXITED(status)) {
-        WriteFdFmt(fd, "e2fsck exited abnormally with status %d\n", status);
-        return false;
-    }
-    int rc = WEXITSTATUS(status);
-    if (rc != 0) {
-        WriteFdFmt(fd,
-                   "%s is deduplicated, and an e2fsck check failed. It might not "
-                   "have enough free-space to be remounted as writable.\n",
-                   dev);
-        return false;
-    }
-    return true;
-}
-
-static unsigned long get_mount_flags(int fd, const char* dir) {
-    struct statvfs st_vfs;
-    if (statvfs(dir, &st_vfs) == -1) {
-        // Even though we could not get the original mount flags, assume that
-        // the mount was originally read-only.
-        WriteFdFmt(fd, "statvfs of the %s mount failed: %s.\n", dir, strerror(errno));
-        return MS_RDONLY;
-    }
-    return st_vfs.f_flag;
-}
-
-static bool remount_partition(int fd, const char* dir) {
-    if (!directory_exists(dir)) {
-        return true;
-    }
-    bool is_root = strcmp(dir, "/") == 0;
-    if (is_root && dev_is_overlayfs(find_mount("/system", false))) {
-        dir = "/system";
-        is_root = false;
-    }
-    std::string dev = find_mount(dir, is_root);
-    if (is_root && dev.empty()) {
-        // The fstab entry will be /system if the device switched roots during
-        // first-stage init.
-        dev = find_mount("/system", true);
-    }
-    // Even if the device for the root is not found, we still try to remount it
-    // as rw. This typically only happens when running Android in a container:
-    // the root will almost always be in a loop device, which is dynamic, so
-    // it's not convenient to put in the fstab.
-    if (dev.empty() && !is_root) {
-        return true;
-    }
-    if (!dev.empty() && !make_block_device_writable(dev)) {
-        WriteFdFmt(fd, "remount of %s failed; couldn't make block device %s writable: %s\n",
-                   dir, dev.c_str(), strerror(errno));
-        return false;
-    }
-
-    unsigned long remount_flags = get_mount_flags(fd, dir);
-    remount_flags &= ~MS_RDONLY;
-    remount_flags |= MS_REMOUNT;
-
-    if (mount(dev.c_str(), dir, "none", remount_flags | MS_BIND, nullptr) == -1) {
-        // This is useful for cases where the superblock is already marked as
-        // read-write, but the mount itself is read-only, such as containers
-        // where the remount with just MS_REMOUNT is forbidden by the kernel.
-        WriteFdFmt(fd, "remount of the %s mount failed: %s.\n", dir, strerror(errno));
-        return false;
-    }
-    if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
-        WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
-        return false;
-    }
-    return true;
-}
-
-static void reboot_for_remount(int fd, bool need_fsck) {
-    std::string reboot_cmd = "reboot";
-    if (need_fsck) {
-        const std::vector<std::string> options = {"--fsck_unshare_blocks"};
-        std::string err;
-        if (!write_bootloader_message(options, &err)) {
-            WriteFdFmt(fd, "Failed to set bootloader message: %s\n", err.c_str());
-            return;
-        }
-
-        WriteFdExactly(fd,
-                       "The device will now reboot to recovery and attempt "
-                       "un-deduplication.\n");
-        reboot_cmd = "reboot,recovery";
-    }
-
-    sync();
-    android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd.c_str());
-}
-
-static void try_unmount_bionic(int fd) {
-    static constexpr const char* kBionic = "/bionic";
-    struct statfs buf;
-    if (statfs(kBionic, &buf) == -1) {
-        WriteFdFmt(fd, "statfs of the %s mount failed: %s.\n", kBionic, strerror(errno));
-        return;
-    }
-    if (buf.f_flags & ST_RDONLY) {
-        // /bionic is on a read-only partition; can happen for
-        // non-system-as-root-devices. Don' try to unmount.
-        return;
-    }
-    // Success/Fail of the actual remount will be reported by the function.
-    remount_partition(fd, kBionic);
-    return;
-}
 
 void remount_service(unique_fd fd, const std::string& cmd) {
-    bool user_requested_reboot = cmd == "-R";
+    static constexpr char remount_cmd[] = "/system/bin/remount";
+    static constexpr char remount_failed[] = "remount failed\n";
 
     if (getuid() != 0) {
         WriteFdExactly(fd.get(), "Not running as root. Try \"adb root\" first.\n");
+        WriteFdExactly(fd.get(), remount_failed);
         return;
     }
 
-    bool system_verified = !(android::base::GetProperty("partition.system.verified", "").empty());
-    bool vendor_verified = !(android::base::GetProperty("partition.vendor.verified", "").empty());
-
-    std::vector<std::string> partitions{"/",        "/odm",   "/oem", "/product_services",
-                                        "/product", "/vendor"};
-
-    if (system_verified || vendor_verified) {
-        // Disable verity automatically (reboot will be required).
-        set_verity_enabled_state_service(unique_fd(dup(fd.get())), false);
-
-        // If overlayfs is not supported, we try and remount or set up
-        // un-deduplication. If it is supported, we can go ahead and wait for
-        // a reboot.
-        if (fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported) {
-            if (user_requested_reboot) {
-                if (android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot")) {
-                    WriteFdExactly(fd.get(), "rebooting device\n");
-                } else {
-                    WriteFdExactly(fd.get(), "reboot failed\n");
-                }
-            }
-            return;
-        }
-    } else if (fs_mgr_overlayfs_setup()) {
-        // If we can use overlayfs, lets get it in place first before we
-        // struggle with determining deduplication operations.
-        Fstab fstab;
-        if (ReadDefaultFstab(&fstab) && fs_mgr_overlayfs_mount_all(&fstab)) {
-            WriteFdExactly(fd.get(), "overlayfs mounted\n");
-        }
-    }
-
-    // If overlayfs is supported, we don't bother trying to un-deduplicate
-    // partitions.
-    std::set<std::string> dedup;
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
-        // Find partitions that are deduplicated, and can be un-deduplicated.
-        for (const auto& part : partitions) {
-            auto partition = part;
-            if ((part == "/") && !find_mount("/system", false).empty()) partition = "/system";
-            std::string dev = find_mount(partition.c_str(), partition == "/");
-            if (dev.empty() || !fs_mgr_has_shared_blocks(partition, dev)) {
-                continue;
-            }
-            if (can_unshare_blocks(fd.get(), dev.c_str())) {
-                dedup.emplace(partition);
-            }
-        }
-
-        // Reboot now if the user requested it (and an operation needs a reboot).
-        if (user_requested_reboot) {
-            if (!dedup.empty()) {
-                reboot_for_remount(fd.get(), !dedup.empty());
-                return;
-            }
-            WriteFdExactly(fd.get(), "No reboot needed, skipping -R.\n");
-        }
-    }
-
-    bool success = true;
-    for (const auto& partition : partitions) {
-        // Don't try to remount partitions that need an fsck in recovery.
-        if (dedup.count(partition)) {
-            continue;
-        }
-        success &= remount_partition(fd.get(), partition.c_str());
-    }
-
-    if (!dedup.empty()) {
-        WriteFdExactly(fd.get(),
-                       "The following partitions are deduplicated and cannot "
-                       "yet be remounted:\n");
-        for (const std::string& name : dedup) {
-            WriteFdFmt(fd.get(), "  %s\n", name.c_str());
-        }
-
-        WriteFdExactly(fd.get(),
-                       "To reboot and un-deduplicate the listed partitions, "
-                       "please retry with adb remount -R.\n");
-        if (system_verified || vendor_verified) {
-            WriteFdExactly(fd.get(), "Note: verity will be automatically disabled after reboot.\n");
-        }
+    auto pid = vfork();
+    if (pid < 0) {
+        WriteFdFmt(fd.get(), "Failed to fork to %s: %s\n", remount_cmd, strerror(errno));
+        WriteFdExactly(fd.get(), remount_failed);
         return;
     }
 
-    try_unmount_bionic(fd.get());
+    if (pid == 0) {
+        // child side of the fork
+        fcntl(fd.get(), F_SETFD, 0);
+        dup2(fd.get(), STDIN_FILENO);
+        dup2(fd.get(), STDOUT_FILENO);
+        dup2(fd.get(), STDERR_FILENO);
 
-    if (!success) {
-        WriteFdExactly(fd.get(), "remount failed\n");
-    } else {
-        WriteFdExactly(fd.get(), "remount succeeded\n");
+        execl(remount_cmd, remount_cmd, cmd.empty() ? nullptr : cmd.c_str(), nullptr);
+        _exit(-errno ?: 42);
     }
+
+    int wstatus = 0;
+    auto ret = waitpid(pid, &wstatus, 0);
+
+    if (ret == -1) {
+        WriteFdFmt(fd.get(), "Failed to wait for %s: %s\n", remount_cmd, strerror(errno));
+        goto err;
+    }
+
+    if (ret != pid) {
+        WriteFdFmt(fd.get(), "pid %d and waitpid return %d do not match for %s\n",
+                   static_cast<int>(pid), static_cast<int>(ret), remount_cmd);
+        goto err;
+    }
+
+    if (WIFSIGNALED(wstatus)) {
+        WriteFdFmt(fd.get(), "%s terminated with signal %s\n", remount_cmd,
+                   strsignal(WTERMSIG(wstatus)));
+        goto err;
+    }
+
+    if (!WIFEXITED(wstatus)) {
+        WriteFdFmt(fd.get(), "%s stopped with status 0x%x\n", remount_cmd, wstatus);
+        goto err;
+    }
+
+    if (WEXITSTATUS(wstatus)) {
+        WriteFdFmt(fd.get(), "%s exited with status %d\n", remount_cmd,
+                   static_cast<signed char>(WEXITSTATUS(wstatus)));
+        goto err;
+    }
+
+    WriteFdExactly(fd.get(), "remount succeeded\n");
+    return;
+
+err:
+    WriteFdExactly(fd.get(), remount_failed);
 }
diff --git a/adb/daemon/remount_service.h b/adb/daemon/remount_service.h
index c847403..522a5da 100644
--- a/adb/daemon/remount_service.h
+++ b/adb/daemon/remount_service.h
@@ -21,6 +21,5 @@
 #include "adb_unique_fd.h"
 
 #if defined(__ANDROID__)
-bool make_block_device_writable(const std::string&);
 void remount_service(unique_fd, const std::string&);
 #endif
diff --git a/adb/daemon/set_verity_enable_state_service.cpp b/adb/daemon/set_verity_enable_state_service.cpp
index 92851c0..658261e 100644
--- a/adb/daemon/set_verity_enable_state_service.cpp
+++ b/adb/daemon/set_verity_enable_state_service.cpp
@@ -25,6 +25,7 @@
 #include <libavb_user/libavb_user.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <sys/mount.h>
 #include <sys/stat.h>
 
 #include <android-base/properties.h>
@@ -37,7 +38,6 @@
 #include "adb.h"
 #include "adb_io.h"
 #include "adb_unique_fd.h"
-#include "remount_service.h"
 
 #include "fec/io.h"
 
@@ -51,6 +51,18 @@
     if (getuid() != 0) WriteFdExactly(fd, "Maybe run adb root?\n");
 }
 
+static bool make_block_device_writable(const std::string& dev) {
+    int fd = unix_open(dev, O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        return false;
+    }
+
+    int OFF = 0;
+    bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
+    unix_close(fd);
+    return result;
+}
+
 /* Turn verity on/off */
 static bool set_verity_enabled_state(int fd, const char* block_device, const char* mount_point,
                                      bool enable) {
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index c0e0ccd..6312734 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -42,13 +42,14 @@
 
 [[noreturn]] void usage(int exit_status) {
     LOG(INFO) << getprogname()
-              << " [-h] [-R] [-T fstab_file]\n"
+              << " [-h] [-R] [-T fstab_file] [partition]...\n"
                  "\t-h --help\tthis help\n"
                  "\t-R --reboot\tdisable verity & reboot to facilitate remount\n"
                  "\t-T --fstab\tcustom fstab file location\n"
+                 "\tpartition\tspecific partition(s) (empty does all)\n"
                  "\n"
-                 "Remount all partitions read-write.\n"
-                 "-R notwithstanding, verity must be disabled.";
+                 "Remount specified partition(s) read-write, by name or mount point.\n"
+                 "-R notwithstanding, verity must be disabled on partition(s).";
 
     ::exit(exit_status);
 }
@@ -138,6 +139,8 @@
         BADARG,
         NOT_ROOT,
         NO_FSTAB,
+        UNKNOWN_PARTITION,
+        INVALID_PARTITION,
         VERITY_PARTITION,
         BAD_OVERLAY,
         NO_MOUNTS,
@@ -183,11 +186,6 @@
         }
     }
 
-    if (argc > optind) {
-        LOG(ERROR) << "Bad Argument " << argv[optind];
-        usage(BADARG);
-    }
-
     // Make sure we are root.
     if (::getuid() != 0) {
         LOG(ERROR) << "must be run as root";
@@ -211,16 +209,58 @@
     auto overlayfs_candidates = fs_mgr_overlayfs_candidate_list(fstab);
 
     // Generate the all remountable partitions sub-list
-    android::fs_mgr::Fstab partitions;
+    android::fs_mgr::Fstab all;
     for (auto const& entry : fstab) {
         if (!remountable_partition(entry)) continue;
         if (overlayfs_candidates.empty() ||
             GetEntryForMountPoint(&overlayfs_candidates, entry.mount_point) ||
             (is_wrapped(overlayfs_candidates, entry) == nullptr)) {
-            partitions.emplace_back(entry);
+            all.emplace_back(entry);
         }
     }
 
+    // Parse the unique list of valid partition arguments.
+    android::fs_mgr::Fstab partitions;
+    for (; argc > optind; ++optind) {
+        auto partition = std::string(argv[optind]);
+        if (partition.empty()) continue;
+        if (partition == "/") partition = "/system";
+        auto find_part = [&partition](const auto& entry) {
+            const auto mount_point = system_mount_point(entry);
+            if (partition == mount_point) return true;
+            if (partition == android::base::Basename(mount_point)) return true;
+            return false;
+        };
+        // Do we know about the partition?
+        auto it = std::find_if(fstab.begin(), fstab.end(), find_part);
+        if (it == fstab.end()) {
+            LOG(ERROR) << "Unknown partition " << partition << ", skipping";
+            retval = UNKNOWN_PARTITION;
+            continue;
+        }
+        // Is that one covered by an existing overlayfs?
+        auto wrap = is_wrapped(overlayfs_candidates, *it);
+        if (wrap) {
+            LOG(INFO) << "partition " << partition << " covered by overlayfs for "
+                      << wrap->mount_point << ", switching";
+            partition = system_mount_point(*wrap);
+        }
+        // Is it a remountable partition?
+        it = std::find_if(all.begin(), all.end(), find_part);
+        if (it == all.end()) {
+            LOG(ERROR) << "Invalid partition " << partition << ", skipping";
+            retval = INVALID_PARTITION;
+            continue;
+        }
+        if (GetEntryForMountPoint(&partitions, it->mount_point) == nullptr) {
+            partitions.emplace_back(*it);
+        }
+    }
+
+    if (partitions.empty() && !retval) {
+        partitions = all;
+    }
+
     // Check verity and optionally setup overlayfs backing.
     auto reboot_later = false;
     for (auto it = partitions.begin(); it != partitions.end();) {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 1ded954..a6baf1d 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -620,7 +620,7 @@
 
   echo "${GREEN}[ RUN      ]${NORMAL} Testing adb shell su root remount -R command" >&2
 
-  adb_su remount -R </dev/null || true
+  adb_su remount -R system </dev/null || true
   sleep 2
   adb_wait 2m ||
     die "waiting for device after remount -R `usb_status`"
@@ -1159,10 +1159,12 @@
   die "lost device after reboot to ro state (USB stack broken?)"
 adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
   die "/vendor is not read-only"
-adb_su remount </dev/null ||
+adb_su remount vendor </dev/null ||
   die "remount command"
 adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
   die "/vendor is not read-write"
+adb_sh grep " /system .* rw," /proc/mounts >/dev/null </dev/null &&
+  die "/vendor is not read-only"
 echo "${GREEN}[       OK ]${NORMAL} remount command works from setup" >&2
 
 # Prerequisite is an overlayfs deconstructed device but with verity disabled.
@@ -1177,10 +1179,12 @@
   die "lost device after reboot after wipe (USB stack broken?)"
 adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null &&
   die "/vendor is not read-only"
-adb_su remount </dev/null ||
+adb_su remount vendor </dev/null ||
   die "remount command"
 adb_sh grep " /vendor .* rw," /proc/mounts >/dev/null </dev/null ||
   die "/vendor is not read-write"
+adb_sh grep " /system .* rw," /proc/mounts >/dev/null </dev/null &&
+  die "/system is not read-only"
 echo "${GREEN}[       OK ]${NORMAL} remount command works from scratch" >&2
 
 restore
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 538ed00..6511d29 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1119,13 +1119,21 @@
 }
 
 static Result<Success> do_setup_runtime_bionic(const BuiltinArguments& args) {
-    if (SwitchToDefaultMountNamespace()) {
+    if (SetupRuntimeBionic()) {
         return Success();
     } else {
         return Error() << "Failed to setup runtime bionic";
     }
 }
 
+static Result<Success> do_enter_default_mount_ns(const BuiltinArguments& args) {
+    if (SwitchToDefaultMountNamespace()) {
+        return Success();
+    } else {
+        return Error() << "Failed to enter into default mount namespace";
+    }
+}
+
 // Builtin-function-map start
 const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
     constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
@@ -1177,6 +1185,7 @@
         {"start",                   {1,     1,    {false,  do_start}}},
         {"stop",                    {1,     1,    {false,  do_stop}}},
         {"swapon_all",              {1,     1,    {false,  do_swapon_all}}},
+        {"enter_default_mount_ns",  {0,     0,    {false,  do_enter_default_mount_ns}}},
         {"symlink",                 {2,     2,    {true,   do_symlink}}},
         {"sysclktz",                {1,     1,    {false,  do_sysclktz}}},
         {"trigger",                 {1,     1,    {false,  do_trigger}}},
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index e11d897..7cf4c3f 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -155,6 +155,10 @@
     // part of the product partition, e.g. because they are mounted read-write.
     CHECKCALL(mkdir("/mnt/product", 0755));
 
+    // /apex is used to mount APEXes
+    CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+                    "mode=0755,uid=0,gid=0"));
+
 #undef CHECKCALL
 
     // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index 413fe8f..327446a 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -172,6 +172,11 @@
                          kBionicLibsMountPointDir64))
         return false;
 
+    // /apex is also a private mountpoint to give different sets of APEXes for
+    // the bootstrap and default mount namespaces. The processes running with
+    // the bootstrap namespace get APEXes from the read-only partition.
+    if (!(MakePrivate("/apex"))) return false;
+
     bootstrap_ns_fd.reset(OpenMountNamespace());
     bootstrap_ns_id = GetMountNamespaceId();
 
@@ -227,6 +232,17 @@
         }
     }
 
+    LOG(INFO) << "Switched to default mount namespace";
+    return true;
+}
+
+// TODO(jiyong): remove this when /system/lib/libc.so becomes
+// a symlink to /apex/com.android.runtime/lib/bionic/libc.so
+bool SetupRuntimeBionic() {
+    if (IsRecoveryMode()) {
+        // We don't have multiple namespaces in recovery mode
+        return true;
+    }
     // Bind-mount bionic from the runtime APEX since it is now available. Note
     // that in case of IsBionicUpdatable() == false, these mounts are over the
     // existing existing bind mounts for the bootstrap bionic, which effectively
@@ -238,7 +254,7 @@
                          kBionicLibsMountPointDir64))
         return false;
 
-    LOG(INFO) << "Switched to default mount namespace";
+    LOG(INFO) << "Runtime bionic is set up";
     return true;
 }
 
diff --git a/init/mount_namespace.h b/init/mount_namespace.h
index c41a449..4eef785 100644
--- a/init/mount_namespace.h
+++ b/init/mount_namespace.h
@@ -20,6 +20,7 @@
 namespace init {
 
 bool SetupMountNamespaces();
+bool SetupRuntimeBionic();
 bool SwitchToDefaultMountNamespace();
 bool SwitchToBootstrapMountNamespaceIfNeeded();
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index ee302c1..3fadfed 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -459,6 +459,8 @@
 
     selinux_android_restorecon("/dev/block", SELINUX_ANDROID_RESTORECON_RECURSE);
     selinux_android_restorecon("/dev/device-mapper", 0);
+
+    selinux_android_restorecon("/apex", 0);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 98b3aa1..18421e8 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -1329,7 +1329,7 @@
 static int last_killed_pid = -1;
 
 /* Kill one process specified by procp.  Returns the size of the process killed */
-static int kill_one_process(struct proc* procp) {
+static int kill_one_process(struct proc* procp, int min_oom_score) {
     int pid = procp->pid;
     uid_t uid = procp->uid;
     char *taskname;
@@ -1340,6 +1340,9 @@
 #ifdef LMKD_LOG_STATS
     struct memory_stat mem_st = {};
     int memory_stat_parse_result = -1;
+#else
+    /* To prevent unused parameter warning */
+    (void)(min_oom_score);
 #endif
 
     taskname = proc_get_name(pid);
@@ -1385,10 +1388,12 @@
         if (memory_stat_parse_result == 0) {
             stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname,
                     procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes,
-                    mem_st.cache_in_bytes, mem_st.swap_in_bytes, mem_st.process_start_time_ns);
+                    mem_st.cache_in_bytes, mem_st.swap_in_bytes, mem_st.process_start_time_ns,
+                    min_oom_score);
         } else if (enable_stats_log) {
             stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj,
-                                          -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1, -1);
+                                          -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1, -1,
+                                          min_oom_score);
         }
 #endif
         result = tasksize;
@@ -1425,7 +1430,7 @@
             if (!procp)
                 break;
 
-            killed_size = kill_one_process(procp);
+            killed_size = kill_one_process(procp, min_score_adj);
             if (killed_size >= 0) {
 #ifdef LMKD_LOG_STATS
                 if (enable_stats_log && !lmk_state_change_start) {
diff --git a/lmkd/statslog.c b/lmkd/statslog.c
index 689e8ae..0c230ae 100644
--- a/lmkd/statslog.c
+++ b/lmkd/statslog.c
@@ -65,7 +65,8 @@
 stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
                               char const* process_name, int32_t oom_score, int64_t pgfault,
                               int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
-                              int64_t swap_in_bytes, int64_t process_start_time_ns) {
+                              int64_t swap_in_bytes, int64_t process_start_time_ns,
+                              int32_t min_oom_score) {
     assert(ctx != NULL);
     int ret = -EINVAL;
     if (!ctx) {
@@ -117,5 +118,9 @@
         return ret;
     }
 
+    if ((ret = android_log_write_int32(ctx, min_oom_score)) < 0) {
+        return ret;
+    }
+
     return write_to_logger(ctx, LOG_ID_STATS);
 }
diff --git a/lmkd/statslog.h b/lmkd/statslog.h
index f3abe11..2edba7a 100644
--- a/lmkd/statslog.h
+++ b/lmkd/statslog.h
@@ -88,7 +88,8 @@
 stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid,
                               char const* process_name, int32_t oom_score, int64_t pgfault,
                               int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes,
-                              int64_t swap_in_bytes, int64_t process_start_time_ns);
+                              int64_t swap_in_bytes, int64_t process_start_time_ns,
+                              int32_t min_oom_score);
 
 __END_DECLS
 
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 28703d2..4b2dd07 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -68,6 +68,9 @@
 namespace.default.permitted.paths += /vendor/framework
 namespace.default.permitted.paths += /vendor/app
 namespace.default.permitted.paths += /vendor/priv-app
+namespace.default.permitted.paths += /system/vendor/framework
+namespace.default.permitted.paths += /system/vendor/app
+namespace.default.permitted.paths += /system/vendor/priv-app
 namespace.default.permitted.paths += /odm/framework
 namespace.default.permitted.paths += /odm/app
 namespace.default.permitted.paths += /odm/priv-app
@@ -100,6 +103,9 @@
 namespace.default.asan.permitted.paths += /vendor/framework
 namespace.default.asan.permitted.paths += /vendor/app
 namespace.default.asan.permitted.paths += /vendor/priv-app
+namespace.default.asan.permitted.paths += /system/vendor/framework
+namespace.default.asan.permitted.paths += /system/vendor/app
+namespace.default.asan.permitted.paths += /system/vendor/priv-app
 namespace.default.asan.permitted.paths += /odm/framework
 namespace.default.asan.permitted.paths += /odm/app
 namespace.default.asan.permitted.paths += /odm/priv-app
@@ -236,6 +242,7 @@
 
 namespace.sphal.permitted.paths  = /odm/${LIB}
 namespace.sphal.permitted.paths += /vendor/${LIB}
+namespace.sphal.permitted.paths += /system/vendor/${LIB}
 
 namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.sphal.asan.search.paths +=           /odm/${LIB}
@@ -278,6 +285,7 @@
 
 namespace.rs.permitted.paths  = /odm/${LIB}
 namespace.rs.permitted.paths += /vendor/${LIB}
+namespace.rs.permitted.paths += /system/vendor/${LIB}
 namespace.rs.permitted.paths += /data
 
 namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
@@ -323,6 +331,8 @@
 namespace.vndk.permitted.paths += /odm/${LIB}/egl
 namespace.vndk.permitted.paths += /vendor/${LIB}/hw
 namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+namespace.vndk.permitted.paths += /system/vendor/${LIB}/hw
+namespace.vndk.permitted.paths += /system/vendor/${LIB}/egl
 # This is exceptionally required since android.hidl.memory@1.0-impl.so is here
 namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
 
@@ -390,6 +400,7 @@
 
 namespace.default.permitted.paths  = /odm
 namespace.default.permitted.paths += /vendor
+namespace.default.permitted.paths += /system/vendor
 #VNDK27#namespace.default.search.paths += /vendor/${LIB}/hw
 #VNDK27#namespace.default.search.paths += /vendor/${LIB}/egl
 
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index a5beb4e..54f4c98 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -184,6 +184,7 @@
 
 namespace.sphal.permitted.paths  = /odm/${LIB}
 namespace.sphal.permitted.paths += /vendor/${LIB}
+namespace.sphal.permitted.paths += /system/vendor/${LIB}
 
 namespace.sphal.asan.search.paths  = /data/asan/odm/${LIB}
 namespace.sphal.asan.search.paths +=           /odm/${LIB}
@@ -226,6 +227,7 @@
 
 namespace.rs.permitted.paths  = /odm/${LIB}
 namespace.rs.permitted.paths += /vendor/${LIB}
+namespace.rs.permitted.paths += /system/vendor/${LIB}
 namespace.rs.permitted.paths += /data
 
 namespace.rs.asan.search.paths  = /data/asan/odm/${LIB}/vndk-sp
@@ -271,6 +273,7 @@
 namespace.vndk.permitted.paths += /odm/${LIB}/egl
 namespace.vndk.permitted.paths += /vendor/${LIB}/hw
 namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+namespace.vndk.permitted.paths += /system/vendor/${LIB}/egl
 # This is exceptionally required since android.hidl.memory@1.0-impl.so is here
 namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ce4b380..b44cc3e 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -13,12 +13,6 @@
 
 # Cgroups are mounted right before early-init using list from /etc/cgroups.json
 on early-init
-    # Mount shared so changes propagate into child namespaces
-    # Do this before other processes are started from init. Otherwise,
-    # processes launched while the propagation type of / is 'private'
-    # won't get mount events from others.
-    mount rootfs rootfs / shared rec
-
     # Set init and its forked children's oom_adj.
     write /proc/1/oom_score_adj -1000
 
@@ -43,6 +37,11 @@
 
     start ueventd
 
+    # Run apexd-bootstrap so that APEXes that provide critical libraries
+    # become available. Note that this is executed as exec_start to ensure that
+    # the libraries are available to the processes started after this statement.
+    exec_start apexd-bootstrap
+
 on init
     sysclktz 0
 
@@ -278,18 +277,9 @@
     write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}
     chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}
 
-    # Setup APEX mount point and its security context
-    mount tmpfs tmpfs /apex nodev noexec nosuid
-    chmod 0755 /apex
-    chown root root /apex
-    restorecon /apex
-
     # Start logd before any other services run to ensure we capture all of their logs.
     start logd
 
-    # Start apexd as soon as we can
-    start apexd
-
     # Start essential services.
     start servicemanager
     start hwservicemanager
@@ -425,8 +415,16 @@
     mkdir /data/bootchart 0755 shell shell
     bootchart start
 
-    # /data/apex is now available. Let apexd to scan and activate APEXes.
-    setprop apexd.data.status ready
+    # Make sure that apexd is started in the default namespace
+    enter_default_mount_ns
+
+    # /data/apex is now available. Start apexd to scan and activate APEXes.
+    mkdir /data/apex 0750 root system
+    mkdir /data/apex/active 0750 root system
+    mkdir /data/apex/backup 0700 root system
+    mkdir /data/apex/sessions 0700 root system
+    mkdir /data/pkg_staging 0750 system system
+    start apexd
 
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom
@@ -543,12 +541,6 @@
 
     mkdir /data/anr 0775 system system
 
-    mkdir /data/apex 0750 root system
-    mkdir /data/apex/active 0750 root system
-    mkdir /data/apex/backup 0700 root system
-    mkdir /data/apex/sessions 0700 root system
-    mkdir /data/pkg_staging 0750 system system
-
     # NFC: create data/nfc for nv storage
     mkdir /data/nfc 0770 nfc nfc
     mkdir /data/nfc/param 0770 nfc nfc
@@ -581,6 +573,12 @@
     mkdir /data/cache/backup_stage 0700 system system
     mkdir /data/cache/backup 0700 system system
 
+    # Wait for apexd to finish activating APEXes before starting more processes.
+    wait_for_prop apexd.status ready
+    # TODO(jiyong): remove setup_runtime_bionic
+    setup_runtime_bionic
+    parse_apex_configs
+
     init_user0
 
     # Set SELinux security contexts on upgrade or policy update.
@@ -589,14 +587,6 @@
     # load fsverity keys
     exec -- /system/bin/mini-keyctl -c /product/etc/security/cacerts_fsverity,/vendor/etc/security/cacerts_fsverity -k .fs-verity
 
-    # Wait for apexd to finish activating APEXes before starting more processes.
-    # This certainly reduces the parallelism but is required to make as many processes
-    # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms
-    # so the impact on the booting time is not significant.
-    wait_for_prop apexd.status ready
-    setup_runtime_bionic
-    parse_apex_configs
-
     # Check any timezone data in /data is newer than the copy in the runtime module, delete if not.
     exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo
 
diff --git a/toolbox/Android.bp b/toolbox/Android.bp
index f08cf93..7ad6f1c 100644
--- a/toolbox/Android.bp
+++ b/toolbox/Android.bp
@@ -59,6 +59,7 @@
     name: "r",
     defaults: ["toolbox_defaults"],
     srcs: ["r.c"],
+    vendor_available: true,
 }
 
 // We build BSD grep separately (but see http://b/111849261).