Merge "Fix multiple calls to set_[source/type]" into main
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index 25c5a6e..0947ff9 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -224,7 +224,7 @@
     auto remove_if_callback = [&](const auto& task) -> bool {
         if (auto flash_task = task->AsFlashTask()) {
             return helper->WillFlash(flash_task->GetPartitionAndSlot());
-        } else if (auto update_super_task = task->AsUpdateSuperTask()) {
+        } else if (task->AsUpdateSuperTask()) {
             return true;
         } else if (auto reboot_task = task->AsRebootTask()) {
             if (reboot_task->GetTarget() == "fastboot") {
diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING
index 324f50a..edecd7c 100644
--- a/fs_mgr/TEST_MAPPING
+++ b/fs_mgr/TEST_MAPPING
@@ -25,7 +25,7 @@
     {
       "name": "vab_legacy_tests"
     },
-    // TODO: b/279009697
+    // TODO(b/279009697):
     //{"name": "vabc_legacy_tests"},
     {
       "name": "cow_api_test"
@@ -47,7 +47,7 @@
     {
       "name": "vab_legacy_tests"
     },
-    // TODO: b/279009697
+    // TODO(b/279009697):
     //{"name": "vabc_legacy_tests"}
     {
       "name": "snapuserd_test"
diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp
index 622f181..8e76150 100644
--- a/fs_mgr/fs_mgr_format.cpp
+++ b/fs_mgr/fs_mgr_format.cpp
@@ -136,6 +136,7 @@
     /* Format the partition using the calculated length */
 
     const auto size_str = std::to_string(dev_sz / getpagesize());
+    std::string block_size = std::to_string(getpagesize());
 
     std::vector<const char*> args = {"/system/bin/make_f2fs", "-g", "android"};
     if (needs_projid) {
@@ -154,6 +155,10 @@
         args.push_back("-O");
         args.push_back("extra_attr");
     }
+    args.push_back("-w");
+    args.push_back(block_size.c_str());
+    args.push_back("-b");
+    args.push_back(block_size.c_str());
     if (!zoned_device.empty()) {
         args.push_back("-c");
         args.push_back(zoned_device.c_str());
diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp
index 9be236d..06214ef 100644
--- a/fs_mgr/fs_mgr_overlayfs_control.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_control.cpp
@@ -356,6 +356,8 @@
         fs_type = "f2fs";
         command = kMkF2fs + " -w "s;
         command += std::to_string(getpagesize());
+        command = kMkF2fs + " -b "s;
+        command += std::to_string(getpagesize());
         command += " -f -d1 -l" + android::base::Basename(kScratchMountPoint);
     } else if (!access(kMkExt4, X_OK) && fs_mgr_filesystem_available("ext4")) {
         fs_type = "ext4";
@@ -854,21 +856,6 @@
         return;
     }
 
-    bool want_scratch = false;
-    for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
-        if (fs_mgr_is_verity_enabled(entry)) {
-            continue;
-        }
-        if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) {
-            continue;
-        }
-        want_scratch = true;
-        break;
-    }
-    if (!want_scratch) {
-        return;
-    }
-
     if (ScratchIsOnData()) {
         if (auto images = IImageManager::Open("remount", 0ms)) {
             images->MapAllImages(init);
diff --git a/fs_mgr/liblp/super_layout_builder.cpp b/fs_mgr/liblp/super_layout_builder.cpp
index 5349e41..fd7416b 100644
--- a/fs_mgr/liblp/super_layout_builder.cpp
+++ b/fs_mgr/liblp/super_layout_builder.cpp
@@ -17,6 +17,8 @@
 
 #include <liblp/liblp.h>
 
+#include <algorithm>
+
 #include "images.h"
 #include "utility.h"
 #include "writer.h"
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index d8e171b..70c7b79 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -25,6 +25,7 @@
 #include <sys/ioctl.h>
 #endif
 
+#include <algorithm>
 #include <map>
 #include <string>
 #include <vector>
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 08a79ba..d102863 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -826,6 +826,9 @@
     bool DeleteDeviceIfExists(const std::string& name,
                               const std::chrono::milliseconds& timeout_ms = {});
 
+    // Set read-ahead size during OTA
+    void SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb);
+
     android::dm::IDeviceMapper& dm_;
     std::unique_ptr<IDeviceInfo> device_;
     std::string metadata_dir_;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 79cebab..f6a35a8 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -30,6 +30,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <cutils/sockets.h>
@@ -82,12 +83,28 @@
 using std::chrono::duration_cast;
 using namespace std::chrono_literals;
 using namespace std::string_literals;
+using android::base::Realpath;
+using android::base::StringPrintf;
 
 static constexpr char kBootSnapshotsWithoutSlotSwitch[] =
         "/metadata/ota/snapshot-boot-without-slot-switch";
 static constexpr char kBootIndicatorPath[] = "/metadata/ota/snapshot-boot";
 static constexpr char kRollbackIndicatorPath[] = "/metadata/ota/rollback-indicator";
 static constexpr auto kUpdateStateCheckInterval = 2s;
+/*
+ * The readahead size is set to 32kb so that
+ * there is no significant memory pressure (/proc/pressure/memory) during boot.
+ * After OTA, during boot, partitions are scanned before marking slot as successful.
+ * This scan will trigger readahead both on source and COW block device thereby
+ * leading to Inactive(file) pages to be very high.
+ *
+ * A lower value may help reduce memory pressure further, however, that will
+ * increase the boot time. Thus, for device which don't care about OTA boot
+ * time, they could use O_DIRECT functionality wherein the I/O to the source
+ * block device will be O_DIRECT.
+ */
+static constexpr auto kCowReadAheadSizeKb = 32;
+static constexpr auto kSourceReadAheadSizeKb = 32;
 
 // Note: IImageManager is an incomplete type in the header, so the default
 // destructor doesn't work.
@@ -1748,6 +1765,9 @@
                 snapuserd_argv->emplace_back(std::move(message));
             }
 
+            SetReadAheadSize(cow_image_device, kCowReadAheadSizeKb);
+            SetReadAheadSize(source_device, kSourceReadAheadSizeKb);
+
             // Do not attempt to connect to the new snapuserd yet, it hasn't
             // been started. We do however want to wait for the misc device
             // to have been created.
@@ -4407,5 +4427,31 @@
     return true;
 }
 
+void SnapshotManager::SetReadAheadSize(const std::string& entry_block_device, off64_t size_kb) {
+    std::string block_device;
+    if (!Realpath(entry_block_device, &block_device)) {
+        PLOG(ERROR) << "Failed to realpath " << entry_block_device;
+        return;
+    }
+
+    static constexpr std::string_view kDevBlockPrefix("/dev/block/");
+    if (!android::base::StartsWith(block_device, kDevBlockPrefix)) {
+        LOG(ERROR) << block_device << " is not a block device";
+        return;
+    }
+
+    std::string block_name = block_device.substr(kDevBlockPrefix.length());
+    std::string sys_partition =
+            android::base::StringPrintf("/sys/class/block/%s/partition", block_name.c_str());
+    struct stat info;
+    if (lstat(sys_partition.c_str(), &info) == 0) {
+        block_name += "/..";
+    }
+    std::string sys_ra = android::base::StringPrintf("/sys/class/block/%s/queue/read_ahead_kb",
+                                                     block_name.c_str());
+    std::string size = std::to_string(size_kb);
+    android::base::WriteStringToFile(size, sys_ra.c_str());
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
index c5718d5..c85331b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/extractor.cpp
@@ -41,7 +41,7 @@
 bool Extractor::Init() {
     auto opener = factory_.CreateTestOpener(control_name_);
     handler_ = std::make_shared<SnapshotHandler>(control_name_, cow_path_, base_path_, base_path_,
-                                                 opener, 1, false, false);
+                                                 opener, 1, false, false, false);
     if (!handler_->InitCowDevice()) {
         return false;
     }
@@ -50,7 +50,7 @@
     }
 
     read_worker_ = std::make_unique<ReadWorker>(cow_path_, base_path_, control_name_, base_path_,
-                                                handler_->GetSharedPtr(), opener);
+                                                handler_->GetSharedPtr(), opener, false);
     if (!read_worker_->Init()) {
         return false;
     }
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 ffd7a4b..711e704 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -51,10 +51,11 @@
 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) {
-    auto snapuserd = std::make_shared<SnapshotHandler>(misc_name, cow_device_path, backing_device,
-                                                       base_path_merge, opener, num_worker_threads,
-                                                       use_iouring, perform_verification_);
+        std::shared_ptr<IBlockServerOpener> opener, int num_worker_threads, bool use_iouring,
+        bool o_direct) {
+    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);
     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 ff6ee8f..f23f07e 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.h
