Merge changes I41ebaf72,I638bc2d7 into main am: 900221fe33

Original change: https://android-review.googlesource.com/c/platform/system/core/+/3556468

Change-Id: If6beb34d287922c7bc827856356ca6f0e377351f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index f47c317..ab6430f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -8,4 +8,3 @@
 rustfmt = --config-path=rustfmt.toml
 
 [Hook Scripts]
-aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index 94b2f8c..df5d775 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -79,16 +79,15 @@
   done file by file. Be mindful of wasted space. For example, defining
   **BOARD_IMAGE_PARTITION_RESERVED_SIZE** has a negative impact on the
   right-sizing of images and requires more free dynamic partition space.
-- The kernel requires **CONFIG_OVERLAY_FS=y**. If the kernel version is higher
-  than 4.4, it requires source to be in line with android-common kernels. 
-  The patch series is available on the upstream mailing list and the latest as
-  of Sep 5 2019 is https://www.spinics.net/lists/linux-mtd/msg08331.html
-  This patch adds an override_creds _mount_ option to OverlayFS that
-  permits legacy behavior for systems that do not have overlapping
-  sepolicy rules, principals of least privilege, which is how Android behaves.
-  For 4.19 and higher a rework of the xattr handling to deal with recursion
-  is required. https://patchwork.kernel.org/patch/11117145/ is a start of that
-  adjustment.
+- The kernel requires **CONFIG_OVERLAY_FS=y**. overlayfs is used 'as is' as of
+  android 16, no modifications are required.
+- In order for overlayfs to work, overlays are mounted in the overlay_remounter
+  domain, defined here: system/sepolicy/private/overlay_remounter.te. This domain
+  must have full access to the files on the underlying volumes, add any other file
+  and directory types here
+- For devices with dynamic partitions, we use a simpler logic to decide which
+  partitions to remount, being all logical ones. In case this isn't correct,
+  we added the overlay=on and overlay=off mount flags to allow detailed control.
 - _adb enable-verity_ frees up OverlayFS and reverts the device to the state
   prior to content updates. The update engine performs a full OTA.
 - _adb remount_ overrides are incompatible with OTA resources, so the update
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index 69d3161..762e70d 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -49,6 +49,10 @@
 #include "fs_mgr_overlayfs_mount.h"
 #include "fs_mgr_priv.h"
 
+// Flag to simplify algorithm for choosing which partitions to overlay to simply overlay
+// all dynamic partitions
+constexpr bool overlay_dynamic_partitions_only = true;
+
 using namespace std::literals;
 using namespace android::fs_mgr;
 using namespace android::storage_literals;
@@ -669,6 +673,19 @@
 
     Fstab candidates;
     for (const auto& entry : fstab) {
+        // fstab overlay flag overrides all other behavior
+        if (entry.fs_mgr_flags.overlay_off) continue;
+        if (entry.fs_mgr_flags.overlay_on) {
+            candidates.push_back(entry);
+            continue;
+        }
+
+        // overlay_dynamic_partitions_only simplifies logic to overlay exactly dynamic partitions
+        if (overlay_dynamic_partitions_only) {
+            if (entry.fs_mgr_flags.logical) candidates.push_back(entry);
+            continue;
+        }
+
         // Filter out partitions whose type doesn't match what's mounted.
         // This avoids spammy behavior on devices which can mount different
         // filesystems for each partition.
diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp
index 010fbc8..ec23ce5 100644
--- a/fs_mgr/libfstab/fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -209,6 +209,8 @@
         CheckFlag("metadata_csum", ext_meta_csum);
         CheckFlag("fscompress", fs_compress);
         CheckFlag("overlayfs_remove_missing_lowerdir", overlayfs_remove_missing_lowerdir);
+        CheckFlag("overlay=on", overlay_on);
+        CheckFlag("overlay=off", overlay_off);
 
 #undef CheckFlag
 
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 0ff3188..4924ae3 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -87,6 +87,8 @@
         bool fs_compress : 1;
         bool overlayfs_remove_missing_lowerdir : 1;
         bool is_zoned : 1;
+        bool overlay_on : 1;
+        bool overlay_off : 1;
     } fs_mgr_flags = {};
 
     bool is_encryptable() const { return fs_mgr_flags.crypt; }
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 6f31251..94d8e9f 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -17,7 +17,6 @@
 
 option optimize_for = LITE_RUNTIME;
 
-// Next: 4
 enum SnapshotState {
     // No snapshot is found.
     NONE = 0;
@@ -34,7 +33,6 @@
     MERGE_COMPLETED = 3;
 }
 
-// Next: 3
 enum MergePhase {
     // No merge is in progress.
     NO_MERGE = 0;
@@ -46,7 +44,6 @@
     SECOND_PHASE = 2;
 }
 
-// Next: 13
 message SnapshotStatus {
     // Name of the snapshot. This is usually the name of the snapshotted
     // logical partition; for example, "system_b".
@@ -126,14 +123,11 @@
 
     reserved 18;
 
-    // Blocks size to be verified at once
-    uint64 verify_block_size = 19;
+    reserved 19;
 
-    // Default value is 2, configures threads to do verification phase
-    uint32 num_verify_threads = 20;
+    reserved 20;
 }
 
-// Next: 8
 enum UpdateState {
     // No update or merge is in progress.
     None = 0;
@@ -162,7 +156,6 @@
     Cancelled = 7;
 };
 
-// Next 14:
 //
 // To understand the source of each failure, read snapshot.cpp. To handle new
 // sources of failure, avoid reusing an existing code; add a new code instead.
@@ -190,7 +183,6 @@
     WrongMergeCountConsistencyCheck = 20;
 };
 
