Merge changes from topic "b/129002747"

* changes:
  Make VTS run libdm_test
  Create a VTS test from liblp_test
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index d07a007..b42236e 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -640,7 +640,10 @@
 }
 
 void usb_init() {
-    bool use_nonblocking = android::base::GetBoolProperty("persist.adb.nonblocking_ffs", true);
+    bool use_nonblocking = android::base::GetBoolProperty(
+            "persist.adb.nonblocking_ffs",
+            android::base::GetBoolProperty("ro.adb.nonblocking_ffs", true));
+
     if (use_nonblocking) {
         std::thread(usb_ffs_open_thread).detach();
     } else {
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index fc5c1ce..8e9716f 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -56,23 +56,17 @@
 extern template std::string Join(const std::vector<const char*>&, const std::string&);
 
 // Tests whether 's' starts with 'prefix'.
-// TODO: string_view
-bool StartsWith(const std::string& s, const char* prefix);
-bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
-bool StartsWith(const std::string& s, const std::string& prefix);
-bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix);
-bool StartsWith(const std::string& s, char prefix);
+bool StartsWith(std::string_view s, std::string_view prefix);
+bool StartsWith(std::string_view s, char prefix);
+bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix);
 
 // Tests whether 's' ends with 'suffix'.
-// TODO: string_view
-bool EndsWith(const std::string& s, const char* suffix);
-bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
-bool EndsWith(const std::string& s, const std::string& suffix);
-bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix);
-bool EndsWith(const std::string& s, char suffix);
+bool EndsWith(std::string_view s, std::string_view suffix);
+bool EndsWith(std::string_view s, char suffix);
+bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix);
 
 // Tests whether 'lhs' equals 'rhs', ignoring case.
-bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
+bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs);
 
 }  // namespace base
 }  // namespace android
diff --git a/base/strings.cpp b/base/strings.cpp
index 2d6eef0..bb3167e 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,58 +87,33 @@
 template std::string Join(const std::vector<std::string>&, const std::string&);
 template std::string Join(const std::vector<const char*>&, const std::string&);
 
-bool StartsWith(const std::string& s, const char* prefix) {
-  return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
+bool StartsWith(std::string_view s, std::string_view prefix) {
+  return s.substr(0, prefix.size()) == prefix;
 }
 
-bool StartsWith(const std::string& s, const std::string& prefix) {
-  return strncmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+bool StartsWith(std::string_view s, char prefix) {
+  return !s.empty() && s.front() == prefix;
 }
 
-bool StartsWith(const std::string& s, char prefix) {
-  return *s.c_str() == prefix;  // Use c_str() to guarantee there is at least a '\0'.
+bool StartsWithIgnoreCase(std::string_view s, std::string_view prefix) {
+  return s.size() >= prefix.size() && strncasecmp(s.data(), prefix.data(), prefix.size()) == 0;
 }
 
-bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
-  return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+bool EndsWith(std::string_view s, std::string_view suffix) {
+  return s.size() >= suffix.size() && s.substr(s.size() - suffix.size(), suffix.size()) == suffix;
 }
 
-bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix) {
-  return strncasecmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+bool EndsWith(std::string_view s, char suffix) {
+  return !s.empty() && s.back() == suffix;
 }
 
-static bool EndsWith(const std::string& s, const char* suffix, size_t suffix_length,
-                     bool case_sensitive) {
-  size_t string_length = s.size();
-  if (suffix_length > string_length) {
-    return false;
-  }
-  size_t offset = string_length - suffix_length;
-  return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+bool EndsWithIgnoreCase(std::string_view s, std::string_view suffix) {
+  return s.size() >= suffix.size() &&
+         strncasecmp(s.data() + (s.size() - suffix.size()), suffix.data(), suffix.size()) == 0;
 }
 
-bool EndsWith(const std::string& s, const char* suffix) {
-  return EndsWith(s, suffix, strlen(suffix), true);
-}
-
-bool EndsWith(const std::string& s, const std::string& suffix) {
-  return EndsWith(s, suffix.c_str(), suffix.size(), true);
-}
-
-bool EndsWith(const std::string& s, char suffix) {
-  return EndsWith(s, &suffix, 1, true);
-}
-
-bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
-  return EndsWith(s, suffix, strlen(suffix), false);
-}
-
-bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix) {
-  return EndsWith(s, suffix.c_str(), suffix.size(), false);
-}
-
-bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs) {
-  return strcasecmp(lhs.c_str(), rhs.c_str()) == 0;
+bool EqualsIgnoreCase(std::string_view lhs, std::string_view rhs) {
+  return lhs.size() == rhs.size() && strncasecmp(lhs.data(), rhs.data(), lhs.size()) == 0;
 }
 
 }  // namespace base
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index ea49798..1ce0ec4 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -295,6 +295,10 @@
     {"kernel_panic,_sde_encoder_phys_cmd_handle_ppdone_timeout", 168},
     {"recovery,quiescent", 169},
     {"reboot,quiescent", 170},
+    {"reboot,rtc", 171},
+    {"reboot,dm-verity_device_corrupted", 172},
+    {"reboot,dm-verity_enforcing", 173},
+    {"reboot,keys_clear", 174},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index a064ca0..bca5e36 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -383,7 +383,9 @@
 
     execle(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type,
            nullptr, nullptr);
-    fatal_errno("exec failed");
+    async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to exec crash_dump helper: %s",
+                          strerror(errno));
+    return 1;
   }
 
   input_write.reset();
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index 280cfb6..c23da01 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -55,6 +55,8 @@
 #include "test_utils.h"
 #include "usb_transport_sniffer.h"
 