@@ -57,7 +57,8 @@
                                                       const std::string& backing_device,
                                                       const std::string& base_path_merge,
                                                       std::shared_ptr<IBlockServerOpener> opener,
-                                                      int num_worker_threads, bool use_iouring) = 0;
+                                                      int num_worker_threads, bool use_iouring,
+                                                      bool o_direct) = 0;
 
     // Start serving requests on a snapshot handler.
     virtual bool StartHandler(const std::string& misc_name) = 0;
@@ -96,7 +97,8 @@
                                               const std::string& backing_device,
                                               const std::string& base_path_merge,
                                               std::shared_ptr<IBlockServerOpener> opener,
-                                              int num_worker_threads, bool use_iouring) override;
+                                              int num_worker_threads, bool use_iouring,
+                                              bool o_direct) 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/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
index 3a56669..bcf9aab 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp
@@ -557,7 +557,7 @@
         return true;
     }
 
-    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+    if (!SetThreadPriority(ANDROID_PRIORITY_BACKGROUND)) {
         SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
index 431baf0..f1d4065 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
@@ -31,16 +31,19 @@
 void ReadWorker::CloseFds() {
     block_server_ = {};
     backing_store_fd_ = {};
+    backing_store_direct_fd_ = {};
     Worker::CloseFds();
 }
 
 ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device,
                        const std::string& misc_name, const std::string& base_path_merge,
                        std::shared_ptr<SnapshotHandler> snapuserd,
-                       std::shared_ptr<IBlockServerOpener> opener)
+                       std::shared_ptr<IBlockServerOpener> opener, bool direct_read)
     : Worker(cow_device, misc_name, base_path_merge, snapuserd),
       backing_store_device_(backing_device),
