Merge "Migrate gettid to GetThreadId" into main
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 30eb7b5..61c7204 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -76,6 +76,7 @@
 #include "constants.h"
 #include "diagnose_usb.h"
 #include "fastboot_driver.h"
+#include "fastboot_driver_interface.h"
 #include "fs.h"
 #include "storage.h"
 #include "super_flash_helper.h"
@@ -173,7 +174,7 @@
         // clang-format on
 };
 
-static char* get_android_product_out() {
+char* get_android_product_out() {
     char* dir = getenv("ANDROID_PRODUCT_OUT");
     if (dir == nullptr || dir[0] == '\0') {
         return nullptr;
@@ -996,7 +997,7 @@
     return resparse_file(s.get(), max_size);
 }
 
-static uint64_t get_uint_var(const char* var_name) {
+static uint64_t get_uint_var(const char* var_name, fastboot::IFastBootDriver* fb) {
     std::string value_str;
     if (fb->GetVar(var_name, &value_str) != fastboot::SUCCESS || value_str.empty()) {
         verbose("target didn't report %s", var_name);
@@ -1021,7 +1022,7 @@
         // Unlimited, so see what the target device's limit is.
         // TODO: shouldn't we apply this limit even if you've used -S?
         if (target_sparse_limit == -1) {
-            target_sparse_limit = static_cast<int64_t>(get_uint_var("max-download-size"));
+            target_sparse_limit = static_cast<int64_t>(get_uint_var("max-download-size", fp->fb));
         }
         if (target_sparse_limit > 0) {
             limit = target_sparse_limit;
@@ -1410,7 +1411,7 @@
     }
 }
 
-bool is_retrofit_device() {
+bool is_retrofit_device(fastboot::IFastBootDriver* fb) {
     std::string value;
     if (fb->GetVar("super-partition-name", &value) != fastboot::SUCCESS) {
         return false;
@@ -1420,8 +1421,9 @@
 
 // Fetch a partition from the device to a given fd. This is a wrapper over FetchToFd to fetch
 // the full image.
-static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd) {
-    uint64_t fetch_size = get_uint_var(FB_VAR_MAX_FETCH_SIZE);
+static uint64_t fetch_partition(const std::string& partition, borrowed_fd fd,
+                                fastboot::IFastBootDriver* fb) {
+    uint64_t fetch_size = get_uint_var(FB_VAR_MAX_FETCH_SIZE, fb);
     if (fetch_size == 0) {
         die("Unable to get %s. Device does not support fetch command.", FB_VAR_MAX_FETCH_SIZE);
     }
@@ -1443,17 +1445,18 @@
 }
 
 static void do_fetch(const std::string& partition, const std::string& slot_override,
-                     const std::string& outfile) {
+                     const std::string& outfile, fastboot::IFastBootDriver* fb) {
     unique_fd fd(TEMP_FAILURE_RETRY(
             open(outfile.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY, 0644)));
-    auto fetch = std::bind(fetch_partition, _1, borrowed_fd(fd));
+    auto fetch = std::bind(fetch_partition, _1, borrowed_fd(fd), fb);
     do_for_partitions(partition, slot_override, fetch, false /* force slot */);
 }
 
 // Return immediately if not flashing a vendor boot image. If flashing a vendor boot image,
 // repack vendor_boot image with an updated ramdisk. After execution, buf is set
 // to the new image to flash, and return value is the real partition name to flash.
-static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf) {
+static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf,
+                                  fastboot::IFastBootDriver* fb) {
     std::string_view pname_sv{pname};
 
     if (!android::base::StartsWith(pname_sv, "vendor_boot:") &&
@@ -1471,7 +1474,7 @@
     std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1));
 
     unique_fd vendor_boot(make_temporary_fd("vendor boot repack"));
-    uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot);
+    uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot, fb);
     auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd,
                                              static_cast<uint64_t>(buf->sz));
     if (!repack_res.ok()) {
@@ -1486,10 +1489,13 @@
 
 void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
               const FlashingPlan* fp) {
+    if (!fp) {
+        die("do flash was called without a valid flashing plan");
+    }
     verbose("Do flash %s %s", pname, fname);
     struct fastboot_buffer buf;
 
-    if (fp && fp->source) {
+    if (fp->source) {
         unique_fd fd = fp->source->OpenFile(fname);
         if (fd < 0 || !load_buf_fd(std::move(fd), &buf, fp)) {
             die("could not load '%s': %s", fname, strerror(errno));
@@ -1508,7 +1514,7 @@
     if (is_logical(pname)) {
         fb->ResizePartition(pname, std::to_string(buf.image_size));
     }
-    std::string flash_pname = repack_ramdisk(pname, &buf);
+    std::string flash_pname = repack_ramdisk(pname, &buf, fp->fb);
     flash_buf(flash_pname, &buf, apply_vbmeta);
 }
 
@@ -1747,7 +1753,7 @@
         }
         tasks.emplace_back(std::move(task));
     }
-    if (auto flash_super_task = FlashSuperLayoutTask::InitializeFromTasks(fp, tasks)) {
+    if (auto flash_super_task = OptimizedFlashSuperTask::InitializeFromTasks(fp, tasks)) {
         auto it = tasks.begin();
         for (size_t i = 0; i < tasks.size(); i++) {
             if (auto flash_task = tasks[i]->AsFlashTask()) {
@@ -1787,13 +1793,25 @@
 
     CancelSnapshotIfNeeded();
 
-    tasks_ = CollectTasksFromImageList();
+    tasks_ = CollectTasks();
     for (auto& task : tasks_) {
         task->Run();
     }
     return;
 }
 
+std::vector<std::unique_ptr<Task>> FlashAllTool::CollectTasks() {
+    std::vector<std::unique_ptr<Task>> tasks;
+    if (fp_->should_use_fastboot_info) {
+        tasks = CollectTasksFromFastbootInfo();
+
+    } else {
+        tasks = CollectTasksFromImageList();
+    }
+
+    return tasks;
+}
+
 void FlashAllTool::CheckRequirements() {
     std::vector<char> contents;
     if (!fp_->source->ReadFile("android-info.txt", &contents)) {
@@ -1848,8 +1866,7 @@
     // or in bootloader fastboot.
     std::vector<std::unique_ptr<Task>> tasks;
     AddFlashTasks(boot_images_, tasks);
-
-    if (auto flash_super_task = FlashSuperLayoutTask::Initialize(fp_, os_images_)) {
+    if (auto flash_super_task = OptimizedFlashSuperTask::Initialize(fp_, os_images_)) {
         tasks.emplace_back(std::move(flash_super_task));
     } else {
         // Sync the super partition. This will reboot to userspace fastboot if needed.
@@ -1861,7 +1878,7 @@
             // On these devices, secondary slots must be flashed as physical
             // partitions (otherwise they would not mount on first boot). To enforce
             // this, we delete any logical partitions for the "other" slot.
-            if (is_retrofit_device()) {
+            if (is_retrofit_device(fp_->fb)) {
                 std::string partition_name = image->part_name + "_"s + slot;
                 if (image->IsSecondary() && should_flash_in_userspace(partition_name)) {
                     fp_->fb->DeletePartition(partition_name);
@@ -1871,10 +1888,23 @@
             tasks.emplace_back(std::make_unique<ResizeTask>(fp_, image->part_name, "0", slot));
         }
     }
+
     AddFlashTasks(os_images_, tasks);
     return tasks;
 }
 
+std::vector<std::unique_ptr<Task>> FlashAllTool::CollectTasksFromFastbootInfo() {
+    std::vector<std::unique_ptr<Task>> tasks;
+    std::vector<char> contents;
+    if (!fp_->source->ReadFile("fastboot-info.txt", &contents)) {
+        LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not "
+                        "exist";
+        return CollectTasksFromImageList();
+    }
+    tasks = ParseFastbootInfo(fp_, Split({contents.data(), contents.size()}, "\n"));
+    return tasks;
+}
+
 void FlashAllTool::AddFlashTasks(const std::vector<std::pair<const Image*, std::string>>& images,
                                  std::vector<std::unique_ptr<Task>>& tasks) {
     for (const auto& [image, slot] : images) {
@@ -2183,6 +2213,7 @@
                                       {"disable-verification", no_argument, 0, 0},
                                       {"disable-verity", no_argument, 0, 0},
                                       {"disable-super-optimization", no_argument, 0, 0},
+                                      {"disable-fastboot-info", no_argument, 0, 0},
                                       {"force", no_argument, 0, 0},
                                       {"fs-options", required_argument, 0, 0},
                                       {"header-version", required_argument, 0, 0},
@@ -2205,8 +2236,9 @@
                                       {0, 0, 0, 0}};
 
     serial = getenv("FASTBOOT_DEVICE");
-    if (!serial)
+    if (!serial) {
         serial = getenv("ANDROID_SERIAL");
+    }
 
     int c;
     while ((c = getopt_long(argc, argv, "a::hls:S:vw", longopts, &longindex)) != -1) {
@@ -2222,6 +2254,8 @@
                 g_disable_verity = true;
             } else if (name == "disable-super-optimization") {
                 fp->should_optimize_flash_super = false;
+            } else if (name == "disable-fastboot-info") {
+                fp->should_use_fastboot_info = false;
             } else if (name == "force") {
                 fp->force_flash = true;
             } else if (name == "fs-options") {
@@ -2551,7 +2585,7 @@
         } else if (command == FB_CMD_FETCH) {
             std::string partition = next_arg(&args);
             std::string outfile = next_arg(&args);
-            do_fetch(partition, fp->slot_override, outfile);
+            do_fetch(partition, fp->slot_override, outfile, fp->fb);
         } else {
             syntax_error("unknown command %s", command.c_str());
         }
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 196bd67..f6ffb64 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -97,6 +97,7 @@
     bool skip_secondary = false;
     bool force_flash = false;
     bool should_optimize_flash_super = true;
+    bool should_use_fastboot_info = true;
     uint64_t sparse_limit = 0;
 
     std::string slot_override;
@@ -111,6 +112,7 @@
     FlashAllTool(FlashingPlan* fp);
 
     void Flash();
+    std::vector<std::unique_ptr<Task>> CollectTasks();
 
   private:
     void CheckRequirements();
@@ -118,6 +120,8 @@
     void CollectImages();
     void AddFlashTasks(const std::vector<std::pair<const Image*, std::string>>& images,
                        std::vector<std::unique_ptr<Task>>& tasks);
+
+    std::vector<std::unique_ptr<Task>> CollectTasksFromFastbootInfo();
     std::vector<std::unique_ptr<Task>> CollectTasksFromImageList();
 
     std::vector<ImageEntry> boot_images_;
@@ -143,6 +147,7 @@
     unique_fd OpenFile(const std::string& name) const override;
 };
 
+char* get_android_product_out();
 bool should_flash_in_userspace(const std::string& partition_name);
 bool is_userspace_fastboot();
 void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
@@ -182,7 +187,7 @@
 int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp);
 std::vector<SparsePtr> resparse_file(sparse_file* s, int64_t max_size);
 
-bool is_retrofit_device();
+bool is_retrofit_device(fastboot::IFastBootDriver* fb);
 bool is_logical(const std::string& partition);
 void fb_perform_format(const std::string& partition, int skip_if_not_supported,
                        const std::string& type_override, const std::string& size_override,
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index 6ac26ce..8774ead 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -105,7 +105,7 @@
                                   std::vector<std::string>* info = nullptr);
     RetCode FetchToFd(const std::string& partition, android::base::borrowed_fd fd,
                       int64_t offset = -1, int64_t size = -1, std::string* response = nullptr,
-                      std::vector<std::string>* info = nullptr);
+                      std::vector<std::string>* info = nullptr) override;
 
     /* HIGHER LEVEL COMMANDS -- Composed of the commands above */
     RetCode FlashPartition(const std::string& partition, const std::vector<char>& data);
diff --git a/fastboot/fastboot_driver_interface.h b/fastboot/fastboot_driver_interface.h
index 795938f..7cb8a6b 100644
--- a/fastboot/fastboot_driver_interface.h
+++ b/fastboot/fastboot_driver_interface.h
@@ -45,6 +45,10 @@
                              std::vector<std::string>* info = nullptr) = 0;
     RetCode virtual GetVar(const std::string& key, std::string* val,
                            std::vector<std::string>* info = nullptr) = 0;
+    RetCode virtual FetchToFd(const std::string& partition, android::base::borrowed_fd fd,
+                              int64_t offset = -1, int64_t size = -1,
+                              std::string* response = nullptr,
+                              std::vector<std::string>* info = nullptr) = 0;
     RetCode virtual Download(const std::string& name, android::base::borrowed_fd fd, size_t size,
                              std::string* response = nullptr,
                              std::vector<std::string>* info = nullptr) = 0;
diff --git a/fastboot/fastboot_driver_mock.h b/fastboot/fastboot_driver_mock.h
index d2a123b..7c41d78 100644
--- a/fastboot/fastboot_driver_mock.h
+++ b/fastboot/fastboot_driver_mock.h
@@ -28,15 +28,16 @@
     MOCK_METHOD(RetCode, Reboot, (std::string*, std::vector<std::string>*), (override));
     MOCK_METHOD(RetCode, RebootTo, (std::string, std::string*, std::vector<std::string>*),
                 (override));
-
     MOCK_METHOD(RetCode, GetVar, (const std::string&, std::string*, std::vector<std::string>*),
                 (override));
-
+    MOCK_METHOD(RetCode, FetchToFd,
+                (const std::string&, android::base::borrowed_fd, int64_t offset, int64_t size,
+                 std::string*, std::vector<std::string>*),
+                (override));
     MOCK_METHOD(RetCode, Download,
                 (const std::string&, android::base::borrowed_fd, size_t, std::string*,
                  std::vector<std::string>*),
                 (override));
-
     MOCK_METHOD(RetCode, RawCommand,
                 (const std::string&, const std::string&, std::string*, std::vector<std::string>*,
                  int*),
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index c1b9a31..bf64f0e 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -96,17 +96,17 @@
     return "reboot " + reboot_target_;
 }
 
-FlashSuperLayoutTask::FlashSuperLayoutTask(const std::string& super_name,
-                                           std::unique_ptr<SuperFlashHelper> helper,
-                                           SparsePtr sparse_layout, uint64_t super_size,
-                                           const FlashingPlan* fp)
+OptimizedFlashSuperTask::OptimizedFlashSuperTask(const std::string& super_name,
+                                                 std::unique_ptr<SuperFlashHelper> helper,
+                                                 SparsePtr sparse_layout, uint64_t super_size,
+                                                 const FlashingPlan* fp)
     : super_name_(super_name),
       helper_(std::move(helper)),
       sparse_layout_(std::move(sparse_layout)),
       super_size_(super_size),
       fp_(fp) {}
 
-void FlashSuperLayoutTask::Run() {
+void OptimizedFlashSuperTask::Run() {
     // Use the reported super partition size as the upper limit, rather than
     // sparse_file_len, which (1) can fail and (2) is kind of expensive, since
     // it will map in all of the embedded fds.
@@ -120,11 +120,11 @@
     // Send the data to the device.
     flash_partition_files(super_name_, files);
 }
-std::string FlashSuperLayoutTask::ToString() {
+std::string OptimizedFlashSuperTask::ToString() {
     return "optimized-flash-super";
 }
 
-std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::Initialize(
+std::unique_ptr<OptimizedFlashSuperTask> OptimizedFlashSuperTask::Initialize(
         const FlashingPlan* fp, std::vector<ImageEntry>& os_images) {
     if (!fp->should_optimize_flash_super) {
         LOG(INFO) << "super optimization is disabled";
@@ -188,11 +188,11 @@
     };
     os_images.erase(std::remove_if(os_images.begin(), os_images.end(), remove_if_callback),
                     os_images.end());
-    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s),
-                                                  partition_size, fp);
+    return std::make_unique<OptimizedFlashSuperTask>(super_name, std::move(helper), std::move(s),
+                                                     partition_size, fp);
 }
 
-std::unique_ptr<FlashSuperLayoutTask> FlashSuperLayoutTask::InitializeFromTasks(
+std::unique_ptr<OptimizedFlashSuperTask> OptimizedFlashSuperTask::InitializeFromTasks(
         const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks) {
     if (!fp->should_optimize_flash_super) {
         LOG(INFO) << "super optimization is disabled";
@@ -261,8 +261,8 @@
     };
     tasks.erase(std::remove_if(tasks.begin(), tasks.end(), remove_if_callback), tasks.end());
 
-    return std::make_unique<FlashSuperLayoutTask>(super_name, std::move(helper), std::move(s),
-                                                  partition_size, fp);
+    return std::make_unique<OptimizedFlashSuperTask>(super_name, std::move(helper), std::move(s),
+                                                     partition_size, fp);
 }
 
 UpdateSuperTask::UpdateSuperTask(const FlashingPlan* fp) : fp_(fp) {}
diff --git a/fastboot/task.h b/fastboot/task.h
index 858f43a..f7c8801 100644
--- a/fastboot/task.h
+++ b/fastboot/task.h
@@ -79,13 +79,13 @@
     const FlashingPlan* fp_;
 };
 
-class FlashSuperLayoutTask : public Task {
+class OptimizedFlashSuperTask : public Task {
   public:
-    FlashSuperLayoutTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
-                         SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp);
-    static std::unique_ptr<FlashSuperLayoutTask> Initialize(const FlashingPlan* fp,
-                                                            std::vector<ImageEntry>& os_images);
-    static std::unique_ptr<FlashSuperLayoutTask> InitializeFromTasks(
+    OptimizedFlashSuperTask(const std::string& super_name, std::unique_ptr<SuperFlashHelper> helper,
+                            SparsePtr sparse_layout, uint64_t super_size, const FlashingPlan* fp);
+    static std::unique_ptr<OptimizedFlashSuperTask> Initialize(const FlashingPlan* fp,
+                                                               std::vector<ImageEntry>& os_images);
+    static std::unique_ptr<OptimizedFlashSuperTask> InitializeFromTasks(
             const FlashingPlan* fp, std::vector<std::unique_ptr<Task>>& tasks);
     using ImageEntry = std::pair<const Image*, std::string>;
     void Run() override;
diff --git a/fastboot/task_test.cpp b/fastboot/task_test.cpp
index b4e139b..1ba3f4a 100644
--- a/fastboot/task_test.cpp
+++ b/fastboot/task_test.cpp
@@ -24,6 +24,7 @@
 #include <memory>
 #include <unordered_map>
 #include "android-base/strings.h"
+
 using android::base::Split;
 using testing::_;
 
@@ -60,6 +61,33 @@
     return ParseFastbootInfoLine(fp, vec_command);
 }
 
+// tests if tasks_a is a superset of tasks_b. Used for checking to ensure all partitions flashed
+// from hardcoded image list is also flashed in new fastboot-info.txt
+static bool compareTaskList(std::vector<std::unique_ptr<Task>>& tasks_a,
+                            std::vector<std::unique_ptr<Task>>& tasks_b) {
+    std::set<std::string> list;
+    for (auto& task : tasks_a) {
+        list.insert(task->ToString());
+    }
+    for (auto& task : tasks_b) {
+        if (list.find(task->ToString()) == list.end()) {
+            std::cout << "ERROR: " << task->ToString()
+                      << " not found in task list created by fastboot-info.txt";
+            return false;
+        }
+    }
+    return true;
+}
+
+static std::string tasksToString(std::vector<std::unique_ptr<Task>>& tasks) {
+    std::string output;
+    for (auto& task : tasks) {
+        output.append(task->ToString());
+        output.append("\n");
+    }
+    return output;
+}
+
 TEST_F(ParseTest, CorrectFlashTaskFormed) {
     std::vector<std::string> commands = {"flash dtbo", "flash --slot-other system system_other.img",
                                          "flash system", "flash --apply-vbmeta vbmeta"};
@@ -159,3 +187,51 @@
         task->Run();
     }
 }
+
+TEST_F(ParseTest, CorrectTaskLists) {
+    if (!get_android_product_out()) {
+        GTEST_SKIP();
+    }
+
+    LocalImageSource s;
+    fp->source = &s;
+    fp->sparse_limit = std::numeric_limits<int64_t>::max();
+
+    fastboot::MockFastbootDriver fb;
+    fp->fb = &fb;
+    fp->should_optimize_flash_super = false;
+
+    ON_CALL(fb, GetVar("super-partition-name", _, _))
+            .WillByDefault(testing::Return(fastboot::BAD_ARG));
+
+    FlashAllTool tool(fp.get());
+
+    fp->should_use_fastboot_info = false;
+    auto hardcoded_tasks = tool.CollectTasks();
+    fp->should_use_fastboot_info = true;
+    auto fastboot_info_tasks = tool.CollectTasks();
+
+    auto is_non_flash_task = [](const auto& task) -> bool {
+        return task->AsFlashTask() == nullptr;
+    };
+
+    // remove non flash tasks for testing purposes
+    hardcoded_tasks.erase(
+            std::remove_if(hardcoded_tasks.begin(), hardcoded_tasks.end(), is_non_flash_task),
+            hardcoded_tasks.end());
+    fastboot_info_tasks.erase(std::remove_if(fastboot_info_tasks.begin(), fastboot_info_tasks.end(),
+                                             is_non_flash_task),
+                              fastboot_info_tasks.end());
+
+    if (!compareTaskList(fastboot_info_tasks, hardcoded_tasks)) {
+        std::cout << "\n\n---Hardcoded Task List---\n"
+                  << tasksToString(hardcoded_tasks) << "\n---Fastboot-Info Task List---\n"
+                  << tasksToString(fastboot_info_tasks);
+    }
+
+    ASSERT_TRUE(compareTaskList(fastboot_info_tasks, hardcoded_tasks));
+
+    ASSERT_TRUE(fastboot_info_tasks.size() >= hardcoded_tasks.size())
+            << "size of fastboot-info task list: " << fastboot_info_tasks.size()
+            << " size of hardcoded task list: " << hardcoded_tasks.size();
+}
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index c16ad24..c984a61 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -119,8 +119,7 @@
     }
 
     // Functions interacting with dm-user
-    bool ReadDmUserHeader();
-    bool WriteDmUserPayload(size_t size, bool header_response);
+    bool WriteDmUserPayload(size_t size);
     bool DmuserReadRequest();
 
     // IO Path
@@ -130,11 +129,11 @@
     bool ReadDataFromBaseDevice(sector_t sector, size_t read_size);
     bool ReadFromSourceDevice(const CowOperation* cow_op);
 
-    bool ReadAlignedSector(sector_t sector, size_t sz, bool header_response);
+    bool ReadAlignedSector(sector_t sector, size_t sz);
     bool ReadUnalignedSector(sector_t sector, size_t size);
     int ReadUnalignedSector(sector_t sector, size_t size,
                             std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it);
-    bool RespondIOError(bool header_response);
+    void RespondIOError();
 
     // Processing COW operations
     bool ProcessCowOp(const CowOperation* cow_op);
@@ -176,6 +175,7 @@
     unique_fd backing_store_fd_;
     unique_fd base_path_merge_fd_;
     unique_fd ctrl_fd_;
+    bool header_response_ = false;
 
     std::unique_ptr<ICowOpIter> cowop_iter_;
     size_t ra_block_index_ = 0;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
index 44b7319..1b17698 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
@@ -290,26 +290,11 @@
     return true;
 }
 
-// Read Header from dm-user misc device. This gives
-// us the sector number for which IO is issued by dm-snapshot device
-bool Worker::ReadDmUserHeader() {
-    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
-        if (errno != ENOTBLK) {
-            SNAP_PLOG(ERROR) << "Control-read failed";
-        }
-
-        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
-        return false;
-    }
-
-    return true;
-}
-
 // Send the payload/data back to dm-user misc device.
-bool Worker::WriteDmUserPayload(size_t size, bool header_response) {
+bool Worker::WriteDmUserPayload(size_t size) {
     size_t payload_size = size;
     void* buf = bufsink_.GetPayloadBufPtr();
-    if (header_response) {
+    if (header_response_) {
         payload_size += sizeof(struct dm_user_header);
         buf = bufsink_.GetBufPtr();
     }
@@ -319,6 +304,9 @@
         return false;
     }
 
+    // After the first header is sent in response to a request, we cannot
+    // send any additional headers.
+    header_response_ = false;
     return true;
 }
 
@@ -341,20 +329,16 @@
     return true;
 }
 
-bool Worker::ReadAlignedSector(sector_t sector, size_t sz, bool header_response) {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
+bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
     size_t remaining_size = sz;
     std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-    bool io_error = false;
     int ret = 0;
 
     do {
         // Process 1MB payload at a time
         size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size);
 
-        header->type = DM_USER_RESP_SUCCESS;
         size_t total_bytes_read = 0;
-        io_error = false;
         bufsink_.ResetBufferOffset();
 
         while (read_size) {
@@ -372,7 +356,7 @@
                 // device.
                 if (!ReadDataFromBaseDevice(sector, size)) {
                     SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed";
-                    header->type = DM_USER_RESP_ERROR;
+                    return false;
                 }
 
                 ret = size;
@@ -381,20 +365,10 @@
                 // process it.
                 if (!ProcessCowOp(it->second)) {
                     SNAP_LOG(ERROR) << "ProcessCowOp failed";
-                    header->type = DM_USER_RESP_ERROR;
-                }
-
-                ret = BLOCK_SZ;
-            }
-
-            // Just return the header if it is an error
-            if (header->type == DM_USER_RESP_ERROR) {
-                if (!RespondIOError(header_response)) {
                     return false;
                 }
 
-                io_error = true;
-                break;
+                ret = BLOCK_SZ;
             }
 
             read_size -= ret;
@@ -403,18 +377,14 @@
             bufsink_.UpdateBufferOffset(ret);
         }
 
-        if (!io_error) {
-            if (!WriteDmUserPayload(total_bytes_read, header_response)) {
-                return false;
-            }
-
-            SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read
-                            << " header-response: " << header_response
-                            << " remaining_size: " << remaining_size;
-            header_response = false;
-            remaining_size -= total_bytes_read;
+        if (!WriteDmUserPayload(total_bytes_read)) {
+            return false;
         }
-    } while (remaining_size > 0 && !io_error);
+
+        SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read
+                        << " remaining_size: " << remaining_size;
+        remaining_size -= total_bytes_read;
+    } while (remaining_size > 0);
 
     return true;
 }
@@ -455,8 +425,6 @@
 }
 
 bool Worker::ReadUnalignedSector(sector_t sector, size_t size) {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
-    header->type = DM_USER_RESP_SUCCESS;
     bufsink_.ResetBufferOffset();
     std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
 
@@ -484,7 +452,6 @@
     // to any COW ops. In that case, we just need to read from the base
     // device.
     bool merge_complete = false;
-    bool header_response = true;
     if (it == chunk_vec.end()) {
         if (chunk_vec.size() > 0) {
             // I/O request beyond the last mapped sector
@@ -503,7 +470,7 @@
             --it;
         }
     } else {
-        return ReadAlignedSector(sector, size, header_response);
+        return ReadAlignedSector(sector, size);
     }
 
     loff_t requested_offset = sector << SECTOR_SHIFT;
@@ -537,7 +504,7 @@
         if (ret < 0) {
             SNAP_LOG(ERROR) << "ReadUnalignedSector failed for sector: " << sector
                             << " size: " << size << " it->sector: " << it->first;
-            return RespondIOError(header_response);
+            return false;
         }
 
         remaining_size -= ret;
@@ -545,14 +512,13 @@
         sector += (ret >> SECTOR_SHIFT);
 
         // Send the data back
-        if (!WriteDmUserPayload(total_bytes_read, header_response)) {
+        if (!WriteDmUserPayload(total_bytes_read)) {
             return false;
         }
 
-        header_response = false;
         // If we still have pending data to be processed, this will be aligned I/O
         if (remaining_size) {
-            return ReadAlignedSector(sector, remaining_size, header_response);
+            return ReadAlignedSector(sector, remaining_size);
         }
     } else {
         // This is all about handling I/O request to be routed to base device
@@ -566,21 +532,21 @@
         CHECK(diff_size <= BLOCK_SZ);
         if (remaining_size < diff_size) {
             if (!ReadDataFromBaseDevice(sector, remaining_size)) {
-                return RespondIOError(header_response);
+                return false;
             }
             total_bytes_read += remaining_size;
 
-            if (!WriteDmUserPayload(total_bytes_read, header_response)) {
+            if (!WriteDmUserPayload(total_bytes_read)) {
                 return false;
             }
         } else {
             if (!ReadDataFromBaseDevice(sector, diff_size)) {
-                return RespondIOError(header_response);
+                return false;
             }
 
             total_bytes_read += diff_size;
 
-            if (!WriteDmUserPayload(total_bytes_read, header_response)) {
+            if (!WriteDmUserPayload(total_bytes_read)) {
                 return false;
             }
 
@@ -588,17 +554,16 @@
             size_t num_sectors_read = (diff_size >> SECTOR_SHIFT);
             sector += num_sectors_read;
             CHECK(IsBlockAligned(sector << SECTOR_SHIFT));
-            header_response = false;
 
             // If we still have pending data to be processed, this will be aligned I/O
-            return ReadAlignedSector(sector, remaining_size, header_response);
+            return ReadAlignedSector(sector, remaining_size);
         }
     }
 
     return true;
 }
 
-bool Worker::RespondIOError(bool header_response) {
+void Worker::RespondIOError() {
     struct dm_user_header* header = bufsink_.GetHeaderPtr();
     header->type = DM_USER_RESP_ERROR;
     // This is an issue with the dm-user interface. There
@@ -610,15 +575,9 @@
     // this back to dm-user.
     //
     // TODO: Fix the interface
-    CHECK(header_response);
+    CHECK(header_response_);
 
-    if (!WriteDmUserPayload(0, header_response)) {
-        return false;
-    }
-
-    // There is no need to process further as we have already seen
-    // an I/O error
-    return true;
+    WriteDmUserPayload(0);
 }
 
 bool Worker::DmuserReadRequest() {
@@ -626,16 +585,22 @@
 
     // Unaligned I/O request
     if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) {
-        return ReadUnalignedSector(header->sector, header->len);
+        return ReadUnalignedSector(header->sector, header->len) != -1;
     }
 
-    return ReadAlignedSector(header->sector, header->len, true);
+    return ReadAlignedSector(header->sector, header->len);
 }
 
 bool Worker::ProcessIORequest() {
+    // Read Header from dm-user misc device. This gives
+    // us the sector number for which IO is issued by dm-snapshot device
     struct dm_user_header* header = bufsink_.GetHeaderPtr();
+    if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
+        if (errno != ENOTBLK) {
+            SNAP_PLOG(ERROR) << "Control-read failed";
+        }
 
-    if (!ReadDmUserHeader()) {
+        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
         return false;
     }
 
@@ -645,24 +610,34 @@
     SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
     SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
 
-    switch (header->type) {
-        case DM_USER_REQ_MAP_READ: {
-            if (!DmuserReadRequest()) {
-                return false;
-            }
-            break;
-        }
+    // Use the same header buffer as the response header.
+    int request_type = header->type;
+    header->type = DM_USER_RESP_SUCCESS;
+    header_response_ = true;
 
-        case DM_USER_REQ_MAP_WRITE: {
+    bool ok;
+    switch (request_type) {
+        case DM_USER_REQ_MAP_READ:
+            ok = DmuserReadRequest();
+            break;
+
+        case DM_USER_REQ_MAP_WRITE:
             // TODO: We should not get any write request
             // to dm-user as we mount all partitions
             // as read-only. Need to verify how are TRIM commands
             // handled during mount.
-            return false;
-        }
+            ok = false;
+            break;
+
+        default:
+            ok = false;
+            break;
     }
 
-    return true;
+    if (!ok && header->type != DM_USER_RESP_ERROR) {
+        RespondIOError();
+    }
+    return ok;
 }
 
 }  // namespace snapshot
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 585eca2..2176233 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -577,7 +577,7 @@
  *
  * return code is processed based on input code
  */
-static Result<void> queue_fs_event(int code, bool userdata_remount) {
+static Result<void> queue_fs_event(int code) {
     if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
         SetProperty("ro.crypto.state", "unsupported");
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
@@ -591,27 +591,9 @@
         const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
         return reboot_into_recovery(options);
         /* If reboot worked, there is no return. */
-    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
-        if (!FscryptInstallKeyring()) {
-            return Error() << "FscryptInstallKeyring() failed";
-        }
-        SetProperty("ro.crypto.state", "encrypted");
-
-        // Although encrypted, we have device key, so we do not need to
-        // do anything different from the nonencrypted case.
-        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
-        return {};
-    } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
-        if (!FscryptInstallKeyring()) {
-            return Error() << "FscryptInstallKeyring() failed";
-        }
-        SetProperty("ro.crypto.state", "encrypted");
-
-        // Although encrypted, vold has already set the device up, so we do not need to
-        // do anything different from the nonencrypted case.
-        ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
-        return {};
-    } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+    } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED ||
+               code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED ||
+               code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
         if (!FscryptInstallKeyring()) {
             return Error() << "FscryptInstallKeyring() failed";
         }
@@ -683,7 +665,7 @@
     if (queue_event) {
         /* queue_fs_event will queue event based on mount_fstab return code
          * and return processed return code*/
-        auto queue_fs_result = queue_fs_event(mount_fstab_result.code, false);
+        auto queue_fs_result = queue_fs_event(mount_fstab_result.code);
         if (!queue_fs_result.ok()) {
             return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
         }
@@ -1217,7 +1199,7 @@
                                          "/metadata/userspacereboot/mount_info.txt");
         trigger_shutdown("reboot,mount_userdata_failed");
     }
-    if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result.ok()) {
+    if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result.ok()) {
         return Error() << "queue_fs_event() failed: " << result.error();
     }
     return {};
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index bff80c5..7fabbac 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -257,6 +257,16 @@
     return BootMode::NORMAL_MODE;
 }
 
+static std::unique_ptr<FirstStageMount> CreateFirstStageMount(const std::string& cmdline) {
+    auto ret = FirstStageMount::Create(cmdline);
+    if (ret.ok()) {
+        return std::move(*ret);
+    } else {
+        LOG(ERROR) << "Failed to create FirstStageMount : " << ret.error();
+        return nullptr;
+    }
+}
+
 int FirstStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -347,6 +357,18 @@
 
     LOG(INFO) << "init first stage started!";
 
+    // We only allow /vendor partition in debuggable Microdrod until it is verified during boot.
+    // TODO(b/285855436): remove this check.
+    if (IsMicrodroid()) {
+        bool mount_vendor =
+                cmdline.find("androidboot.microdroid.mount_vendor=1") != std::string::npos;
+        bool debuggable =
+                bootconfig.find("androidboot.microdroid.debuggable = \"1\"") != std::string::npos;
+        if (mount_vendor && !debuggable) {
+            LOG(FATAL) << "Attempted to mount /vendor partition for non-debuggable Microdroid VM";
+        }
+    }
+
     auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir};
     if (!old_root_dir) {
         PLOG(ERROR) << "Could not opendir(\"/\"), not freeing ramdisk";
@@ -381,12 +403,17 @@
                   << module_elapse_time.count() << " ms";
     }
 