+using namespace std::literals::chrono_literals;
+
 namespace fastboot {
 
 int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) {
@@ -128,10 +130,14 @@
         ASSERT_EQ(device_path, cb_scratch);  // The path can not change
     }
     fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+    // No error checking since non-A/B devices may not support the command
+    fb->GetVar("current-slot", &initial_slot);
 }
 
 void FastBootTest::TearDown() {
     EXPECT_TRUE(UsbStillAvailible()) << USB_PORT_GONE;
+    // No error checking since non-A/B devices may not support the command
+    fb->SetActive(initial_slot);
 
     TearDownSerial();
 
@@ -159,6 +165,26 @@
     }
 }
 
+void FastBootTest::ReconnectFastbootDevice() {
+    fb.reset();
+    transport.reset();
+    while (UsbStillAvailible())
+        ;
+    printf("WAITING FOR DEVICE\n");
+    // Need to wait for device
+    const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
+    while (!transport) {
+        std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
+        if (usb) {
+            transport = std::unique_ptr<UsbTransportSniffer>(
+                    new UsbTransportSniffer(std::move(usb), serial_port));
+        }
+        std::this_thread::sleep_for(1s);
+    }
+    device_path = cb_scratch;
+    fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+}
+
 void FastBootTest::SetLockState(bool unlock, bool assert_change) {
     if (!fb) {
         return;
@@ -197,25 +223,8 @@
         std::string cmd = unlock ? "unlock" : "lock";
         ASSERT_EQ(fb->RawCommand("flashing " + cmd, &resp), SUCCESS)
                 << "Attempting to change locked state, but 'flashing" + cmd + "' command failed";
-        fb.reset();
-        transport.reset();
         printf("PLEASE RESPOND TO PROMPT FOR '%sing' BOOTLOADER ON DEVICE\n", cmd.c_str());
-        while (UsbStillAvailible())
-            ;  // Wait for disconnect
-        printf("WAITING FOR DEVICE");
-        // Need to wait for device
-        const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); };
-        while (!transport) {
-            std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
-            if (usb) {
-                transport = std::unique_ptr<UsbTransportSniffer>(
-                        new UsbTransportSniffer(std::move(usb), serial_port));
-            }
-            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
-            putchar('.');
-        }
-        device_path = cb_scratch;
-        fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+        ReconnectFastbootDevice();
         if (assert_change) {
             ASSERT_EQ(fb->GetVar("unlocked", &resp), SUCCESS) << "getvar:unlocked failed";
             ASSERT_EQ(resp, unlock ? "yes" : "no")
@@ -227,6 +236,7 @@
 
 std::string FastBootTest::device_path = "";
 std::string FastBootTest::cb_scratch = "";
+std::string FastBootTest::initial_slot = "";
 int FastBootTest::serial_port = 0;
 
 template <bool UNLOCKED>
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index e0f829e..7c8d54d 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -48,6 +48,7 @@
     static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr);
     bool UsbStillAvailible();
     bool UserSpaceFastboot();
+    void ReconnectFastbootDevice();
 
   protected:
     RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
@@ -69,6 +70,7 @@
     // This is an annoying hack
     static std::string cb_scratch;
     static std::string device_path;
+    static std::string initial_slot;
 };
 
 template <bool UNLOCKED>
@@ -86,6 +88,7 @@
 // differently
 class BasicFunctionality : public ModeTest<true> {};
 class Conformance : public ModeTest<true> {};
+class LogicalPartitionCompliance : public ModeTest<true> {};
 class UnlockPermissions : public ModeTest<true> {};
 class LockPermissions : public ModeTest<false> {};
 
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index ef34771..7ffc7d5 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -177,6 +177,93 @@
     }
 }
 