-      block_server_opener_(opener) {}
+      direct_read_(direct_read),
+      block_server_opener_(opener),
+      aligned_buffer_(std::unique_ptr<void, decltype(&::free)>(nullptr, &::free)) {}
 
 // Start the replace operation. This will read the
 // internal COW format and if the block is compressed,
@@ -61,6 +64,17 @@
     }
     SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
                     << " Op: " << *cow_op;
+
+    if (direct_read_ && IsBlockAligned(offset)) {
+        if (!android::base::ReadFullyAtOffset(backing_store_direct_fd_, aligned_buffer_.get(),
+                                              BLOCK_SZ, offset)) {
+            SNAP_PLOG(ERROR) << "O_DIRECT Read failed at offset: " << offset;
+            return false;
+        }
+        std::memcpy(buffer, aligned_buffer_.get(), BLOCK_SZ);
+        return true;
+    }
+
     if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
         std::string op;
         if (cow_op->type() == kCowCopyOp)
@@ -201,6 +215,24 @@
         return false;
     }
 
+    if (direct_read_) {
+        backing_store_direct_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY | O_DIRECT));
+        if (backing_store_direct_fd_ < 0) {
+            SNAP_PLOG(ERROR) << "Open Failed with O_DIRECT: " << backing_store_direct_fd_;
+            direct_read_ = false;
+        } else {
+            void* aligned_addr;
+            ssize_t page_size = getpagesize();
+            if (posix_memalign(&aligned_addr, page_size, page_size) < 0) {
+                direct_read_ = false;
+                SNAP_PLOG(ERROR) << "posix_memalign failed "
+                                 << " page_size: " << page_size << " read_sz: " << page_size;
+            } else {
+                aligned_buffer_.reset(aligned_addr);
+            }
+        }
+    }
+
     block_server_ = block_server_opener_->Open(this, PAYLOAD_BUFFER_SZ);
     if (!block_server_) {
         SNAP_PLOG(ERROR) << "Unable to open block server";
@@ -214,7 +246,7 @@
 
     pthread_setname_np(pthread_self(), "ReadWorker");
 
-    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+    if (!SetThreadPriority(ANDROID_PRIORITY_NORMAL)) {
         SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
index 6dbae81..1aff50c 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
@@ -28,7 +28,7 @@
     ReadWorker(const std::string& cow_device, const std::string& backing_device,
                const std::string& misc_name, const std::string& base_path_merge,
                std::shared_ptr<SnapshotHandler> snapuserd,
-               std::shared_ptr<IBlockServerOpener> opener);
+               std::shared_ptr<IBlockServerOpener> opener, bool direct_read = false);
 
     bool Run();
     bool Init() override;
@@ -59,11 +59,14 @@
 
     std::string backing_store_device_;
     unique_fd backing_store_fd_;
+    unique_fd backing_store_direct_fd_;
+    bool direct_read_ = false;
 
     std::shared_ptr<IBlockServerOpener> block_server_opener_;
     std::unique_ptr<IBlockServer> block_server_;
 
     std::basic_string<uint8_t> xor_buffer_;
+    std::unique_ptr<void, decltype(&::free)> aligned_buffer_;
 };
 
 }  // namespace snapshot
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 9b8c70d..05ba047 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -36,7 +36,7 @@
 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 use_iouring, bool perform_verification, bool o_direct) {
     misc_name_ = std::move(misc_name);
     cow_device_ = std::move(cow_device);
     backing_store_device_ = std::move(backing_device);
@@ -45,13 +45,14 @@
     num_worker_threads_ = num_worker_threads;
     is_io_uring_enabled_ = use_iouring;
     perform_verification_ = perform_verification;
+    o_direct_ = o_direct;
 }
 
 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_);
