Merge "[vts-core] Add vts_core_liblp_test to vts-core"
diff --git a/adb/Android.bp b/adb/Android.bp
index 57872b0..9ef82bf 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -629,6 +629,7 @@
         "libselinux",
     ],
     test_suites: ["device-tests"],
+    require_root: true,
 }
 
 python_test_host {
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index dd24aac..d08a59f 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -311,6 +311,7 @@
     {"shutdown,userrequested,recovery", 182},
     {"reboot,unknown[0-9]*", 183},
     {"reboot,longkey,.*", 184},
+    {"reboot,boringssl-self-check-failed", 185},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index c86a018..c9a193c 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -176,7 +176,7 @@
   if (crasher_pid != -1) {
     kill(crasher_pid, SIGKILL);
     int status;
-    waitpid(crasher_pid, &status, WUNTRACED);
+    TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED));
   }
 
   android::base::SetProperty(kWaitForGdbKey, previous_wait_for_gdb ? "1" : "0");
@@ -195,8 +195,7 @@
 void CrasherTest::FinishIntercept(int* result) {
   InterceptResponse response;
 
-  // Timeout for tombstoned intercept is 10 seconds.
-  ssize_t rc = TIMEOUT(20, read(intercept_fd.get(), &response, sizeof(response)));
+  ssize_t rc = TIMEOUT(30, read(intercept_fd.get(), &response, sizeof(response)));
   if (rc == -1) {
     FAIL() << "failed to read response from tombstoned: " << strerror(errno);
   } else if (rc == 0) {
@@ -233,7 +232,7 @@
     FAIL() << "crasher pipe uninitialized";
   }
 
-  ssize_t rc = write(crasher_pipe.get(), "\n", 1);
+  ssize_t rc = TEMP_FAILURE_RETRY(write(crasher_pipe.get(), "\n", 1));
   if (rc == -1) {
     FAIL() << "failed to write to crasher pipe: " << strerror(errno);
   } else if (rc == 0) {
@@ -243,7 +242,7 @@
 
 void CrasherTest::AssertDeath(int signo) {
   int status;
-  pid_t pid = TIMEOUT(10, waitpid(crasher_pid, &status, 0));
+  pid_t pid = TIMEOUT(30, waitpid(crasher_pid, &status, 0));
   if (pid != crasher_pid) {
     printf("failed to wait for crasher (expected pid %d, return value %d): %s\n", crasher_pid, pid,
            strerror(errno));
@@ -441,7 +440,7 @@
   FinishCrasher();
 
   int status;
-  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, WUNTRACED));
+  ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, WUNTRACED)));
   ASSERT_TRUE(WIFSTOPPED(status));
   ASSERT_EQ(SIGSTOP, WSTOPSIG(status));
 
@@ -611,7 +610,7 @@
     PLOG(FATAL) << "tmpfile failed";
   }
 
-  unique_fd tmp_fd(dup(fileno(tmp_file)));
+  unique_fd tmp_fd(TEMP_FAILURE_RETRY(dup(fileno(tmp_file))));
   if (!android::base::WriteStringToFd(policy, tmp_fd.get())) {
     PLOG(FATAL) << "failed to write policy to tmpfile";
   }
@@ -824,7 +823,7 @@
   FinishCrasher();
 
   int status;
-  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+  ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
   ASSERT_TRUE(WIFSTOPPED(status));
   ASSERT_EQ(SIGABRT, WSTOPSIG(status));
 
@@ -839,7 +838,7 @@
   regex += R"( \(.+debuggerd_test)";
   ASSERT_MATCH(result, regex.c_str());
 
-  ASSERT_EQ(crasher_pid, waitpid(crasher_pid, &status, 0));
+  ASSERT_EQ(crasher_pid, TEMP_FAILURE_RETRY(waitpid(crasher_pid, &status, 0)));
   ASSERT_TRUE(WIFSTOPPED(status));
   ASSERT_EQ(SIGABRT, WSTOPSIG(status));
 
@@ -853,7 +852,7 @@
 
   StartProcess([]() {
     android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
-    unique_fd fd(open("/dev/null", O_RDONLY | O_CLOEXEC));
+    unique_fd fd(TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY | O_CLOEXEC)));
     if (fd == -1) {
       abort();
     }
@@ -888,13 +887,13 @@
     raise(DEBUGGER_SIGNAL);
 
     errno = 0;
-    rc = waitpid(-1, &status, __WALL | __WNOTHREAD);
+    rc = TEMP_FAILURE_RETRY(waitpid(-1, &status, __WALL | __WNOTHREAD));
     if (rc != -1 || errno != ECHILD) {
       errx(2, "second waitpid returned %d (%s), expected failure with ECHILD", rc, strerror(errno));
     }
     _exit(0);
   } else {
-    rc = waitpid(forkpid, &status, 0);
+    rc = TEMP_FAILURE_RETRY(waitpid(forkpid, &status, 0));
     ASSERT_EQ(forkpid, rc);
     ASSERT_TRUE(WIFEXITED(status));
     ASSERT_EQ(0, WEXITSTATUS(status));
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 4dbacd7..e50f7c3 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -36,6 +36,7 @@
 
 #include "fs_mgr_priv.h"
 
+using android::base::EndsWith;
 using android::base::ParseByteCount;
 using android::base::ParseInt;
 using android::base::ReadFileToString;
@@ -598,7 +599,7 @@
     return boot_devices;
 }
 
-FstabEntry BuildGsiUserdataFstabEntry() {
+FstabEntry BuildDsuUserdataFstabEntry() {
     constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV;
 
     FstabEntry userdata = {
@@ -627,7 +628,12 @@
     return false;
 }
 
-void TransformFstabForGsi(Fstab* fstab) {
+}  // namespace
+
+void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions) {
+    static constexpr char kGsiKeys[] =
+            "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey";
+    // Convert userdata
     // Inherit fstab properties for userdata.
     FstabEntry userdata;
     if (FstabEntry* entry = GetEntryForMountPoint(fstab, "/data")) {
@@ -639,19 +645,75 @@
             userdata.key_dir += "/gsi";
         }
     } else {
-        userdata = BuildGsiUserdataFstabEntry();
-    }
-
-    if (EraseFstabEntry(fstab, "/system")) {
-        fstab->emplace_back(BuildGsiSystemFstabEntry());
+        userdata = BuildDsuUserdataFstabEntry();
     }
 
     if (EraseFstabEntry(fstab, "/data")) {
         fstab->emplace_back(userdata);
     }
-}
 
-}  // namespace
+    // Convert others
+    for (auto&& partition : dsu_partitions) {
+        if (!EndsWith(partition, gsi::kDsuPostfix)) {
+            continue;
+        }
+        // userdata has been handled
+        if (StartsWith(partition, "user")) {
+            continue;
+        }
+        // dsu_partition_name = corresponding_partition_name + kDsuPostfix
+        // e.g.
+        //    system_gsi for system
+        //    product_gsi for product
+        //    vendor_gsi for vendor
+        std::string lp_name = partition.substr(0, partition.length() - strlen(gsi::kDsuPostfix));
+        std::string mount_point = "/" + lp_name;
+        std::vector<FstabEntry*> entries = GetEntriesForMountPoint(fstab, mount_point);
+        if (entries.empty()) {
+            FstabEntry entry = {
+                    .blk_device = partition,
+                    .mount_point = mount_point,
+                    .fs_type = "ext4",
+                    .flags = MS_RDONLY,
+                    .fs_options = "barrier=1",
+                    .avb_keys = kGsiKeys,
+                    // .logical_partition_name is required to look up AVB Hashtree descriptors.
+                    .logical_partition_name = "system"};
+            entry.fs_mgr_flags.wait = true;
+            entry.fs_mgr_flags.logical = true;
+            entry.fs_mgr_flags.first_stage_mount = true;
+            // Use the system key which may be in the vbmeta or vbmeta_system
+            // TODO: b/141284191
+            entry.vbmeta_partition = "vbmeta";
+            fstab->emplace_back(entry);
+            entry.vbmeta_partition = "vbmeta_system";
+            fstab->emplace_back(entry);
+        } else {
+            // If the corresponding partition exists, transform all its Fstab
+            // by pointing .blk_device to the DSU partition.
+            for (auto&& entry : entries) {
+                entry->blk_device = partition;
+                if (entry->avb_keys.size() > 0) {
+                    entry->avb_keys += ":";
+                }
+                // If the DSU is signed by OEM, the original Fstab already has the information
+                // required by avb, otherwise the DSU is GSI and will need the avb_keys as listed
+                // below.
+                entry->avb_keys += kGsiKeys;
+            }
+            // Make sure the ext4 is included to support GSI.
+            auto partition_ext4 =
+                    std::find_if(fstab->begin(), fstab->end(), [&](const auto& entry) {
+                        return entry.mount_point == mount_point && entry.fs_type == "ext4";
+                    });
+            if (partition_ext4 == fstab->end()) {
+                auto new_entry = *GetEntryForMountPoint(fstab, mount_point);
+                new_entry.fs_type = "ext4";
+                fstab->emplace_back(new_entry);
+            }
+        }
+    }
+}
 
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab) {
     auto fstab_file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
@@ -667,7 +729,9 @@
         return false;
     }
     if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) {
-        TransformFstabForGsi(fstab);
+        std::string lp_names;
+        ReadFileToString(gsi::kGsiLpNamesFile, &lp_names);
+        TransformFstabForDsu(fstab, Split(lp_names, ","));
     }
 
     SkipMountingPartitions(fstab);
@@ -779,6 +843,21 @@
     return nullptr;
 }
 
+std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path) {
+    std::vector<FstabEntry*> entries;
+    if (fstab == nullptr) {
+        return entries;
+    }
+
+    for (auto& entry : *fstab) {
+        if (entry.mount_point == path) {
+            entries.emplace_back(&entry);
+        }
+    }
+
+    return entries;
+}
+
 std::set<std::string> GetBootDevices() {
     // First check the kernel commandline, then try the device tree otherwise
     std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
@@ -798,23 +877,6 @@
     return ExtraBootDevices(fstab);
 }
 
-FstabEntry BuildGsiSystemFstabEntry() {
-    // .logical_partition_name is required to look up AVB Hashtree descriptors.
-    FstabEntry system = {
-            .blk_device = "system_gsi",
-            .mount_point = "/system",
-            .fs_type = "ext4",
-            .flags = MS_RDONLY,
-            .fs_options = "barrier=1",
-            // could add more keys separated by ':'.
-            .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey",
-            .logical_partition_name = "system"};
-    system.fs_mgr_flags.wait = true;
-    system.fs_mgr_flags.logical = true;
-    system.fs_mgr_flags.first_stage_mount = true;
-    return system;
-}
-
 std::string GetVerityDeviceName(const FstabEntry& entry) {
     std::string base_device;
     if (entry.mount_point == "/") {
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index c7193ab..d999ae1 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -101,9 +101,18 @@
 bool SkipMountingPartitions(Fstab* fstab);
 
 FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path);
+// The Fstab can contain multiple entries for the same mount point with different configurations.
+std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string& path);
 
-// Helper method to build a GSI fstab entry for mounting /system.
-FstabEntry BuildGsiSystemFstabEntry();
+// This method builds DSU fstab entries and transfer the fstab.
+//
+// fstab points to the unmodified fstab.
+//
+// dsu_partitions contains partition names, e.g.
+//     dsu_partitions[0] = "system_gsi"
+//     dsu_partitions[1] = "userdata_gsi"
+//     dsu_partitions[2] = ...
+void TransformFstabForDsu(Fstab* fstab, const std::vector<std::string>& dsu_partitions);
 
 std::set<std::string> GetBootDevices();
 
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index 4cdea71..449a170 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -44,9 +44,24 @@
     },
 }
 