+// Test commands related to super partition
+TEST_F(LogicalPartitionCompliance, SuperPartition) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    std::string partition_type;
+    // getvar partition-type:super must fail for retrofit devices because the
+    // partition does not exist.
+    if (fb->GetVar("partition-type:super", &partition_type) == SUCCESS) {
+        std::string is_logical;
+        EXPECT_EQ(fb->GetVar("is-logical:super", &is_logical), SUCCESS)
+                << "getvar is-logical:super failed";
+        EXPECT_EQ(is_logical, "no") << "super must not be a logical partition";
+        std::string super_name;
+        EXPECT_EQ(fb->GetVar("super-partition-name", &super_name), SUCCESS)
+                << "'getvar super-partition-name' failed";
+        EXPECT_EQ(super_name, "super") << "'getvar super-partition-name' must return 'super' for "
+                                          "device with a super partition";
+    }
+}
+
+// Test 'fastboot getvar is-logical'
+TEST_F(LogicalPartitionCompliance, GetVarIsLogical) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    std::string has_slot;
+    EXPECT_EQ(fb->GetVar("has-slot:system", &has_slot), SUCCESS) << "getvar has-slot:system failed";
+    std::string is_logical_cmd;
+    if (has_slot == "yes") {
+        std::string current_slot;
+        EXPECT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
+                << "getvar current-slot failed";
+        is_logical_cmd = "is-logical:system_" + current_slot;
+    } else {
+        is_logical_cmd = "is-logical:system";
+    }
+    std::string is_logical;
+    EXPECT_EQ(fb->GetVar(is_logical_cmd, &is_logical), SUCCESS) << "getvar is-logical failed";
+    ASSERT_EQ(is_logical, "yes");
+}
+
+TEST_F(LogicalPartitionCompliance, FastbootRebootTest) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
+    // Test 'fastboot reboot bootloader' from fastbootd
+    fb->RebootTo("bootloader");
+
+    // Test fastboot reboot fastboot from bootloader
+    ReconnectFastbootDevice();
+    ASSERT_FALSE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
+    fb->RebootTo("fastboot");
+
+    ReconnectFastbootDevice();
+    ASSERT_TRUE(UserSpaceFastboot());
+}
+
+// Testing creation/resize/delete of logical partitions
+TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) {
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Testing 'fastboot create-logical-partition' command";
+    EXPECT_EQ(fb->CreatePartition("test_partition_a", "0"), SUCCESS)
+            << "create-logical-partition failed";
+    GTEST_LOG_(INFO) << "Testing 'fastboot resize-logical-partition' command";
+    EXPECT_EQ(fb->ResizePartition("test_partition_a", "4096"), SUCCESS)
+            << "resize-logical-partition failed";
+    std::vector<char> buf(4096);
+
+    GTEST_LOG_(INFO) << "Flashing a logical partition..";
+    EXPECT_EQ(fb->FlashPartition("test_partition_a", buf), SUCCESS)
+            << "flash logical -partition failed";
+    GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
+    // Reboot to bootloader mode and attempt to flash the logical partitions
+    fb->RebootTo("bootloader");
+
+    ReconnectFastbootDevice();
+    ASSERT_FALSE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Attempt to flash a logical partition..";
+    EXPECT_EQ(fb->FlashPartition("test_partition", buf), DEVICE_FAIL)
+            << "flash logical partition must fail in bootloader";
+    GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
+    fb->RebootTo("fastboot");
+
+    ReconnectFastbootDevice();
+    ASSERT_TRUE(UserSpaceFastboot());
+    GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
+    EXPECT_EQ(fb->DeletePartition("test_partition_a"), SUCCESS)
+            << "delete logical-partition failed";
+}
+
 // Conformance tests
 TEST_F(Conformance, GetVar) {
     std::string product;
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 272190e..d26f2d5 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -307,7 +307,7 @@
         return false;
     }
 
-    if (pread(fd, sb, sizeof(*sb), 1024) != sizeof(*sb)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, sb, sizeof(*sb), 1024)) != sizeof(*sb)) {
         PERROR << "Can't read '" << blk_device << "' superblock";
         return false;
     }
@@ -326,6 +326,17 @@
     return true;
 }
 
+// exported silent version of the above that just answer the question is_ext4
+bool fs_mgr_is_ext4(const std::string& blk_device) {
+    android::base::ErrnoRestorer restore;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd < 0) return false;
+    ext4_super_block sb;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), 1024)) != sizeof(sb)) return false;
+    if (!is_ext4_superblock_valid(&sb)) return false;
+    return true;
+}
+
 // Some system images do not have tune2fs for licensing reasons.
 // Detect these and skip running it.
 static bool tune2fs_available(void) {
@@ -494,11 +505,12 @@
         return false;
     }
 
-    if (pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET) != sizeof(sb1)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb1, sizeof(sb1), F2FS_SUPER_OFFSET)) != sizeof(sb1)) {
         PERROR << "Can't read '" << blk_device << "' superblock1";
         return false;
     }
-    if (pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET) != sizeof(sb2)) {
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb2, sizeof(sb2), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) !=
+        sizeof(sb2)) {
         PERROR << "Can't read '" << blk_device << "' superblock2";
         return false;
     }
@@ -511,6 +523,23 @@
     return true;
 }
 
+// exported silent version of the above that just answer the question is_f2fs
+bool fs_mgr_is_f2fs(const std::string& blk_device) {
+    android::base::ErrnoRestorer restore;
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(blk_device.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (fd < 0) return false;
+    __le32 sb;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), F2FS_SUPER_OFFSET)) != sizeof(sb)) {
+        return false;
+    }
+    if (sb == cpu_to_le32(F2FS_SUPER_MAGIC)) return true;
+    if (TEMP_FAILURE_RETRY(pread(fd, &sb, sizeof(sb), F2FS_BLKSIZE + F2FS_SUPER_OFFSET)) !=
+        sizeof(sb)) {
+        return false;
+    }
+    return sb == cpu_to_le32(F2FS_SUPER_MAGIC);
+}
+
 //
 // Prepare the filesystem on the given block device to be mounted.
 //
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index e61f588..dea4844 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -543,6 +543,10 @@
         if (!fs_mgr_rw_access(device_path)) return false;
     }
 
+    auto f2fs = fs_mgr_is_f2fs(device_path);
+    auto ext4 = fs_mgr_is_ext4(device_path);
+    if (!f2fs && !ext4) return false;
+
     if (setfscreatecon(kOverlayfsFileContext)) {
         PERROR << "setfscreatecon " << kOverlayfsFileContext;
     }
@@ -554,6 +558,8 @@
     entry.blk_device = device_path;
     entry.mount_point = kScratchMountPoint;
     entry.fs_type = mnt_type;