+                                               block_server_opener_, o_direct_);
         if (!wt->Init()) {
             SNAP_LOG(ERROR) << "Thread initialization failed";
             return false;
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 fa1e7a0..9b7238a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -47,6 +47,7 @@
 #include <snapuserd/snapuserd_buffer.h>
 #include <snapuserd/snapuserd_kernel.h>
 #include <storage_literals/storage_literals.h>
+#include <system/thread_defs.h>
 #include "snapuserd_readahead.h"
 #include "snapuserd_verify.h"
 
@@ -62,8 +63,6 @@
 
 static constexpr int kNumWorkerThreads = 4;
 
-static constexpr int kNiceValueForMergeThreads = -5;
-
 #define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
 #define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
 
@@ -105,7 +104,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);
+                    int num_workers, bool use_iouring, bool perform_verification, bool o_direct);
     bool InitCowDevice();
     bool Start();
 
@@ -247,6 +246,7 @@
     bool perform_verification_ = true;
     bool resume_merge_ = false;
     bool merge_complete_ = false;
+    bool o_direct_ = false;
 
     std::unique_ptr<UpdateVerify> update_verify_;
     std::shared_ptr<IBlockServerOpener> block_server_opener_;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index 034cda1..c08c1b1 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -778,7 +778,7 @@
 
     InitializeIouring();
 
-    if (!SetThreadPriority(kNiceValueForMergeThreads)) {
+    if (!SetThreadPriority(ANDROID_PRIORITY_BACKGROUND)) {
         SNAP_PLOG(ERROR) << "Failed to set thread priority";
     }
 
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 6eee357..0b881b6 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -346,7 +346,8 @@
 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) {
+                                                              const std::string& base_path_merge,
+                                                              const bool o_direct) {
     // 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
@@ -368,7 +369,7 @@
     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, io_uring_enabled_);