+    std::unique_ptr<FirstStageMount> fsm;
+
     bool created_devices = false;
     if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
         if (!IsRecoveryMode()) {
-            created_devices = DoCreateDevices();
-            if (!created_devices) {
-                LOG(ERROR) << "Failed to create device nodes early";
+            fsm = CreateFirstStageMount(cmdline);
+            if (fsm) {
+                created_devices = fsm->DoCreateDevices();
+                if (!created_devices) {
+                    LOG(ERROR) << "Failed to create device nodes early";
+                }
             }
         }
         StartConsole(cmdline);
@@ -437,8 +464,23 @@
         SwitchRoot("/first_stage_ramdisk");
     }
 
-    if (!DoFirstStageMount(!created_devices)) {
-        LOG(FATAL) << "Failed to mount required partitions early ...";
+    if (IsRecoveryMode()) {
+        LOG(INFO) << "First stage mount skipped (recovery mode)";
+    } else {
+        if (!fsm) {
+            fsm = CreateFirstStageMount(cmdline);
+        }
+        if (!fsm) {
+            LOG(FATAL) << "FirstStageMount not available";
+        }
+
+        if (!created_devices && !fsm->DoCreateDevices()) {
+            LOG(FATAL) << "Failed to create devices required for first stage mount";
+        }
+
+        if (!fsm->DoFirstStageMount()) {
+            LOG(FATAL) << "Failed to mount required partitions early ...";
+        }
     }
 
     struct stat new_root_info;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 07ce458..d0f68a8 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -76,21 +76,21 @@
 
 // Class Declarations
 // ------------------
-class FirstStageMount {
+class FirstStageMountVBootV2 : public FirstStageMount {
   public:
-    FirstStageMount(Fstab fstab);
-    virtual ~FirstStageMount() = default;
+    friend void SetInitAvbVersionInRecovery();
 
-    // The factory method to create a FirstStageMountVBootV2 instance.
-    static Result<std::unique_ptr<FirstStageMount>> Create();
-    bool DoCreateDevices();    // Creates devices and logical partitions from storage devices
-    bool DoFirstStageMount();  // Mounts fstab entries read from device tree.
+    FirstStageMountVBootV2(Fstab fstab);
+    virtual ~FirstStageMountVBootV2() = default;
+
+    bool DoCreateDevices() override;
+    bool DoFirstStageMount() override;
+
+  private:
     bool InitDevices();
-
-  protected:
     bool InitRequiredDevices(std::set<std::string> devices);
     bool CreateLogicalPartitions();
-    bool CreateSnapshotPartitions(android::snapshot::SnapshotManager* sm);
+    bool CreateSnapshotPartitions(SnapshotManager* sm);
     bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
                         Fstab::iterator* end = nullptr);
 
@@ -106,9 +106,10 @@
     // revocation check by DSU installation service.
     void CopyDsuAvbKeys();
 
-    // Pure virtual functions.
-    virtual bool GetDmVerityDevices(std::set<std::string>* devices) = 0;
-    virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
+    bool GetDmVerityDevices(std::set<std::string>* devices);
+    bool SetUpDmVerity(FstabEntry* fstab_entry);
+
+    bool InitAvbHandle();
 
     bool need_dm_verity_;
     bool dsu_not_on_userdata_ = false;
@@ -122,19 +123,6 @@
     // Reads all AVB keys before chroot into /system, as they might be used
     // later when mounting other partitions, e.g., /vendor and /product.
     std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
-};
-
-class FirstStageMountVBootV2 : public FirstStageMount {
-  public:
-    friend void SetInitAvbVersionInRecovery();
-
-    FirstStageMountVBootV2(Fstab fstab);
-    ~FirstStageMountVBootV2() override = default;
-
-  protected:
-    bool GetDmVerityDevices(std::set<std::string>* devices) override;
-    bool SetUpDmVerity(FstabEntry* fstab_entry) override;
-    bool InitAvbHandle();
 
     std::vector<std::string> vbmeta_partitions_;
     AvbUniquePtr avb_handle_;
@@ -150,7 +138,7 @@
     return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
 }
 
-static Result<Fstab> ReadFirstStageFstab() {
+static Result<Fstab> ReadFirstStageFstabAndroid() {
     Fstab fstab;
     if (!ReadFstabFromDt(&fstab)) {
         if (ReadDefaultFstab(&fstab)) {
@@ -166,6 +154,24 @@
     return fstab;
 }
 
+// Note: this is a temporary solution to avoid blocking devs that depend on /vendor partition in
+// Microdroid. For the proper solution the /vendor fstab should probably be defined in the DT.
+// TODO(b/285855430): refactor this
+// TODO(b/285855436): verify key microdroid-vendor was signed with.
+// TODO(b/285855436): should be mounted on top of dm-verity device.
+static Result<Fstab> ReadFirstStageFstabMicrodroid(const std::string& cmdline) {
+    Fstab fstab;
+    if (!ReadDefaultFstab(&fstab)) {
+        return Error() << "failed to read fstab";
+    }
+    if (cmdline.find("androidboot.microdroid.mount_vendor=1") == std::string::npos) {
+        // We weren't asked to mount /vendor partition, filter it out from the fstab.
+        auto predicate = [](const auto& entry) { return entry.mount_point == "/vendor"; };
+        fstab.erase(std::remove_if(fstab.begin(), fstab.end(), predicate), fstab.end());
+    }
+    return fstab;
+}
+
 static bool GetRootEntry(FstabEntry* root_entry) {
     Fstab proc_mounts;
     if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
@@ -218,14 +224,13 @@
     return rollbacked;
 }
 
-// Class Definitions
-// -----------------
-FirstStageMount::FirstStageMount(Fstab fstab) : need_dm_verity_(false), fstab_(std::move(fstab)) {
-    super_partition_name_ = fs_mgr_get_super_partition_name();
-}
-
-Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
-    auto fstab = ReadFirstStageFstab();
+Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create(const std::string& cmdline) {
+    Result<Fstab> fstab;
+    if (IsMicrodroid()) {
+        fstab = ReadFirstStageFstabMicrodroid(cmdline);
+    } else {
+        fstab = ReadFirstStageFstabAndroid();
+    }
     if (!fstab.ok()) {
         return fstab.error();
     }
@@ -233,7 +238,7 @@
     return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
 }
 
-bool FirstStageMount::DoCreateDevices() {
+bool FirstStageMountVBootV2::DoCreateDevices() {
     if (!InitDevices()) return false;
 
     // Mount /metadata before creating logical partitions, since we need to
@@ -255,7 +260,7 @@
     return true;
 }
 
-bool FirstStageMount::DoFirstStageMount() {
+bool FirstStageMountVBootV2::DoFirstStageMount() {
     if (!IsDmLinearEnabled() && fstab_.empty()) {
         // Nothing to mount.
         LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
@@ -267,7 +272,7 @@
     return true;
 }
 
-bool FirstStageMount::InitDevices() {
+bool FirstStageMountVBootV2::InitDevices() {
     std::set<std::string> devices;
     GetSuperDeviceName(&devices);
 
@@ -288,14 +293,14 @@
     return true;
 }
 
-bool FirstStageMount::IsDmLinearEnabled() {
+bool FirstStageMountVBootV2::IsDmLinearEnabled() {
     for (const auto& entry : fstab_) {
         if (entry.fs_mgr_flags.logical) return true;
     }
     return false;
 }
 
-void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
+void FirstStageMountVBootV2::GetSuperDeviceName(std::set<std::string>* devices) {
     // Add any additional devices required for dm-linear mappings.
     if (!IsDmLinearEnabled()) {
         return;
@@ -307,7 +312,7 @@
 // Creates devices with uevent->partition_name matching ones in the given set.
 // Found partitions will then be removed from it for the subsequent member
 // function to check which devices are NOT created.
-bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
+bool FirstStageMountVBootV2::InitRequiredDevices(std::set<std::string> devices) {
     if (!block_dev_init_.InitDeviceMapper()) {
         return false;
     }
@@ -317,7 +322,8 @@
     return block_dev_init_.InitDevices(std::move(devices));
 }
 
-bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
+bool FirstStageMountVBootV2::InitDmLinearBackingDevices(
+        const android::fs_mgr::LpMetadata& metadata) {
     std::set<std::string> devices;
 
     auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
@@ -334,7 +340,7 @@
     return InitRequiredDevices(std::move(devices));
 }
 
-bool FirstStageMount::CreateLogicalPartitions() {
+bool FirstStageMountVBootV2::CreateLogicalPartitions() {
     if (!IsDmLinearEnabled()) {
         return true;
     }
@@ -365,7 +371,7 @@
     return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
 }
 
-bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
+bool FirstStageMountVBootV2::CreateSnapshotPartitions(SnapshotManager* sm) {
     // When COW images are present for snapshots, they are stored on
     // the data partition.
     if (!InitRequiredDevices({"userdata"})) {
@@ -400,8 +406,8 @@
     return true;
 }
 
-bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
-                                     Fstab::iterator* end) {
+bool FirstStageMountVBootV2::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
+                                            Fstab::iterator* end) {
     // Sets end to begin + 1, so we can just return on failure below.
     if (end) {
         *end = begin + 1;
@@ -445,7 +451,7 @@
     return mounted;
 }
 
-void FirstStageMount::PreloadAvbKeys() {
+void FirstStageMountVBootV2::PreloadAvbKeys() {
     for (const auto& entry : fstab_) {
         // No need to cache the key content if it's empty, or is already cached.
         if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
@@ -492,7 +498,7 @@
 // If system is in the fstab then we're not a system-as-root device, and in
 // this case, we mount system first then pivot to it.  From that point on,
 // we are effectively identical to a system-as-root device.
-bool FirstStageMount::TrySwitchSystemAsRoot() {
+bool FirstStageMountVBootV2::TrySwitchSystemAsRoot() {
     UseDsuIfPresent();
     // Preloading all AVB keys from the ramdisk before switching root to /system.
     PreloadAvbKeys();
@@ -521,7 +527,7 @@
     return true;
 }
 
-bool FirstStageMount::MountPartitions() {
+bool FirstStageMountVBootV2::MountPartitions() {
     if (!TrySwitchSystemAsRoot()) return false;
 
     if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;
@@ -604,7 +610,7 @@
 // copy files to /metadata is NOT fatal, because it is auxiliary to perform
 // public key matching before booting into DSU images on next boot. The actual
 // public key matching will still be done on next boot to DSU.
-void FirstStageMount::CopyDsuAvbKeys() {
+void FirstStageMountVBootV2::CopyDsuAvbKeys() {
     std::error_code ec;
     // Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale.
     std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec);
@@ -620,7 +626,7 @@
     }
 }
 
-void FirstStageMount::UseDsuIfPresent() {
+void FirstStageMountVBootV2::UseDsuIfPresent() {
     std::string error;
 
     if (!android::gsi::CanBootIntoGsi(&error)) {
@@ -657,10 +663,10 @@
     TransformFstabForDsu(&fstab_, active_dsu, dsu_partitions);
 }
 
-// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab
-// for any further vbmeta partitions.
 FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
-    : FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
+    : need_dm_verity_(false), fstab_(std::move(fstab)), avb_handle_(nullptr) {
+    super_partition_name_ = fs_mgr_get_super_partition_name();
+
     std::string device_tree_vbmeta_parts;
     read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);
 
@@ -793,46 +799,13 @@
     return true;
 }
 
-// Public functions
-// ----------------
-// Creates devices and logical partitions from storage devices
-bool DoCreateDevices() {
-    auto fsm = FirstStageMount::Create();
-    if (!fsm.ok()) {
-        LOG(ERROR) << "Failed to create FirstStageMount: " << fsm.error();
-        return false;
-    }
-    return (*fsm)->DoCreateDevices();
-}
-
-// Mounts partitions specified by fstab in device tree.
-bool DoFirstStageMount(bool create_devices) {
-    // Skips first stage mount if we're in recovery mode.
-    if (IsRecoveryMode()) {
-        LOG(INFO) << "First stage mount skipped (recovery mode)";
-        return true;
-    }
-
-    auto fsm = FirstStageMount::Create();
-    if (!fsm.ok()) {
-        LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error();
-        return false;
-    }
-
-    if (create_devices) {
-        if (!(*fsm)->DoCreateDevices()) return false;
-    }
-
-    return (*fsm)->DoFirstStageMount();
-}
-
 void SetInitAvbVersionInRecovery() {
     if (!IsRecoveryMode()) {
         LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
         return;
     }
 
-    auto fstab = ReadFirstStageFstab();
+    auto fstab = ReadFirstStageFstabAndroid();
     if (!fstab.ok()) {
         LOG(ERROR) << fstab.error();
         return;
diff --git a/init/first_stage_mount.h b/init/first_stage_mount.h
index 2f4e663..54501d8 100644
--- a/init/first_stage_mount.h
+++ b/init/first_stage_mount.h
@@ -16,11 +16,28 @@
 
 #pragma once
 
+#include <memory>
+
+#include "result.h"
+
 namespace android {
 namespace init {
 
-bool DoCreateDevices();
-bool DoFirstStageMount(bool create_devices);
+class FirstStageMount {
+  public:
+    virtual ~FirstStageMount() = default;
+
+    // The factory method to create a FirstStageMount instance.
+    static Result<std::unique_ptr<FirstStageMount>> Create(const std::string& cmdline);
+    // Creates devices and logical partitions from storage devices
+    virtual bool DoCreateDevices() = 0;
+    // Mounts fstab entries read from device tree.
+    virtual bool DoFirstStageMount() = 0;
+
+  protected:
+    FirstStageMount() = default;
+};
+
 void SetInitAvbVersionInRecovery();
 
 }  // namespace init
diff --git a/libbinderwrapper/Android.bp b/libbinderwrapper/Android.bp
deleted file mode 100644
index 75f43ee..0000000
--- a/libbinderwrapper/Android.bp
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2015 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.
-//
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_defaults {
-    name: "libbinderwrapper_defaults",
-
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wno-unused-parameter",
-
-        // for libchrome
-        "-Wno-sign-promo",
-    ],
-    export_include_dirs: ["include"],
-    shared_libs: [
-        "libbinder",
-        "libchrome",
-        "libutils",
-    ],
-}
-
-// libbinderwrapper shared library
-// ========================================================
-cc_library_shared {
-    name: "libbinderwrapper",
-    defaults: ["libbinderwrapper_defaults"],
-    vendor_available: true,
-
-    srcs: [
-        "binder_wrapper.cc",
-        "real_binder_wrapper.cc",
-    ],
-}
-
-// libbinderwrapper_test_support static library
-// ========================================================
-cc_library_static {
-    name: "libbinderwrapper_test_support",
-    defaults: ["libbinderwrapper_defaults"],
-
-    static_libs: ["libgtest"],
-    shared_libs: ["libbinderwrapper"],
-
-    srcs: [
-        "binder_test_base.cc",
-        "stub_binder_wrapper.cc",
-    ],
-}
diff --git a/libbinderwrapper/binder_test_base.cc b/libbinderwrapper/binder_test_base.cc
deleted file mode 100644
index af93a04..0000000
--- a/libbinderwrapper/binder_test_base.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2015 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 <binderwrapper/binder_test_base.h>
-
-#include <binderwrapper/binder_wrapper.h>
-#include <binderwrapper/stub_binder_wrapper.h>
-
-namespace android {
-
-BinderTestBase::BinderTestBase() : binder_wrapper_(new StubBinderWrapper()) {
-  // Pass ownership.
-  BinderWrapper::InitForTesting(binder_wrapper_);
-}
-
-BinderTestBase::~BinderTestBase() {
-  BinderWrapper::Destroy();
-}
-
-}  // namespace android
diff --git a/libbinderwrapper/binder_wrapper.cc b/libbinderwrapper/binder_wrapper.cc
deleted file mode 100644
index ca9c1df..0000000
--- a/libbinderwrapper/binder_wrapper.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015 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 <binderwrapper/binder_wrapper.h>
-
-#include <base/logging.h>
-
-#include "real_binder_wrapper.h"
-
-namespace android {
-
-// Singleton instance.
-BinderWrapper* BinderWrapper::instance_ = nullptr;
-
-// static
-void BinderWrapper::Create() {
-  CHECK(!instance_) << "Already initialized; missing call to Destroy()?";
-  instance_ = new RealBinderWrapper();
-}
-
-// static
-void BinderWrapper::InitForTesting(BinderWrapper* wrapper) {
-  CHECK(!instance_) << "Already initialized; missing call to Destroy()?";
-  instance_ = wrapper;
-}
-
-// static
-void BinderWrapper::Destroy() {
-  CHECK(instance_) << "Not initialized; missing call to Create()?";
-  delete instance_;
-  instance_ = nullptr;
-}
-
-// static
-BinderWrapper* BinderWrapper::Get() {
-  CHECK(instance_) << "Not initialized; missing call to Create()?";
-  return instance_;
-}
-
-// static
-BinderWrapper* BinderWrapper::GetOrCreateInstance() {
-  if (!instance_)
-    instance_ = new RealBinderWrapper();
-  return instance_;
-}
-
-}  // namespace android
diff --git a/libbinderwrapper/include/binderwrapper/binder_test_base.h b/libbinderwrapper/include/binderwrapper/binder_test_base.h
deleted file mode 100644
index 06543de..0000000
--- a/libbinderwrapper/include/binderwrapper/binder_test_base.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_
-#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_
-
-#include <base/macros.h>
-#include <gtest/gtest.h>
-
-namespace android {
-
-class StubBinderWrapper;
-
-// Class that can be inherited from (or aliased via typedef/using) when writing
-// tests that use StubBinderManager.
-class BinderTestBase : public ::testing::Test {
- public:
-  BinderTestBase();
-  ~BinderTestBase() override;
-
-  StubBinderWrapper* binder_wrapper() { return binder_wrapper_; }
-
- protected:
-  StubBinderWrapper* binder_wrapper_;  // Not owned.
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BinderTestBase);
-};
-
-}  // namespace android
-
-#endif  // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_TEST_BASE_H_
diff --git a/libbinderwrapper/include/binderwrapper/binder_wrapper.h b/libbinderwrapper/include/binderwrapper/binder_wrapper.h
deleted file mode 100644
index a104bff..0000000
--- a/libbinderwrapper/include/binderwrapper/binder_wrapper.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_
-#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_
-
-#include <sys/types.h>
-
-#include <string>
-
-#include <base/callback.h>
-#include <utils/StrongPointer.h>
-
-namespace android {
-
-class BBinder;
-class IBinder;
-
-// Wraps libbinder to make it testable.
-// NOTE: Static methods of this class are not thread-safe.
-class BinderWrapper {
- public:
-  virtual ~BinderWrapper() {}
-
-  // Creates and initializes the singleton (using a wrapper that communicates
-  // with the real binder system).
-  static void Create();
-
-  // Initializes |wrapper| as the singleton, taking ownership of it. Tests that
-  // want to inject their own wrappers should call this instead of Create().
-  static void InitForTesting(BinderWrapper* wrapper);
-
-  // Destroys the singleton. Must be called before calling Create() or
-  // InitForTesting() a second time.
-  static void Destroy();
-
-  // Returns the singleton instance previously created by Create() or set by
-  // InitForTesting().
-  static BinderWrapper* Get();
-
-  // Returns the singleton instance if it was previously created by Create() or
-  // set by InitForTesting(), or creates a new one by calling Create().
-  static BinderWrapper* GetOrCreateInstance();
-
-  // Gets the binder for communicating with the service identified by
-  // |service_name|, returning null immediately if it doesn't exist.
-  virtual sp<IBinder> GetService(const std::string& service_name) = 0;
-
-  // Registers |binder| as |service_name| with the service manager.
-  virtual bool RegisterService(const std::string& service_name,
-                               const sp<IBinder>& binder) = 0;
-
-  // Creates a local binder object.
-  virtual sp<BBinder> CreateLocalBinder() = 0;
-
-  // Registers |callback| to be invoked when |binder| dies. If another callback
-  // is currently registered for |binder|, it will be replaced.
-  virtual bool RegisterForDeathNotifications(
-      const sp<IBinder>& binder,
-      const ::base::Closure& callback) = 0;
-
-  // Unregisters the callback, if any, for |binder|.
-  virtual bool UnregisterForDeathNotifications(const sp<IBinder>& binder) = 0;
-
-  // When called while in a transaction, returns the caller's UID or PID.
-  virtual uid_t GetCallingUid() = 0;
-  virtual pid_t GetCallingPid() = 0;
-
- private:
-  static BinderWrapper* instance_;
-};
-
-}  // namespace android
-
-#endif  // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_BINDER_WRAPPER_H_
diff --git a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h b/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h
deleted file mode 100644
index 9d4578e..0000000
--- a/libbinderwrapper/include/binderwrapper/stub_binder_wrapper.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_
-#define SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <binder/Binder.h>
-#include <binder/IBinder.h>
-#include <binderwrapper/binder_wrapper.h>
-
-namespace android {
-
-// Stub implementation of BinderWrapper for testing.
-//
-// Example usage:
-//
-// First, assuming a base IFoo binder interface, create a stub class that
-// derives from BnFoo to implement the receiver side of the communication:
-//
-//   class StubFoo : public BnFoo {
-//    public:
-//     ...
-//     status_t doSomething(int arg) override {
-//       // e.g. save passed-in value for later inspection by tests.
-//       return OK;
-//     }
-//   };
-//
-// Next, from your test code, inject a StubBinderManager either directly or by
-// inheriting from the BinderTestBase class:
-//
-//   StubBinderWrapper* wrapper = new StubBinderWrapper();
-//   BinderWrapper::InitForTesting(wrapper);  // Takes ownership.
-//
-// Also from your test, create a StubFoo and register it with the wrapper:
-//
-//   StubFoo* foo = new StubFoo();
-//   sp<IBinder> binder(foo);
-//   wrapper->SetBinderForService("foo", binder);
-//
-// The code being tested can now use the wrapper to get the stub and call it:
-//
-//   sp<IBinder> binder = BinderWrapper::Get()->GetService("foo");
-//   CHECK(binder.get());
-//   sp<IFoo> foo = interface_cast<IFoo>(binder);
-//   CHECK_EQ(foo->doSomething(3), OK);
-//
-// To create a local BBinder object, production code can call
-// CreateLocalBinder(). Then, a test can get the BBinder's address via
-// local_binders() to check that they're passed as expected in binder calls.
-//
-class StubBinderWrapper : public BinderWrapper {
- public:
-  StubBinderWrapper();
-  ~StubBinderWrapper() override;
-
-  const std::vector<sp<BBinder>>& local_binders() const {
-    return local_binders_;
-  }
-  void clear_local_binders() { local_binders_.clear(); }
-
-  void set_calling_uid(uid_t uid) { calling_uid_ = uid; }
-  void set_calling_pid(pid_t pid) { calling_pid_ = pid; }
-
-  // Sets the binder to return when |service_name| is passed to GetService() or
-  // WaitForService().
-  void SetBinderForService(const std::string& service_name,
-                           const sp<IBinder>& binder);
-
-  // Returns the binder previously registered for |service_name| via
-  // RegisterService(), or null if the service hasn't been registered.
-  sp<IBinder> GetRegisteredService(const std::string& service_name) const;
-
-  // Run the calback in |death_callbacks_| corresponding to |binder|.
-  void NotifyAboutBinderDeath(const sp<IBinder>& binder);
-
-  // BinderWrapper:
-  sp<IBinder> GetService(const std::string& service_name) override;
-  bool RegisterService(const std::string& service_name,
-                       const sp<IBinder>& binder) override;
-  sp<BBinder> CreateLocalBinder() override;
-  bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const ::base::Closure& callback) override;
-  bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
-  uid_t GetCallingUid() override;
-  pid_t GetCallingPid() override;
-
- private:
-  using ServiceMap = std::map<std::string, sp<IBinder>>;
-
-  // Map from service name to associated binder handle. Used by GetService() and
-  // WaitForService().
-  ServiceMap services_to_return_;
-
-  // Map from service name to associated binder handle. Updated by
-  // RegisterService().
-  ServiceMap registered_services_;
-
-  // Local binders returned by CreateLocalBinder().
-  std::vector<sp<BBinder>> local_binders_;
-
-  // Map from binder handle to the callback that should be invoked on binder
-  // death.
-  std::map<sp<IBinder>, ::base::Closure> death_callbacks_;
-
-  // Values to return from GetCallingUid() and GetCallingPid();
-  uid_t calling_uid_;
-  pid_t calling_pid_;
-
-  DISALLOW_COPY_AND_ASSIGN(StubBinderWrapper);
-};
-
-}  // namespace android
-
-#endif  // SYSTEM_CORE_INCLUDE_BINDERWRAPPER_STUB_BINDER_WRAPPER_H_
diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc
deleted file mode 100644
index f93f183..0000000
--- a/libbinderwrapper/real_binder_wrapper.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2015 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 "real_binder_wrapper.h"
-
-#include <base/logging.h>
-#include <binder/Binder.h>
-#include <binder/IBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-
-namespace android {
-
-// Class that handles binder death notifications. libbinder wants the recipient
-// to be wrapped in sp<>, so registering RealBinderWrapper as a recipient would
-// be awkward.
-class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient {
- public:
-  explicit DeathRecipient(const ::base::Closure& callback)
-      : callback_(callback) {}
-  ~DeathRecipient() = default;
-
-  // IBinder::DeathRecipient:
-  void binderDied(const wp<IBinder>& who) override {
-    callback_.Run();
-  }
-
- private:
-  // Callback to run in response to binder death.
-  ::base::Closure callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(DeathRecipient);
-};
-
-RealBinderWrapper::RealBinderWrapper() = default;
-
-RealBinderWrapper::~RealBinderWrapper() = default;
-
-sp<IBinder> RealBinderWrapper::GetService(const std::string& service_name) {
-  sp<IServiceManager> service_manager = defaultServiceManager();
-  if (!service_manager.get()) {
-    LOG(ERROR) << "Unable to get service manager";
-    return sp<IBinder>();
-  }
-  sp<IBinder> binder =
-      service_manager->checkService(String16(service_name.c_str()));
-  if (!binder.get())
-    LOG(ERROR) << "Unable to get \"" << service_name << "\" service";
-  return binder;
-}
-
-bool RealBinderWrapper::RegisterService(const std::string& service_name,
-                                        const sp<IBinder>& binder) {
-  sp<IServiceManager> service_manager = defaultServiceManager();
-  if (!service_manager.get()) {
-    LOG(ERROR) << "Unable to get service manager";
-    return false;
-  }
-  status_t status = defaultServiceManager()->addService(
-      String16(service_name.c_str()), binder);
-  if (status != OK) {
-    LOG(ERROR) << "Failed to register \"" << service_name << "\" with service "
-               << "manager";
-    return false;
-  }
-  return true;
-}
-
-sp<BBinder> RealBinderWrapper::CreateLocalBinder() {
-  return sp<BBinder>(new BBinder());
-}
-
-bool RealBinderWrapper::RegisterForDeathNotifications(
-    const sp<IBinder>& binder,
-    const ::base::Closure& callback) {
-  sp<DeathRecipient> recipient(new DeathRecipient(callback));
-  if (binder->linkToDeath(recipient) != OK) {
-    LOG(ERROR) << "Failed to register for death notifications on "
-               << binder.get();
-    return false;
-  }
-  death_recipients_[binder] = recipient;
-  return true;
-}
-
-bool RealBinderWrapper::UnregisterForDeathNotifications(
-    const sp<IBinder>& binder) {
-  auto it = death_recipients_.find(binder);
-  if (it == death_recipients_.end()) {
-    LOG(ERROR) << "Not registered for death notifications on " << binder.get();
-    return false;
-  }
-  if (binder->unlinkToDeath(it->second) != OK) {
-    LOG(ERROR) << "Failed to unregister for death notifications on "
-               << binder.get();
-    return false;
-  }
-  death_recipients_.erase(it);
-  return true;
-}
-
-uid_t RealBinderWrapper::GetCallingUid() {
-  return IPCThreadState::self()->getCallingUid();
-}
-
-pid_t RealBinderWrapper::GetCallingPid() {
-  return IPCThreadState::self()->getCallingPid();
-}
-
-}  // namespace android
diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h
deleted file mode 100644
index fa05383..0000000
--- a/libbinderwrapper/real_binder_wrapper.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#ifndef SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
-#define SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
-
-#include <map>
-
-#include <base/macros.h>
-#include <binderwrapper/binder_wrapper.h>
-
-namespace android {
-
-class IBinder;
-
-// Real implementation of BinderWrapper.
-class RealBinderWrapper : public BinderWrapper {
- public:
-  RealBinderWrapper();
-  ~RealBinderWrapper() override;
-
-  // BinderWrapper:
-  sp<IBinder> GetService(const std::string& service_name) override;
-  bool RegisterService(const std::string& service_name,
-                       const sp<IBinder>& binder) override;
-  sp<BBinder> CreateLocalBinder() override;
-  bool RegisterForDeathNotifications(const sp<IBinder>& binder,
-                                     const ::base::Closure& callback) override;
-  bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
-  uid_t GetCallingUid() override;
-  pid_t GetCallingPid() override;
-
- private:
-  class DeathRecipient;
-
-  // Map from binder handle to object that should be notified of the binder's
-  // death.
-  std::map<sp<IBinder>, sp<DeathRecipient>> death_recipients_;
-
-  DISALLOW_COPY_AND_ASSIGN(RealBinderWrapper);
-};
-
-}  // namespace android
-
-#endif  // SYSTEM_CORE_LIBBINDER_WRAPPER_REAL_BINDER_WRAPPER_H_
diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc
deleted file mode 100644
index 8e75f62..0000000
--- a/libbinderwrapper/stub_binder_wrapper.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2015 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 <binderwrapper/stub_binder_wrapper.h>
-
-#include <base/logging.h>
-#include <binder/Binder.h>
-#include <binder/IBinder.h>
-
-namespace android {
-
-StubBinderWrapper::StubBinderWrapper()
-    : calling_uid_(-1),
-      calling_pid_(-1) {}
-
-StubBinderWrapper::~StubBinderWrapper() = default;
-
-void StubBinderWrapper::SetBinderForService(const std::string& service_name,
-                                            const sp<IBinder>& binder) {
-  services_to_return_[service_name] = binder;
-}
-
-sp<IBinder> StubBinderWrapper::GetRegisteredService(
-    const std::string& service_name) const {
-  const auto it = registered_services_.find(service_name);
-  return it != registered_services_.end() ? it->second : sp<IBinder>();
-}
-
-void StubBinderWrapper::NotifyAboutBinderDeath(const sp<IBinder>& binder) {
-  const auto it = death_callbacks_.find(binder);
-  if (it != death_callbacks_.end())
-    it->second.Run();
-}
-
-sp<IBinder> StubBinderWrapper::GetService(const std::string& service_name) {
-  const auto it = services_to_return_.find(service_name);
-  return it != services_to_return_.end() ? it->second : sp<IBinder>();
-}
-
-bool StubBinderWrapper::RegisterService(const std::string& service_name,
-                                        const sp<IBinder>& binder) {
-  registered_services_[service_name] = binder;
-  return true;
-}
-
-sp<BBinder> StubBinderWrapper::CreateLocalBinder() {
-  sp<BBinder> binder(new BBinder());
-  local_binders_.push_back(binder);
-  return binder;
-}
-
-bool StubBinderWrapper::RegisterForDeathNotifications(
-    const sp<IBinder>& binder,
-    const ::base::Closure& callback) {
-  death_callbacks_[binder] = callback;
-  return true;
-}
-
-bool StubBinderWrapper::UnregisterForDeathNotifications(
-    const sp<IBinder>& binder) {
-  death_callbacks_.erase(binder);
-  return true;
-}
-
-uid_t StubBinderWrapper::GetCallingUid() {
-  return calling_uid_;
-}
-
-pid_t StubBinderWrapper::GetCallingPid() {
-  return calling_pid_;
-}
-
-}  // namespace android
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index 5999e39..7cca105 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -362,14 +362,19 @@
     return err->error;
 }
 
+// Pass bitwise complement of prefix length to disable DAD, ie. use ~64 instead of 64.
 // Returns zero on success and negative errno on failure.
 int ifc_add_address(const char *name, const char *address, int prefixlen) {
-    return ifc_act_on_address(RTM_NEWADDR, name, address, prefixlen, /*nodad*/ false);
+    bool nodad = (prefixlen < 0);
+    if (nodad) prefixlen = ~prefixlen;
+    return ifc_act_on_address(RTM_NEWADDR, name, address, prefixlen, nodad);
 }
 
 // Returns zero on success and negative errno on failure.
 int ifc_del_address(const char *name, const char * address, int prefixlen) {
-    return ifc_act_on_address(RTM_DELADDR, name, address, prefixlen, /*nodad*/ false);
+    bool nodad = (prefixlen < 0);
+    if (nodad) prefixlen = ~prefixlen;
+    return ifc_act_on_address(RTM_DELADDR, name, address, prefixlen, nodad);
 }
 
 /*
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index cd9db54..55bbe46 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -150,15 +150,10 @@
 }
 
 NetlinkEvent::~NetlinkEvent() {
-    int i;
-    if (mPath)
-        free(mPath);
-    if (mSubsystem)
-        free(mSubsystem);
-    for (i = 0; i < NL_PARAMS_MAX; i++) {
-        if (!mParams[i])
-            break;
-        free(mParams[i]);
+    free(mPath);
+    free(mSubsystem);
+    for (auto param : mParams) {
+        free(param);
     }
 }
 
diff --git a/libutils/Vector_fuzz.cpp b/libutils/Vector_fuzz.cpp
index f6df051..6fd2baf 100644
--- a/libutils/Vector_fuzz.cpp
+++ b/libutils/Vector_fuzz.cpp
@@ -13,71 +13,203 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "fuzzer/FuzzedDataProvider.h"
-#include "utils/Vector.h"
-static constexpr uint16_t MAX_VEC_SIZE = 5000;
+#include <fuzzer/FuzzedDataProvider.h>
+#include <utils/Log.h>
+#include <utils/Vector.h>
 
-void runVectorFuzz(const uint8_t* data, size_t size) {
-    FuzzedDataProvider dataProvider(data, size);
-    android::Vector<uint8_t> vec = android::Vector<uint8_t>();
-    // We want to test handling of sizeof as well.
-    android::Vector<uint32_t> vec32 = android::Vector<uint32_t>();
+#include <functional>
 
-    // We're going to generate two vectors of this size
-    size_t vectorSize = dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
-    vec.setCapacity(vectorSize);
-    vec32.setCapacity(vectorSize);
-    for (size_t i = 0; i < vectorSize; i++) {
-        uint8_t count = dataProvider.ConsumeIntegralInRange<uint8_t>(1, 5);
-        vec.insertAt((uint8_t)i, i, count);
-        vec32.insertAt((uint32_t)i, i, count);
-        vec.push_front(i);
-        vec32.push(i);
+using android::Vector;
+
+static constexpr uint16_t MAX_VEC_SIZE = 100;
+static constexpr bool kLog = false;
+
+struct NonTrivialDestructor {
+    NonTrivialDestructor() : mInit(1) {}
+    ~NonTrivialDestructor() {
+        LOG_ALWAYS_FATAL_IF(mInit != 1, "mInit should be 1, but it's: %d", mInit);
+        mInit--;
+        LOG_ALWAYS_FATAL_IF(mInit != 0, "mInit should be 0, but it's: %d", mInit);
     }
 
-    // Now we'll perform some test operations with any remaining data
-    // Index to perform operations at
-    size_t index = dataProvider.ConsumeIntegralInRange<size_t>(0, vec.size());
-    std::vector<uint8_t> remainingVec = dataProvider.ConsumeRemainingBytes<uint8_t>();
-    // Insert an array and vector
-    vec.insertArrayAt(remainingVec.data(), index, remainingVec.size());
-    android::Vector<uint8_t> vecCopy = android::Vector<uint8_t>(vec);
-    vec.insertVectorAt(vecCopy, index);
-    // Same thing for 32 bit vector
-    android::Vector<uint32_t> vec32Copy = android::Vector<uint32_t>(vec32);
-    vec32.insertArrayAt(vec32Copy.array(), index, vec32.size());
-    vec32.insertVectorAt(vec32Copy, index);
-    // Replace single character
-    if (remainingVec.size() > 0) {
-        vec.replaceAt(remainingVec[0], index);
-        vec32.replaceAt(static_cast<uint32_t>(remainingVec[0]), index);
-    } else {
-        vec.replaceAt(0, index);
-        vec32.replaceAt(0, index);
+  private:
+    uint8_t mInit;
+};
+
+template <typename T>
+struct VectorFuzzerData {
+    Vector<T> vector;
+    const std::vector<std::function<void(FuzzedDataProvider&, Vector<T>&)>> funcs = {
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                // operator= Vector<TYPE>, still needs for SortedVector
+                if (kLog) ALOGI("operator=");
+                vector = testVector(provider);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("clear");
+                vector.clear();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("size");
+                vector.size();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("isEmpty");
+                vector.isEmpty();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("capacity");
+                vector.capacity();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+                if (kLog) ALOGI("setCapacity");
+                vector.setCapacity(vectorSize);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+                if (kLog) ALOGI("resize");
+                vector.resize(vectorSize);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("array");
+                vector.array();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("editArray");
+                vector.editArray();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                if (vector.size() == 0) return;
+                size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("operator[]");
+                vector[idx];  // returns a const value for Vector
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                if (vector.size() == 0) return;
+                size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("itemAt");
+                vector.itemAt(idx);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (vector.size() == 0) return;
+                if (kLog) ALOGI("top");
+                vector.top();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                if (vector.size() == 0) return;
+                size_t idx = provider.ConsumeIntegralInRange<size_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("editItemAt");
+                vector.editItemAt(idx);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (vector.size() == 0) return;
+                if (kLog) ALOGI("editTop");
+                vector.editTop() = T{};
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+                Vector vec2 = testVector(provider);
+                if (vec2.size() == 0) return;  // TODO: maybe we should support this?
+                if (kLog) ALOGI("insertVectorAt %d of size %zu", idx, vec2.size());
+                vector.insertVectorAt(vec2, idx);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                if (kLog) ALOGI("appendVector");
+                vector.appendVector(testVector(provider));
+            },
+            // TODO: insertArrayAt
+            // TODO: appendArray
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+                uint8_t numItems = provider.ConsumeIntegralInRange<uint8_t>(1, 100);
+                if (kLog) ALOGI("insertAt");
+                vector.insertAt(idx, numItems);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size());
+                uint8_t numItems = provider.ConsumeIntegralInRange<uint8_t>(1, 100);
+                if (kLog) ALOGI("insertAt");
+                vector.insertAt(T{}, idx, numItems);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (vector.size() == 0) return;
+                if (kLog) ALOGI("pop");
+                vector.pop();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("push");
+                vector.push();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("add");
+                vector.add();
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("add");
+                vector.add(T{});
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("replaceAt");
+                vector.replaceAt(idx);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("replaceAt");
+                vector.replaceAt(T{}, idx);
+            },
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                if (vector.size() == 0) return;
+                uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, vector.size() - 1);
+                if (kLog) ALOGI("remoteItemsAt");
+                vector.removeItemsAt(idx);  // TODO: different count
+            },
+            // removeAt is alias for removeItemsAt
+            // TODO: sort
+            [&](FuzzedDataProvider& provider, Vector<T>& vector) {
+                (void)provider;
+                if (kLog) ALOGI("getItemSize");
+                vector.getItemSize();
+            },
+            // TODO: iterators
+    };
+
+    Vector<T> testVector(FuzzedDataProvider& provider) {
+        Vector<T> vec;
+        size_t vectorSize = provider.ConsumeIntegralInRange<size_t>(0, MAX_VEC_SIZE);
+        return vec;
     }
-    // Add any remaining bytes
-    for (uint8_t i : remainingVec) {
-        vec.add(i);
-        vec32.add(static_cast<uint32_t>(i));
+
+    void fuzz(FuzzedDataProvider&& provider) {
+        while (provider.remaining_bytes()) {
+            size_t funcIdx = provider.ConsumeIntegralInRange<size_t>(0, funcs.size() - 1);
+            funcs[funcIdx](provider, vector);
+        }
     }
-    // Shrink capactiy
-    vec.setCapacity(remainingVec.size());
-    vec32.setCapacity(remainingVec.size());
-    // Iterate through each pointer
-    size_t sum = 0;
-    for (auto& it : vec) {
-        sum += it;
-    }
-    for (auto& it : vec32) {
-        sum += it;
-    }
-    // Cleanup
-    vec.clear();
-    vecCopy.clear();
-    vec32.clear();
-    vec32Copy.clear();
-}
+};
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    runVectorFuzz(data, size);
+    FuzzedDataProvider provider(data, size);
+
+    provider.PickValueInArray<std::function<void()>>({
+            [&]() { VectorFuzzerData<uint8_t>().fuzz(std::move(provider)); },
+            [&]() { VectorFuzzerData<int32_t>().fuzz(std::move(provider)); },
+            [&]() { VectorFuzzerData<NonTrivialDestructor>().fuzz(std::move(provider)); },
+    })();
+
     return 0;
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a8b78d5..4f3959f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -533,7 +533,7 @@
     # Should be before netd, but after apex, properties and logging is available.
     trigger load_bpf_programs
 
-    # Now we can start zygote for devices with file based encryption
+    # Now we can start zygote.
     trigger zygote-start
 
     # Remove a file to wake up anything waiting for firmware.
@@ -1056,25 +1056,7 @@
 
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
-on zygote-start && property:ro.crypto.state=unencrypted
-    wait_for_prop odsign.verification.done 1
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
-    start statsd
-    start netd
-    start zygote
-    start zygote_secondary
-
-on zygote-start && property:ro.crypto.state=unsupported
-    wait_for_prop odsign.verification.done 1
-    # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
-    start statsd
-    start netd
-    start zygote
-    start zygote_secondary
-
-on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
+on zygote-start
     wait_for_prop odsign.verification.done 1
     # A/B update verifier that marks a successful boot.
     exec_start update_verifier_nonencrypted