+    if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4";
+    if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs";
     entry.flags = MS_RELATIME;
     if (readonly) {
         entry.flags |= MS_RDONLY;
@@ -563,12 +569,13 @@
     auto save_errno = errno;
     auto mounted = fs_mgr_do_mount_one(entry) == 0;
     if (!mounted) {
-        if (mnt_type == "f2fs") {
+        if ((entry.fs_type == "f2fs") && ext4) {
             entry.fs_type = "ext4";
-        } else {
+            mounted = fs_mgr_do_mount_one(entry) == 0;
+        } else if ((entry.fs_type == "ext4") && f2fs) {
             entry.fs_type = "f2fs";
+            mounted = fs_mgr_do_mount_one(entry) == 0;
         }
-        mounted = fs_mgr_do_mount_one(entry) == 0;
         if (!mounted) save_errno = errno;
     }
     setfscreatecon(nullptr);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 166c32b..11602ea 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -100,3 +100,6 @@
 const std::string& get_android_dt_dir();
 bool is_dt_compatible();
 int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
+
+bool fs_mgr_is_ext4(const std::string& blk_device);
+bool fs_mgr_is_f2fs(const std::string& blk_device);
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index e2a4d16..24044d8 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -176,6 +176,15 @@
         fstab_read = android::fs_mgr::ReadFstabFromFile(fstab_file, &fstab);
     } else {
         fstab_read = android::fs_mgr::ReadDefaultFstab(&fstab);
+        // Manufacture a / entry from /proc/mounts if missing.
+        if (!GetEntryForMountPoint(&fstab, "/system") && !GetEntryForMountPoint(&fstab, "/")) {
+            android::fs_mgr::Fstab mounts;
+            if (android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+                if (auto entry = GetEntryForMountPoint(&mounts, "/")) {
+                    if (entry->fs_type != "rootfs") fstab.emplace_back(*entry);
+                }
+            }
+        }
     }
     if (!fstab_read || fstab.empty()) {
         PLOG(ERROR) << "Failed to read fstab";
@@ -211,21 +220,21 @@
         // 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";
+            LOG(ERROR) << "Unknown partition " << argv[optind] << ", 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 "
+            LOG(INFO) << "partition " << argv[optind] << " 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";
+            LOG(ERROR) << "Invalid partition " << argv[optind] << ", skipping";
             retval = INVALID_PARTITION;
             continue;
         }
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index bd5a4fe..c09dc3d 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -447,59 +447,71 @@
   exit 1
 }
 