-// Next: 8
 message SnapshotUpdateStatus {
     UpdateState state = 1;
 
@@ -235,9 +227,17 @@
 
     // Number of worker threads to serve I/O from dm-user
     uint32 num_worker_threads = 14;
+
+    // Block size to be verified after OTA reboot
+    uint64 verify_block_size = 15;
+
+    // Default value is 3, configures threads to do verification phase
+    uint32 num_verification_threads = 16;
+
+    // Skips verification of partitions
+    bool skip_verification = 17;
 }
 
-// Next: 10
 message SnapshotMergeReport {
     // Status of the update after the merge attempts.
     UpdateState state = 1;
@@ -285,12 +285,12 @@
 }
 
 message VerityHash {
-  // Partition name
-  string partition_name = 1;
+    // Partition name
+    string partition_name = 1;
 
-  // Salt used for verity hashes
-  string salt = 2;
+    // Salt used for verity hashes
+    string salt = 2;
 
-  // sha256 hash values of each block in the image
-  repeated bytes block_hash = 3;
+    // sha256 hash values of each block in the image
+    repeated bytes block_hash = 3;
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 8a8100c..4520b21 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -859,12 +859,21 @@
     // Check if direct reads are enabled for the source image
     bool UpdateUsesODirect(LockedFile* lock);
 
+    // Check if we skip the verification of the target image
+    bool UpdateUsesSkipVerification(LockedFile* lock);
+
     // Get value of maximum cow op merge size
     uint32_t GetUpdateCowOpMergeSize(LockedFile* lock);
 
     // Get number of threads to perform post OTA boot verification
     uint32_t GetUpdateWorkerCount(LockedFile* lock);
 
+    // Get the verification block size
+    uint32_t GetVerificationBlockSize(LockedFile* lock);
+
+    // Get the number of verification threads
+    uint32_t GetNumVerificationThreads(LockedFile* lock);
+
     // Wrapper around libdm, with diagnostics.
     bool DeleteDeviceIfExists(const std::string& name,
                               const std::chrono::milliseconds& timeout_ms = {});
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index adfb16b..fa2f569 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1792,6 +1792,15 @@
         if (worker_count != 0) {
             snapuserd_argv->emplace_back("-worker_count=" + std::to_string(worker_count));
         }
+        uint32_t verify_block_size = GetVerificationBlockSize(lock.get());
+        if (verify_block_size != 0) {
+            snapuserd_argv->emplace_back("-verify_block_size=" + std::to_string(verify_block_size));
+        }
+        uint32_t num_verify_threads = GetNumVerificationThreads(lock.get());
+        if (num_verify_threads != 0) {
+            snapuserd_argv->emplace_back("-num_verify_threads=" +
+                                         std::to_string(num_verify_threads));
+        }
     }
 
     size_t num_cows = 0;
@@ -2225,6 +2234,11 @@
     return update_status.o_direct();
 }
 
+bool SnapshotManager::UpdateUsesSkipVerification(LockedFile* lock) {
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
+    return update_status.skip_verification();
+}
+
 uint32_t SnapshotManager::GetUpdateCowOpMergeSize(LockedFile* lock) {
     SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
     return update_status.cow_op_merge_size();
@@ -2235,6 +2249,16 @@
     return update_status.num_worker_threads();
 }
 
+uint32_t SnapshotManager::GetVerificationBlockSize(LockedFile* lock) {
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
+    return update_status.verify_block_size();
+}
+
+uint32_t SnapshotManager::GetNumVerificationThreads(LockedFile* lock) {
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
+    return update_status.num_verification_threads();
+}
+
 bool SnapshotManager::MarkSnapuserdFromSystem() {
     auto path = GetSnapuserdFromSystemPath();
 
@@ -3225,8 +3249,11 @@
         status.set_io_uring_enabled(old_status.io_uring_enabled());
         status.set_legacy_snapuserd(old_status.legacy_snapuserd());
         status.set_o_direct(old_status.o_direct());
+        status.set_skip_verification(old_status.skip_verification());
         status.set_cow_op_merge_size(old_status.cow_op_merge_size());
         status.set_num_worker_threads(old_status.num_worker_threads());
+        status.set_verify_block_size(old_status.verify_block_size());
+        status.set_num_verification_threads(old_status.num_verification_threads());
     }
     return WriteSnapshotUpdateStatus(lock, status);
 }
@@ -3605,6 +3632,10 @@
             status.set_o_direct(true);
             LOG(INFO) << "o_direct for source image enabled";
         }
+        if (GetSkipVerificationProperty()) {
+            status.set_skip_verification(true);
+            LOG(INFO) << "skipping verification of images";
+        }
         if (is_legacy_snapuserd) {
             status.set_legacy_snapuserd(true);
             LOG(INFO) << "Setting legacy_snapuserd to true";
@@ -3613,7 +3644,10 @@
                 android::base::GetUintProperty<uint32_t>("ro.virtual_ab.cow_op_merge_size", 0));
         status.set_num_worker_threads(
                 android::base::GetUintProperty<uint32_t>("ro.virtual_ab.num_worker_threads", 0));