+                                 opener, num_worker_threads, io_uring_enabled_, o_direct);
 }
 
 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 9926071..3013c47 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h
@@ -86,7 +86,8 @@
     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);
+                                              const std::string& base_path_merge,
+                                              bool o_direct = false);
     bool StartHandler(const std::string& misc_name);
 
     void SetTerminating() { terminating_ = true; }
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 73c3cbf..8ddb0f4 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -59,10 +59,16 @@
 using testing::AssertionFailure;
 using testing::AssertionResult;
 using testing::AssertionSuccess;
+using ::testing::TestWithParam;
 
-class SnapuserdTestBase : public ::testing::TestWithParam<bool> {
+struct TestParam {
+    bool io_uring;
+    bool o_direct;
+};
+
+class SnapuserdTestBase : public ::testing::TestWithParam<TestParam> {
   protected:
-    void SetUp() override;
+    virtual void SetUp() override;
     void TearDown() override;
     void CreateBaseDevice();
     void CreateCowDevice();
@@ -628,9 +634,10 @@
     auto factory = harness_->GetBlockServerFactory();
     auto opener = factory->CreateOpener(system_device_ctrl_name_);
     handlers_->DisableVerification();
-    auto handler =
-            handlers_->AddHandler(system_device_ctrl_name_, cow_system_->path, base_dev_->GetPath(),
-                                  base_dev_->GetPath(), opener, 1, GetParam());
+    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);
     ASSERT_NE(handler, nullptr);
     ASSERT_NE(handler->snapuserd(), nullptr);
 #ifdef __ANDROID__
@@ -898,9 +905,10 @@
     opener_ = factory_.CreateTestOpener(system_device_ctrl_name_);
     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);
+                                                 opener_, 1, false, false, params.o_direct);
     ASSERT_TRUE(handler_->InitCowDevice());
     ASSERT_TRUE(handler_->InitializeWorkers());
 
@@ -990,14 +998,28 @@
     return {false, true};
 }
 
-std::string IoUringConfigName(const testing::TestParamInfo<SnapuserdTest::ParamType>& info) {
-    return info.param ? "io_uring" : "sync";
+std::vector<TestParam> GetTestConfigs() {
+    std::vector<TestParam> testParams;
+    std::vector<bool> uring_configs = GetIoUringConfigs();
+
+    for (bool config : uring_configs) {
+        TestParam param;
+        param.io_uring = config;
+        param.o_direct = false;
+        testParams.push_back(std::move(param));
+    }
+
+    for (bool config : uring_configs) {
+        TestParam param;
+        param.io_uring = config;
+        param.o_direct = true;
+        testParams.push_back(std::move(param));
+    }
+    return testParams;
 }
 
-INSTANTIATE_TEST_SUITE_P(Io, SnapuserdTest, ::testing::ValuesIn(GetIoUringConfigs()),
-                         IoUringConfigName);
-INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetIoUringConfigs()),
-                         IoUringConfigName);
+INSTANTIATE_TEST_SUITE_P(Io, SnapuserdTest, ::testing::ValuesIn(GetTestConfigs()));
+INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetTestConfigs()));
 
 }  // namespace snapshot
 }  // namespace android
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 d07d2f8..7c99085 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h
@@ -48,10 +48,27 @@
     std::mutex m_lock_;
     std::condition_variable m_cv_;
 
+    /*
+     * Scanning of partitions is an expensive operation both in terms of memory
+     * and CPU usage. The goal here is to scan the partitions fast enough without
+     * significant increase in the boot time.
+     *
+     * Partitions such as system, product which may be huge and may need multiple
+     * threads to speed up the verification process. Using multiple threads for
+     * all partitions may increase CPU usage significantly. Hence, limit that to
+     * 1 thread per partition.
+     *
+     * These numbers were derived by monitoring the memory and CPU pressure
+     * (/proc/pressure/{cpu,memory}; and monitoring the Inactive(file) and
+     * Active(file) pages from /proc/meminfo.
+     *
+     * Additionally, for low memory devices, it is advisible to use O_DIRECT
+     * fucntionality for source block device.
+     */
     int kMinThreadsToVerify = 1;