-[ "USAGE: EXPECT_EQ <lval> <rval> [message]
+[ "USAGE: EXPECT_EQ <lval> <rval> [--warning [message]]
 
 Returns true if (regex) lval matches rval" ]
 EXPECT_EQ() {
   local lval="${1}"
   local rval="${2}"
   shift 2
+  local error=1
+  local prefix="${RED}[    ERROR ]${NORMAL}"
+  if [ X"${1}" = X"--warning" ]; then
+      prefix="${RED}[  WARNING ]${NORMAL}"
+      error=0
+      shift 1
+  fi
   if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
     if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
 *}" ]; then
-      echo "ERROR: expected \"${lval}\"" >&2
-      echo "       got \"${rval}\"" |
+      echo "${prefix} expected \"${lval}\"" >&2
+      echo "${prefix} got \"${rval}\"" |
         sed ': again
              N
              s/\(\n\)\([^ ]\)/\1             \2/
              t again' >&2
       if [ -n "${*}" ] ; then
-        echo "       ${*}" >&2
+        echo "${prefix} ${*}" >&2
       fi
     else
-      echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
+      echo "${prefix} expected \"${lval}\" got \"${rval}\" ${*}" >&2
     fi
-    return 1
+    return ${error}
   fi
   if [ -n "${*}" ] ; then
-    if [ X"${lval}" != X"${rval}" ]; then
+    prefix="${GREEN}[     INFO ]${NORMAL}"
+    if [ X"${lval}" != X"${rval}" ]; then  # we were supplied a regex?
       if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
-        echo "INFO: ok \"${lval}\"" >&2
+        echo "${prefix} ok \"${lval}\"" >&2
         echo "       = \"${rval}\"" |
           sed ': again
                N
                s/\(\n\)\([^ ]\)/\1          \2/
                t again' >&2
         if [ -n "${*}" ] ; then
-          echo "      ${*}" >&2
+          echo "${prefix} ${*}" >&2
         fi
       else
-        echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+        echo "${prefix} ok \"${lval}\" = \"${rval}\" ${*}" >&2
       fi
     else
-      echo "INFO: ok \"${lval}\" ${*}" >&2
+      echo "${prefix} ok \"${lval}\" ${*}" >&2
     fi
   fi
   return 0
 }
 
-[ "USAGE: check_eq <lval> <rval> [message]
+[ "USAGE: check_eq <lval> <rval> [--warning [message]]
 
 Exits if (regex) lval mismatches rval" ]
 check_eq() {
   local lval="${1}"
   local rval="${2}"
   shift 2
+  if [ X"${1}" = X"--warning" ]; then
+      EXPECT_EQ "${lval}" "${rval}" ${*}
+      return
+  fi
   EXPECT_EQ "${lval}" "${rval}" ||
     die "${@}"
 }
@@ -514,8 +526,8 @@
     cat -
   fi |
   grep -v \
-    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\) " \
-    -e "^\(bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
+    -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
+    -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
     -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
     -e "^rootfs / rootfs rw," \
     -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|persist\|metadata\) "
@@ -608,7 +620,7 @@
 
 D=`get_property ro.serialno`
 [ -n "${D}" ] || D=`get_property ro.boot.serialno`
-[ -z "${D}" ] || ANDROID_SERIAL=${D}
+[ -z "${D}" -o -n "${ANDROID_SERIAL}" ] || ANDROID_SERIAL=${D}
 USB_SERIAL=
 [ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial |
                                           grep usb |
@@ -951,7 +963,7 @@
 
 adb_reboot &&
   adb_wait 2m ||
-  die "reboot after override content added failed"
+  die "reboot after override content added failed `usb_status`"
 
 if ${overlayfs_needed}; then
   D=`adb_su df -k </dev/null` &&
@@ -998,8 +1010,14 @@
 echo "${GREEN}[ RUN      ]${NORMAL} flash vendor, confirm its content disappears" >&2
 
 H=`adb_sh echo '${HOSTNAME}' </dev/null 2>/dev/null`
+is_bootloader_fastboot=false
+# cuttlefish?
+[ X"${H}" != X"${H#vsoc}" ] || is_bootloader_fastboot=true
 is_userspace_fastboot=false
-if [ -z "${ANDROID_PRODUCT_OUT}" ]; then
+
+if ! ${is_bootloader_fastboot}; then
+  echo "${ORANGE}[  WARNING ]${NORMAL} does not support fastboot, skipping"
+elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} build tree not setup, skipping"
 elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then
   echo "${ORANGE}[  WARNING ]${NORMAL} vendor image missing, skipping"
@@ -1079,14 +1097,9 @@
     check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
              vendor content after flash vendor
   else
-    (
-      echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
-      restore() {
-        true
-      }
-      check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
-               vendor content after flash vendor
-    )
+    echo "${ORANGE}[  WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2
+    check_eq "cat: /vendor/hello: No such file or directory" "${B}" \
+             --warning vendor content after flash vendor
   fi
 fi
 
diff --git a/init/Android.bp b/init/Android.bp
index 8a0bb55..8292aa0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -91,7 +91,7 @@
 cc_library_static {
     name: "libinit",
     recovery_available: true,
-    defaults: ["init_defaults"],
+    defaults: ["init_defaults", "selinux_policy_version"],
     srcs: [
         "action.cpp",
         "action_manager.cpp",
diff --git a/init/Android.mk b/init/Android.mk
index cc514ed..39af0e6 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -2,6 +2,8 @@
 
 LOCAL_PATH:= $(call my-dir)
 
+-include system/sepolicy/policy_version.mk
+
 # --
 
 ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
@@ -28,7 +30,8 @@
     -DSHUTDOWN_ZERO_TIMEOUT=0
 endif
 
-init_options += -DLOG_UEVENTS=0
+init_options += -DLOG_UEVENTS=0 \
+    -DSEPOLICY_VERSION=$(POLICYVERS)
 
 init_cflags += \
     $(init_options) \
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 797c4e0..aa66baa 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -316,14 +316,6 @@
 
     LOG(INFO) << "Compiling SELinux policy";
 
-    // Determine the highest policy language version supported by the kernel
-    set_selinuxmnt("/sys/fs/selinux");
-    int max_policy_version = security_policyvers();
-    if (max_policy_version == -1) {
-        PLOG(ERROR) << "Failed to determine highest policy version supported by kernel";
-        return false;
-    }
-
     // We store the output of the compilation on /dev because this is the most convenient tmpfs
     // storage mount available this early in the boot sequence.
     char compiled_sepolicy[] = "/dev/sepolicy.XXXXXX";
@@ -370,14 +362,13 @@
     if (access(odm_policy_cil_file.c_str(), F_OK) == -1) {
         odm_policy_cil_file.clear();
     }
-    const std::string version_as_string = std::to_string(max_policy_version);
+    const std::string version_as_string = std::to_string(SEPOLICY_VERSION);
 
     // clang-format off
     std::vector<const char*> compile_args {
         "/system/bin/secilc",
         use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file,
         "-m", "-M", "true", "-G", "-N",
-        // Target the highest policy language version supported by the kernel
         "-c", version_as_string.c_str(),
         plat_mapping_file.c_str(),
         "-o", compiled_sepolicy,
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 908fe7f..7fa3f43 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -413,6 +413,8 @@
   if (!tag) tag = "";
 
   /* XXX: This needs to go! */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wstring-plus-int"
   if (bufID != LOG_ID_RADIO) {
     switch (tag[0]) {
       case 'H':
@@ -454,6 +456,7 @@
         break;
     }
   }
+#pragma clang diagnostic pop
 
 #if __BIONIC__
   if (prio == ANDROID_LOG_FATAL) {
diff --git a/libmemunreachable/HeapWalker.cpp b/libmemunreachable/HeapWalker.cpp
index 89837f7..7cae048 100644
--- a/libmemunreachable/HeapWalker.cpp
+++ b/libmemunreachable/HeapWalker.cpp
@@ -59,12 +59,19 @@
   }
 }
 
+// Sanitizers may consider certain memory inaccessible through certain pointers.
+// With MTE this will need to use unchecked instructions or disable tag checking globally.
+static uintptr_t ReadWordAtAddressUnsafe(uintptr_t word_ptr)
+    __attribute__((no_sanitize("address", "hwaddress"))) {
+  return *reinterpret_cast<uintptr_t*>(word_ptr);
+}
+
 bool HeapWalker::WordContainsAllocationPtr(uintptr_t word_ptr, Range* range, AllocationInfo** info) {
   walking_ptr_ = word_ptr;
   // This access may segfault if the process under test has done something strange,
   // for example mprotect(PROT_NONE) on a native heap page.  If so, it will be
   // caught and handled by mmaping a zero page over the faulting page.
-  uintptr_t value = *reinterpret_cast<uintptr_t*>(word_ptr);
+  uintptr_t value = ReadWordAtAddressUnsafe(word_ptr);
   walking_ptr_ = 0;
   if (value >= valid_allocations_range_.begin && value < valid_allocations_range_.end) {
     AllocationMap::iterator it = allocations_.find(Range{value, value + 1});
@@ -200,6 +207,6 @@
   }
 }
 
-ScopedSignalHandler::SignalFn ScopedSignalHandler::handler_;
+Allocator<ScopedSignalHandler::SignalFnMap>::unique_ptr ScopedSignalHandler::handler_map_;
 
 }  // namespace android
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 9e3db08..f00bcca 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -52,7 +52,8 @@
         allocation_bytes_(0),
         roots_(allocator),
         root_vals_(allocator),
-        segv_handler_(),
+        sigsegv_handler_(allocator),
+        sigbus_handler_(allocator),
         walking_ptr_(0),
         walking_range_{0, 0},
         segv_logged_(false),
@@ -62,10 +63,14 @@
     valid_mappings_range_.end = 0;
     valid_mappings_range_.begin = ~valid_allocations_range_.end;
 
-    segv_handler_.install(
+    sigsegv_handler_.install(
         SIGSEGV, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
           this->HandleSegFault(handler, signal, siginfo, uctx);
         });
+    sigbus_handler_.install(
+        SIGBUS, [=](ScopedSignalHandler& handler, int signal, siginfo_t* siginfo, void* uctx) {
+          this->HandleSegFault(handler, signal, siginfo, uctx);
+        });
   }
 
   ~HeapWalker() {}
@@ -106,7 +111,8 @@
   allocator::vector<Range> roots_;
   allocator::vector<uintptr_t> root_vals_;
 
-  ScopedSignalHandler segv_handler_;
+  ScopedSignalHandler sigsegv_handler_;
+  ScopedSignalHandler sigbus_handler_;
   volatile uintptr_t walking_ptr_;
   Range walking_range_;
   bool segv_logged_;
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index 3d7b8a8..299c320 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -217,6 +217,10 @@
   return ret == 0;
 }
 
+static bool is_sanitizer_mapping(const allocator::string& s) {
+  return s == "[anon:low shadow]" || s == "[anon:high shadow]" || has_prefix(s, "[anon:hwasan");
+}
+
 bool MemUnreachable::ClassifyMappings(const allocator::vector<Mapping>& mappings,
                                       allocator::vector<Mapping>& heap_mappings,
                                       allocator::vector<Mapping>& anon_mappings,
@@ -258,7 +262,8 @@
     } else if (mapping_name.size() == 0) {
       globals_mappings.emplace_back(*it);
     } else if (has_prefix(mapping_name, "[anon:") &&
-               mapping_name != "[anon:leak_detector_malloc]") {
+               mapping_name != "[anon:leak_detector_malloc]" &&
+               !is_sanitizer_mapping(mapping_name)) {
       // TODO(ccross): it would be nice to treat named anonymous mappings as
       // possible leaks, but naming something in a .bss or .data section makes
       // it impossible to distinguish them from mmaped and then named mappings.
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index 9e08a8e..ef4473f 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -24,6 +24,7 @@
 
 #include "android-base/macros.h"
 
+#include "Allocator.h"
 #include "log.h"
 
 namespace android {
@@ -32,17 +33,29 @@
  public:
   using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
 
-  explicit ScopedSignalHandler() : signal_(-1) {}
+  explicit ScopedSignalHandler(Allocator<ScopedSignalHandler> allocator) : signal_(-1) {
+    if (handler_map_ == nullptr) {
+      Allocator<SignalFnMap> map_allocator = allocator;
+      handler_map_ = map_allocator.make_unique(allocator);
+    }
+  }
   ~ScopedSignalHandler() { reset(); }
 
   template <class F>
   void install(int signal, F&& f) {
     if (signal_ != -1) MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed");
 
-    handler_ = SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
+    if (handler_map_->find(signal) != handler_map_->end()) {
+      MEM_LOG_ALWAYS_FATAL("ScopedSignalHandler already installed for %d", signal);
+    }
+
+    (*handler_map_)[signal] =
+        SignalFn([=](int signal, siginfo_t* si, void* uctx) { f(*this, signal, si, uctx); });
 
     struct sigaction act {};
-    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) { handler_(signal, si, uctx); };
+    act.sa_sigaction = [](int signal, siginfo_t* si, void* uctx) {
+      ((*handler_map_)[signal])(signal, si, uctx);
+    };
     act.sa_flags = SA_SIGINFO;
 
     int ret = sigaction(signal, &act, &old_act_);
@@ -59,19 +72,22 @@
       if (ret < 0) {
         MEM_ALOGE("failed to uninstall segfault handler");
       }
-      handler_ = SignalFn{};
+
+      handler_map_->erase(signal_);
+      if (handler_map_->empty()) {
+        handler_map_.reset();
+      }
       signal_ = -1;
     }
   }
 
  private:
   using SignalFn = std::function<void(int, siginfo_t*, void*)>;
+  using SignalFnMap = allocator::unordered_map<int, SignalFn>;
   DISALLOW_COPY_AND_ASSIGN(ScopedSignalHandler);
   int signal_;
   struct sigaction old_act_;
-  // TODO(ccross): to support multiple ScopedSignalHandlers handler_ would need
-  // to be a static map of signals to handlers, but allocated with Allocator.
-  static SignalFn handler_;
+  static Allocator<SignalFnMap>::unique_ptr handler_map_;
 };
 
 }  // namespace android
diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
index 8bcc1e2..3cb6b9a 100644
--- a/libpackagelistparser/include/packagelistparser/packagelistparser.h
+++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h
@@ -54,6 +54,7 @@
     gid_list gids;
     void *private_data;
     bool profileable_from_shell;
+    long version_code;
 };
 
 /**
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
index 4ce2363..edc533c 100644
--- a/libpackagelistparser/packagelistparser.c
+++ b/libpackagelistparser/packagelistparser.c
@@ -239,6 +239,15 @@
 
             pkg_info->profileable_from_shell = (bool)tmp;
         }
+        cur = strsep(&next, " \t\r\n");
+        if (cur) {
+            tmp = strtoul(cur, &endptr, 10);
+            if (*endptr != '\0') {
+                errmsg = "Could not convert field \"versionCode\" to integer value";
+                goto err;
+            }
+            pkg_info->version_code = tmp;
+        }
 
         rc = callback(pkg_info, userdata);
         if (rc == false) {
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 9951621..b3b497f 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -336,8 +336,10 @@
 }
 
 CgroupMap& CgroupMap::GetInstance() {
-    static CgroupMap instance;
-    return instance;
+    // Deliberately leak this object to avoid a race between destruction on
+    // process exit and concurrent access from another thread.
+    static auto* instance = new CgroupMap;
+    return *instance;
 }
 
 bool CgroupMap::LoadRcFile() {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index f1fbcde..9362c03 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -284,8 +284,10 @@
 }
 
 TaskProfiles& TaskProfiles::GetInstance() {
-    static TaskProfiles instance;
-    return instance;
+    // Deliberately leak this object to avoid a race between destruction on
+    // process exit and concurrent access from another thread.
+    static auto* instance = new TaskProfiles;
+    return *instance;
 }
 
 TaskProfiles::TaskProfiles() {
diff --git a/libziparchive/entry_name_utils-inl.h b/libziparchive/entry_name_utils-inl.h
index 5fc2fb4..1714586 100644
--- a/libziparchive/entry_name_utils-inl.h
+++ b/libziparchive/entry_name_utils-inl.h
@@ -35,7 +35,7 @@
       return false;
     } else {
       // 2-5 byte sequences.
-      for (uint8_t first = byte << 1; first & 0x80; first <<= 1) {
+      for (uint8_t first = (byte & 0x7f) << 1; first & 0x80; first = (first & 0x7f) << 1) {
         ++i;
 
         // Missing continuation byte..
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 6b9f6e1..0710d0a 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -278,11 +278,6 @@
   if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
           eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
-#if defined(__ANDROID__)
-    if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
-      android_errorWriteLog(0x534e4554, "31251826");
-    }
-#endif
     return kInvalidOffset;
   }
   if (eocd->num_records == 0) {
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 641a536..927587b 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -377,7 +377,7 @@
 # (LL-NDK only) access.
 ###############################################################################
 [vendor]
-additional.namespaces = runtime,system,vndk
+additional.namespaces = runtime,system,vndk%VNDK_IN_SYSTEM_NS%
 
 ###############################################################################
 # "default" namespace
@@ -418,8 +418,9 @@
 namespace.default.asan.permitted.paths += /data/asan/vendor
 namespace.default.asan.permitted.paths +=           /vendor
 
-namespace.default.links = system,vndk
+namespace.default.links = system,vndk%VNDK_IN_SYSTEM_NS%
 namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
 namespace.default.link.vndk.shared_libs  = %VNDK_SAMEPROCESS_LIBRARIES%
 namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
 
@@ -468,14 +469,18 @@
 
 # When these NDK libs are required inside this namespace, then it is redirected
 # to the system namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = system,default
+# Android releases.  The links here should be identical to that of the
+# 'vndk_in_system' namespace, except for the link between 'vndk' and
+# 'vndk_in_system'.
+namespace.vndk.links = system,default%VNDK_IN_SYSTEM_NS%
 
 namespace.vndk.link.system.shared_libs  = %LLNDK_LIBRARIES%
 namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
 
 namespace.vndk.link.default.allow_all_shared_libs = true
 
+namespace.vndk.link.vndk_in_system.shared_libs = %VNDK_USING_CORE_VARIANT_LIBRARIES%
+
 ###############################################################################
 # "system" namespace
 #
@@ -504,6 +509,51 @@
 namespace.system.link.runtime.shared_libs += libandroidicu.so
 
 ###############################################################################
+# "vndk_in_system" namespace
+#
+# This namespace is where no-vendor-variant VNDK libraries are loaded for a
+# vendor process.  Note that we do not simply export these libraries from
+# "system" namespace, because in some case both the core variant and the
+# vendor variant of a VNDK library may be loaded.  In such case, we do not
+# want to eliminate double-loading because doing so means the global states
+# of the library would be shared.
+#
+# Only the no-vendor-variant VNDK libraries are whitelisted in this namespace.
+# This is to ensure that we do not load libraries needed by no-vendor-variant
+# VNDK libraries into vndk_in_system namespace.
+###############################################################################
+namespace.vndk_in_system.isolated = true
+namespace.vndk_in_system.visible = true
+
+# The search paths here should be kept the same as that of the 'system'
+# namespace.
+namespace.vndk_in_system.search.paths  = /system/${LIB}
+namespace.vndk_in_system.search.paths += /%PRODUCT%/${LIB}
+namespace.vndk_in_system.search.paths += /%PRODUCT_SERVICES%/${LIB}
+
+namespace.vndk_in_system.asan.search.paths  = /data/asan/system/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /system/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/product/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT%/${LIB}
+namespace.vndk_in_system.asan.search.paths += /data/asan/product_services/${LIB}
+namespace.vndk_in_system.asan.search.paths +=           /%PRODUCT_SERVICES%/${LIB}
+
+namespace.vndk_in_system.whitelisted = %VNDK_USING_CORE_VARIANT_LIBRARIES%
+
+# The links here should be identical to that of the 'vndk' namespace, with the
+# following exception:
+#   1. 'vndk_in_system' needs to be freely linked back to 'vndk'.
+#   2. 'vndk_in_system' does not need to link to 'default', as any library that
+#      requires anything vendor would not be a vndk_in_system library.
+namespace.vndk_in_system.links = vndk,system
+
+namespace.vndk_in_system.link.system.shared_libs  = %LLNDK_LIBRARIES%
+namespace.vndk_in_system.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.vndk_in_system.link.vndk.allow_all_shared_libs = true
+
+
+###############################################################################
 # Namespace config for native tests that need access to both system and vendor
 # libraries. This replicates the default linker config (done by
 # init_default_namespace_no_config in bionic/linker/linker.cpp), except that it
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 852e234..912a73e 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -23,6 +23,11 @@
 lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts))
 libz_is_llndk := $(strip $(libz_is_llndk))
 
+my_vndk_use_core_variant := $(TARGET_VNDK_USE_CORE_VARIANT)
+ifeq ($(lib_list_from_prebuilts),true)
+my_vndk_use_core_variant := false
+endif
+
 compatibility_check_script := \
   $(LOCAL_PATH)/ld_config_backward_compatibility_check.py
 intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE))
@@ -35,6 +40,9 @@
 vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt
 vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt
 vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt
+ifeq ($(my_vndk_use_core_variant),true)
+vndk_using_core_variant_libraries_file := $(library_lists_dir)/vndk_using_core_variant.libraries.$(vndk_version).txt
+endif
 
 sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
   $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \
@@ -68,6 +76,9 @@
 $(eval $(call write-libs-to-file,$(vndksp_libraries_list),$(vndksp_libraries_file)))
 $(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),$(vndkcore_libraries_file)))
 $(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),$(vndkprivate_libraries_file)))
+ifeq ($(my_vndk_use_core_variant),true)
+$(eval $(call write-libs-to-file,$(VNDK_USING_CORE_VARIANT_LIBRARIES),$(vndk_using_core_variant_libraries_file)))
+endif
 endif # ifneq ($(lib_list_from_prebuilts),true)
 
 # Given a file with a list of libs, filter-out the VNDK private libraries
@@ -94,6 +105,10 @@
 ifeq ($(check_backward_compatibility),true)
 deps += $(compatibility_check_script)
 endif
+ifeq ($(my_vndk_use_core_variant),true)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE := $(vndk_using_core_variant_libraries_file)
+deps += $(vndk_using_core_variant_libraries_file)
+endif
 
 $(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps)
 	@echo "Generate: $< -> $@"
@@ -109,6 +124,20 @@
 	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)
 	$(hide) sed -i.bak -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@
 
+ifeq ($(my_vndk_use_core_variant),true)
+	$(call private-filter-out-private-libs,$(PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)
+	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%?,vndk_in_system?g" $@
+	$(hide) sed -i.bak -e "s?%VNDK_USING_CORE_VARIANT_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndk_using_core_variant_filtered)?g" $@
+else
+	$(hide) sed -i.bak -e "s?%VNDK_IN_SYSTEM_NS%??g" $@
+	# Unlike LLNDK or VNDK-SP, VNDK_USING_CORE_VARIANT_LIBRARIES can be nothing
+	# if TARGET_VNDK_USE_CORE_VARIANT is not set.  In this case, we need to remove
+	# the entire line in the linker config so that we are not left with a line
+	# like:
+	#   namespace.sphal.link.default.shared_libs +=
+	$(hide) sed -i.bak -e "s?^.*\+= %VNDK_USING_CORE_VARIANT_LIBRARIES%\$$??" $@
+endif
+
 	$(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \
 	cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \
 	xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \
@@ -146,3 +175,10 @@
 llndk_libraries_list :=
 vndksp_libraries_list :=
 write-libs-to-file :=
+
+ifeq ($(my_vndk_use_core_variant),true)
+vndk_using_core_variant_libraries_file :=
+vndk_using_core_variant_libraries_list :=
+endif
+
+my_vndk_use_core_variant :=