-
+        status.set_verify_block_size(
+                android::base::GetUintProperty<uint32_t>("ro.virtual_ab.verify_block_size", 0));
+        status.set_num_verification_threads(
+                android::base::GetUintProperty<uint32_t>("ro.virtual_ab.num_verify_threads", 0));
     } else if (legacy_compression) {
         LOG(INFO) << "Virtual A/B using legacy snapuserd";
     } else {
@@ -4049,8 +4083,11 @@
     ss << "Using userspace snapshots: " << update_status.userspace_snapshots() << std::endl;
     ss << "Using io_uring: " << update_status.io_uring_enabled() << std::endl;
     ss << "Using o_direct: " << update_status.o_direct() << std::endl;
+    ss << "Using skip_verification: " << update_status.skip_verification() << std::endl;
     ss << "Cow op merge size (0 for uncapped): " << update_status.cow_op_merge_size() << std::endl;
     ss << "Worker thread count: " << update_status.num_worker_threads() << std::endl;
+    ss << "Num verification threads: " << update_status.num_verification_threads() << std::endl;
+    ss << "Verify block size: " << update_status.verify_block_size() << std::endl;
     ss << "Using XOR compression: " << GetXorCompressionEnabledProperty() << std::endl;
     ss << "Current slot: " << device_->GetSlotSuffix() << std::endl;
     ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl;
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index 32e16cc..d29223e 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -20,8 +20,13 @@
 #include <gflags/gflags.h>
 #include <snapuserd/snapuserd_client.h>
 
+#include <storage_literals/storage_literals.h>
+#include "user-space-merge/snapuserd_core.h"
+
 #include "snapuserd_daemon.h"
 
+using namespace android::storage_literals;
+
 DEFINE_string(socket, android::snapshot::kSnapuserdSocket, "Named socket or socket path.");
 DEFINE_bool(no_socket, false,
             "If true, no socket is used. Each additional argument is an INIT message.");
@@ -30,8 +35,12 @@
 DEFINE_bool(user_snapshot, false, "If true, user-space snapshots are used");
 DEFINE_bool(io_uring, false, "If true, io_uring feature is enabled");
 DEFINE_bool(o_direct, false, "If true, enable direct reads on source device");
+DEFINE_bool(skip_verification, false, "If true, skip verification of partitions");
 DEFINE_int32(cow_op_merge_size, 0, "number of operations to be processed at once");
-DEFINE_int32(worker_count, 4, "number of worker threads used to serve I/O requests to dm-user");
+DEFINE_int32(worker_count, android::snapshot::kNumWorkerThreads,
+             "number of worker threads used to serve I/O requests to dm-user");
+DEFINE_int32(verify_block_size, 1_MiB, "block sized used during verification of snapshots");
+DEFINE_int32(num_verify_threads, 3, "number of threads used during verification phase");
 
 namespace android {
 namespace snapshot {
@@ -95,9 +104,6 @@
     MaskAllSignalsExceptIntAndTerm();
 
     user_server_.SetServerRunning();
-    if (FLAGS_io_uring) {
-        user_server_.SetIouringEnabled();
-    }
 
     if (FLAGS_socket_handoff) {
         return user_server_.RunForSocketHandoff();
@@ -110,14 +116,20 @@
     }
     for (int i = arg_start; i < argc; i++) {
         auto parts = android::base::Split(argv[i], ",");
-
         if (parts.size() != 4) {
             LOG(ERROR) << "Malformed message, expected at least four sub-arguments.";
             return false;
         }
-        auto handler =
-                user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3], FLAGS_worker_count,
-                                        FLAGS_o_direct, FLAGS_cow_op_merge_size);
+        HandlerOptions options = {
+                .num_worker_threads = FLAGS_worker_count,
+                .use_iouring = FLAGS_io_uring,
+                .o_direct = FLAGS_o_direct,
+                .skip_verification = FLAGS_skip_verification,
+                .cow_op_merge_size = static_cast<uint32_t>(FLAGS_cow_op_merge_size),
+                .verify_block_size = static_cast<uint32_t>(FLAGS_verify_block_size),
+                .num_verification_threads = static_cast<uint32_t>(FLAGS_num_verify_threads),
+        };
+        auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3], options);
         if (!handler || !user_server_.StartHandler(parts[0])) {
             return false;
         }
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
index ef4ba93..c15ac6b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
@@ -40,8 +40,9 @@
 
 bool Extractor::Init() {
     auto opener = factory_.CreateTestOpener(control_name_);
+    HandlerOptions options;
     handler_ = std::make_shared<SnapshotHandler>(control_name_, cow_path_, base_path_, base_path_,
-                                                 opener, 1, false, false, false, 0);
+                                                 opener, options);
     if (!handler_->InitCowDevice()) {
         return false;
     }
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h
index 65285b1..814bc85 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.h
@@ -14,8 +14,8 @@
 
 #pragma once
 
+#include <future>
 #include <string>