-cc_test {
-    name: "libdm_test",
-    defaults: ["fs_mgr_defaults"],
+filegroup {
+    name: "libdm_test_srcs",
+    srcs: [
+        "dm_test.cpp",
+        "loop_control_test.cpp",
+        "test_util.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "libdm_defaults",
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
     static_libs: [
         "libdm",
         "libbase",
@@ -54,9 +69,10 @@
         "libfs_mgr",
         "liblog",
     ],
-    srcs: [
-        "dm_test.cpp",
-        "loop_control_test.cpp",
-        "test_util.cpp",
-    ]
+    srcs: [":libdm_test_srcs"],
+}
+
+cc_test {
+    name: "libdm_test",
+    defaults: ["libdm_defaults"],
 }
diff --git a/fs_mgr/libdm/vts_core/Android.bp b/fs_mgr/libdm/vts_core/Android.bp
new file mode 100644
index 0000000..2eceb28
--- /dev/null
+++ b/fs_mgr/libdm/vts_core/Android.bp
@@ -0,0 +1,23 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "vts_libdm_test",
+    defaults: ["libdm_defaults"],
+    test_suites: ["vts-core"],
+    require_root: true,
+    test_min_api_level: 29,
+}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index bb941dd..a012099 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -114,3 +114,29 @@
         "libstorage_literals_headers",
     ],
 }
+
+cc_binary {
+    name: "snapshotctl",
+    srcs: [
+        "snapshotctl.cpp",
+    ],
+    static_libs: [
+        "libdm",
+        "libext2_uuid",
+        "libfiemap_binder",
+        "libfstab",
+        "libsnapshot",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libext4_utils",
+        "libfs_mgr",
+        "libutils",
+        "liblog",
+        "liblp",
+    ],
+    init_rc: [
+        "snapshotctl.rc",
+    ],
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index aeeb4aa..0dd275a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -19,6 +19,7 @@
 #include <chrono>
 #include <map>
 #include <memory>
+#include <ostream>
 #include <string>
 #include <string_view>
 #include <vector>
@@ -84,6 +85,7 @@
     // operation via fastboot. This state can only be returned by WaitForMerge.
     Cancelled
 };
+std::ostream& operator<<(std::ostream& os, UpdateState state);
 
 class SnapshotManager final {
     using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
@@ -125,8 +127,9 @@
     // will fail if GetUpdateState() != None.
     bool BeginUpdate();
 
-    // Cancel an update; any snapshots will be deleted. This will fail if the
-    // state != Initiated or None.
+    // Cancel an update; any snapshots will be deleted. This is allowed if the
+    // state == Initiated, None, or Unverified (before rebooting to the new
+    // slot).
     bool CancelUpdate();
 
     // Mark snapshot writes as having completed. After this, new snapshots cannot
@@ -189,6 +192,9 @@
     // call to CreateLogicalPartitions when snapshots are present.
     bool CreateLogicalAndSnapshotPartitions(const std::string& super_device);
 
+    // Dump debug information.
+    bool Dump(std::ostream& os);
+
   private:
     FRIEND_TEST(SnapshotTest, CleanFirstStageMount);
     FRIEND_TEST(SnapshotTest, CreateSnapshot);
@@ -393,6 +399,13 @@
     // The reverse of MapPartitionWithSnapshot.
     bool UnmapPartitionWithSnapshot(LockedFile* lock, const std::string& target_partition_name);
 
+    // If there isn't a previous update, return true. |needs_merge| is set to false.
+    // If there is a previous update but the device has not boot into it, tries to cancel the
+    //   update and delete any snapshots. Return true if successful. |needs_merge| is set to false.
+    // If there is a previous update and the device has boot into it, do nothing and return true.
+    //   |needs_merge| is set to true.
+    bool TryCancelUpdate(bool* needs_merge);
+
     std::string gsid_dir_;
     std::string metadata_dir_;
     std::unique_ptr<IDeviceInfo> device_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b5b3af3..9d0272b 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -131,6 +131,16 @@
 }
 
 bool SnapshotManager::BeginUpdate() {
+    bool needs_merge = false;
+    if (!TryCancelUpdate(&needs_merge)) {
+        return false;
+    }
+    if (needs_merge) {
+        LOG(INFO) << "Wait for merge (if any) before beginning a new update.";
+        auto state = ProcessUpdateState();
+        LOG(INFO) << "Merged with state = " << state;
+    }
+
     auto file = LockExclusive();
     if (!file) return false;
 
@@ -143,6 +153,19 @@
 }
 
 bool SnapshotManager::CancelUpdate() {
+    bool needs_merge = false;
+    if (!TryCancelUpdate(&needs_merge)) {
+        return false;
+    }
+    if (needs_merge) {
+        LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
+    }
+    return !needs_merge;
+}
+
+bool SnapshotManager::TryCancelUpdate(bool* needs_merge) {
+    *needs_merge = false;
+
     auto file = LockExclusive();
     if (!file) return false;
 
@@ -167,8 +190,8 @@
             return RemoveAllUpdateState(file.get());
         }
     }
-    LOG(ERROR) << "Cannot cancel update after it has completed or started merging";
-    return false;
+    *needs_merge = true;
+    return true;
 }
 
 bool SnapshotManager::RemoveAllUpdateState(LockedFile* lock) {
@@ -1459,7 +1482,7 @@
         PLOG(ERROR) << "Open failed: " << file;
         return nullptr;
     }
-    if (flock(fd, lock_flags) < 0) {
+    if (lock_flags != 0 && flock(fd, lock_flags) < 0) {
         PLOG(ERROR) << "Acquire flock failed: " << file;
         return nullptr;
     }
@@ -1526,34 +1549,33 @@
     }
 }
 