-    int kMaxThreadsToVerify = 4;
-    uint64_t kThresholdSize = 512_MiB;
-    uint64_t kBlockSizeVerify = 1_MiB;
+    int kMaxThreadsToVerify = 3;
+    uint64_t kThresholdSize = 750_MiB;
+    uint64_t kBlockSizeVerify = 2_MiB;
 
     bool IsBlockAligned(uint64_t read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
     void UpdatePartitionVerificationState(UpdateVerifyState state);
diff --git a/init/service_test.cpp b/init/service_test.cpp
index c81b007..a3590b5 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -236,6 +236,11 @@
 // Service::Stop() if their uid_%d/pid_%d cgroup directory got removed. This test, if run with the
 // parameter set to 'true', verifies that such services are stopped.
 TEST_P(ServiceStopTest, stop) {
+    if (getuid() != 0) {
+        GTEST_SKIP() << "Must be run as root.";
+        return;
+    }
+
     static constexpr std::string_view kServiceName = "ServiceA";
     static constexpr std::string_view kScriptTemplate = R"init(
 service $name /system/bin/yes
diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json
index 2c08b0b..f2ef316 100644
--- a/libprocessgroup/profiles/task_profiles.json
+++ b/libprocessgroup/profiles/task_profiles.json
@@ -91,6 +91,11 @@
       "Name": "CfqWeight",
       "Controller": "io",
       "File": "io.weight"
+    },
+    {
+      "Name": "IoPrioClass",
+      "Controller": "io",
+      "File": "io.prio.class"
     }
   ],
 
@@ -479,6 +484,15 @@
             "Value": "200",
             "Optional": "true"
           }
+        },
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "IoPrioClass",
+            "Value": "restrict-to-be",
+            "Optional": "true"
+          }
         }
       ]
     },
@@ -511,6 +525,15 @@
             "Value": "1000",
             "Optional": "true"
           }
+        },
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "IoPrioClass",
+            "Value": "restrict-to-be",
+            "Optional": "true"
+          }
         }
       ]
     },
@@ -543,6 +566,15 @@
             "Value": "1000",
             "Optional": "true"
           }
+        },
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "IoPrioClass",
+            "Value": "promote-to-rt",
+            "Optional": "true"
+          }
         }
       ]
     },
@@ -575,6 +607,15 @@
             "Value": "1000",
             "Optional": "true"
           }
+        },
+        {
+          "Name": "SetAttribute",
+          "Params":
+          {
+            "Name": "IoPrioClass",
+            "Value": "promote-to-rt",
+            "Optional": "true"
+          }
         }
       ]
     },
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index cc6b64a..7deb173 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -72,6 +72,11 @@
   endif
 endif
 
+EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE :=
+ifneq ($(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE),)
+  EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE := export SCUDO_ALLOCATION_RING_BUFFER_SIZE $(PRODUCT_SCUDO_ALLOCATION_RING_BUFFER_SIZE)
+endif
+
 EXPORT_GLOBAL_GCOV_OPTIONS :=
 ifeq ($(NATIVE_COVERAGE),true)
   EXPORT_GLOBAL_GCOV_OPTIONS := export GCOV_PREFIX /data/misc/trace
@@ -216,6 +221,7 @@
 	$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
 	$(hide) sed -i -e 's?%EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%?$(EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS)?g' $@
 	$(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
+	$(hide) sed -i -e 's?%EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE%?$(EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE)?g' $@
 
 # Append PLATFORM_VNDK_VERSION to base name.
 define append_vndk_version
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index bf6e986..7ba1f46 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -14,3 +14,4 @@
     %EXPORT_GLOBAL_GCOV_OPTIONS%
     %EXPORT_GLOBAL_CLANG_COVERAGE_OPTIONS%
     %EXPORT_GLOBAL_HWASAN_OPTIONS%
+    %EXPORT_GLOBAL_SCUDO_ALLOCATION_RING_BUFFER_SIZE%