-#include <thread>
 
 #include <android-base/unique_fd.h>
 #include "merge_worker.h"
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
index cf507e3..6b6f071 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -52,11 +52,9 @@
 std::shared_ptr<HandlerThread> SnapshotHandlerManager::AddHandler(
         const std::string& misc_name, const std::string& cow_device_path,
         const std::string& backing_device, const std::string& base_path_merge,
-        std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads, bool use_iouring,
-        bool o_direct, uint32_t cow_op_merge_size) {
-    auto snapuserd = std::make_shared<SnapshotHandler>(
-            misc_name, cow_device_path, backing_device, base_path_merge, opener, num_worker_threads,
-            use_iouring, perform_verification_, o_direct, cow_op_merge_size);
+        std::shared_ptr<IBlockServerOpener> opener, HandlerOptions options) {
+    auto snapuserd = std::make_shared<SnapshotHandler>(misc_name, cow_device_path, backing_device,
+                                                       base_path_merge, opener, options);
     if (!snapuserd->InitCowDevice()) {
         LOG(ERROR) << "Failed to initialize Snapuserd";
         return nullptr;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
index 89f3461..d10d8e8 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
@@ -27,6 +27,16 @@
 namespace android {
 namespace snapshot {
 
+struct HandlerOptions {
+    int num_worker_threads{};
+    bool use_iouring{};
+    bool o_direct{};
+    bool skip_verification{};
+    uint32_t cow_op_merge_size{};
+    uint32_t verify_block_size{};
+    uint32_t num_verification_threads{};
+};
+
 class SnapshotHandler;
 
 class HandlerThread {
@@ -53,11 +63,12 @@
     virtual ~ISnapshotHandlerManager() {}
 
     // Add a new snapshot handler but do not start serving requests yet.
-    virtual std::shared_ptr<HandlerThread> AddHandler(
-            const std::string& misc_name, const std::string& cow_device_path,
-            const std::string& backing_device, const std::string& base_path_merge,
-            std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads, bool use_iouring,
-            bool o_direct, uint32_t cow_op_merge_size) = 0;
+    virtual std::shared_ptr<HandlerThread> AddHandler(const std::string& misc_name,
+                                                      const std::string& cow_device_path,
+                                                      const std::string& backing_device,
+                                                      const std::string& base_path_merge,
+                                                      std::shared_ptr<IBlockServerOpener> opener,
+                                                      HandlerOptions options) = 0;
 
     // Start serving requests on a snapshot handler.
     virtual bool StartHandler(const std::string& misc_name) = 0;
@@ -102,8 +113,8 @@
                                               const std::string& backing_device,
                                               const std::string& base_path_merge,
                                               std::shared_ptr<IBlockServerOpener> opener,
-                                              int num_worker_threads, bool use_iouring,
-                                              bool o_direct, uint32_t cow_op_merge_size) override;
+                                              HandlerOptions options) override;
+
     bool StartHandler(const std::string& misc_name) override;
     bool DeleteHandler(const std::string& misc_name) override;
     bool InitiateMerge(const std::string& misc_name) override;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 7c9a64e..1f3d3a0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -22,6 +22,8 @@
 #include <android-base/strings.h>
 #include <snapuserd/dm_user_block_server.h>
 
+#include <future>
+
 #include "merge_worker.h"
 #include "read_worker.h"
 #include "utility.h"
@@ -35,26 +37,21 @@
 
 SnapshotHandler::SnapshotHandler(std::string misc_name, std::string cow_device,
                                  std::string backing_device, std::string base_path_merge,
-                                 std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads,
-                                 bool use_iouring, bool perform_verification, bool o_direct,
-                                 uint32_t cow_op_merge_size) {
+                                 std::shared_ptr<IBlockServerOpener> opener,
+                                 HandlerOptions options) {
     misc_name_ = std::move(misc_name);
     cow_device_ = std::move(cow_device);
     backing_store_device_ = std::move(backing_device);
     block_server_opener_ = std::move(opener);
     base_path_merge_ = std::move(base_path_merge);
-    num_worker_threads_ = num_worker_threads;
-    is_io_uring_enabled_ = use_iouring;
-    perform_verification_ = perform_verification;
-    o_direct_ = o_direct;
-    cow_op_merge_size_ = cow_op_merge_size;
+    handler_options_ = options;
 }
 
 bool SnapshotHandler::InitializeWorkers() {
     for (int i = 0; i < num_worker_threads_; i++) {
         auto wt = std::make_unique<ReadWorker>(cow_device_, backing_store_device_, misc_name_,
                                                base_path_merge_, GetSharedPtr(),
-                                               block_server_opener_, o_direct_);
+                                               block_server_opener_, handler_options_.o_direct);
         if (!wt->Init()) {
             SNAP_LOG(ERROR) << "Thread initialization failed";
             return false;
@@ -62,13 +59,16 @@
 
         worker_threads_.push_back(std::move(wt));
     }
-    merge_thread_ = std::make_unique<MergeWorker>(cow_device_, misc_name_, base_path_merge_,
-                                                  GetSharedPtr(), cow_op_merge_size_);
+    merge_thread_ =
+            std::make_unique<MergeWorker>(cow_device_, misc_name_, base_path_merge_, GetSharedPtr(),
+                                          handler_options_.cow_op_merge_size);
 
-    read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_,
-                                                     GetSharedPtr(), cow_op_merge_size_);
+    read_ahead_thread_ =
+            std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_,
+                                        GetSharedPtr(), handler_options_.cow_op_merge_size);
 
-    update_verify_ = std::make_unique<UpdateVerify>(misc_name_);
+    update_verify_ = std::make_unique<UpdateVerify>(misc_name_, handler_options_.verify_block_size,
+                                                    handler_options_.num_verification_threads);
 
     return true;
 }
@@ -429,7 +429,7 @@
     // During selinux init transition, libsnapshot will propagate the
     // status of io_uring enablement. As properties are not initialized,
     // we cannot query system property.
-    if (is_io_uring_enabled_) {
+    if (handler_options_.use_iouring) {
         return true;
     }
 
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 924539f..9c5d58b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -24,15 +24,11 @@
 
 #include <condition_variable>
 #include <cstring>
-#include <future>
 #include <iostream>
-#include <limits>
 #include <mutex>
 #include <ostream>
 #include <string>
-#include <thread>
 #include <unordered_map>
-#include <unordered_set>
 #include <vector>
 
 #include <android-base/file.h>
@@ -48,6 +44,7 @@
 #include <snapuserd/snapuserd_kernel.h>
 #include <storage_literals/storage_literals.h>
 #include <system/thread_defs.h>
+#include <user-space-merge/handler_manager.h>
 #include "snapuserd_readahead.h"
 #include "snapuserd_verify.h"
 
@@ -104,8 +101,7 @@
   public:
     SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device,
                     std::string base_path_merge, std::shared_ptr<IBlockServerOpener> opener,
-                    int num_workers, bool use_iouring, bool perform_verification, bool o_direct,
-                    uint32_t cow_op_merge_size);
+                    HandlerOptions options);
     bool InitCowDevice();
     bool Start();
 
@@ -248,14 +244,12 @@
     bool merge_initiated_ = false;
     bool merge_monitored_ = false;
     bool attached_ = false;