-bool SnapshotManager::WriteUpdateState(LockedFile* file, UpdateState state) {
-    std::string contents;
+std::ostream& operator<<(std::ostream& os, UpdateState state) {
     switch (state) {
         case UpdateState::None:
-            contents = "none";
-            break;
+            return os << "none";
         case UpdateState::Initiated:
-            contents = "initiated";
-            break;
+            return os << "initiated";
         case UpdateState::Unverified:
-            contents = "unverified";
-            break;
+            return os << "unverified";
         case UpdateState::Merging:
-            contents = "merging";
-            break;
+            return os << "merging";
         case UpdateState::MergeCompleted:
-            contents = "merge-completed";
-            break;
+            return os << "merge-completed";
         case UpdateState::MergeNeedsReboot:
-            contents = "merge-needs-reboot";
-            break;
+            return os << "merge-needs-reboot";
         case UpdateState::MergeFailed:
-            contents = "merge-failed";
-            break;
+            return os << "merge-failed";
         default:
             LOG(ERROR) << "Unknown update state";
-            return false;
+            return os;
     }
+}
+
+bool SnapshotManager::WriteUpdateState(LockedFile* file, UpdateState state) {
+    std::stringstream ss;
+    ss << state;
+    std::string contents = ss.str();
+    if (contents.empty()) return false;
 
     if (!Truncate(file)) return false;
     if (!android::base::WriteStringToFd(contents, file->fd())) {
@@ -1940,5 +1962,47 @@
     return UnmapPartitionWithSnapshot(lock.get(), target_partition_name);
 }
 
+bool SnapshotManager::Dump(std::ostream& os) {
+    // Don't actually lock. Dump() is for debugging purposes only, so it is okay
+    // if it is racy.
+    auto file = OpenStateFile(O_RDONLY, 0);
+    if (!file) return false;
+
+    std::stringstream ss;
+
+    ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
+
+    auto boot_file = GetSnapshotBootIndicatorPath();
+    std::string boot_indicator;
+    if (android::base::ReadFileToString(boot_file, &boot_indicator)) {
+        ss << "Boot indicator: old slot = " << boot_indicator << std::endl;
+    }
+
+    bool ok = true;
+    std::vector<std::string> snapshots;
+    if (!ListSnapshots(file.get(), &snapshots)) {
+        LOG(ERROR) << "Could not list snapshots";
+        snapshots.clear();
+        ok = false;
+    }
+    for (const auto& name : snapshots) {
+        ss << "Snapshot: " << name << std::endl;
+        SnapshotStatus status;
+        if (!ReadSnapshotStatus(file.get(), name, &status)) {
+            ok = false;
+            continue;
+        }
+        ss << "    state: " << to_string(status.state) << std::endl;
+        ss << "    device size (bytes): " << status.device_size << std::endl;
+        ss << "    snapshot size (bytes): " << status.snapshot_size << std::endl;
+        ss << "    cow partition size (bytes): " << status.cow_partition_size << std::endl;
+        ss << "    cow file size (bytes): " << status.cow_file_size << std::endl;
+        ss << "    allocated sectors: " << status.sectors_allocated << std::endl;
+        ss << "    metadata sectors: " << status.metadata_sectors << std::endl;
+    }
+    os << ss.rdbuf();
+    return ok;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 36982a9..bc764fd 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -761,8 +761,7 @@
 // Also test UnmapUpdateSnapshot unmaps everything.
 // Also test first stage mount and merge after this.
 TEST_F(SnapshotUpdateTest, FullUpdateFlow) {
-    // OTA client calls CancelUpdate then BeginUpdate before doing anything.
-    ASSERT_TRUE(sm->CancelUpdate());
+    // OTA client calls BeginUpdate before doing anything.
     ASSERT_TRUE(sm->BeginUpdate());
 
     // OTA client blindly unmaps all partitions that are possibly mapped.
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
new file mode 100644
index 0000000..d65320c
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include <sysexits.h>
+
+#include <chrono>
+#include <iostream>
+#include <map>
+
+#include <android-base/logging.h>
+#include <libsnapshot/snapshot.h>
+
+using namespace std::string_literals;
+
+int Usage() {
+    std::cerr << "snapshotctl: Control snapshots.\n"
+                 "Usage: snapshotctl [action] [flags]\n"
+                 "Actions:\n"
+                 "  dump\n"
+                 "    Print snapshot states.\n"
+                 "  merge [--logcat]\n"
+                 "    Initialize merge and wait for it to be completed.\n"
+                 "    If --logcat is specified, log to logcat. Otherwise, log to stdout.\n";
+    return EX_USAGE;
+}
+
+namespace android {
+namespace snapshot {
+
+bool DumpCmdHandler(int /*argc*/, char** argv) {
+    android::base::InitLogging(argv, &android::base::StderrLogger);
+    return SnapshotManager::New()->Dump(std::cout);
+}
+
+bool MergeCmdHandler(int argc, char** argv) {
+    auto begin = std::chrono::steady_clock::now();
+
+    bool log_to_logcat = false;
+    for (int i = 2; i < argc; ++i) {
+        if (argv[i] == "--logcat"s) {
+            log_to_logcat = true;
+        }
+    }
+    if (log_to_logcat) {
+        android::base::InitLogging(argv);
+    } else {
+        android::base::InitLogging(argv, &android::base::StdioLogger);
+    }
+
+    auto sm = SnapshotManager::New();
+
+    auto state = sm->GetUpdateState();
+    if (state == UpdateState::None) {
+        LOG(INFO) << "Can't find any snapshot to merge.";
+        return true;
+    }
+    if (state == UpdateState::Unverified) {
+        if (!sm->InitiateMerge()) {
+            LOG(ERROR) << "Failed to initiate merge.";
+            return false;
+        }
+    }
+
+    // All other states can be handled by ProcessUpdateState.
+    LOG(INFO) << "Waiting for any merge to complete. This can take up to 1 minute.";
+    state = SnapshotManager::New()->ProcessUpdateState();
+
+    if (state == UpdateState::MergeCompleted) {
+        auto end = std::chrono::steady_clock::now();
+        auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count();
+        LOG(INFO) << "Snapshot merged in " << passed << " ms.";
+        return true;
+    }
+
+    LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\".";
+    return false;
+}
+
+static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
+        // clang-format off
+        {"dump", DumpCmdHandler},
+        {"merge", MergeCmdHandler},
+        // clang-format on
+};
+
+}  // namespace snapshot
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using namespace android::snapshot;
+    if (argc < 2) {
+        return Usage();
+    }
+
+    for (const auto& cmd : kCmdMap) {
+        if (cmd.first == argv[1]) {
+            return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE;
+        }
+    }
+
+    return Usage();
+}
diff --git a/fs_mgr/libsnapshot/snapshotctl.rc b/fs_mgr/libsnapshot/snapshotctl.rc
new file mode 100644
index 0000000..29707f1
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshotctl.rc
@@ -0,0 +1,2 @@
+on property:sys.boot_completed=1
+    exec - root root -- /system/bin/snapshotctl merge --logcat
diff --git a/fs_mgr/libvbmeta/Android.bp b/fs_mgr/libvbmeta/Android.bp
new file mode 100644
index 0000000..937e0f3
--- /dev/null
+++ b/fs_mgr/libvbmeta/Android.bp
@@ -0,0 +1,52 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+libvbmeta_lib_deps = [
+    "libbase",
+    "libcrypto",
+]
+
+cc_library {
+    name: "libvbmeta",
+    host_supported: true,
+    srcs: [
+        "builder.cpp",
+        "reader.cpp",
+        "utility.cpp",
+        "writer.cpp",
+    ],
+    shared_libs: [
+        "liblog",
+    ] + libvbmeta_lib_deps,
+    export_include_dirs: ["include"],
+}
+
+cc_test_host {
+    name: "libvbmeta_test",
+    static_libs: [
+        "libsparse",
+        "libvbmeta",
+        "libz",
+    ] + libvbmeta_lib_deps,
+    srcs: [
+        "builder_test.cpp",
+        "super_vbmeta_test.cpp",
+    ],
+    required: [
+        "avbtool",
+        "vbmake",
+    ],
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder.cpp b/fs_mgr/libvbmeta/builder.cpp
new file mode 100644
index 0000000..a901a4f
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "builder.h"
+
+#include <android-base/file.h>
+#include <openssl/sha.h>
+
+#include "reader.h"
+#include "utility.h"
+#include "writer.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+using android::base::unique_fd;
+
+namespace android {
+namespace fs_mgr {
+
+SuperVBMetaBuilder::SuperVBMetaBuilder() {}
+
+SuperVBMetaBuilder::SuperVBMetaBuilder(const int super_vbmeta_fd,
+                                       const std::map<std::string, std::string>& images_path)
+    : super_vbmeta_fd_(super_vbmeta_fd), images_path_(images_path) {}
+
+Result<void> SuperVBMetaBuilder::Build() {
+    for (const auto& [vbmeta_name, file_path] : images_path_) {
+        Result<std::string> content = ReadVBMetaImageFromFile(file_path);
+        if (!content) {
+            return content.error();
+        }
+
+        Result<uint8_t> vbmeta_index = AddVBMetaImage(vbmeta_name);
+        if (!vbmeta_index) {
+            return vbmeta_index.error();
+        }
+
+        Result<void> rv_export_vbmeta_image =
+                ExportVBMetaImageToFile(vbmeta_index.value(), content.value());
+        if (!rv_export_vbmeta_image) {
+            return rv_export_vbmeta_image;
+        }
+    }
+    return {};
+}
+
+Result<std::string> SuperVBMetaBuilder::ReadVBMetaImageFromFile(const std::string& file) {
+    unique_fd source_fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
+    if (source_fd < 0) {
+        return ErrnoError() << "Couldn't open vbmeta image file " << file;
+    }
+
+    Result<uint64_t> file_size = GetFileSize(source_fd);
+    if (!file_size) {
+        return file_size.error();
+    }
+
+    if (file_size.value() > VBMETA_IMAGE_MAX_SIZE) {
+        return Error() << "vbmeta image file size " << file_size.value() << " is too large";
+    }
+
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+    if (!android::base::ReadFully(source_fd, buffer.get(), file_size.value())) {
+        return ErrnoError() << "Couldn't read vbmeta image file " << file;
+    }
+
+    return std::string(reinterpret_cast<const char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+Result<uint8_t> SuperVBMetaBuilder::GetEmptySlot() {
+    for (uint8_t i = 0; i < VBMETA_IMAGE_MAX_NUM; ++i) {
+        if ((table_.header.in_use & (1 << i)) == 0) return i;
+    }
+    return Error() << "There isn't empty slot in super vbmeta";
+}
+
+Result<uint8_t> SuperVBMetaBuilder::AddVBMetaImage(const std::string& vbmeta_name) {
+    auto desc = std::find_if(
+            table_.descriptors.begin(), table_.descriptors.end(),
+            [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
+
+    uint8_t slot_number = 0;
+    if (desc != table_.descriptors.end()) {
+        slot_number = desc->vbmeta_index;
+    } else {
+        Result<uint8_t> new_slot = GetEmptySlot();
+        if (!new_slot) {
+            return new_slot;
+        }
+        slot_number = new_slot.value();
+
+        // insert new descriptor into table
+        InternalVBMetaDescriptor new_desc;
+        new_desc.vbmeta_index = slot_number;
+        new_desc.vbmeta_name_length = vbmeta_name.length();
+        new_desc.vbmeta_name = vbmeta_name;
+        memset(new_desc.reserved, 0, sizeof(new_desc.reserved));
+        table_.descriptors.emplace_back(std::move(new_desc));
+
+        // mark slot as in use
+        table_.header.in_use |= (1 << slot_number);
+    }
+
+    return slot_number;
+}
+
+void SuperVBMetaBuilder::DeleteVBMetaImage(const std::string& vbmeta_name) {
+    auto desc = std::find_if(
+            table_.descriptors.begin(), table_.descriptors.end(),
+            [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
+
+    if (desc != table_.descriptors.end()) {
+        // mark slot as not in use
+        table_.header.in_use &= ~(1 << desc->vbmeta_index);
+
+        // erase descriptor in table
+        table_.descriptors.erase(desc);
+    }
+}
+
+std::unique_ptr<VBMetaTable> SuperVBMetaBuilder::ExportVBMetaTable() {
+    // calculate descriptors size
+    uint32_t descriptors_size = 0;
+    for (const auto& desc : table_.descriptors) {
+        descriptors_size += SUPER_VBMETA_DESCRIPTOR_SIZE + desc.vbmeta_name_length * sizeof(char);
+    }
+
+    // export header
+    table_.header.magic = SUPER_VBMETA_MAGIC;
+    table_.header.major_version = SUPER_VBMETA_MAJOR_VERSION;
+    table_.header.minor_version = SUPER_VBMETA_MINOR_VERSION;
+    table_.header.header_size = SUPER_VBMETA_HEADER_SIZE;
+    table_.header.total_size = SUPER_VBMETA_HEADER_SIZE + descriptors_size;
+    memset(table_.header.checksum, 0, sizeof(table_.header.checksum));
+    table_.header.descriptors_size = descriptors_size;
+    memset(table_.header.reserved, 0, sizeof(table_.header.reserved));
+    std::string serialized_table = SerializeVBMetaTable(table_);
+    ::SHA256(reinterpret_cast<const uint8_t*>(serialized_table.c_str()), table_.header.total_size,
+             &table_.header.checksum[0]);
+
+    return std::make_unique<VBMetaTable>(table_);
+}
+
+Result<void> SuperVBMetaBuilder::ExportVBMetaTableToFile() {
+    std::unique_ptr<VBMetaTable> table = ExportVBMetaTable();
+
+    std::string serialized_table = SerializeVBMetaTable(*table);
+
+    android::base::Result<void> rv_write_primary_vbmeta_table =
+            WritePrimaryVBMetaTable(super_vbmeta_fd_, serialized_table);
+    if (!rv_write_primary_vbmeta_table) {
+        return rv_write_primary_vbmeta_table;
+    }
+
+    android::base::Result<void> rv_write_backup_vbmeta_table =
+            WriteBackupVBMetaTable(super_vbmeta_fd_, serialized_table);
+    return rv_write_backup_vbmeta_table;
+}
+
+Result<void> SuperVBMetaBuilder::ExportVBMetaImageToFile(const uint8_t vbmeta_index,
+                                                         const std::string& vbmeta_image) {
+    Result<void> rv_write_vbmeta_image =
+            WriteVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
+    if (!rv_write_vbmeta_image) {
+        return rv_write_vbmeta_image;
+    }
+
+    Result<void> rv_validate_vbmeta_image =
+            ValidateVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
+    return rv_validate_vbmeta_image;
+}
+
+bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
+                            const std::map<std::string, std::string>& images_path) {
+    unique_fd super_vbmeta_fd(TEMP_FAILURE_RETRY(
+            open(super_vbmeta_file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644)));
+    if (super_vbmeta_fd < 0) {
+        PERROR << "Couldn't open super vbmeta file " << super_vbmeta_file;
+        return false;
+    }
+
+    SuperVBMetaBuilder builder(super_vbmeta_fd, images_path);
+
+    Result<void> rv_build = builder.Build();
+    if (!rv_build) {
+        LERROR << rv_build.error();
+        return false;
+    }
+
+    Result<void> rv_export = builder.ExportVBMetaTableToFile();
+    if (!rv_export) {
+        LERROR << rv_export.error();
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder.h b/fs_mgr/libvbmeta/builder.h
new file mode 100644
index 0000000..58ea36a
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+class SuperVBMetaBuilder {
+  public:
+    SuperVBMetaBuilder();
+    SuperVBMetaBuilder(const int super_vbmeta_fd,
+                       const std::map<std::string, std::string>& images_path);
+    android::base::Result<void> Build();
+    android::base::Result<std::string> ReadVBMetaImageFromFile(const std::string& file);
+    // It adds the vbmeta image in super_vbmeta and returns the index
+    // (which has the same meaning with vbmeta_index of VBMetaDescriptor).
+    android::base::Result<uint8_t> AddVBMetaImage(const std::string& vbmeta_name);
+    void DeleteVBMetaImage(const std::string& vbmeta_name);
+    std::unique_ptr<VBMetaTable> ExportVBMetaTable();
+    android::base::Result<void> ExportVBMetaTableToFile();
+    android::base::Result<void> ExportVBMetaImageToFile(const uint8_t vbmeta_index,
+                                                        const std::string& vbmeta_image);
+
+  private:
+    android::base::Result<uint8_t> GetEmptySlot();
+
+    int super_vbmeta_fd_;
+    VBMetaTable table_;
+    // Maps vbmeta image name to vbmeta image file path.
+    std::map<std::string, std::string> images_path_;
+};
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/builder_test.cpp b/fs_mgr/libvbmeta/builder_test.cpp
new file mode 100644
index 0000000..9a015fd
--- /dev/null
+++ b/fs_mgr/libvbmeta/builder_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "builder.h"
+#include "super_vbmeta_format.h"
+
+using android::base::Result;
+using android::fs_mgr::SuperVBMetaBuilder;
+
+TEST(BuilderTest, VBMetaTableBasic) {
+    std::unique_ptr<SuperVBMetaBuilder> builder = std::make_unique<SuperVBMetaBuilder>();
+    ASSERT_NE(builder, nullptr);
+
+    Result<uint8_t> vbmeta_index = builder->AddVBMetaImage("vbmeta" /* vbmeta_name */
+    );
+    EXPECT_TRUE(vbmeta_index);
+
+    Result<uint8_t> vbmeta_system_slot = builder->AddVBMetaImage("vbmeta_system" /* vbmeta_name */
+    );
+    EXPECT_TRUE(vbmeta_system_slot);
+
+    Result<uint8_t> vbmeta_vendor_slot = builder->AddVBMetaImage("vbmeta_vendor" /* vbmeta_name */
+    );
+    EXPECT_TRUE(vbmeta_vendor_slot);
+
+    builder->DeleteVBMetaImage("vbmeta_system" /* vbmeta_name */
+    );
+
+    Result<uint8_t> vbmeta_product_slot = builder->AddVBMetaImage("vbmeta_product" /* vbmeta_name */
+    );
+    EXPECT_TRUE(vbmeta_product_slot);
+
+    std::unique_ptr<VBMetaTable> table = builder->ExportVBMetaTable();
+    ASSERT_NE(table, nullptr);
+
+    // check for vbmeta table header
+    EXPECT_EQ(table->header.magic, SUPER_VBMETA_MAGIC);
+    EXPECT_EQ(table->header.major_version, SUPER_VBMETA_MAJOR_VERSION);
+    EXPECT_EQ(table->header.minor_version, SUPER_VBMETA_MINOR_VERSION);
+    EXPECT_EQ(table->header.header_size, SUPER_VBMETA_HEADER_SIZE);
+    EXPECT_EQ(table->header.total_size,
+              SUPER_VBMETA_HEADER_SIZE + SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);
+    EXPECT_EQ(table->header.descriptors_size, SUPER_VBMETA_DESCRIPTOR_SIZE * 3 + 33);
+
+    // Test for vbmeta table descriptors
+    EXPECT_EQ(table->descriptors.size(), 3);
+
+    EXPECT_EQ(table->descriptors[0].vbmeta_index, 0);
+    EXPECT_EQ(table->descriptors[0].vbmeta_name_length, 6);
+    for (int i = 0; i < sizeof(table->descriptors[0].reserved); i++)
+        EXPECT_EQ(table->descriptors[0].reserved[i], 0);
+    EXPECT_EQ(table->descriptors[0].vbmeta_name, "vbmeta");
+
+    EXPECT_EQ(table->descriptors[1].vbmeta_index, 2);
+    EXPECT_EQ(table->descriptors[1].vbmeta_name_length, 13);
+    for (int i = 0; i < sizeof(table->descriptors[1].reserved); i++)
+        EXPECT_EQ(table->descriptors[1].reserved[i], 0);
+    EXPECT_EQ(table->descriptors[1].vbmeta_name, "vbmeta_vendor");
+
+    EXPECT_EQ(table->descriptors[2].vbmeta_index, 1);
+    EXPECT_EQ(table->descriptors[2].vbmeta_name_length, 14);
+    for (int i = 0; i < sizeof(table->descriptors[2].reserved); i++)
+        EXPECT_EQ(table->descriptors[2].reserved[i], 0);
+    EXPECT_EQ(table->descriptors[2].vbmeta_name, "vbmeta_product");
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h b/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
new file mode 100644
index 0000000..ab7ba73
--- /dev/null
+++ b/fs_mgr/libvbmeta/include/libvbmeta/libvbmeta.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <string>
+
+namespace android {
+namespace fs_mgr {
+
+bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
+                            const std::map<std::string, std::string>& images_path);
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/reader.cpp b/fs_mgr/libvbmeta/reader.cpp
new file mode 100644
index 0000000..212d186
--- /dev/null
+++ b/fs_mgr/libvbmeta/reader.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "reader.h"
+
+#include <android-base/file.h>
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+Result<void> LoadAndVerifySuperVBMetaHeader(const void* buffer, SuperVBMetaHeader* header) {
+    memcpy(header, buffer, sizeof(*header));
+
+    // Do basic validation of super vbmeta.
+    if (header->magic != SUPER_VBMETA_MAGIC) {
+        return Error() << "Super VBMeta has invalid magic value";
+    }
+
+    // Check that the version is compatible.
+    if (header->major_version != SUPER_VBMETA_MAJOR_VERSION ||
+        header->minor_version > SUPER_VBMETA_MINOR_VERSION) {
+        return Error() << "Super VBMeta has incompatible version";
+    }
+    return {};
+}
+
+void LoadVBMetaDescriptors(const void* buffer, uint32_t size,
+                           std::vector<InternalVBMetaDescriptor>* descriptors) {
+    for (int p = 0; p < size;) {
+        InternalVBMetaDescriptor descriptor;
+        memcpy(&descriptor, (char*)buffer + p, SUPER_VBMETA_DESCRIPTOR_SIZE);
+        p += SUPER_VBMETA_DESCRIPTOR_SIZE;
+
+        descriptor.vbmeta_name = std::string((char*)buffer + p, descriptor.vbmeta_name_length);
+        p += descriptor.vbmeta_name_length;
+
+        descriptors->emplace_back(std::move(descriptor));
+    }
+}
+
+Result<void> ReadVBMetaTable(int fd, uint64_t offset, VBMetaTable* table) {
+    std::unique_ptr<uint8_t[]> header_buffer =
+            std::make_unique<uint8_t[]>(SUPER_VBMETA_HEADER_SIZE);
+    if (!android::base::ReadFullyAtOffset(fd, header_buffer.get(), SUPER_VBMETA_HEADER_SIZE,
+                                          offset)) {
+        return ErrnoError() << "Couldn't read super vbmeta header at offset " << offset;
+    }
+
+    Result<void> rv_header = LoadAndVerifySuperVBMetaHeader(header_buffer.get(), &table->header);
+    if (!rv_header) {
+        return rv_header;
+    }
+
+    const uint64_t descriptors_offset = offset + table->header.header_size;
+    std::unique_ptr<uint8_t[]> descriptors_buffer =
+            std::make_unique<uint8_t[]>(table->header.descriptors_size);
+    if (!android::base::ReadFullyAtOffset(fd, descriptors_buffer.get(),
+                                          table->header.descriptors_size, descriptors_offset)) {
+        return ErrnoError() << "Couldn't read super vbmeta descriptors at offset "
+                            << descriptors_offset;
+    }
+
+    LoadVBMetaDescriptors(descriptors_buffer.get(), table->header.descriptors_size,
+                          &table->descriptors);
+    return {};
+}
+
+Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table) {
+    uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
+    return ReadVBMetaTable(fd, offset, table);
+}
+
+Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table) {
+    uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
+    return ReadVBMetaTable(fd, offset, table);
+}
+
+Result<std::string> ReadVBMetaImage(int fd, int slot) {
+    const uint64_t offset = 2 * SUPER_VBMETA_TABLE_MAX_SIZE + slot * VBMETA_IMAGE_MAX_SIZE;
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+    if (!android::base::ReadFullyAtOffset(fd, buffer.get(), VBMETA_IMAGE_MAX_SIZE, offset)) {
+        return ErrnoError() << "Couldn't read vbmeta image at offset " << offset;
+    }
+    return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
+                                 const std::string& vbmeta_image) {
+    Result<std::string> content = ReadVBMetaImage(super_vbmeta_fd, vbmeta_index);
+    if (!content) {
+        return content.error();
+    }
+
+    if (vbmeta_image != content.value()) {
+        return Error() << "VBMeta Image in Super VBMeta differ from the original one.";
+    }
+    return {};
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libvbmeta/reader.h b/fs_mgr/libvbmeta/reader.h
new file mode 100644
index 0000000..f0997ff
--- /dev/null
+++ b/fs_mgr/libvbmeta/reader.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+android::base::Result<void> ReadPrimaryVBMetaTable(int fd, VBMetaTable* table);
+android::base::Result<void> ReadBackupVBMetaTable(int fd, VBMetaTable* table);
+android::base::Result<std::string> ReadVBMetaImage(int fd, int slot);
+
+android::base::Result<void> ValidateVBMetaImage(int super_vbmeta_fd, int vbmeta_index,
+                                                const std::string& vbmeta_image);
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_format.h b/fs_mgr/libvbmeta/super_vbmeta_format.h
new file mode 100644
index 0000000..c62a2dd
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_format.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This .h file is intended for CPP clients (usually fastbootd, recovery and update_engine)  */
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "super_vbmeta_format_c.h"
+
+struct InternalVBMetaDescriptor : VBMetaDescriptor {
+    /*  64: The vbmeta image's name */
+    std::string vbmeta_name;
+};
+
+struct VBMetaTable {
+    SuperVBMetaHeader header;
+    std::vector<InternalVBMetaDescriptor> descriptors;
+};
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_format_c.h b/fs_mgr/libvbmeta/super_vbmeta_format_c.h
new file mode 100644
index 0000000..6d79801
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_format_c.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This .h file is intended for C clients (usually bootloader).  */
+
+#pragma once
+
+#include <stdint.h>
+
+/* Magic signature for super vbmeta. */
+#define SUPER_VBMETA_MAGIC 0x5356424d
+
+/* Current super vbmeta version. */
+#define SUPER_VBMETA_MAJOR_VERSION 1
+#define SUPER_VBMETA_MINOR_VERSION 0
+
+/* super vbmeta size. */
+#define SUPER_VBMETA_HEADER_SIZE sizeof(SuperVBMetaHeader)
+#define SUPER_VBMETA_DESCRIPTOR_SIZE sizeof(VBMetaDescriptor)
+#define SUPER_VBMETA_TABLE_MAX_SIZE 2048
+
+/* super vbmeta offset. */
+#define PRIMARY_SUPER_VBMETA_TABLE_OFFSET 0
+#define BACKUP_SUPER_VBMETA_TABLE_OFFSET SUPER_VBMETA_TABLE_MAX_SIZE
+
+/* restriction of vbmeta image */
+#define VBMETA_IMAGE_MAX_NUM 32
+#define VBMETA_IMAGE_MAX_SIZE 64 * 1024
+
+/* Binary format of the super vbmeta image.
+ *
+ * The super vbmeta image consists of two blocks:
+ *
+ *  +------------------------------------------+
+ *  | Super VBMeta Table - fixed size          |
+ *  +------------------------------------------+
+ *  | Backup Super VBMeta Table - fixed size   |
+ *  +------------------------------------------+
+ *  | VBMeta Images - fixed size               |
+ *  +------------------------------------------+
+ *
+ *  The "Super VBMeta Table" records the offset
+ *  and the size of each vbmeta_partition within
+ *  /super_vbmeta.
+ *
+ *  The "VBMeta Image" is copied from each vbmeta_partition
+ *  and filled with 0 until 64K bytes.
+ *
+ * The super vbmeta table consists of two blocks:
+ *
+ *  +-----------------------------------------+
+ *  | Header data - fixed size                |
+ *  +-----------------------------------------+
+ *  | VBMeta descriptors - variable size      |
+ *  +-----------------------------------------+
+ *
+ * The "Header data" block is described by the following struct and
+ * is always 128 bytes long.
+ *
+ * The "VBMeta descriptor" is |descriptors_size| + |vbmeta_name_length|
+ * bytes long. It contains the offset and size for each vbmeta image
+ * and is followed by |vbmeta_name_length| bytes of the partition name
+ * (UTF-8 encoded).
+ */
+
+typedef struct SuperVBMetaHeader {
+    /*  0: Magic signature (SUPER_VBMETA_MAGIC). */
+    uint32_t magic;
+
+    /*  4: Major version. Version number required to read this super vbmeta. If the version is not
+     * equal to the library version, the super vbmeta should be considered incompatible.
+     */
+    uint16_t major_version;
+
+    /*  6: Minor version. A library supporting newer features should be able to
+     * read super vbmeta with an older minor version. However, an older library
+     * should not support reading super vbmeta if its minor version is higher.
+     */
+    uint16_t minor_version;
+
+    /*  8: The size of this header struct. */
+    uint32_t header_size;
+
+    /*  12: The size of this super vbmeta table. */
+    uint32_t total_size;
+
+    /*  16: SHA256 checksum of this super vbmeta table, with this field set to 0. */
+    uint8_t checksum[32];
+
+    /*  48: The size of the vbmeta table descriptors. */
+    uint32_t descriptors_size;
+
+    /*  52: mark which slot is in use. */
+    uint32_t in_use = 0;
+
+    /*  56: reserved for other usage, filled with 0. */
+    uint8_t reserved[72];
+} __attribute__((packed)) SuperVBMetaHeader;
+
+typedef struct VBMetaDescriptor {
+    /*  0: The slot number of the vbmeta image. */
+    uint8_t vbmeta_index;
+
+    /*  12: The length of the vbmeta image name. */
+    uint32_t vbmeta_name_length;
+
+    /*  16: Space reserved for other usage, filled with 0. */
+    uint8_t reserved[48];
+} __attribute__((packed)) VBMetaDescriptor;
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/super_vbmeta_test.cpp b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
new file mode 100644
index 0000000..6b4fc5d
--- /dev/null
+++ b/fs_mgr/libvbmeta/super_vbmeta_test.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <openssl/sha.h>
+#include <sparse/sparse.h>
+
+#include "reader.h"
+#include "super_vbmeta_format.h"
+#include "utility.h"
+#include "writer.h"
+
+#define FAKE_DATA_SIZE 40960
+#define FAKE_PARTITION_SIZE FAKE_DATA_SIZE * 25
+
+using android::base::Result;
+using android::fs_mgr::GetFileSize;
+using android::fs_mgr::ReadVBMetaImage;
+using SparsePtr = std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)>;
+
+void GeneratePartitionImage(int fd, const std::string& file_name,
+                            const std::string& partition_name) {
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(FAKE_DATA_SIZE);
+    for (size_t c = 0; c < FAKE_DATA_SIZE; c++) {
+        buffer[c] = uint8_t(c);
+    }
+
+    SparsePtr file(sparse_file_new(512 /* block size */, FAKE_DATA_SIZE), sparse_file_destroy);
+    EXPECT_TRUE(file);
+    EXPECT_EQ(0, sparse_file_add_data(file.get(), buffer.get(), FAKE_DATA_SIZE,
+                                      0 /* offset in blocks */));
+    EXPECT_EQ(0, sparse_file_write(file.get(), fd, false /* gz */, true /* sparse */,
+                                   false /* crc */));
+
+    std::stringstream cmd;
+    cmd << "avbtool add_hashtree_footer"
+        << " --image " << file_name << " --partition_name " << partition_name
+        << " --partition_size " << FAKE_PARTITION_SIZE << " --algorithm SHA256_RSA2048"
+        << " --key external/avb/test/data/testkey_rsa2048.pem";
+
+    int rc = system(cmd.str().c_str());
+    EXPECT_TRUE(WIFEXITED(rc));
+    EXPECT_EQ(WEXITSTATUS(rc), 0);
+}
+
+void GenerateVBMetaImage(const std::string& vbmeta_file_name,
+                         const std::string& include_file_name) {
+    std::stringstream cmd;
+    cmd << "avbtool make_vbmeta_image"
+        << " --output " << vbmeta_file_name << " --include_descriptors_from_image "
+        << include_file_name;
+
+    int rc = system(cmd.str().c_str());
+    EXPECT_TRUE(WIFEXITED(rc));
+    EXPECT_EQ(WEXITSTATUS(rc), 0);
+}
+
+std::string ReadVBMetaImageFromFile(const std::string& file) {
+    android::base::unique_fd fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
+    EXPECT_GT(fd, 0);
+    Result<uint64_t> file_size = GetFileSize(fd);
+    EXPECT_TRUE(file_size);
+    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
+    EXPECT_TRUE(android::base::ReadFully(fd, buffer.get(), file_size.value()));
+    return std::string(reinterpret_cast<char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
+}
+
+TEST(VBMetaTableTest, VBMetaTableBasic) {
+    TemporaryDir td;
+
+    // Generate Partition Image
+    TemporaryFile system_tf(std::string(td.path));
+    std::string system_path(system_tf.path);
+    GeneratePartitionImage(system_tf.fd, system_path, "system");
+    system_tf.release();
+
+    TemporaryFile vendor_tf(std::string(td.path));
+    std::string vendor_path(vendor_tf.path);
+    GeneratePartitionImage(vendor_tf.fd, vendor_path, "vendor");
+    vendor_tf.release();
+
+    TemporaryFile product_tf(std::string(td.path));
+    std::string product_path(product_tf.path);
+    GeneratePartitionImage(product_tf.fd, product_path, "product");
+    product_tf.release();
+
+    // Generate VBMeta Image
+    std::string vbmeta_system_path(td.path);
+    vbmeta_system_path.append("/vbmeta_system.img");
+    GenerateVBMetaImage(vbmeta_system_path, system_path);
+
+    std::string vbmeta_vendor_path(td.path);
+    vbmeta_vendor_path.append("/vbmeta_vendor.img");
+    GenerateVBMetaImage(vbmeta_vendor_path, vendor_path);
+
+    std::string vbmeta_product_path(td.path);
+    vbmeta_product_path.append("/vbmeta_product.img");
+    GenerateVBMetaImage(vbmeta_product_path, product_path);
+
+    // Generate Super VBMeta Image
+    std::string super_vbmeta_path(td.path);
+    super_vbmeta_path.append("/super_vbmeta.img");
+
+    std::stringstream cmd;
+    cmd << "vbmake"
+        << " --image "
+        << "vbmeta_system"
+        << "=" << vbmeta_system_path << " --image "
+        << "vbmeta_vendor"
+        << "=" << vbmeta_vendor_path << " --image "
+        << "vbmeta_product"
+        << "=" << vbmeta_product_path << " --output=" << super_vbmeta_path;
+
+    int rc = system(cmd.str().c_str());
+    ASSERT_TRUE(WIFEXITED(rc));
+    ASSERT_EQ(WEXITSTATUS(rc), 0);
+
+    android::base::unique_fd fd(open(super_vbmeta_path.c_str(), O_RDONLY | O_CLOEXEC));
+    EXPECT_GT(fd, 0);
+
+    // Check the size of vbmeta table
+    Result<uint64_t> super_vbmeta_size = GetFileSize(fd);
+    EXPECT_TRUE(super_vbmeta_size);
+    EXPECT_EQ(super_vbmeta_size.value(),
+              SUPER_VBMETA_TABLE_MAX_SIZE * 2 + VBMETA_IMAGE_MAX_SIZE * 3);
+
+    // Check Primary vbmeta table is equal to Backup one
+    VBMetaTable table;
+    EXPECT_TRUE(android::fs_mgr::ReadPrimaryVBMetaTable(fd, &table));
+    VBMetaTable table_backup;
+    EXPECT_TRUE(android::fs_mgr::ReadBackupVBMetaTable(fd, &table_backup));
+    EXPECT_EQ(android::fs_mgr::SerializeVBMetaTable(table),
+              android::fs_mgr::SerializeVBMetaTable(table_backup));
+
+    // Check vbmeta table Header Checksum
+    std::string serial_table = android::fs_mgr::SerializeVBMetaTable(table);
+    std::string serial_removed_checksum(serial_table);
+    // Replace checksum 32 bytes (starts at 16th byte) with 0
+    serial_removed_checksum.replace(16, 32, 32, 0);
+    uint8_t test_checksum[32];
+    ::SHA256(reinterpret_cast<const uint8_t*>(serial_removed_checksum.c_str()),
+             table.header.total_size, &test_checksum[0]);
+    EXPECT_EQ(memcmp(table.header.checksum, test_checksum, 32), 0);
+
+    // Check vbmeta table descriptors and vbmeta images
+    EXPECT_EQ(table.descriptors.size(), 3);
+
+    EXPECT_EQ(table.descriptors[0].vbmeta_index, 0);
+    EXPECT_EQ(table.descriptors[0].vbmeta_name_length, 14);
+    EXPECT_EQ(table.descriptors[0].vbmeta_name, "vbmeta_product");
+    Result<std::string> vbmeta_product_content = ReadVBMetaImage(fd, 0);
+    EXPECT_TRUE(vbmeta_product_content);
+    EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_product_path), vbmeta_product_content.value());
+
+    EXPECT_EQ(table.descriptors[1].vbmeta_index, 1);
+    EXPECT_EQ(table.descriptors[1].vbmeta_name_length, 13);
+    EXPECT_EQ(table.descriptors[1].vbmeta_name, "vbmeta_system");
+    Result<std::string> vbmeta_system_content = ReadVBMetaImage(fd, 1);
+    EXPECT_TRUE(vbmeta_system_content);
+    EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_system_path), vbmeta_system_content.value());
+
+    EXPECT_EQ(table.descriptors[2].vbmeta_index, 2);
+    EXPECT_EQ(table.descriptors[2].vbmeta_name_length, 13);
+    EXPECT_EQ(table.descriptors[2].vbmeta_name, "vbmeta_vendor");
+    Result<std::string> vbmeta_vendor_content = ReadVBMetaImage(fd, 2);
+    EXPECT_TRUE(vbmeta_vendor_content);
+    EXPECT_EQ(ReadVBMetaImageFromFile(vbmeta_vendor_path), vbmeta_vendor_content.value());
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    return RUN_ALL_TESTS();
+}
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/utility.cpp b/fs_mgr/libvbmeta/utility.cpp
new file mode 100644
index 0000000..c184227
--- /dev/null
+++ b/fs_mgr/libvbmeta/utility.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utility.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "super_vbmeta_format.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+Result<uint64_t> GetFileSize(int fd) {
+    struct stat sb;
+    if (fstat(fd, &sb) == -1) {
+        return ErrnoError() << "Couldn't get the file size";
+    }
+    return sb.st_size;
+}
+
+uint64_t IndexOffset(const uint8_t vbmeta_index) {
+    /* There are primary and backup vbmeta table in super_vbmeta,
+       so SUPER_VBMETA_TABLE_MAX_SIZE is counted twice. */
+    return 2 * SUPER_VBMETA_TABLE_MAX_SIZE + vbmeta_index * VBMETA_IMAGE_MAX_SIZE;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/libvbmeta/utility.h b/fs_mgr/libvbmeta/utility.h
new file mode 100644
index 0000000..91db0ad
--- /dev/null
+++ b/fs_mgr/libvbmeta/utility.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/result.h>
+
+#define VBMETA_TAG "[libvbmeta]"
+#define LWARN LOG(WARNING) << VBMETA_TAG
+#define LINFO LOG(INFO) << VBMETA_TAG
+#define LERROR LOG(ERROR) << VBMETA_TAG
+#define PWARNING PLOG(WARNING) << VBMETA_TAG
+#define PERROR PLOG(ERROR) << VBMETA_TAG
+
+namespace android {
+namespace fs_mgr {
+
+android::base::Result<uint64_t> GetFileSize(int fd);
+
+uint64_t IndexOffset(const uint8_t vbmeta_index);
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/writer.cpp b/fs_mgr/libvbmeta/writer.cpp
new file mode 100644
index 0000000..fc0e0fb
--- /dev/null
+++ b/fs_mgr/libvbmeta/writer.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "writer.h"
+
+#include <android-base/file.h>
+
+#include "utility.h"
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeVBMetaTable(const VBMetaTable& input) {
+    std::string table;
+    table.append(reinterpret_cast<const char*>(&input.header), SUPER_VBMETA_HEADER_SIZE);
+
+    for (const auto& desc : input.descriptors) {
+        table.append(reinterpret_cast<const char*>(&desc), SUPER_VBMETA_DESCRIPTOR_SIZE);
+        table.append(desc.vbmeta_name);
+    }
+
+    // Ensure the size of vbmeta table is SUPER_VBMETA_TABLE_MAX_SIZE
+    table.resize(SUPER_VBMETA_TABLE_MAX_SIZE, '\0');
+
+    return table;
+}
+
+Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table) {
+    const uint64_t offset = PRIMARY_SUPER_VBMETA_TABLE_OFFSET;
+    if (lseek(fd, offset, SEEK_SET) < 0) {
+        return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+    }
+
+    if (!android::base::WriteFully(fd, table.data(), table.size())) {
+        return ErrnoError() << "Failed to write primary vbmeta table at offset " << offset;
+    }
+    return {};
+}
+
+Result<void> WriteBackupVBMetaTable(int fd, const std::string& table) {
+    const uint64_t offset = BACKUP_SUPER_VBMETA_TABLE_OFFSET;
+    if (lseek(fd, offset, SEEK_SET) < 0) {
+        return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+    }
+
+    if (!android::base::WriteFully(fd, table.data(), table.size())) {
+        return ErrnoError() << "Failed to write backup vbmeta table at offset " << offset;
+    }
+    return {};
+}
+
+Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number, const std::string& vbmeta_image) {
+    const uint64_t offset = IndexOffset(slot_number);
+    if (lseek(fd, offset, SEEK_SET) < 0) {
+        return ErrnoError() << __PRETTY_FUNCTION__ << " lseek failed";
+    }
+
+    if (!android::base::WriteFully(fd, vbmeta_image.data(), vbmeta_image.size())) {
+        return ErrnoError() << "Failed to write vbmeta image at offset " << offset;
+    }
+    return {};
+}
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/fs_mgr/libvbmeta/writer.h b/fs_mgr/libvbmeta/writer.h
new file mode 100644
index 0000000..f8eed36
--- /dev/null
+++ b/fs_mgr/libvbmeta/writer.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <android-base/result.h>
+
+#include "super_vbmeta_format.h"
+
+namespace android {
+namespace fs_mgr {
+
+std::string SerializeVBMetaTable(const VBMetaTable& input);
+
+android::base::Result<void> WritePrimaryVBMetaTable(int fd, const std::string& table);
+android::base::Result<void> WriteBackupVBMetaTable(int fd, const std::string& table);
+android::base::Result<void> WriteVBMetaImage(int fd, const uint8_t slot_number,
+                                             const std::string& vbmeta_image);
+
+}  // namespace fs_mgr
+}  // namespace android
\ No newline at end of file
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index ff20e43..9736824 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -121,13 +121,8 @@
     }
 
     Subcontext* action_subcontext = nullptr;
-    if (subcontexts_) {
-        for (auto& subcontext : *subcontexts_) {
-            if (StartsWith(filename, subcontext.path_prefix())) {
-                action_subcontext = &subcontext;
-                break;
-            }
-        }
+    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
+        action_subcontext = subcontext_;
     }
 
     std::string event_trigger;
diff --git a/init/action_parser.h b/init/action_parser.h
index 2fe9983..3000132 100644
--- a/init/action_parser.h
+++ b/init/action_parser.h
@@ -30,8 +30,8 @@
 
 class ActionParser : public SectionParser {
   public:
-    ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
-        : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
+    ActionParser(ActionManager* action_manager, Subcontext* subcontext)
+        : action_manager_(action_manager), subcontext_(subcontext), action_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
                               int line) override;
     Result<void> ParseLineSection(std::vector<std::string>&& args, int line) override;
@@ -39,7 +39,7 @@
 
   private:
     ActionManager* action_manager_;
-    std::vector<Subcontext>* subcontexts_;
+    Subcontext* subcontext_;
     std::unique_ptr<Action> action_;
 };
 
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 4a1bc5a..9121bac 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -50,12 +50,13 @@
 using android::fs_mgr::AvbHandleStatus;
 using android::fs_mgr::AvbHashtreeResult;
 using android::fs_mgr::AvbUniquePtr;
-using android::fs_mgr::BuildGsiSystemFstabEntry;
 using android::fs_mgr::Fstab;
 using android::fs_mgr::FstabEntry;
 using android::fs_mgr::ReadDefaultFstab;
 using android::fs_mgr::ReadFstabFromDt;
 using android::fs_mgr::SkipMountingPartitions;
+using android::fs_mgr::TransformFstabForDsu;
+using android::init::WriteFile;
 using android::snapshot::SnapshotManager;
 
 using namespace std::literals;
@@ -596,14 +597,14 @@
 }
 
 void FirstStageMount::UseGsiIfPresent() {
-    std::string metadata_file, error;
+    std::string error;
 
-    if (!android::gsi::CanBootIntoGsi(&metadata_file, &error)) {
+    if (!android::gsi::CanBootIntoGsi(&error)) {
         LOG(INFO) << "GSI " << error << ", proceeding with normal boot";
         return;
     }
 
-    auto metadata = android::fs_mgr::ReadFromImageFile(metadata_file.c_str());
+    auto metadata = android::fs_mgr::ReadFromImageFile(gsi::kDsuLpMetadataFile);
     if (!metadata) {
         LOG(ERROR) << "GSI partition layout could not be read";
         return;
@@ -627,14 +628,16 @@
         return;
     }
 
-    // Replace the existing system fstab entry.
-    auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {
-        return entry.mount_point == "/system";
-    });
-    if (system_partition != fstab_.end()) {
-        fstab_.erase(system_partition);
+    std::string lp_names = "";
+    std::vector<std::string> dsu_partitions;
+    for (auto&& partition : metadata->partitions) {
+        auto name = fs_mgr::GetPartitionName(partition);
+        dsu_partitions.push_back(name);
+        lp_names += name + ",";
     }
-    fstab_.emplace_back(BuildGsiSystemFstabEntry());
+    // Publish the logical partition names for TransformFstabForDsu
+    WriteFile(gsi::kGsiLpNamesFile, lp_names);
+    TransformFstabForDsu(&fstab_, dsu_partitions);
     gsi_not_on_userdata_ = (super_name != "userdata");
 }
 
diff --git a/init/init.cpp b/init/init.cpp
index 8326466..ad31fa0 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -103,7 +103,7 @@
 static bool do_shutdown = false;
 static bool load_debug_prop = false;
 
-static std::vector<Subcontext>* subcontexts;
+static std::unique_ptr<Subcontext> subcontext;
 
 void DumpState() {
     ServiceList::GetInstance().DumpState();
@@ -113,9 +113,10 @@
 Parser CreateParser(ActionManager& action_manager, ServiceList& service_list) {
     Parser parser;
 
-    parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
-    parser.AddSectionParser("on", std::make_unique<ActionParser>(&action_manager, subcontexts));
+    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
+                                               &service_list, subcontext.get(), std::nullopt));
+    parser.AddSectionParser("on",
+                            std::make_unique<ActionParser>(&action_manager, subcontext.get()));
     parser.AddSectionParser("import", std::make_unique<ImportParser>(&parser));
 
     return parser;
@@ -125,8 +126,8 @@
 Parser CreateServiceOnlyParser(ServiceList& service_list) {
     Parser parser;
 
-    parser.AddSectionParser(
-            "service", std::make_unique<ServiceParser>(&service_list, subcontexts, std::nullopt));
+    parser.AddSectionParser("service", std::make_unique<ServiceParser>(
+                                               &service_list, subcontext.get(), std::nullopt));
     return parser;
 }
 
@@ -749,7 +750,7 @@
         PLOG(FATAL) << "SetupMountNamespaces failed";
     }
 
-    subcontexts = InitializeSubcontexts();
+    subcontext = InitializeSubcontext();
 
     ActionManager& am = ActionManager::GetInstance();
     ServiceList& sm = ServiceList::GetInstance();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index c18decc..f5d1143 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -530,7 +530,7 @@
     uint32_t result = 0;
     ucred cr = {.pid = 1, .uid = 0, .gid = 0};
     std::string error;
-    result = HandlePropertySet(name, value, kInitContext.c_str(), cr, nullptr, &error);
+    result = HandlePropertySet(name, value, kInitContext, cr, nullptr, &error);
     if (result != PROP_SUCCESS) {
         LOG(ERROR) << "Init cannot set '" << name << "' to '" << value << "': " << error;
     }
@@ -645,11 +645,16 @@
     char *key, *value, *eol, *sol, *tmp, *fn;
     size_t flen = 0;
 
-    const char* context = kInitContext.c_str();
+    static constexpr const char* const kVendorPathPrefixes[2] = {
+            "/vendor",
+            "/odm",
+    };
+
+    const char* context = kInitContext;
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
-        for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
-            if (StartsWith(filename, path_prefix)) {
-                context = secontext;
+        for (const auto& vendor_path_prefix : kVendorPathPrefixes) {
+            if (StartsWith(filename, vendor_path_prefix)) {
+                context = kVendorContext;
             }
         }
     }
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 786a084..2cf0f5c 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -60,6 +60,8 @@
 
 #define PROC_SYSRQ "/proc/sysrq-trigger"
 
+using namespace std::literals;
+
 using android::base::GetBoolProperty;
 using android::base::Split;
 using android::base::Timer;
@@ -170,9 +172,23 @@
                  << stat;
 }
 
-/* Find all read+write block devices and emulated devices in /proc/mounts
- * and add them to correpsponding list.
- */
+static bool IsDataMounted() {
+    std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
+    if (fp == nullptr) {
+        PLOG(ERROR) << "Failed to open /proc/mounts";
+        return false;
+    }
+    mntent* mentry;
+    while ((mentry = getmntent(fp.get())) != nullptr) {
+        if (mentry->mnt_dir == "/data"s) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// Find all read+write block devices and emulated devices in /proc/mounts and add them to
+// the correpsponding list.
 static bool FindPartitionsToUmount(std::vector<MountEntry>* blockDevPartitions,
                                    std::vector<MountEntry>* emulatedPartitions, bool dump) {
     std::unique_ptr<std::FILE, int (*)(std::FILE*)> fp(setmntent("/proc/mounts", "re"), endmntent);
@@ -295,12 +311,15 @@
             LOG(ERROR) << "Reboot thread timed out";
 
             if (android::base::GetBoolProperty("ro.debuggable", false) == true) {
-                LOG(INFO) << "Try to dump init process call trace:";
-                const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
-                int status;
-                android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
-                                        LOG_KLOG, true, nullptr, nullptr, 0);
-
+                if (false) {
+                    // SEPolicy will block debuggerd from running and this is intentional.
+                    // But these lines are left to be enabled during debugging.
+                    LOG(INFO) << "Try to dump init process call trace:";
+                    const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
+                    int status;
+                    android_fork_execvp_ext(arraysize(vdc_argv), (char**)vdc_argv, &status, true,
+                                            LOG_KLOG, true, nullptr, nullptr, 0);
+                }
                 LOG(INFO) << "Show stack for all active CPU:";
                 WriteStringToFile("l", PROC_SYSRQ);
 
@@ -436,6 +455,14 @@
     Timer t;
     LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
 
+    // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
+    // worry about unmounting it.
+    if (!IsDataMounted()) {
+        sync();
+        RebootSystem(cmd, rebootTarget);
+        abort();
+    }
+
     // Ensure last reboot reason is reduced to canonical
     // alias reported in bootloader or system boot reason.
     size_t skip = 0;
diff --git a/init/service.cpp b/init/service.cpp
index 793a2b2..e8b75d4 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -441,6 +441,23 @@
 
     LOG(INFO) << "starting service '" << name_ << "'...";
 
+    std::vector<Descriptor> descriptors;
+    for (const auto& socket : sockets_) {
+        if (auto result = socket.Create(scon)) {
+            descriptors.emplace_back(std::move(*result));
+        } else {
+            LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
+        }
+    }
+
+    for (const auto& file : files_) {
+        if (auto result = file.Create()) {
+            descriptors.emplace_back(std::move(*result));
+        } else {
+            LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
+        }
+    }
+
     pid_t pid = -1;
     if (namespaces_.flags) {
         pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr);
@@ -460,16 +477,8 @@
             setenv(key.c_str(), value.c_str(), 1);
         }
 
-        for (const auto& socket : sockets_) {
-            if (auto result = socket.CreateAndPublish(scon); !result) {
-                LOG(INFO) << "Could not create socket '" << socket.name << "': " << result.error();
-            }
-        }
-
-        for (const auto& file : files_) {
-            if (auto result = file.CreateAndPublish(); !result) {
-                LOG(INFO) << "Could not open file '" << file.name << "': " << result.error();
-            }
+        for (const auto& descriptor : descriptors) {
+            descriptor.Publish();
         }
 
         if (auto result = WritePidToFiles(&writepid_files_); !result) {
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index 4322dc7..45d1852 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -537,13 +537,8 @@
     filename_ = filename;
 
     Subcontext* restart_action_subcontext = nullptr;
-    if (subcontexts_) {
-        for (auto& subcontext : *subcontexts_) {
-            if (StartsWith(filename, subcontext.path_prefix())) {
-                restart_action_subcontext = &subcontext;
-                break;
-            }
-        }
+    if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) {
+        restart_action_subcontext = subcontext_;
     }
 
     std::vector<std::string> str_args(args.begin() + 2, args.end());
diff --git a/init/service_parser.h b/init/service_parser.h
index ace4d70..f063102 100644
--- a/init/service_parser.h
+++ b/init/service_parser.h
@@ -30,10 +30,10 @@
 class ServiceParser : public SectionParser {
   public:
     ServiceParser(
-            ServiceList* service_list, std::vector<Subcontext>* subcontexts,
+            ServiceList* service_list, Subcontext* subcontext,
             const std::optional<InterfaceInheritanceHierarchyMap>& interface_inheritance_hierarchy)
         : service_list_(service_list),
-          subcontexts_(subcontexts),
+          subcontext_(subcontext),
           interface_inheritance_hierarchy_(interface_inheritance_hierarchy),
           service_(nullptr) {}
     Result<void> ParseSection(std::vector<std::string>&& args, const std::string& filename,
@@ -84,7 +84,7 @@
     bool IsValidName(const std::string& name) const;
 
     ServiceList* service_list_;
-    std::vector<Subcontext>* subcontexts_;
+    Subcontext* subcontext_;
     std::optional<InterfaceInheritanceHierarchyMap> interface_inheritance_hierarchy_;
     std::unique_ptr<Service> service_;
     std::string filename_;
diff --git a/init/service_utils.cpp b/init/service_utils.cpp
index 836145d..35f2acf 100644
--- a/init/service_utils.cpp
+++ b/init/service_utils.cpp
@@ -26,7 +26,6 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android-base/unique_fd.h>
 #include <cutils/android_get_control_file.h>
 #include <cutils/sockets.h>
 #include <processgroup/processgroup.h>
@@ -138,37 +137,44 @@
     dup2(fd, 2);
 }
 
-void PublishDescriptor(const std::string& key, const std::string& name, int fd) {
-    std::string published_name = key + name;
+}  // namespace
+
+void Descriptor::Publish() const {
+    auto published_name = name_;
+
     for (auto& c : published_name) {
         c = isalnum(c) ? c : '_';
     }
 
+    int fd = fd_.get();
+    // For safety, the FD is created as CLOEXEC, so that must be removed before publishing.
+    auto fd_flags = fcntl(fd, F_GETFD);
+    fd_flags &= ~FD_CLOEXEC;
+    if (fcntl(fd, F_SETFD, fd_flags) != 0) {
+        PLOG(ERROR) << "Failed to remove CLOEXEC from '" << published_name << "'";
+    }
+
     std::string val = std::to_string(fd);
     setenv(published_name.c_str(), val.c_str(), 1);
 }
 
-}  // namespace
-
-Result<void> SocketDescriptor::CreateAndPublish(const std::string& global_context) const {
+Result<Descriptor> SocketDescriptor::Create(const std::string& global_context) const {
     const auto& socket_context = context.empty() ? global_context : context;
-    auto result = CreateSocket(name, type, passcred, perm, uid, gid, socket_context);
+    auto result = CreateSocket(name, type | SOCK_CLOEXEC, passcred, perm, uid, gid, socket_context);
     if (!result) {
         return result.error();
     }
 
-    PublishDescriptor(ANDROID_SOCKET_ENV_PREFIX, name, *result);
-
-    return {};
+    return Descriptor(ANDROID_SOCKET_ENV_PREFIX + name, unique_fd(*result));
 }
 
-Result<void> FileDescriptor::CreateAndPublish() const {
+Result<Descriptor> FileDescriptor::Create() const {
     int flags = (type == "r") ? O_RDONLY : (type == "w") ? O_WRONLY : O_RDWR;
 
     // Make sure we do not block on open (eg: devices can chose to block on carrier detect).  Our
     // intention is never to delay launch of a service for such a condition.  The service can
     // perform its own blocking on carrier detect.
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK)));
+    unique_fd fd(TEMP_FAILURE_RETRY(open(name.c_str(), flags | O_NONBLOCK | O_CLOEXEC)));
 
     if (fd < 0) {
         return ErrnoError() << "Failed to open file '" << name << "'";
@@ -179,9 +185,7 @@
 
     LOG(INFO) << "Opened file '" << name << "', flags " << flags;
 
-    PublishDescriptor(ANDROID_FILE_ENV_PREFIX, name, fd.release());
-
-    return {};
+    return Descriptor(ANDROID_FILE_ENV_PREFIX + name, std::move(fd));
 }
 
 Result<void> EnterNamespaces(const NamespaceInfo& info, const std::string& name, bool pre_apexd) {
diff --git a/init/service_utils.h b/init/service_utils.h
index befce25..d2e69d9 100644
--- a/init/service_utils.h
+++ b/init/service_utils.h
@@ -22,6 +22,7 @@
 #include <string>
 #include <vector>
 
+#include <android-base/unique_fd.h>
 #include <cutils/iosched_policy.h>
 
 #include "result.h"
@@ -29,6 +30,18 @@
 namespace android {
 namespace init {
 
+class Descriptor {
+  public:
+    Descriptor(const std::string& name, android::base::unique_fd fd)
+        : name_(name), fd_(std::move(fd)){};
+
+    void Publish() const;
+
+  private:
+    std::string name_;
+    android::base::unique_fd fd_;
+};
+
 struct SocketDescriptor {
     std::string name;
     int type = 0;
@@ -38,14 +51,14 @@
     std::string context;
     bool passcred = false;
 
-    Result<void> CreateAndPublish(const std::string& global_context) const;
+    Result<Descriptor> Create(const std::string& global_context) const;
 };
 
 struct FileDescriptor {
     std::string name;
     std::string type;
 
-    Result<void> CreateAndPublish() const;
+    Result<Descriptor> Create() const;
 };
 
 struct NamespaceInfo {
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index ec93b58..79fc372 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -49,15 +49,6 @@
 
 namespace android {
 namespace init {
-
-const std::string kInitContext = "u:r:init:s0";
-const std::string kVendorContext = "u:r:vendor_init:s0";
-
-const char* const paths_and_secontexts[2][2] = {
-    {"/vendor", kVendorContext.c_str()},
-    {"/odm", kVendorContext.c_str()},
-};
-
 namespace {
 
 class SubcontextProcess {
@@ -237,6 +228,15 @@
     Fork();
 }
 
+bool Subcontext::PathMatchesSubcontext(const std::string& path) {
+    for (const auto& prefix : path_prefixes_) {
+        if (StartsWith(path, prefix)) {
+            return true;
+        }
+    }
+    return false;
+}
+
 Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
     if (auto result = SendMessage(socket_, subcontext_command); !result) {
         Restart();
@@ -313,13 +313,12 @@
 static std::vector<Subcontext> subcontexts;
 static bool shutting_down;
 
-std::vector<Subcontext>* InitializeSubcontexts() {
+std::unique_ptr<Subcontext> InitializeSubcontext() {
     if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
-        for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
-            subcontexts.emplace_back(path_prefix, secontext);
-        }
+        return std::make_unique<Subcontext>(std::vector<std::string>{"/vendor", "/odm"},
+                                            kVendorContext);
     }
-    return &subcontexts;
+    return nullptr;
 }
 
 bool SubcontextChildReap(pid_t pid) {
diff --git a/init/subcontext.h b/init/subcontext.h
index 591521f..bcaad29 100644
--- a/init/subcontext.h
+++ b/init/subcontext.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef _INIT_SUBCONTEXT_H
-#define _INIT_SUBCONTEXT_H
+#pragma once
 
 #include <signal.h>
 
@@ -31,22 +30,21 @@
 namespace android {
 namespace init {
 
-extern const std::string kInitContext;
-extern const std::string kVendorContext;
-extern const char* const paths_and_secontexts[2][2];
+static constexpr const char kInitContext[] = "u:r:init:s0";
+static constexpr const char kVendorContext[] = "u:r:vendor_init:s0";
 
 class Subcontext {
   public:
-    Subcontext(std::string path_prefix, std::string context)
-        : path_prefix_(std::move(path_prefix)), context_(std::move(context)), pid_(0) {
+    Subcontext(std::vector<std::string> path_prefixes, std::string context)
+        : path_prefixes_(std::move(path_prefixes)), context_(std::move(context)), pid_(0) {
         Fork();
     }
 
     Result<void> Execute(const std::vector<std::string>& args);
     Result<std::vector<std::string>> ExpandArgs(const std::vector<std::string>& args);
     void Restart();
+    bool PathMatchesSubcontext(const std::string& path);
 
-    const std::string& path_prefix() const { return path_prefix_; }
     const std::string& context() const { return context_; }
     pid_t pid() const { return pid_; }
 
@@ -54,18 +52,16 @@
     void Fork();
     Result<SubcontextReply> TransmitMessage(const SubcontextCommand& subcontext_command);
 
-    std::string path_prefix_;
+    std::vector<std::string> path_prefixes_;
     std::string context_;
     pid_t pid_;
     android::base::unique_fd socket_;
 };
 
 int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map);
-std::vector<Subcontext>* InitializeSubcontexts();
+std::unique_ptr<Subcontext> InitializeSubcontext();
 bool SubcontextChildReap(pid_t pid);
 void SubcontextTerminate();
 
 }  // namespace init
 }  // namespace android
-
-#endif
diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp
index f6fee8a..ccef2f3 100644
--- a/init/subcontext_benchmark.cpp
+++ b/init/subcontext_benchmark.cpp
@@ -33,7 +33,7 @@
         return;
     }
 
-    auto subcontext = Subcontext("path", context);
+    auto subcontext = Subcontext({"path"}, context);
     free(context);
 
     while (state.KeepRunning()) {
diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp
index 7565eb6..9cac35e 100644
--- a/init/subcontext_test.cpp
+++ b/init/subcontext_test.cpp
@@ -52,7 +52,7 @@
     auto context_string = std::string(context);
     free(context);
 
-    auto subcontext = Subcontext("dummy_path", context_string);
+    auto subcontext = Subcontext({"dummy_path"}, context_string);
     ASSERT_NE(0, subcontext.pid());
 
     test_function(subcontext, context_string);
diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp
index ac633776..416d942 100644
--- a/init/uevent_listener.cpp
+++ b/init/uevent_listener.cpp
@@ -171,7 +171,7 @@
     return RegenerateUeventsForDir(d.get(), callback);
 }
 
-static const char* kRegenerationPaths[] = {"/sys/class", "/sys/block", "/sys/devices"};
+static const char* kRegenerationPaths[] = {"/sys/devices"};
 
 void UeventListener::RegenerateUevents(const ListenerCallback& callback) const {
     for (const auto path : kRegenerationPaths) {
diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp
index 4c2be91..cf5341d 100644
--- a/libmeminfo/libmeminfo_test.cpp
+++ b/libmeminfo/libmeminfo_test.cpp
@@ -31,6 +31,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 using namespace std;
 using namespace android::meminfo;
@@ -334,7 +335,9 @@
     // Check for names
     EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
     EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
-    EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
+    EXPECT_TRUE(vmas[2].name == "[anon:libc_malloc]" ||
+                android::base::StartsWith(vmas[2].name, "[anon:scudo:"))
+            << "Unknown map name " << vmas[2].name;
     EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
     EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
     EXPECT_EQ(vmas[5].name, "[vsyscall]");
@@ -432,7 +435,9 @@
     // Check for names
     EXPECT_EQ(vmas[0].name, "[anon:dalvik-zygote-jit-code-cache]");
     EXPECT_EQ(vmas[1].name, "/system/framework/x86_64/boot-framework.art");
-    EXPECT_EQ(vmas[2].name, "[anon:libc_malloc]");
+    EXPECT_TRUE(vmas[2].name == "[anon:libc_malloc]" ||
+                android::base::StartsWith(vmas[2].name, "[anon:scudo:"))
+            << "Unknown map name " << vmas[2].name;
     EXPECT_EQ(vmas[3].name, "/system/priv-app/SettingsProvider/oat/x86_64/SettingsProvider.odex");
     EXPECT_EQ(vmas[4].name, "/system/lib64/libhwui.so");
     EXPECT_EQ(vmas[5].name, "[vsyscall]");
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index ce937fd..c4add19 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -25,6 +25,7 @@
 #include <unordered_map>
 
 #include <android-base/macros.h>
+#include <android-base/strings.h>
 #include <backtrace.h>
 
 #include "Allocator.h"
@@ -250,7 +251,8 @@
     } else if (mapping_name == current_lib) {
       // .rodata or .data section
       globals_mappings.emplace_back(*it);
-    } else if (mapping_name == "[anon:libc_malloc]") {
+    } else if (mapping_name == "[anon:libc_malloc]" ||
+               android::base::StartsWith(mapping_name, "[anon:scudo:")) {
       // named malloc mapping
       heap_mappings.emplace_back(*it);
     } else if (has_prefix(mapping_name, "[anon:dalvik-")) {
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
index b860db9..939bdd7 100644
--- a/libnativeloader/Android.bp
+++ b/libnativeloader/Android.bp
@@ -63,14 +63,6 @@
     export_include_dirs: ["include"],
 }
 
-// TODO(jiyong) Remove this when its use in the internal master is
-// switched to libnativeloader-headers
-cc_library_headers {
-    name: "libnativeloader-dummy-headers",
-    host_supported: true,
-    export_include_dirs: ["include"],
-}
-
 cc_test {
     name: "libnativeloader_test",
     srcs: [
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
index 0740e7d..b56dcdb 100644
--- a/libpackagelistparser/Android.bp
+++ b/libpackagelistparser/Android.bp
@@ -19,4 +19,5 @@
         "libpackagelistparser",
     ],
     test_suites: ["device-tests"],
+    require_root: true,
 }
diff --git a/libutils/Looper_test.cpp b/libutils/Looper_test.cpp
index 6fdc0ed..37bdf05 100644
--- a/libutils/Looper_test.cpp
+++ b/libutils/Looper_test.cpp
@@ -11,8 +11,9 @@
 
 #include <utils/threads.h>
 
+// b/141212746 - increased for virtual platforms with higher volatility
 // # of milliseconds to fudge stopwatch measurements
-#define TIMING_TOLERANCE_MS 25
+#define TIMING_TOLERANCE_MS 100
 
 namespace android {
 
diff --git a/libutils/Timers.cpp b/libutils/Timers.cpp
index c3641ef..1172ae7 100644
--- a/libutils/Timers.cpp
+++ b/libutils/Timers.cpp
@@ -22,7 +22,8 @@
 #include <limits.h>
 #include <time.h>
 
-#if defined(__ANDROID__)
+// host linux support requires Linux 2.6.39+
+#if defined(__linux__)
 nsecs_t systemTime(int clock)
 {
     static const clockid_t clocks[] = {
@@ -41,8 +42,7 @@
 nsecs_t systemTime(int /*clock*/)
 {
     // Clock support varies widely across hosts. Mac OS doesn't support
-    // posix clocks, older glibcs don't support CLOCK_BOOTTIME and Windows
-    // is windows.
+    // CLOCK_BOOTTIME, and Windows is windows.
     struct timeval t;
     t.tv_sec = t.tv_usec = 0;
     gettimeofday(&t, nullptr);
diff --git a/libutils/include/utils/ByteOrder.h b/libutils/include/utils/ByteOrder.h
index 44ea13d..9b940e6 100644
--- a/libutils/include/utils/ByteOrder.h
+++ b/libutils/include/utils/ByteOrder.h
@@ -14,10 +14,17 @@
  * limitations under the License.
  */
 
-//
+#pragma once
 
-#ifndef _LIBS_UTILS_BYTE_ORDER_H
-#define _LIBS_UTILS_BYTE_ORDER_H
+/*
+ * If you're looking for a portable <endian.h> that's available on Android,
+ * Linux, macOS, and Windows, see <android-base/endian.h> instead.
+ *
+ * Nothing in this file is useful because all supported Android ABIs are
+ * little-endian and all our code that runs on the host assumes that the host is
+ * also little-endian. What pretense at big-endian support exists is completely
+ * untested and unlikely to actually work.
+ */
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -27,55 +34,12 @@
 #include <netinet/in.h>
 #endif
 
-/*
- * These macros are like the hton/ntoh byte swapping macros,
- * except they allow you to swap to and from the "device" byte
- * order.  The device byte order is the endianness of the target
- * device -- for the ARM CPUs we use today, this is little endian.
- *
- * Note that the byte swapping functions have not been optimized
- * much; performance is currently not an issue for them since the
- * intent is to allow us to avoid byte swapping on the device.
- */
+/* TODO: move this cruft to frameworks/. */
 
-static inline uint32_t android_swap_long(uint32_t v)
-{
-    return (v<<24) | ((v<<8)&0x00FF0000) | ((v>>8)&0x0000FF00) | (v>>24);
-}
+#define dtohl(x) (x)
+#define dtohs(x) (x)
+#define htodl(x) (x)
+#define htods(x) (x)
 
-static inline uint16_t android_swap_short(uint16_t v)
-{
-    return (v<<8) | (v>>8);
-}
-
-#define DEVICE_BYTE_ORDER LITTLE_ENDIAN
-
-#if BYTE_ORDER == DEVICE_BYTE_ORDER
-
-#define	dtohl(x)	(x)
-#define	dtohs(x)	(x)
-#define	htodl(x)	(x)
-#define	htods(x)	(x)
-
-#else
-
-#define	dtohl(x)	(android_swap_long(x))
-#define	dtohs(x)	(android_swap_short(x))
-#define	htodl(x)	(android_swap_long(x))
-#define	htods(x)	(android_swap_short(x))
-
-#endif
-
-#if BYTE_ORDER == LITTLE_ENDIAN
 #define fromlel(x) (x)
-#define fromles(x) (x)
 #define tolel(x) (x)
-#define toles(x) (x)
-#else
-#define fromlel(x) (android_swap_long(x))
-#define fromles(x) (android_swap_short(x))
-#define tolel(x) (android_swap_long(x))
-#define toles(x) (android_swap_short(x))
-#endif
-
-#endif // _LIBS_UTILS_BYTE_ORDER_H
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index 4b9c91e..fec0ffa 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -17,7 +17,12 @@
 #ifndef ANDROID_TRACE_H
 #define ANDROID_TRACE_H
 
-#if defined(__ANDROID__)
+#if defined(_WIN32)
+
+#define ATRACE_NAME(...)
+#define ATRACE_CALL()
+
+#else  // !_WIN32
 
 #include <stdint.h>
 
@@ -51,11 +56,6 @@
 
 }  // namespace android
 
-#else // !__ANDROID__
-
-#define ATRACE_NAME(...)
-#define ATRACE_CALL()
-
-#endif // __ANDROID__
+#endif  // _WIN32
 
 #endif // ANDROID_TRACE_H
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 5a375ec..665bd38 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -160,7 +160,7 @@
     }
     auto search = denial_to_bug.find(scontext + tcontext + tclass);
     if (search != denial_to_bug.end()) {
-        bug_num->assign(" b/" + search->second);
+        bug_num->assign(" " + search->second);
     } else {
         bug_num->assign("");
     }
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
index 51c1226..aa02a3a 100644
--- a/property_service/libpropertyinfoserializer/Android.bp
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -1,7 +1,6 @@
 cc_defaults {
     name: "propertyinfoserializer_defaults",
     host_supported: true,
-    vendor_available: true,
     cpp_std: "experimental",
     cppflags: [
         "-Wall",
@@ -9,8 +8,8 @@
         "-Werror",
     ],
     static_libs: [
-        "libpropertyinfoparser",
         "libbase",
+        "libpropertyinfoparser",
     ],
 }
 
diff --git a/rootdir/avb/Android.bp b/rootdir/avb/Android.bp
new file mode 100644
index 0000000..85d2786
--- /dev/null
+++ b/rootdir/avb/Android.bp
@@ -0,0 +1,20 @@
+filegroup {
+    name: "q-gsi_avbpubkey",
+    srcs: [
+        "q-gsi.avbpubkey",
+    ],
+}
+
+filegroup {
+    name: "r-gsi_avbpubkey",
+    srcs: [
+        "r-gsi.avbpubkey",
+    ],
+}
+
+filegroup {
+    name: "s-gsi_avbpubkey",
+    srcs: [
+        "s-gsi.avbpubkey",
+    ],
+}
diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt
index e598f05..bb8d4d0 100644
--- a/rootdir/etc/ld.config.legacy.txt
+++ b/rootdir/etc/ld.config.legacy.txt
@@ -80,16 +80,14 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
@@ -181,6 +179,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index e1da587..60035aa 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -161,16 +161,14 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
@@ -422,6 +420,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
@@ -490,13 +489,11 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = system
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -645,6 +642,7 @@
 namespace.neuralnetworks.link.system.shared_libs += liblog.so
 namespace.neuralnetworks.link.system.shared_libs += libm.so
 namespace.neuralnetworks.link.system.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.system.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.system.shared_libs += libsync.so
 namespace.neuralnetworks.link.system.shared_libs += libvndksupport.so
 
@@ -697,16 +695,14 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -788,6 +784,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
index 4beabd6..b9b95a6 100644
--- a/rootdir/etc/ld.config.vndk_lite.txt
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -100,16 +100,14 @@
 # This namespace pulls in externally accessible libs from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # Need allow_all_shared_libs because libart.so can dlopen oat files in
 # /system/framework and /data.
@@ -346,6 +344,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
@@ -420,13 +419,11 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -449,6 +446,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
@@ -504,16 +502,14 @@
 # This namespace exposes externally accessible libraries from the Runtime APEX.
 # Keep in sync with the "runtime" namespace in art/build/apex/ld.config.txt.
 ###############################################################################
+# TODO(b/139408016): Rename this namespace to "art".
 namespace.runtime.isolated = true
 # Visible to allow links to be created at runtime, e.g. through
 # android_link_namespaces in libnativeloader.
 namespace.runtime.visible = true
 
-# TODO(b/139408016): Split the namespaces for the ART and Runtime APEXes
-namespace.runtime.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.search.paths += /apex/com.android.runtime/${LIB}
-namespace.runtime.asan.search.paths  = /apex/com.android.art/${LIB}
-namespace.runtime.asan.search.paths += /apex/com.android.runtime/${LIB}
+namespace.runtime.search.paths = /apex/com.android.art/${LIB}
+namespace.runtime.asan.search.paths = /apex/com.android.art/${LIB}
 namespace.runtime.links = default
 # TODO(b/130340935): Use a dynamically created linker namespace similar to
 # classloader-namespace for oat files, and tighten this up.
@@ -591,6 +587,7 @@
 namespace.neuralnetworks.link.default.shared_libs += liblog.so
 namespace.neuralnetworks.link.default.shared_libs += libm.so
 namespace.neuralnetworks.link.default.shared_libs += libnativewindow.so
+namespace.neuralnetworks.link.default.shared_libs += libneuralnetworks_packageinfo.so
 namespace.neuralnetworks.link.default.shared_libs += libsync.so
 namespace.neuralnetworks.link.default.shared_libs += libvndksupport.so
 
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 17f6596..50005d9 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -5,7 +5,7 @@
     export ANDROID_ASSETS /system/app
     export ANDROID_DATA /data
     export ANDROID_STORAGE /storage
-    export ANDROID_RUNTIME_ROOT /apex/com.android.art
+    export ANDROID_ART_ROOT /apex/com.android.art
     export ANDROID_I18N_ROOT /apex/com.android.i18n
     export ANDROID_TZDATA_ROOT /apex/com.android.tzdata
     export EXTERNAL_STORAGE /sdcard
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a15b501..0fa6efc 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -68,19 +68,19 @@
 
 service boringssl_self_test32 /system/bin/boringssl_self_test32
     setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
-    reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+    reboot_on_failure reboot,boringssl-self-check-failed
 
 service boringssl_self_test64 /system/bin/boringssl_self_test64
     setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
-    reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+    reboot_on_failure reboot,boringssl-self-check-failed
 
 service boringssl_self_test_apex32 /apex/com.android.conscrypt/bin/boringssl_self_test32
     setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
-    reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+    reboot_on_failure reboot,boringssl-self-check-failed
 
 service boringssl_self_test_apex64 /apex/com.android.conscrypt/bin/boringssl_self_test64
     setenv BORINGSSL_SELF_TEST_CREATE_FLAG true # Any nonempty value counts as true
-    reboot_on_failure reboot,bootloader,boringssl-self-check-failed
+    reboot_on_failure reboot,boringssl-self-check-failed
 
 on init
     sysclktz 0
@@ -154,6 +154,14 @@
     mkdir /mnt/user/0/self 0755 root root
     mkdir /mnt/user/0/emulated 0755 root root
     mkdir /mnt/user/0/emulated/0 0755 root root
+
+    # Prepare directories for pass through processes
+    mkdir /mnt/pass_through 0755 root root
+    mkdir /mnt/pass_through/0 0755 root root
+    mkdir /mnt/pass_through/0/self 0755 root root
+    mkdir /mnt/pass_through/0/emulated 0755 root root
+    mkdir /mnt/pass_through/0/emulated/0 0755 root root
+
     mkdir /mnt/expand 0771 system system
     mkdir /mnt/appfuse 0711 root root
 
@@ -678,6 +686,8 @@
   # Mount default storage into root namespace
   mount none /mnt/user/0 /storage bind rec
   mount none none /storage slave rec
+  # Bootstrap the emulated volume for the pass_through directory for user 0
+  mount none /data/media /mnt/pass_through/0/emulated bind rec
 on zygote-start && property:persist.sys.fuse=false
   # Mount default storage into root namespace
   mount none /mnt/runtime/default /storage bind rec
diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk
index 9d131dc..c4b8e4e 100644
--- a/rootdir/update_and_install_ld_config.mk
+++ b/rootdir/update_and_install_ld_config.mk
@@ -128,7 +128,7 @@
 deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \
   $(vndkprivate_libraries_file)
 ifeq ($(check_backward_compatibility),true)
-deps += $(compatibility_check_script)
+deps += $(compatibility_check_script) $(wildcard prebuilts/vndk/*/*/configs/ld.config.*.txt)
 endif
 ifeq ($(my_vndk_use_core_variant),true)
 $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_USING_CORE_VARIANT_LIBRARIES_FILE := $(vndk_using_core_variant_libraries_file)