-    bool is_io_uring_enabled_ = false;
     bool scratch_space_ = false;
     int num_worker_threads_ = kNumWorkerThreads;
     bool perform_verification_ = true;
     bool resume_merge_ = false;
     bool merge_complete_ = false;
-    bool o_direct_ = false;
-    uint32_t cow_op_merge_size_ = 0;
+    HandlerOptions handler_options_;
     std::unique_ptr<UpdateVerify> update_verify_;
     std::shared_ptr<IBlockServerOpener> block_server_opener_;
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index 372b2f2..b21189c 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -35,6 +35,7 @@
 #include <snapuserd/dm_user_block_server.h>
 #include <snapuserd/snapuserd_client.h>
 #include "snapuserd_server.h"
+#include "user-space-merge/handler_manager.h"
 #include "user-space-merge/snapuserd_core.h"
 
 namespace android {
@@ -126,7 +127,8 @@
             return Sendmsg(fd, "fail");
         }
 
-        auto handler = AddHandler(out[1], out[2], out[3], out[4], std::nullopt);
+        HandlerOptions options;
+        auto handler = AddHandler(out[1], out[2], out[3], out[4], options);
         if (!handler) {
             return Sendmsg(fd, "fail");
         }
@@ -348,11 +350,11 @@
     SetTerminating();
 }
 
-std::shared_ptr<HandlerThread> UserSnapshotServer::AddHandler(
-        const std::string& misc_name, const std::string& cow_device_path,
-        const std::string& backing_device, const std::string& base_path_merge,
-        std::optional<uint32_t> num_worker_threads, const bool o_direct,
-        uint32_t cow_op_merge_size) {
+std::shared_ptr<HandlerThread> UserSnapshotServer::AddHandler(const std::string& misc_name,
+                                                              const std::string& cow_device_path,
+                                                              const std::string& backing_device,
+                                                              const std::string& base_path_merge,
+                                                              HandlerOptions options) {
     // We will need multiple worker threads only during
     // device boot after OTA. For all other purposes,
     // one thread is sufficient. We don't want to consume
@@ -361,23 +363,19 @@
     //
     // During boot up, we need multiple threads primarily for
     // update-verification.
-    if (!num_worker_threads.has_value()) {
-        num_worker_threads = kNumWorkerThreads;
-    }
     if (is_socket_present_) {
-        num_worker_threads = 1;
+        options.num_worker_threads = 1;
     }
 
-    if (android::base::EndsWith(misc_name, "-init") || is_socket_present_ ||
-        (access(kBootSnapshotsWithoutSlotSwitch, F_OK) == 0)) {
+    if (options.skip_verification || android::base::EndsWith(misc_name, "-init") ||
+        is_socket_present_ || (access(kBootSnapshotsWithoutSlotSwitch, F_OK) == 0)) {
         handlers_->DisableVerification();
     }
 
     auto opener = block_server_factory_->CreateOpener(misc_name);
 
     return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge,
-                                 opener, num_worker_threads.value(), io_uring_enabled_, o_direct,
-                                 cow_op_merge_size);
+                                 opener, options);
 }
 
 bool UserSnapshotServer::WaitForSocket() {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
index f002e8d..73ce7b2 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -51,7 +51,6 @@
     std::vector<struct pollfd> watched_fds_;
     bool is_socket_present_ = false;
     bool is_server_running_ = false;
-    bool io_uring_enabled_ = false;
     std::unique_ptr<ISnapshotHandlerManager> handlers_;
     std::unique_ptr<IBlockServerFactory> block_server_factory_;
 
@@ -87,17 +86,13 @@
                                               const std::string& cow_device_path,
                                               const std::string& backing_device,
                                               const std::string& base_path_merge,
-                                              std::optional<uint32_t> num_worker_threads,
-                                              bool o_direct = false,
-                                              uint32_t cow_op_merge_size = 0);
+                                              HandlerOptions options);
     bool StartHandler(const std::string& misc_name);
 
     void SetTerminating() { terminating_ = true; }
     void ReceivedSocketSignal() { received_socket_signal_ = true; }
     void SetServerRunning() { is_server_running_ = true; }
     bool IsServerRunning() { return is_server_running_; }
-    void SetIouringEnabled() { io_uring_enabled_ = true; }
-    bool IsIouringEnabled() { return io_uring_enabled_; }
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index 0790a19..f3795a1 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -24,9 +24,8 @@
 #include <unistd.h>
 
 #include <chrono>
-#include <iostream>
+#include <future>
 #include <memory>
-#include <string_view>
 
 #include <android-base/file.h>
 #include <android-base/properties.h>
@@ -44,7 +43,6 @@
 #include "snapuserd_core.h"
 #include "testing/dm_user_harness.h"
 #include "testing/host_harness.h"
-#include "testing/temp_device.h"
 #include "utility.h"
 
 namespace android {
@@ -68,6 +66,8 @@
     int block_size;
     int num_threads;
     uint32_t cow_op_merge_size;
+    uint32_t verification_block_size;
+    uint32_t num_verification_threads;
 };
 
 class SnapuserdTestBase : public ::testing::TestWithParam<TestParam> {
@@ -731,9 +731,17 @@
     auto opener = factory->CreateOpener(system_device_ctrl_name_);
     handlers_->DisableVerification();
     const TestParam params = GetParam();
-    auto handler = handlers_->AddHandler(
-            system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(), base_dev_->GetPath(),
-            opener, 1, params.io_uring, params.o_direct, params.cow_op_merge_size);
+    HandlerOptions options = {
+            .num_worker_threads = params.num_threads,
+            .use_iouring = params.io_uring,
+            .o_direct = params.o_direct,
+            .cow_op_merge_size = params.cow_op_merge_size,
+            .verify_block_size = params.verification_block_size,
+            .num_verification_threads = params.num_verification_threads,
+    };
+    auto handler =
+            handlers_->AddHandler(system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(),
+                                  base_dev_->GetPath(), opener, options);
     ASSERT_NE(handler, nullptr);
     ASSERT_NE(handler->snapuserd(), nullptr);
 #ifdef __ANDROID__
@@ -1273,9 +1281,17 @@
     ASSERT_NE(opener_, nullptr);
 
     const TestParam params = GetParam();
-    handler_ = std::make_shared<SnapshotHandler>(
-            system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(), base_dev_->GetPath(),
-            opener_, 1, false, false, params.o_direct, params.cow_op_merge_size);
+    HandlerOptions options = {
+            .num_worker_threads = params.num_threads,
+            .use_iouring = params.io_uring,
+            .o_direct = params.o_direct,
+            .cow_op_merge_size = params.cow_op_merge_size,
+            .verify_block_size = params.verification_block_size,
+            .num_verification_threads = params.num_verification_threads,
+    };
+    handler_ = std::make_shared<SnapshotHandler>(system_device_ctrl_name_, cow_system_->path,
+                                                 base_dev_->GetPath(), base_dev_->GetPath(),
+                                                 opener_, options);
     ASSERT_TRUE(handler_->InitCowDevice());
     ASSERT_TRUE(handler_->InitializeWorkers());
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp
index 97f8df4..2dfcc36 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.cpp
@@ -20,7 +20,8 @@
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 
-#include "android-base/properties.h"
+#include <future>
+
 #include "snapuserd_core.h"
 #include "utility.h"
 
@@ -31,8 +32,12 @@
 using namespace android::dm;
 using android::base::unique_fd;
 
-UpdateVerify::UpdateVerify(const std::string& misc_name)
-    : misc_name_(misc_name), state_(UpdateVerifyState::VERIFY_UNKNOWN) {}
+UpdateVerify::UpdateVerify(const std::string& misc_name, uint32_t verify_block_size,
+                           uint32_t num_verification_threads)
+    : misc_name_(misc_name),
+      state_(UpdateVerifyState::VERIFY_UNKNOWN),
+      verify_block_size_(verify_block_size),
+      num_verification_threads_(num_verification_threads) {}
 
 bool UpdateVerify::CheckPartitionVerification() {
     auto now = std::chrono::system_clock::now();
@@ -204,9 +209,8 @@
         }
     }
 
-    SNAP_LOG(DEBUG) << "Verification success with io_uring: "
-                    << " dev_sz: " << dev_sz << " partition_name: " << partition_name
-                    << " total_read: " << total_read;
+    SNAP_LOG(DEBUG) << "Verification success with io_uring: " << " dev_sz: " << dev_sz
+                    << " partition_name: " << partition_name << " total_read: " << total_read;
 
     return true;
 }
@@ -250,6 +254,9 @@
     int num_threads = kMinThreadsToVerify;
     if (dev_sz > threshold_size_) {
         num_threads = kMaxThreadsToVerify;
+        if (num_verification_threads_ != 0) {
+            num_threads = num_verification_threads_;
+        }
     }
 
     std::vector<std::future<bool>> threads;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h
index 69a334b..f995c7f 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h
@@ -34,7 +34,8 @@
 
 class UpdateVerify {
   public:
-    UpdateVerify(const std::string& misc_name);
+    UpdateVerify(const std::string& misc_name, uint32_t verify_block_size,
+                 uint32_t num_verification_threads);
     void VerifyUpdatePartition();
     bool CheckPartitionVerification();
 
@@ -66,6 +67,7 @@
      */
     uint64_t verify_block_size_ = 1_MiB;
     uint64_t threshold_size_ = 2_GiB;
+    uint32_t num_verification_threads_;
     int queue_depth_ = 4;
 
     bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index 30510d0..04ee069 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -199,7 +199,7 @@
 }
 
 std::ostream& operator<<(std::ostream& os, const Now&) {
-    struct tm now{};
+    struct tm now {};
     time_t t = time(nullptr);
     localtime_r(&t, &now);
     return os << std::put_time(&now, "%Y%m%d-%H%M%S");
@@ -293,6 +293,11 @@
     return fetcher->GetBoolProperty("ro.virtual_ab.o_direct.enabled", false);
 }
 
+bool GetSkipVerificationProperty() {
+    auto fetcher = IPropertyFetcher::GetInstance();
+    return fetcher->GetBoolProperty("ro.virtual_ab.skip_verification", false);
+}
+
 std::string GetOtherPartitionName(const std::string& name) {
     auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
     CHECK(suffix == "_a" || suffix == "_b");
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 30c75c0..eaf51c1 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -136,6 +136,7 @@
 bool GetIouringEnabledProperty();
 bool GetXorCompressionEnabledProperty();
 bool GetODirectEnabledProperty();
+bool GetSkipVerificationProperty();
 
 bool CanUseUserspaceSnapshots();
 bool IsDmSnapshotTestingEnabled();
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index b0a14bb..64c85e2 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -342,9 +342,10 @@
     return value;
 }
 
-static int getIntField(const String8& path) {
+template <typename T = int>
+static T getIntField(const String8& path) {
     std::string buf;
-    int value = 0;
+    T value = 0;
 
     if (readFromFile(path, &buf) > 0)
         android::base::ParseInt(buf, &value);
@@ -416,11 +417,11 @@
 
     if (!mHealthdConfig->batteryManufacturingDatePath.empty())
         ensureBatteryHealthData(mHealthInfo.get())->batteryManufacturingDateSeconds =
-                getIntField(mHealthdConfig->batteryManufacturingDatePath);
+                getIntField<int64_t>(mHealthdConfig->batteryManufacturingDatePath);
 
     if (!mHealthdConfig->batteryFirstUsageDatePath.empty())
         ensureBatteryHealthData(mHealthInfo.get())->batteryFirstUsageSeconds =
-                getIntField(mHealthdConfig->batteryFirstUsageDatePath);
+                getIntField<int64_t>(mHealthdConfig->batteryFirstUsageDatePath);
 
     mHealthInfo->batteryTemperatureTenthsCelsius =
             mBatteryFixedTemperature ? mBatteryFixedTemperature
@@ -715,49 +716,54 @@
     char vs[128];
     const HealthInfo& props = *mHealthInfo;
 
+    snprintf(vs, sizeof(vs), "Cached HealthInfo:\n");
+    write(fd, vs, strlen(vs));
     snprintf(vs, sizeof(vs),
-             "ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
+             "  ac: %d usb: %d wireless: %d dock: %d current_max: %d voltage_max: %d\n",
              props.chargerAcOnline, props.chargerUsbOnline, props.chargerWirelessOnline,
              props.chargerDockOnline, props.maxChargingCurrentMicroamps,
              props.maxChargingVoltageMicrovolts);
     write(fd, vs, strlen(vs));
-    snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n",
+    snprintf(vs, sizeof(vs), "  status: %d health: %d present: %d\n",
              props.batteryStatus, props.batteryHealth, props.batteryPresent);
     write(fd, vs, strlen(vs));
-    snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", props.batteryLevel,
+    snprintf(vs, sizeof(vs), "  level: %d voltage: %d temp: %d\n", props.batteryLevel,
              props.batteryVoltageMillivolts, props.batteryTemperatureTenthsCelsius);
     write(fd, vs, strlen(vs));
 
     if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
+        snprintf(vs, sizeof(vs), "  current now: %d\n", props.batteryCurrentMicroamps);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryCycleCountPath.empty()) {
+        snprintf(vs, sizeof(vs), "  cycle count: %d\n", props.batteryCycleCount);
+        write(fd, vs, strlen(vs));
+    }
+
+    if (!mHealthdConfig->batteryFullChargePath.empty()) {
+        snprintf(vs, sizeof(vs), "  Full charge: %d\n", props.batteryFullChargeUah);
+        write(fd, vs, strlen(vs));
+    }
+
+    snprintf(vs, sizeof(vs), "Real-time Values:\n");
+    write(fd, vs, strlen(vs));
+
+    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentNowPath);
-        snprintf(vs, sizeof(vs), "current now: %d\n", v);
+        snprintf(vs, sizeof(vs), "  current now: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
     if (!mHealthdConfig->batteryCurrentAvgPath.empty()) {
         v = getIntField(mHealthdConfig->batteryCurrentAvgPath);
-        snprintf(vs, sizeof(vs), "current avg: %d\n", v);
+        snprintf(vs, sizeof(vs), "  current avg: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 
     if (!mHealthdConfig->batteryChargeCounterPath.empty()) {
         v = getIntField(mHealthdConfig->batteryChargeCounterPath);
-        snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
-        write(fd, vs, strlen(vs));
-    }
-
-    if (!mHealthdConfig->batteryCurrentNowPath.empty()) {
-        snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrentMicroamps);
-        write(fd, vs, strlen(vs));
-    }
-
-    if (!mHealthdConfig->batteryCycleCountPath.empty()) {
-        snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
-        write(fd, vs, strlen(vs));
-    }
-
-    if (!mHealthdConfig->batteryFullChargePath.empty()) {
-        snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullChargeUah);
+        snprintf(vs, sizeof(vs), "  charge counter: %d\n", v);
         write(fd, vs, strlen(vs));
     }
 }
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index cc5f658..1405fff 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -403,7 +403,7 @@
 
     // /second_stage_resources is used to preserve files from first to second
     // stage init
-    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOSUID | MS_NODEV,
+    CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
                     "mode=0755,uid=0,gid=0"));
 
     if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) {
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 2a27c1d..03fd2d2 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -56,6 +56,7 @@
 #include <linux/audit.h>
 #include <linux/netlink.h>
 #include <stdlib.h>
+#include <sys/mount.h>
 #include <sys/wait.h>
 #include <unistd.h>
 
@@ -701,8 +702,8 @@
 }
 
 #ifdef ALLOW_REMOUNT_OVERLAYS
-void SetupOverlays() {
-    if (android::fs_mgr::use_override_creds) return;
+bool EarlySetupOverlays() {
+    if (android::fs_mgr::use_override_creds) return false;
 
     bool has_overlays = false;
     std::string contents;
@@ -715,8 +716,16 @@
             break;
         }
 
-    if (!has_overlays) return;
+    if (!has_overlays) return false;
+    if (mount("tmpfs", kSecondStageRes, "tmpfs", MS_REMOUNT | MS_NOSUID | MS_NODEV,
+              "mode=0755,uid=0,gid=0") == -1) {
+        PLOG(FATAL) << "Failed to remount tmpfs on " << kSecondStageRes << " to remove NO_EXEC";
+    }
 
+    return true;
+}
+
+void SetupOverlays() {
     // After adb remount, we mount all r/o volumes with overlayfs to allow writing.
     // However, since overlayfs performs its file operations in the context of the
     // mounting process, this will not work as is - init is in the kernel domain in
@@ -728,7 +737,6 @@
     // We will call overlay_remounter which will do the unmounts/mounts.
     // But for that to work, the volumes must not be busy, so we need to copy
     // overlay_remounter from system to a ramdisk and run it from there.
-
     const char* kOverlayRemounter = "overlay_remounter";
     auto or_src = std::filesystem::path("/system/xbin/") / kOverlayRemounter;
     auto or_dest = std::filesystem::path(kSecondStageRes) / kOverlayRemounter;
@@ -756,6 +764,9 @@
     PLOG(FATAL) << "execv(\"" << or_dest << "\") failed";
 }
 #else
+bool EarlySetupOverlays() {
+    return false;
+}
 void SetupOverlays() {}
 #endif
 
@@ -771,6 +782,9 @@
 
     SelinuxSetupKernelLogging();
 
+    // Test to see if we should use overlays, and if so remount tmpfs before selinux will block
+    bool use_overlays = EarlySetupOverlays();
+
     // TODO(b/287206497): refactor into different headers to only include what we need.
     if (IsMicrodroid()) {
         LoadSelinuxPolicyMicrodroid();
@@ -801,7 +815,7 @@
 
     // SetupOverlays does not return if overlays exist, instead it execs overlay_remounter
     // which then execs second stage init
-    SetupOverlays();
+    if (use_overlays) SetupOverlays();
 
     const char* path = "/system/bin/init";
     const char* args[] = {path, "second_stage", nullptr};
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index 2aaafbe..b6aded0 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -144,6 +144,7 @@
 #define AID_UPROBESTATS 1093         /* uid for uprobestats */
 #define AID_CROS_EC 1094             /* uid for accessing ChromeOS EC (cros_ec) */
 #define AID_MMD 1095                 /* uid for memory management daemon */
+#define AID_UPDATE_ENGINE_LOG 1096   /* GID for accessing update_engine logs */
 // Additions to this file must be made in AOSP, *not* in internal branches.
 // You will also need to update expect_ids() in bionic/tests/grp_pwd_test.cpp.
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 54493d5..471059b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -787,7 +787,8 @@
     mkdir /data/misc/vold 0700 root root
     mkdir /data/misc/boottrace 0771 system shell
     mkdir /data/misc/update_engine 0700 root root
-    mkdir /data/misc/update_engine_log 02750 root log
+    mkdir /data/misc/update_engine_log 02750 root update_engine_log
+    chown root update_engine_log /data/misc/update_engine_log
     mkdir /data/misc/trace 0700 root root
     # create location to store surface and window trace files
     mkdir /data/misc/wmtrace 0700 system system
@@ -994,8 +995,11 @@
     mkdir /data/misc/stats-service/ 0770 statsd system
     mkdir /data/misc/train-info/ 0770 statsd system
 
-    # Wait for apexd to finish activating APEXes before starting more processes.
+    # TODO(b/400439023): Remove once attest modules flagging is removed.
     wait_for_prop apexd.status activated
+    # Wait for KeyMints to receive APEX module info before starting code from updateable APEXes.
+    # This is to prevent APEX modules from interfering in module measurement.
+    wait_for_prop keystore.module_hash.sent true
     perform_apex_config
 
     exec_start system_aconfigd_mainline_init
@@ -1230,7 +1234,7 @@
 # and chown/chmod does not work for /proc/sys/ entries.
 # So proxy writes through init.
 on property:sys.sysctl.extra_free_kbytes=*
-    exec -- /system/bin/extra_free_kbytes.sh ${sys.sysctl.extra_free_kbytes}
+    exec_background -- /system/bin/extra_free_kbytes.sh ${sys.sysctl.extra_free_kbytes}
 
 # Allow users to drop caches
 on property:perf.drop_caches=3
diff --git a/storaged/main.cpp b/storaged/main.cpp
index bbed210..8e71180 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -25,13 +25,12 @@
 #include <sys/types.h>
 #include <vector>
 
-#include <android-base/macros.h>
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
 #include <binder/IPCThreadState.h>
-#include <cutils/android_get_control_file.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <cutils/sched_policy.h>
 #include <private/android_filesystem_config.h>
 
diff --git a/storaged/storaged.rc b/storaged/storaged.rc
index 7085743..6debb69 100644
--- a/storaged/storaged.rc
+++ b/storaged/storaged.rc
@@ -2,7 +2,6 @@
     class main
     capabilities DAC_READ_SEARCH
     priority 10
-    file /d/mmc0/mmc0:0001/ext_csd r
     task_profiles ServiceCapacityLow
     user root
     group package_info
diff --git a/storaged/uid_info.cpp b/storaged/uid_info.cpp
index 0f718de..6f25898 100644
--- a/storaged/uid_info.cpp
+++ b/storaged/uid_info.cpp
@@ -23,13 +23,13 @@
 
 status_t UidInfo::writeToParcel(Parcel* parcel) const {
     parcel->writeInt32(uid);
-    parcel->writeCString(name.c_str());
+    parcel->writeString8(String8(name.c_str()));
     parcel->write(&io, sizeof(io));
 
     parcel->writeInt32(tasks.size());
     for (const auto& task_it : tasks) {
         parcel->writeInt32(task_it.first);
-        parcel->writeCString(task_it.second.comm.c_str());
+        parcel->writeString8(String8(task_it.second.comm.c_str()));
         parcel->write(&task_it.second.io, sizeof(task_it.second.io));
     }
     return OK;
@@ -37,14 +37,14 @@
 
 status_t UidInfo::readFromParcel(const Parcel* parcel) {
     uid = parcel->readInt32();
-    name = parcel->readCString();
+    name = parcel->readString8().c_str();
     parcel->read(&io, sizeof(io));
 
     uint32_t tasks_size = parcel->readInt32();
     for (uint32_t i = 0; i < tasks_size; i++) {
         task_info task;
         task.pid = parcel->readInt32();
-        task.comm = parcel->readCString();
+        task.comm = parcel->readString8().c_str();
         parcel->read(&task.io, sizeof(task.io));
         tasks[task.pid] = task;
     }