Merge "libsnapshot: fix -Wdefaulted-function-delete warnings."
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad0231d..c15146b 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -204,6 +204,7 @@
     header_libs: [
         "bionic_libc_platform_headers",
         "gwp_asan_headers",
+        "liblog_headers",
     ],
 
     static_libs: [
@@ -212,7 +213,6 @@
         "liblzma",
         "libbase",
         "libcutils",
-        "liblog",
     ],
     runtime_libs: [
         "libdexfile",           // libdexfile_support dependency
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 26e6e00..b478e6e 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -154,6 +154,7 @@
         "device/flashing.cpp",
         "device/main.cpp",
         "device/usb.cpp",
+        "device/usb_iouring.cpp",
         "device/usb_client.cpp",
         "device/tcp_client.cpp",
         "device/utility.cpp",
@@ -195,7 +196,9 @@
         "liblz4",
         "libsnapshot_nobinder",
         "update_metadata-protos",
+        "liburing",
     ],
+    include_dirs: ["bionic/libc/kernel"],
 
     header_libs: [
         "avb_headers",
@@ -346,9 +349,7 @@
     target: {
         not_windows: {
             required: [
-                "e2fsdroid",
                 "mke2fs.conf",
-                "sload_f2fs",
             ],
         },
         windows: {
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 10bed6d..cde0cb2 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -19,9 +19,7 @@
 #
 
 my_dist_files := $(HOST_OUT_EXECUTABLES)/mke2fs
-my_dist_files += $(HOST_OUT_EXECUTABLES)/e2fsdroid
 my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs
 my_dist_files += $(HOST_OUT_EXECUTABLES)/make_f2fs_casefold
-my_dist_files += $(HOST_OUT_EXECUTABLES)/sload_f2fs
 $(call dist-for-goals,dist_files sdk,$(my_dist_files))
 my_dist_files :=
diff --git a/fastboot/device/usb.cpp b/fastboot/device/usb.cpp
index 4115a6d..b77d772 100644
--- a/fastboot/device/usb.cpp
+++ b/fastboot/device/usb.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "usb.h"
+#include "usb_iouring.h"
 
 #include <dirent.h>
 #include <errno.h>
@@ -28,6 +29,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/functionfs.h>
+#include <sys/utsname.h>
 
 #include <algorithm>
 #include <atomic>
@@ -38,6 +40,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
+#include <liburing.h>
 
 using namespace std::chrono_literals;
 
@@ -65,8 +68,8 @@
     }
 }
 
-static int getMaxPacketSize(int ffs_fd) {
-    usb_endpoint_descriptor desc;
+int getMaxPacketSize(int ffs_fd) {
+    usb_endpoint_descriptor desc{};
     if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
         D("[ could not get endpoint descriptor! (%d) ]", errno);
         return MAX_PACKET_SIZE_HS;
@@ -128,11 +131,9 @@
 
 static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
     aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
-    bool zero_packet = false;
 
     int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
     const char* cur_data = reinterpret_cast<const char*>(data);
-    int packet_size = getMaxPacketSize(aiob->fd);
 
     if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
         0) {
@@ -145,17 +146,6 @@
 
         len -= buf_len;
         cur_data += buf_len;
-
-        if (len == 0 && buf_len % packet_size == 0 && read) {
-            // adb does not expect the device to send a zero packet after data transfer,
-            // but the host *does* send a zero packet for the device to read.
-            zero_packet = h->reads_zero_packets;
-        }
-    }
-    if (zero_packet) {
-        io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
-                packet_size, 0, read);
-        num_bufs += 1;
     }
 
     while (true) {
@@ -204,21 +194,46 @@
     h->open_new_connection = true;
     h->lock.unlock();
     h->notify.notify_one();
+    if (h->aio_type == AIOType::IO_URING) {
+        exit_io_uring_ffs(h);
+    }
 }
 
-usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size) {
-    usb_handle* h = new usb_handle();
+bool DoesKernelSupportIouring() {
+    struct utsname uts {};
+    unsigned int major = 0, minor = 0;
+    if ((uname(&uts) != 0) || (sscanf(uts.release, "%u.%u", &major, &minor) != 2)) {
+        return false;
+    }
+    if (major > 5) {
+        return true;
+    }
+    // We will only support kernels from 5.6 onwards as IOSQE_ASYNC flag and
+    // IO_URING_OP_READ/WRITE opcodes were introduced only on 5.6 kernel
+    return minor >= 6;
+}
 
-    if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
+std::unique_ptr<usb_handle> create_usb_handle(unsigned num_bufs, unsigned io_size) {
+    auto h = std::make_unique<usb_handle>();
+    if (DoesKernelSupportIouring() &&
+        android::base::GetBoolProperty("sys.usb.ffs.io_uring_enabled", false)) {
+        init_io_uring_ffs(h.get(), num_bufs);
+        h->aio_type = AIOType::IO_URING;
+        LOG(INFO) << "Using io_uring for usb ffs";
+    } else if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
         // Devices on older kernels (< 3.18) will not have aio support for ffs
         // unless backported. Fall back on the non-aio functions instead.
         h->write = usb_ffs_write;
         h->read = usb_ffs_read;
+        h->aio_type = AIOType::SYNC_IO;
+        LOG(INFO) << "Using sync io for usb ffs";
     } else {
         h->write = usb_ffs_aio_write;
         h->read = usb_ffs_aio_read;
         aio_block_init(&h->read_aiob, num_bufs);
         aio_block_init(&h->write_aiob, num_bufs);
+        h->aio_type = AIOType::AIO;
+        LOG(INFO) << "Using aio for usb ffs";
     }
     h->io_size = io_size;
     h->close = usb_ffs_close;
diff --git a/fastboot/device/usb.h b/fastboot/device/usb.h
index 6c3f542..8996c31 100644
--- a/fastboot/device/usb.h
+++ b/fastboot/device/usb.h
@@ -18,8 +18,10 @@
 
 #include <linux/usb/functionfs.h>
 
+#include <liburing.h>
 #include <atomic>
 #include <condition_variable>
+#include <memory>
 #include <mutex>
 #include <vector>
 
@@ -35,9 +37,11 @@
     int fd;
 };
 
-struct usb_handle {
-    usb_handle() {}
+int getMaxPacketSize(int ffs_fd);
 
+enum class AIOType { SYNC_IO, AIO, IO_URING };
+
+struct usb_handle {
     std::condition_variable notify;
     std::mutex lock;
     bool open_new_connection = true;
@@ -56,8 +60,9 @@
     struct aio_block read_aiob;
     struct aio_block write_aiob;
 
-    bool reads_zero_packets;
+    io_uring ring;
     size_t io_size;
+    AIOType aio_type;
 };
 
-usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size);
+std::unique_ptr<usb_handle> create_usb_handle(unsigned num_bufs, unsigned io_size);
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 3f9b0f0..d1b38d4 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -232,7 +232,6 @@
 
     h->read_aiob.fd = h->bulk_out.get();
     h->write_aiob.fd = h->bulk_in.get();
-    h->reads_zero_packets = false;
     return true;
 
 err:
diff --git a/fastboot/device/usb_iouring.cpp b/fastboot/device/usb_iouring.cpp
new file mode 100644
index 0000000..d987712
--- /dev/null
+++ b/fastboot/device/usb_iouring.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 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 <android-base/logging.h>
+#include <liburing.h>
+#include "liburing/io_uring.h"
+#include "usb.h"
+
+static int prep_async_read(struct io_uring* ring, int fd, void* data, size_t len, int64_t offset) {
+    if (io_uring_sq_space_left(ring) <= 0) {
+        LOG(ERROR) << "Submission queue run out of space.";
+        return -1;
+    }
+    auto sqe = io_uring_get_sqe(ring);
+    if (sqe == nullptr) {
+        return -1;
+    }
+    io_uring_sqe_set_flags(sqe, IOSQE_IO_LINK | IOSQE_ASYNC);
+    io_uring_prep_read(sqe, fd, data, len, offset);
+    return 0;
+}
+
+static int prep_async_write(struct io_uring* ring, int fd, const void* data, size_t len,
+                            int64_t offset) {
+    if (io_uring_sq_space_left(ring) <= 0) {
+        LOG(ERROR) << "Submission queue run out of space.";
+        return -1;
+    }
+    auto sqe = io_uring_get_sqe(ring);
+    if (sqe == nullptr) {
+        return -1;
+    }
+    io_uring_sqe_set_flags(sqe, IOSQE_IO_LINK | IOSQE_ASYNC);
+    io_uring_prep_write(sqe, fd, data, len, offset);
+    return 0;
+}
+
+template <bool read, typename T>
+int prep_async_io(struct io_uring* ring, int fd, T* data, size_t len, int64_t offset) {
+    if constexpr (read) {
+        return prep_async_read(ring, fd, data, len, offset);
+    } else {
+        return prep_async_write(ring, fd, data, len, offset);
+    }
+}
+
+template <typename T>
+static constexpr T DivRoundup(T x, T y) {
+    return (x + y - 1) / y;
+}
+
+extern int getMaxPacketSize(int ffs_fd);
+
+template <bool read, typename T>
+static int usb_ffs_do_aio(usb_handle* h, T* const data, const int len) {
+    const aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
+    const int num_requests = DivRoundup<int>(len, h->io_size);
+    auto cur_data = data;
+    const auto packet_size = getMaxPacketSize(aiob->fd);
+
+    for (int bytes_remain = len; bytes_remain > 0;) {
+        const int buf_len = std::min(bytes_remain, static_cast<int>(h->io_size));
+        const auto ret = prep_async_io<read>(&h->ring, aiob->fd, cur_data, buf_len, 0);
+        if (ret < 0) {
+            PLOG(ERROR) << "Failed to queue io_uring request";
+            return -1;
+        }
+
+        bytes_remain -= buf_len;
+        cur_data = reinterpret_cast<T*>(reinterpret_cast<size_t>(cur_data) + buf_len);
+    }
+    const int ret = io_uring_submit(&h->ring);
+    if (ret <= 0 || ret != num_requests) {
+        PLOG(ERROR) << "io_uring: failed to submit SQE entries to kernel";
+        return -1;
+    }
+    int res = 0;
+    bool success = true;
+    for (int i = 0; i < num_requests; ++i) {
+        struct io_uring_cqe* cqe{};
+        const auto ret = TEMP_FAILURE_RETRY(io_uring_wait_cqe(&h->ring, &cqe));
+        if (ret < 0 || cqe == nullptr) {
+            PLOG(ERROR) << "Failed to get CQE from kernel";
+            success = false;
+            continue;
+        }
+        res += cqe->res;
+        if (cqe->res < 0) {
+            LOG(ERROR) << "io_uring request failed:, i = " << i
+                       << ", num_requests = " << num_requests << ", res = " << cqe->res << ": "
+                       << strerror(cqe->res) << (read ? " read" : " write")
+                       << " request size: " << len << ", io_size: " << h->io_size
+                       << " max packet size: " << packet_size << ", fd: " << aiob->fd;
+            success = false;
+            errno = -cqe->res;
+        }
+        io_uring_cqe_seen(&h->ring, cqe);
+    }
+    if (!success) {
+        return -1;
+    }
+    return res;
+}
+
+static int usb_ffs_io_uring_read(usb_handle* h, void* data, int len, bool /* allow_partial */) {
+    return usb_ffs_do_aio<true>(h, data, len);
+}
+
+static int usb_ffs_io_uring_write(usb_handle* h, const void* data, int len) {
+    return usb_ffs_do_aio<false>(h, data, len);
+}
+
+void exit_io_uring_ffs(usb_handle* h) {
+    io_uring_queue_exit(&h->ring);
+}
+
+bool init_io_uring_ffs(usb_handle* h, size_t queue_depth) {
+    const auto err = io_uring_queue_init(queue_depth, &h->ring, 0);
+    if (err) {
+        LOG(ERROR) << "Failed to initialize io_uring of depth " << queue_depth << ": "
+                   << strerror(err);
+        return false;
+    }
+    h->write = usb_ffs_io_uring_write;
+    h->read = usb_ffs_io_uring_read;
+    return true;
+}
diff --git a/fastboot/device/usb_iouring.h b/fastboot/device/usb_iouring.h
new file mode 100644
index 0000000..7c14b81
--- /dev/null
+++ b/fastboot/device/usb_iouring.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 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 "usb.h"
+
+bool init_io_uring_ffs(usb_handle* h, size_t queue_depth);
+
+void exit_io_uring_ffs(usb_handle* h);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index c0e3161..1f54f5b 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -889,7 +889,7 @@
 // attempted_idx: On return, will indicate which fstab entry
 //     succeeded. In case of failure, it will be the start_idx.
 // Sets errno to match the 1st mount failure on failure.
-static bool mount_with_alternatives(const Fstab& fstab, int start_idx, int* end_idx,
+static bool mount_with_alternatives(Fstab& fstab, int start_idx, int* end_idx,
                                     int* attempted_idx) {
     unsigned long i;
     int mount_errno = 0;
@@ -909,6 +909,14 @@
             continue;
         }
 
+        // fstab[start_idx].blk_device is already updated to /dev/dm-<N> by
+        // AVB related functions. Copy it from start_idx to the current index i.
+        if ((i != start_idx) && fstab[i].fs_mgr_flags.logical &&
+            fstab[start_idx].fs_mgr_flags.logical &&
+            (fstab[i].logical_partition_name == fstab[start_idx].logical_partition_name)) {
+            fstab[i].blk_device = fstab[start_idx].blk_device;
+        }
+
         int fs_stat = prepare_fs_for_mount(fstab[i].blk_device, fstab[i]);
         if (fs_stat & FS_STAT_INVALID_MAGIC) {
             LERROR << __FUNCTION__
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index b1606d9..354d02a 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -81,6 +81,9 @@
     return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
 }
 
+const auto kLowerdirOption = "lowerdir="s;
+const auto kUpperdirOption = "upperdir="s;
+
 }  // namespace
 
 #if ALLOW_ADBD_DISABLE_VERITY == 0  // If we are a user build, provide stubs
@@ -97,7 +100,7 @@
     return false;
 }
 
-bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) {
+bool fs_mgr_overlayfs_setup(const char*, bool* change, bool) {
     if (change) *change = false;
     return false;
 }
@@ -328,9 +331,6 @@
     return "";
 }
 
-const auto kLowerdirOption = "lowerdir="s;
-const auto kUpperdirOption = "upperdir="s;
-
 static inline bool KernelSupportsUserXattrs() {
     struct utsname uts;
     uname(&uts);
@@ -370,28 +370,6 @@
     return ret;
 }
 
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) {
-    Fstab fstab;
-    auto save_errno = errno;
-    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
-        return false;
-    }
-    errno = save_errno;
-    const auto lowerdir = kLowerdirOption + mount_point;
-    for (const auto& entry : fstab) {
-        if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
-        if (mount_point != entry.mount_point) continue;
-        if (!overlay_only) return true;
-        const auto options = android::base::Split(entry.fs_options, ",");
-        for (const auto& opt : options) {
-            if (opt == lowerdir) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
-
 constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
 
 bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
@@ -1290,8 +1268,23 @@
 }
 
 Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
+    android::fs_mgr::Fstab mounts;
+    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+        PLOG(ERROR) << "Failed to read /proc/mounts";
+        return {};
+    }
+
     Fstab candidates;
     for (const auto& entry : fstab) {
+        // 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.
+        auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
+        auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
+        if (!mounted || mounted->fs_type != entry.fs_type) {
+            continue;
+        }
+
         FstabEntry new_entry = entry;
         if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
             !fs_mgr_wants_overlayfs(&new_entry)) {
@@ -1364,8 +1357,7 @@
 
 // Returns false if setup not permitted, errno set to last error.
 // If something is altered, set *change.
-bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change,
-                            bool force) {
+bool fs_mgr_overlayfs_setup(const char* mount_point, bool* change, bool force) {
     if (change) *change = false;
     auto ret = false;
     if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret;
@@ -1402,7 +1394,6 @@
 
     std::string dir;
     for (const auto& overlay_mount_point : OverlayMountPoints()) {
-        if (backing && backing[0] && (overlay_mount_point != backing)) continue;
         if (overlay_mount_point == kScratchMountPoint) {
             if (!fs_mgr_overlayfs_setup_scratch(fstab, change)) continue;
         } else {
@@ -1698,6 +1689,28 @@
 
 #endif  // ALLOW_ADBD_DISABLE_VERITY != 0
 
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
+    Fstab fstab;
+    auto save_errno = errno;
+    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+        return false;
+    }
+    errno = save_errno;
+    const auto lowerdir = kLowerdirOption + mount_point;
+    for (const auto& entry : fstab) {
+        if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
+        if (mount_point != entry.mount_point) continue;
+        if (!overlay_only) return true;
+        const auto options = android::base::Split(entry.fs_options, ",");
+        for (const auto& opt : options) {
+            if (opt == lowerdir) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
     struct statfs fs;
     if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index c47d110..4a927d0 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -91,12 +91,8 @@
     logd(id, severity, tag, file, line, message);
 }
 
-[[noreturn]] void reboot(bool overlayfs = false) {
-    if (overlayfs) {
-        LOG(INFO) << "Successfully setup overlayfs\nrebooting device";
-    } else {
-        LOG(INFO) << "Successfully disabled verity\nrebooting device";
-    }
+[[noreturn]] void reboot() {
+    LOG(INFO) << "Rebooting device for new settings to take effect";
     ::sync();
     android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,remount");
     ::sleep(60);
@@ -132,11 +128,9 @@
     BAD_OVERLAY,
     NO_MOUNTS,
     REMOUNT_FAILED,
-    MUST_REBOOT,
     BINDER_ERROR,
     CHECKPOINTING,
     GSID_ERROR,
-    CLEAN_SCRATCH_FILES,
 };
 
 static bool ReadFstab(const char* fstab_file, android::fs_mgr::Fstab* fstab) {
@@ -191,8 +185,8 @@
     if (entry.fs_type == "vfat") {
         return false;
     }
-    if (GetEntryForMountPoint(&candidates, entry.mount_point)) {
-        return true;
+    if (auto candidate_entry = GetEntryForMountPoint(&candidates, entry.mount_point)) {
+        return candidate_entry->fs_type == entry.fs_type;
     }
     if (GetWrappedEntry(candidates, entry)) {
         return false;
@@ -201,13 +195,22 @@
 }
 
 static Fstab::const_iterator FindPartition(const Fstab& fstab, const std::string& partition) {
+    Fstab mounts;
+    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+        LOG(ERROR) << "Failed to read /proc/mounts";
+        return fstab.end();
+    }
+
     for (auto iter = fstab.begin(); iter != fstab.end(); iter++) {
         const auto mount_point = system_mount_point(*iter);
-        if (partition == mount_point) {
-            return iter;
-        }
-        if (partition == android::base::Basename(mount_point)) {
-            return iter;
+        if (partition == mount_point || partition == android::base::Basename(mount_point)) {
+            // In case fstab has multiple entries, pick the one that matches the
+            // actual mounted filesystem type.
+            auto proc_mount_point = (iter->mount_point == "/system") ? "/" : iter->mount_point;
+            auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
+            if (mounted && mounted->fs_type == iter->fs_type) {
+                return iter;
+            }
         }
     }
     return fstab.end();
@@ -248,7 +251,10 @@
             entry = wrap;
         }
 
-        if (!IsRemountable(candidates, *entry)) {
+        // If it's already remounted, include it so it gets gracefully skipped
+        // later on.
+        if (!fs_mgr_overlayfs_already_mounted(entry->mount_point) &&
+            !IsRemountable(candidates, *entry)) {
             LOG(ERROR) << "Invalid partition " << arg;
             return INVALID_PARTITION;
         }
@@ -266,6 +272,7 @@
     bool setup_overlayfs = false;
     bool disabled_verity = false;
     bool verity_error = false;
+    bool remounted_anything = false;
 };
 
 static RemountStatus CheckVerity(const FstabEntry& entry, RemountCheckResult* result) {
@@ -312,7 +319,7 @@
         if (fs_mgr_wants_overlayfs(&entry)) {
             bool change = false;
             bool force = result->disabled_verity;
-            if (!fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, force)) {
+            if (!fs_mgr_overlayfs_setup(mount_point.c_str(), &change, force)) {
                 LOG(ERROR) << "Overlayfs setup for " << mount_point << " failed, skipping";
                 status = BAD_OVERLAY;
                 it = partitions->erase(it);
@@ -422,75 +429,8 @@
     return REMOUNT_FAILED;
 }
 
-static int do_remount(int argc, char* argv[]) {
-    // If somehow this executable is delivered on a "user" build, it can
-    // not function, so providing a clear message to the caller rather than
-    // letting if fall through and provide a lot of confusing failure messages.
-    if (!ALLOW_ADBD_DISABLE_VERITY || (android::base::GetProperty("ro.debuggable", "0") != "1")) {
-        LOG(ERROR) << "only functions on userdebug or eng builds";
-        return NOT_USERDEBUG;
-    }
-
-    const char* fstab_file = nullptr;
-    auto can_reboot = false;
-    std::vector<std::string> partition_args;
-
-    struct option longopts[] = {
-            {"fstab", required_argument, nullptr, 'T'},
-            {"help", no_argument, nullptr, 'h'},
-            {"reboot", no_argument, nullptr, 'R'},
-            {"verbose", no_argument, nullptr, 'v'},
-            {"clean_scratch_files", no_argument, nullptr, 'C'},
-            {0, 0, nullptr, 0},
-    };
-    for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
-        switch (opt) {
-            case 'h':
-                usage(SUCCESS);
-                break;
-            case 'R':
-                can_reboot = true;
-                break;
-            case 'T':
-                if (fstab_file) {
-                    LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
-                    usage(BADARG);
-                }
-                fstab_file = optarg;
-                break;
-            case 'v':
-                verbose = true;
-                break;
-            case 'C':
-                return CLEAN_SCRATCH_FILES;
-            default:
-                LOG(ERROR) << "Bad Argument -" << char(opt);
-                usage(BADARG);
-                break;
-        }
-    }
-
-    for (; argc > optind; ++optind) {
-        partition_args.emplace_back(argv[optind]);
-    }
-
-    // Make sure we are root.
-    if (::getuid() != 0) {
-        LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
-        return NOT_ROOT;
-    }
-
-    // Read the selected fstab.
-    Fstab fstab;
-    if (!ReadFstab(fstab_file, &fstab) || fstab.empty()) {
-        PLOG(ERROR) << "Failed to read fstab";
-        return NO_FSTAB;
-    }
-
-    if (auto rv = VerifyCheckpointing(); rv != REMOUNT_SUCCESS) {
-        return rv;
-    }
-
+static int do_remount(Fstab& fstab, const std::vector<std::string>& partition_args,
+                      RemountCheckResult* check_result) {
     Fstab partitions;
     if (partition_args.empty()) {
         partitions = GetAllRemountablePartitions(fstab);
@@ -501,29 +441,12 @@
     }
 
     // Check verity and optionally setup overlayfs backing.
-    RemountCheckResult check_result;
-    auto retval = CheckVerityAndOverlayfs(&partitions, &check_result);
+    auto retval = CheckVerityAndOverlayfs(&partitions, check_result);
 
-    bool auto_reboot = check_result.reboot_later && can_reboot;
-
-    // If (1) remount requires a reboot to take effect, (2) system is currently
-    // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
-    // next reboot would not take us back to the host system but stay within
-    // the guest system.
-    if (auto_reboot) {
-        if (auto rv = EnableDsuIfNeeded(); rv != REMOUNT_SUCCESS) {
-            return rv;
+    if (partitions.empty() || check_result->disabled_verity) {
+        if (partitions.empty()) {
+            LOG(WARNING) << "No remountable partitions were found.";
         }
-    }
-
-    if (partitions.empty() || check_result.disabled_verity) {
-        if (auto_reboot) {
-            reboot(check_result.setup_overlayfs);
-        }
-        if (check_result.reboot_later) {
-            return MUST_REBOOT;
-        }
-        LOG(WARNING) << "No partitions to remount";
         return retval;
     }
 
@@ -545,34 +468,118 @@
     for (auto& entry : partitions) {
         if (auto rv = RemountPartition(fstab, mounts, entry); rv != REMOUNT_SUCCESS) {
             retval = rv;
+        } else {
+            check_result->remounted_anything = true;
         }
     }
-
-    if (auto_reboot) reboot(check_result.setup_overlayfs);
-    if (check_result.reboot_later) {
-        LOG(INFO) << "Now reboot your device for settings to take effect";
-    }
     return retval;
 }
 
-static int do_clean_scratch_files() {
-    android::fs_mgr::CleanupOldScratchFiles();
-    return 0;
-}
-
 int main(int argc, char* argv[]) {
-    android::base::InitLogging(argv, MyLogger);
+    // Do not use MyLogger() when running as clean_scratch_files, as stdout/stderr of daemon process
+    // are discarded.
     if (argc > 0 && android::base::Basename(argv[0]) == "clean_scratch_files"s) {
-        return do_clean_scratch_files();
+        android::fs_mgr::CleanupOldScratchFiles();
+        return 0;
     }
-    int result = do_remount(argc, argv);
-    if (result == MUST_REBOOT) {
-        LOG(INFO) << "Now reboot your device for settings to take effect";
-        result = 0;
-    } else if (result == REMOUNT_SUCCESS) {
+
+    android::base::InitLogging(argv, MyLogger);
+
+    // Make sure we are root.
+    if (::getuid() != 0) {
+        LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
+        return NOT_ROOT;
+    }
+
+    // If somehow this executable is delivered on a "user" build, it can
+    // not function, so providing a clear message to the caller rather than
+    // letting if fall through and provide a lot of confusing failure messages.
+    if (!ALLOW_ADBD_DISABLE_VERITY || (android::base::GetProperty("ro.debuggable", "0") != "1")) {
+        LOG(ERROR) << "only functions on userdebug or eng builds";
+        return NOT_USERDEBUG;
+    }
+
+    const char* fstab_file = nullptr;
+    auto auto_reboot = false;
+    std::vector<std::string> partition_args;
+
+    struct option longopts[] = {
+            {"fstab", required_argument, nullptr, 'T'},
+            {"help", no_argument, nullptr, 'h'},
+            {"reboot", no_argument, nullptr, 'R'},
+            {"verbose", no_argument, nullptr, 'v'},
+            {0, 0, nullptr, 0},
+    };
+    for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
+        switch (opt) {
+            case 'h':
+                usage(SUCCESS);
+                break;
+            case 'R':
+                auto_reboot = true;
+                break;
+            case 'T':
+                if (fstab_file) {
+                    LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
+                    usage(BADARG);
+                }
+                fstab_file = optarg;
+                break;
+            case 'v':
+                verbose = true;
+                break;
+            default:
+                LOG(ERROR) << "Bad Argument -" << char(opt);
+                usage(BADARG);
+                break;
+        }
+    }
+
+    for (; argc > optind; ++optind) {
+        partition_args.emplace_back(argv[optind]);
+    }
+
+    // Make sure checkpointing is disabled if necessary.
+    if (auto rv = VerifyCheckpointing(); rv != REMOUNT_SUCCESS) {
+        return rv;
+    }
+
+    // Read the selected fstab.
+    Fstab fstab;
+    if (!ReadFstab(fstab_file, &fstab) || fstab.empty()) {
+        PLOG(ERROR) << "Failed to read fstab";
+        return NO_FSTAB;
+    }
+
+    RemountCheckResult check_result;
+    int result = do_remount(fstab, partition_args, &check_result);
+
+    if (check_result.disabled_verity && check_result.setup_overlayfs) {
+        LOG(INFO) << "Verity disabled; overlayfs enabled.";
+    } else if (check_result.disabled_verity) {
+        LOG(INFO) << "Verity disabled.";
+    } else if (check_result.setup_overlayfs) {
+        LOG(INFO) << "Overlayfs enabled.";
+    }
+
+    if (check_result.reboot_later) {
+        if (auto_reboot) {
+            // If (1) remount requires a reboot to take effect, (2) system is currently
+            // running a DSU guest and (3) DSU is disabled, then enable DSU so that the
+            // next reboot would not take us back to the host system but stay within
+            // the guest system.
+            if (auto rv = EnableDsuIfNeeded(); rv != REMOUNT_SUCCESS) {
+                LOG(ERROR) << "Unable to automatically enable DSU";
+                return rv;
+            }
+            reboot();
+        } else {
+            LOG(INFO) << "Now reboot your device for settings to take effect";
+        }
+        return REMOUNT_SUCCESS;
+    }
+    if (result == REMOUNT_SUCCESS) {
         printf("remount succeeded\n");
-    } else if (result == CLEAN_SCRATCH_FILES) {
-        return do_clean_scratch_files();
     } else {
         printf("remount failed\n");
     }
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 21d7cd9..ec1d78f 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -28,11 +28,12 @@
 
 bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
 bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab);
-bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
-                            bool* change = nullptr, bool force = true);
+bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* change = nullptr,
+                            bool force = true);
 bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);
 bool fs_mgr_overlayfs_is_setup();
 bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev);
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
 std::string fs_mgr_get_context(const std::string& mount_point);
 
 enum class OverlayfsValidResult {
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index c8a0249..45be191 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -34,12 +34,13 @@
 namespace android {
 namespace snapshot {
 
-CowReader::CowReader(ReaderFlags reader_flag)
+CowReader::CowReader(ReaderFlags reader_flag, bool is_merge)
     : fd_(-1),
       header_(),
       fd_size_(0),
       block_pos_index_(std::make_shared<std::vector<int>>()),
-      reader_flag_(reader_flag) {}
+      reader_flag_(reader_flag),
+      is_merge_(is_merge) {}
 
 static void SHA256(const void*, size_t, uint8_t[]) {
 #if 0
@@ -64,6 +65,7 @@
     cow->has_seq_ops_ = has_seq_ops_;
     cow->data_loc_ = data_loc_;
     cow->block_pos_index_ = block_pos_index_;
+    cow->is_merge_ = is_merge_;
     return cow;
 }
 
@@ -476,15 +478,28 @@
 
     merge_op_blocks->insert(merge_op_blocks->end(), other_ops.begin(), other_ops.end());
 
-    for (auto block : *merge_op_blocks) {
-        block_pos_index_->push_back(block_map->at(block));
-    }
-
     num_total_data_ops_ = merge_op_blocks->size();
     if (header_.num_merge_ops > 0) {
         merge_op_start_ = header_.num_merge_ops;
     }
 
+    if (is_merge_) {
+        // Metadata ops are not required for merge. Thus, just re-arrange
+        // the ops vector as required for merge operations.
+        auto merge_ops_buffer = std::make_shared<std::vector<CowOperation>>();
+        merge_ops_buffer->reserve(num_total_data_ops_);
+        for (auto block : *merge_op_blocks) {
+            merge_ops_buffer->emplace_back(ops_->data()[block_map->at(block)]);
+        }
+        ops_->clear();
+        ops_ = merge_ops_buffer;
+        ops_->shrink_to_fit();
+    } else {
+        for (auto block : *merge_op_blocks) {
+            block_pos_index_->push_back(block_map->at(block));
+        }
+    }
+
     block_map->clear();
     merge_op_blocks->clear();
 
@@ -548,7 +563,7 @@
 
 class CowOpIter final : public ICowOpIter {
   public:
-    CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops);
+    CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start);
 
     bool Done() override;
     const CowOperation& Get() override;
@@ -562,9 +577,9 @@
     std::vector<CowOperation>::iterator op_iter_;
 };
 
-CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops) {
+CowOpIter::CowOpIter(std::shared_ptr<std::vector<CowOperation>>& ops, uint64_t start) {
     ops_ = ops;
-    op_iter_ = ops_->begin();
+    op_iter_ = ops_->begin() + start;
 }
 
 bool CowOpIter::RDone() {
@@ -691,8 +706,8 @@
     return ops_->data()[*block_riter_];
 }
 
-std::unique_ptr<ICowOpIter> CowReader::GetOpIter() {
-    return std::make_unique<CowOpIter>(ops_);
+std::unique_ptr<ICowOpIter> CowReader::GetOpIter(bool merge_progress) {
+    return std::make_unique<CowOpIter>(ops_, merge_progress ? merge_op_start_ : 0);
 }
 
 std::unique_ptr<ICowOpIter> CowReader::GetRevMergeOpIter(bool ignore_progress) {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index fbdd6b9..e8e4d72 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -74,7 +74,7 @@
     virtual bool GetLastLabel(uint64_t* label) = 0;
 
     // Return an iterator for retrieving CowOperation entries.
-    virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
+    virtual std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress) = 0;
 
     // Return an iterator for retrieving CowOperation entries in reverse merge order
     virtual std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress) = 0;
@@ -115,7 +115,7 @@
         USERSPACE_MERGE = 1,
     };
 
-    CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT);
+    CowReader(ReaderFlags reader_flag = ReaderFlags::DEFAULT, bool is_merge = false);
     ~CowReader() { owned_fd_ = {}; }
 
     // Parse the COW, optionally, up to the given label. If no label is
@@ -135,7 +135,7 @@
     // CowOperation objects. Get() returns a unique CowOperation object
     // whose lifetime depends on the CowOpIter object; the return
     // value of these will never be null.
-    std::unique_ptr<ICowOpIter> GetOpIter() override;
+    std::unique_ptr<ICowOpIter> GetOpIter(bool merge_progress = false) override;
     std::unique_ptr<ICowOpIter> GetRevMergeOpIter(bool ignore_progress = false) override;
     std::unique_ptr<ICowOpIter> GetMergeOpIter(bool ignore_progress = false) override;
 
@@ -177,6 +177,7 @@
     bool has_seq_ops_{};
     std::shared_ptr<std::unordered_map<uint64_t, uint64_t>> data_loc_;
     ReaderFlags reader_flag_;
+    bool is_merge_{};
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 91f31b0..2233a38 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -349,7 +349,7 @@
     }
 
     AssertionResult DeleteDevice(const std::string& device) {
-        if (!dm_.DeleteDeviceIfExists(device)) {
+        if (!sm->DeleteDeviceIfExists(device, 1s)) {
             return AssertionFailure() << "Can't delete " << device;
         }
         return AssertionSuccess();
@@ -2660,7 +2660,6 @@
     }
     void TearDown() override {
         RETURN_IF_NON_VIRTUAL_AB();
-        return;  // BUG(149738928)
 
         EXPECT_TRUE(!image_manager_->BackingImageExists(kImageName) ||
                     image_manager_->DeleteBackingImage(kImageName));
@@ -2669,19 +2668,6 @@
     std::unique_ptr<LowSpaceUserdata> userdata_;
 };
 
-TEST_P(ImageManagerTest, CreateImageEnoughAvailSpace) {
-    if (userdata_->available_space() == 0) {
-        GTEST_SKIP() << "/data is full (" << userdata_->available_space()
-                     << " bytes available), skipping";
-    }
-    ASSERT_TRUE(image_manager_->CreateBackingImage(kImageName, userdata_->available_space(),
-                                                   IImageManager::CREATE_IMAGE_DEFAULT))
-            << "Should be able to create image with size = " << userdata_->available_space()
-            << " bytes";
-    ASSERT_TRUE(image_manager_->DeleteBackingImage(kImageName))
-            << "Should be able to delete created image";
-}
-
 TEST_P(ImageManagerTest, CreateImageNoSpace) {
     uint64_t to_allocate = userdata_->free_space() + userdata_->bsize();
     auto res = image_manager_->CreateBackingImage(kImageName, to_allocate,
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 8939b78..492c43f 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -162,7 +162,7 @@
 }
 
 bool SnapshotHandler::ReadMetadata() {
-    reader_ = std::make_unique<CowReader>(CowReader::ReaderFlags::USERSPACE_MERGE);
+    reader_ = std::make_unique<CowReader>(CowReader::ReaderFlags::USERSPACE_MERGE, true);
     CowHeader header;
     CowOptions options;
 
@@ -193,7 +193,7 @@
     UpdateMergeCompletionPercentage();
 
     // Initialize the iterator for reading metadata
-    std::unique_ptr<ICowOpIter> cowop_iter = reader_->GetMergeOpIter();
+    std::unique_ptr<ICowOpIter> cowop_iter = reader_->GetOpIter(true);
 
     int num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ);
     int ra_index = 0;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
index 63f47d6..d57f434 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -466,7 +466,7 @@
 }
 
 bool Worker::Merge() {
-    cowop_iter_ = reader_->GetMergeOpIter();
+    cowop_iter_ = reader_->GetOpIter(true);
 
     bool retry = false;
     bool ordered_ops_merge_status;
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 b9e4255..fbe57d2 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -772,7 +772,7 @@
 }
 
 void ReadAhead::InitializeRAIter() {
-    cowop_iter_ = reader_->GetMergeOpIter();
+    cowop_iter_ = reader_->GetOpIter(true);
 }
 
 bool ReadAhead::RAIterDone() {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index 9542bc1..11e4790 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1099,8 +1099,8 @@
   D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` &&
   echo "${H}" &&
   echo "${D}" &&
-  echo "${YELLOW}[  WARNING ]${NORMAL} overlays present before setup" >&2 ||
-  echo "${GREEN}[       OK ]${NORMAL} no overlay present before setup" >&2
+  die "overlay takeover unexpected at this phase"
+echo "${GREEN}[       OK ]${NORMAL} no overlay present before setup" >&2
 overlayfs_needed=true
 D=`adb_sh cat /proc/mounts </dev/null |
    skip_administrative_mounts data`
@@ -1133,73 +1133,38 @@
   die "need overlayfs, but do not have it"
 fi
 
-echo "${GREEN}[ RUN      ]${NORMAL} disable verity" >&2
+echo "${GREEN}[ RUN      ]${NORMAL} disable-verity -R" >&2
 
-T=`adb_date`
-H=`adb disable-verity 2>&1`
-err=${?}
 L=
-D="${H%?Now reboot your device for settings to take effect*}"
-if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
-  echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
+T=$(adb_date)
+H=$(adb_su disable-verity -R 2>&1)
+err="${?}"
+echo "${H}"
+
+if [ "${err}" != 0 ]; then
+  die -t "${T}" "disable-verity -R"
 fi
-if [ ${err} != 0 ]; then
-  echo "${H}"
-  ( [ -n "${L}" ] && echo "${L}" && false ) ||
-  die -t "${T}" "disable-verity"
+
+# Fuzzy search for a line that contains "overlay" and "fail". Informational only.
+if echo "${H}" | grep -i "overlay" | grep -iq "fail"; then
+  echo "${YELLOW}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
 fi
-rebooted=false
-if [ X"${D}" != X"${H}" ]; then
-  echo "${H}"
-  if [ X"${D}" != X"${D##*setup failed}" ]; then
-    echo "${YELLOW}[  WARNING ]${NORMAL} overlayfs setup whined" >&2
-  fi
-  D=`adb_sh df -k </dev/null` &&
-    H=`echo "${D}" | head -1` &&
-    D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
-    [ -z "${D}" ] ||
-    ( echo "${H}" && echo "${D}" && false ) ||
-    die -t ${T} "overlay takeover unexpected at this phase"
-  echo "${GREEN}[     INFO ]${NORMAL} rebooting as requested" >&2
-  L=`adb_logcat -b all -v nsec -t ${T} 2>&1`
-  adb_reboot &&
-    adb_wait ${ADB_WAIT} ||
-    die "lost device after reboot requested `usb_status`"
+
+adb_wait "${ADB_WAIT}" &&
   adb_root ||
-    die "lost device after elevation to root `usb_status`"
-  rebooted=true
-  # re-disable verity to see the setup remarks expected
-  T=`adb_date`
-  H=`adb disable-verity 2>&1`
-  err=${?}
-  D="${H%?Now reboot your device for settings to take effect*}"
-  if [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ]; then
-    echo "${GREEN}[       OK ]${NORMAL} using overlayfs" >&2
+  die "lost device after adb shell su root disable-verity -R $(usb_status)"
+
+if ${overlayfs_needed}; then
+  has_overlayfs_setup=false
+  for d in ${OVERLAYFS_BACKING}; do
+    if adb_test -d "/${d}/overlay"; then
+      has_overlayfs_setup=true
+      echo "${GREEN}[       OK ]${NORMAL} /${d}/overlay is setup" >&2
+    fi
+  done
+  if ! ${has_overlayfs_setup}; then
+    die "no overlay being setup after disable-verity -R"
   fi
-  if [ ${err} != 0 ]; then
-    T=
-  fi
-fi
-if ${overlayfs_supported} && ${overlayfs_needed} && [ X"${D}" != X"${D##*setup failed}" ]; then
-  echo "${D}"
-  ( [ -n "${L}" ] && echo "${L}" && false ) ||
-  die -t "${T}" "setup for overlay"
-fi
-if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then
-  echo "${H}"
-  D=`adb_sh df -k </dev/null` &&
-    H=`echo "${D}" | head -1` &&
-    D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay " || true` &&
-    [ -z "${D}" ] ||
-    ( echo "${H}" && echo "${D}" && false ) ||
-    ( [ -n "${L}" ] && echo "${L}" && false ) ||
-    die -t "${T}" "overlay takeover unexpected"
-  [ -n "${L}" ] && echo "${L}"
-  die -t "${T}" "unexpected report of verity being disabled a second time"
-elif ${rebooted}; then
-  echo "${GREEN}[       OK ]${NORMAL} verity already disabled" >&2
-else
-  echo "${YELLOW}[  WARNING ]${NORMAL} verity already disabled" >&2
 fi
 
 echo "${GREEN}[ RUN      ]${NORMAL} remount" >&2
@@ -1319,26 +1284,9 @@
 B="`adb_cat /system/priv-app/hello`" ||
   die "system priv-app hello"
 check_eq "${A}" "${B}" /system/priv-app before reboot
-SYSTEM_DEVT=`adb_sh stat --format=%D /system/hello </dev/null`
-VENDOR_DEVT=`adb_sh stat --format=%D /vendor/hello </dev/null`
 SYSTEM_INO=`adb_sh stat --format=%i /system/hello </dev/null`
 VENDOR_INO=`adb_sh stat --format=%i /vendor/hello </dev/null`
-BASE_SYSTEM_DEVT=`adb_sh stat --format=%D /system/bin/stat </dev/null`
-BASE_VENDOR_DEVT=`adb_sh stat --format=%D /vendor/bin/stat </dev/null`
-check_eq "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" vendor and system devt
 check_ne "${SYSTEM_INO}" "${VENDOR_INO}" vendor and system inode
-if ${overlayfs_needed}; then
-  check_ne "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
-  check_ne "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
-else
-  check_eq "${SYSTEM_DEVT}" "${BASE_SYSTEM_DEVT}" system devt
-  check_eq "${VENDOR_DEVT}" "${BASE_VENDOR_DEVT}" vendor devt
-fi
-check_ne "${BASE_SYSTEM_DEVT}" "${BASE_VENDOR_DEVT}" --warning system/vendor devt
-[ -n "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
-  echo "${YELLOW}[  WARNING ]${NORMAL} system devt ${SYSTEM_DEVT} major 0" >&2
-[ -n "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
-  echo "${YELLOW}[  WARNING ]${NORMAL} vendor devt ${VENDOR_DEVT} major 0" >&2
 
 # Download libc.so, append some garbage, push back, and check if the file
 # is updated.
@@ -1411,13 +1359,8 @@
   echo "${GREEN}[       OK ]${NORMAL} ${i} content remains after reboot" >&2
 done
 
-check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
-check_eq "${VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/hello </dev/null`" vendor devt after reboot
 check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
 check_eq "${VENDOR_INO}" "`adb_sh stat --format=%i /vendor/hello </dev/null`" vendor inode after reboot
-check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" --warning base system devt after reboot
-check_eq "${BASE_VENDOR_DEVT}" "`adb_sh stat --format=%D /vendor/bin/stat </dev/null`" --warning base vendor devt after reboot
-check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" --warning devt for su after reboot
 
 # Feed log with selinux denials as a result of overlays
 adb_sh find ${MOUNTS} </dev/null >/dev/null 2>/dev/null || true
@@ -1542,10 +1485,7 @@
              --warning vendor content after flash vendor
   fi
 
-  check_eq "${SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/hello </dev/null`" system devt after reboot
   check_eq "${SYSTEM_INO}" "`adb_sh stat --format=%i /system/hello </dev/null`" system inode after reboot
-  check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/bin/stat </dev/null`" --warning base system devt after reboot
-  check_eq "${BASE_SYSTEM_DEVT}" "`adb_sh stat --format=%D /system/xbin/su </dev/null`" --warning devt for su after reboot
 
 fi
 
diff --git a/init/Android.bp b/init/Android.bp
index 2dd9683..856fe3e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -222,8 +222,8 @@
     ],
     whole_static_libs: [
         "libcap",
-        "com.android.sysprop.apex",
-        "com.android.sysprop.init",
+        "libcom.android.sysprop.apex",
+        "libcom.android.sysprop.init",
     ],
     header_libs: ["bootimg_headers"],
     proto: {
diff --git a/init/TEST_MAPPING b/init/TEST_MAPPING
index 36ca379..402b501 100644
--- a/init/TEST_MAPPING
+++ b/init/TEST_MAPPING
@@ -8,6 +8,14 @@
     },
     {
       "name": "MicrodroidHostTestCases"
+    },
+    {
+      "name": "CtsSecurityHostTestCases",
+      "options": [
+        {
+          "include-filter": "android.security.cts.SeamendcHostTest"
+        }
+      ]
     }
   ],
   "hwasan-presubmit": [
@@ -19,6 +27,14 @@
     },
     {
       "name": "MicrodroidHostTestCases"
+    },
+    {
+      "name": "CtsSecurityHostTestCases",
+      "options": [
+        {
+          "include-filter": "android.security.cts.SeamendcHostTest"
+        }
+      ]
     }
   ]
 }
diff --git a/init/epoll.cpp b/init/epoll.cpp
index 74d8aac..0580f86 100644
--- a/init/epoll.cpp
+++ b/init/epoll.cpp
@@ -23,6 +23,8 @@
 #include <functional>
 #include <map>
 
+#include <android-base/logging.h>
+
 namespace android {
 namespace init {
 
@@ -42,8 +44,11 @@
     if (!events) {
         return Error() << "Must specify events";
     }
-    auto sp = std::make_shared<decltype(handler)>(std::move(handler));
-    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(sp));
+
+    Info info;
+    info.events = events;
+    info.handler = std::make_shared<decltype(handler)>(std::move(handler));
+    auto [it, inserted] = epoll_handlers_.emplace(fd, std::move(info));
     if (!inserted) {
         return Error() << "Cannot specify two epoll handlers for a given FD";
     }
@@ -84,8 +89,14 @@
     }
     std::vector<std::shared_ptr<Handler>> pending_functions;
     for (int i = 0; i < num_events; ++i) {
-        auto sp = *reinterpret_cast<std::shared_ptr<Handler>*>(ev[i].data.ptr);
-        pending_functions.emplace_back(std::move(sp));
+        auto& info = *reinterpret_cast<Info*>(ev[i].data.ptr);
+        if ((info.events & (EPOLLIN | EPOLLPRI)) == (EPOLLIN | EPOLLPRI) &&
+            (ev[i].events & EPOLLIN) != ev[i].events) {
+            // This handler wants to know about exception events, and just got one.
+            // Log something informational.
+            LOG(ERROR) << "Received unexpected epoll event set: " << ev[i].events;
+        }
+        pending_functions.emplace_back(info.handler);
     }
 
     return pending_functions;
diff --git a/init/epoll.h b/init/epoll.h
index 0df5289..f58ae8d 100644
--- a/init/epoll.h
+++ b/init/epoll.h
@@ -46,8 +46,13 @@
             std::optional<std::chrono::milliseconds> timeout);
 
   private:
+    struct Info {
+        std::shared_ptr<Handler> handler;
+        uint32_t events;
+    };
+
     android::base::unique_fd epoll_fd_;
-    std::map<int, std::shared_ptr<Handler>> epoll_handlers_;
+    std::map<int, Info> epoll_handlers_;
 };
 
 }  // namespace init
diff --git a/init/init.cpp b/init/init.cpp
index 5f516b7..be99a1c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -33,7 +33,10 @@
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
+#include <filesystem>
+#include <fstream>
 #include <functional>
+#include <iostream>
 #include <map>
 #include <memory>
 #include <mutex>
@@ -695,10 +698,10 @@
 
 static constexpr std::chrono::milliseconds kDiagnosticTimeout = 10s;
 
-static void HandleSignalFd() {
+static void HandleSignalFd(bool one_off) {
     signalfd_siginfo siginfo;
     auto started = std::chrono::steady_clock::now();
-    for (;;) {
+    do {
         ssize_t bytes_read = TEMP_FAILURE_RETRY(read(signal_fd, &siginfo, sizeof(siginfo)));
         if (bytes_read < 0 && errno == EAGAIN) {
             auto now = std::chrono::steady_clock::now();
@@ -716,7 +719,7 @@
             return;
         }
         break;
-    }
+    } while (!one_off);
 
     switch (siginfo.ssi_signo) {
         case SIGCHLD:
@@ -776,7 +779,9 @@
         PLOG(FATAL) << "failed to create signalfd";
     }
 
-    if (auto result = epoll->RegisterHandler(signal_fd, HandleSignalFd); !result.ok()) {
+    constexpr int flags = EPOLLIN | EPOLLPRI;
+    auto handler = std::bind(HandleSignalFd, false);
+    if (auto result = epoll->RegisterHandler(signal_fd, handler, flags); !result.ok()) {
         LOG(FATAL) << result.error();
     }
 }
@@ -905,6 +910,32 @@
     return {};
 }
 
+static void DumpPidFds(const std::string& prefix, pid_t pid) {
+    std::error_code ec;
+    std::string proc_dir = "/proc/" + std::to_string(pid) + "/fd";
+    for (const auto& entry : std::filesystem::directory_iterator(proc_dir)) {
+        std::string target;
+        if (android::base::Readlink(entry.path(), &target)) {
+            LOG(ERROR) << prefix << target;
+        } else {
+            LOG(ERROR) << prefix << entry.path();
+        }
+    }
+}
+
+static void DumpFile(const std::string& prefix, const std::string& file) {
+    std::ifstream fp(file);
+    if (!fp) {
+        LOG(ERROR) << "Could not open " << file;
+        return;
+    }
+
+    std::string line;
+    while (std::getline(fp, line)) {
+        LOG(ERROR) << prefix << line;
+    }
+}
+
 int SecondStageMain(int argc, char** argv) {
     if (REBOOT_BOOTLOADER_ON_PANIC) {
         InstallRebootSignalHandlers();
@@ -1114,11 +1145,23 @@
                 (*function)();
             }
         } else if (Service::is_exec_service_running()) {
+            static bool dumped_diagnostics = false;
             std::chrono::duration<double> waited =
                     std::chrono::steady_clock::now() - Service::exec_service_started();
             if (waited >= kDiagnosticTimeout) {
                 LOG(ERROR) << "Exec service is hung? Waited " << waited.count()
                            << " without SIGCHLD";
+                if (!dumped_diagnostics) {
+                    DumpPidFds("exec service opened: ", Service::exec_service_pid());
+
+                    std::string status_file =
+                            "/proc/" + std::to_string(Service::exec_service_pid()) + "/status";
+                    DumpFile("exec service: ", status_file);
+                    dumped_diagnostics = true;
+
+                    LOG(INFO) << "Attempting to handle any stuck SIGCHLDs...";
+                    HandleSignalFd(true);
+                }
             }
         }
         if (!IsShuttingDown()) {
diff --git a/init/service.cpp b/init/service.cpp
index 730b6b6..b36584b 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -127,6 +127,7 @@
 
 unsigned long Service::next_start_order_ = 1;
 bool Service::is_exec_service_running_ = false;
+pid_t Service::exec_service_pid_ = -1;
 std::chrono::time_point<std::chrono::steady_clock> Service::exec_service_started_;
 
 Service::Service(const std::string& name, Subcontext* subcontext_for_restart_commands,
@@ -395,6 +396,7 @@
 
     flags_ |= SVC_EXEC;
     is_exec_service_running_ = true;
+    exec_service_pid_ = pid_;
     exec_service_started_ = std::chrono::steady_clock::now();
 
     LOG(INFO) << "SVC_EXEC service '" << name_ << "' pid " << pid_ << " (uid " << proc_attr_.uid
diff --git a/init/service.h b/init/service.h
index f7f32d9..c14b312 100644
--- a/init/service.h
+++ b/init/service.h
@@ -103,6 +103,7 @@
     size_t CheckAllCommands() const { return onrestart_.CheckAllCommands(); }
 
     static bool is_exec_service_running() { return is_exec_service_running_; }
+    static pid_t exec_service_pid() { return exec_service_pid_; }
     static std::chrono::time_point<std::chrono::steady_clock> exec_service_started() {
         return exec_service_started_;
     }
diff --git a/init/sigchld_handler.cpp b/init/sigchld_handler.cpp
index 9b2c7d9..6fc64df 100644
--- a/init/sigchld_handler.cpp
+++ b/init/sigchld_handler.cpp
@@ -95,7 +95,10 @@
         LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;
     }
 
-    if (!service) return pid;
+    if (!service) {
+        LOG(INFO) << name << " did not have an associated service entry and will not be reaped";
+        return pid;
+    }
 
     service->Reap(siginfo);
 
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index b2ace34..e071c96 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -444,6 +444,7 @@
 // until all modules are loaded.
 bool Modprobe::LoadModulesParallel(int num_threads) {
     bool ret = true;
+    int count = -1;
     std::map<std::string, std::set<std::string>> mod_with_deps;
 
     // Get dependencies
@@ -471,18 +472,21 @@
         }
     }
 
-    while (!mod_with_deps.empty()) {
+    while (!mod_with_deps.empty() &&  count != module_loaded_.size()) {
         std::vector<std::thread> threads;
         std::vector<std::string> mods_path_to_load;
         std::mutex vector_lock;
+        count = module_loaded_.size();
 
         // Find independent modules
         for (const auto& [it_mod, it_dep] : mod_with_deps) {
             if (it_dep.size() == 1) {
                 if (module_options_[it_mod].find("load_sequential=1") != std::string::npos) {
-                    LoadWithAliases(it_mod, true);
+                    if (!LoadWithAliases(it_mod, true) && !IsBlocklisted(it_mod)) {
+                      return false;
+                    }
                 } else {
-                    mods_path_to_load.emplace_back(*(it_dep.begin()));
+                    mods_path_to_load.emplace_back(it_mod);
                 }
             }
         }
@@ -491,12 +495,16 @@
         auto thread_function = [&] {
             std::unique_lock lk(vector_lock);
             while (!mods_path_to_load.empty()) {
-                auto mod_path_to_load = std::move(mods_path_to_load.back());
+                auto ret_load = true;
+                auto mod_to_load = std::move(mods_path_to_load.back());
                 mods_path_to_load.pop_back();
 
                 lk.unlock();
-                ret &= Insmod(mod_path_to_load, "");
+                ret_load &= LoadWithAliases(mod_to_load, true);
                 lk.lock();
+                if (!ret_load && !IsBlocklisted(mod_to_load)) {
+                    ret &= ret_load;
+                }
             }
         };
 
@@ -508,6 +516,8 @@
             thread.join();
         }
 
+        if (!ret) return ret;
+
         std::lock_guard guard(module_loaded_lock_);
         // Remove loaded module form mod_with_deps and soft dependencies of other modules
         for (const auto& module_loaded : module_loaded_) {
diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp
index 7b0e0d3..c6a0737 100644
--- a/libprocessgroup/Android.bp
+++ b/libprocessgroup/Android.bp
@@ -2,6 +2,17 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+cc_defaults {
+    name: "libprocessgroup_defaults",
+    cpp_std: "gnu++20",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wexit-time-destructors",
+        "-Wno-unused-parameter",
+    ],
+}
+
 cc_library_headers {
     name: "libprocessgroup_headers",
     vendor_available: true,
@@ -62,11 +73,7 @@
     export_header_lib_headers: [
         "libprocessgroup_headers",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wexit-time-destructors",
-    ],
+    defaults: ["libprocessgroup_defaults"],
     apex_available: [
         "//apex_available:platform",
         "//apex_available:anyapex",
@@ -77,12 +84,7 @@
 cc_test {
     name: "task_profiles_test",
     host_supported: true,
-    cflags: [
-        "-Wall",
-        "-Werror",
-        "-Wexit-time-destructors",
-        "-Wno-unused-parameter",
-    ],
+    defaults: ["libprocessgroup_defaults"],
     srcs: [
         "task_profiles_test.cpp",
     ],
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 39b9f3f..45a723f 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -18,7 +18,10 @@
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <initializer_list>
+#include <span>
 #include <string>
+#include <string_view>
 #include <vector>
 
 __BEGIN_DECLS
@@ -33,6 +36,19 @@
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
 bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
 
+__END_DECLS
+
+bool SetTaskProfiles(int tid, std::initializer_list<std::string_view> profiles,
+                     bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list<std::string_view> profiles);
+#if _LIBCPP_STD_VER > 17
+bool SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
+                     bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const std::string_view> profiles);
+#endif
+
+__BEGIN_DECLS
+
 #ifndef __ANDROID_VNDK__
 
 bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 51c810e..bdda102 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -148,14 +148,35 @@
 }
 
 bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+    return TaskProfiles::GetInstance().SetProcessProfiles(
+            uid, pid, std::span<const std::string>(profiles), false);
+}
+
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list<std::string_view> profiles) {
+    return TaskProfiles::GetInstance().SetProcessProfiles(
+            uid, pid, std::span<const std::string_view>(profiles), false);
+}
+
+bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const std::string_view> profiles) {
     return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, false);
 }
 
 bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
-    return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, true);
+    return TaskProfiles::GetInstance().SetProcessProfiles(
+            uid, pid, std::span<const std::string>(profiles), true);
 }
 
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
+    return TaskProfiles::GetInstance().SetTaskProfiles(tid, std::span<const std::string>(profiles),
+                                                       use_fd_cache);
+}
+
+bool SetTaskProfiles(int tid, std::initializer_list<std::string_view> profiles, bool use_fd_cache) {
+    return TaskProfiles::GetInstance().SetTaskProfiles(
+            tid, std::span<const std::string_view>(profiles), use_fd_cache);
+}
+
+bool SetTaskProfiles(int tid, std::span<const std::string_view> profiles, bool use_fd_cache) {
     return TaskProfiles::GetInstance().SetTaskProfiles(tid, profiles, use_fd_cache);
 }
 
@@ -166,12 +187,12 @@
 // https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3574427/5/src/linux/android.rs#12
 extern "C" bool android_set_process_profiles(uid_t uid, pid_t pid, size_t num_profiles,
                                              const char* profiles[]) {
-    std::vector<std::string> profiles_;
+    std::vector<std::string_view> profiles_;
     profiles_.reserve(num_profiles);
     for (size_t i = 0; i < num_profiles; i++) {
         profiles_.emplace_back(profiles[i]);
     }
-    return SetProcessProfiles(uid, pid, profiles_);
+    return SetProcessProfiles(uid, pid, std::span<const std::string_view>(profiles_));
 }
 
 static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 3831ef2..304248a 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -410,7 +410,7 @@
     // Make sure we do this only one time. No need for std::call_once because
     // init is a single-threaded process
     if (access(CGROUPS_RC_PATH, F_OK) == 0) {
-        LOG(WARNING) << "Attempt to call SetupCgroups more than once";
+        LOG(WARNING) << "Attempt to call CgroupSetup() more than once";
         return true;
     }
 
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index e1c5934..744710f 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -786,7 +786,7 @@
     return true;
 }
 
-TaskProfile* TaskProfiles::GetProfile(const std::string& name) const {
+TaskProfile* TaskProfiles::GetProfile(std::string_view name) const {
     auto iter = profiles_.find(name);
 
     if (iter != profiles_.end()) {
@@ -795,7 +795,7 @@
     return nullptr;
 }
 
-const IProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const {
+const IProfileAttribute* TaskProfiles::GetAttribute(std::string_view name) const {
     auto iter = attributes_.find(name);
 
     if (iter != attributes_.end()) {
@@ -804,8 +804,9 @@
     return nullptr;
 }
 
-bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
-                                      const std::vector<std::string>& profiles, bool use_fd_cache) {
+template <typename T>
+bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles,
+                                      bool use_fd_cache) {
     bool success = true;
     for (const auto& name : profiles) {
         TaskProfile* profile = GetProfile(name);
@@ -825,8 +826,8 @@
     return success;
 }
 
-bool TaskProfiles::SetTaskProfiles(int tid, const std::vector<std::string>& profiles,
-                                   bool use_fd_cache) {
+template <typename T>
+bool TaskProfiles::SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache) {
     bool success = true;
     for (const auto& name : profiles) {
         TaskProfile* profile = GetProfile(name);
@@ -845,3 +846,14 @@
     }
     return success;
 }
+
+template bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
+                                               std::span<const std::string> profiles,
+                                               bool use_fd_cache);
+template bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
+                                               std::span<const std::string_view> profiles,
+                                               bool use_fd_cache);
+template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string> profiles,
+                                            bool use_fd_cache);
+template bool TaskProfiles::SetTaskProfiles(int tid, std::span<const std::string_view> profiles,
+                                            bool use_fd_cache);
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index df08f65..85b3f91 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -18,9 +18,12 @@
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <functional>
 #include <map>
 #include <mutex>
+#include <span>
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include <android-base/unique_fd.h>
@@ -206,18 +209,19 @@
     // Should be used by all users
     static TaskProfiles& GetInstance();
 
-    TaskProfile* GetProfile(const std::string& name) const;
-    const IProfileAttribute* GetAttribute(const std::string& name) const;
+    TaskProfile* GetProfile(std::string_view name) const;
+    const IProfileAttribute* GetAttribute(std::string_view name) const;
     void DropResourceCaching(ProfileAction::ResourceCacheType cache_type) const;
-    bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
-                            bool use_fd_cache);
-    bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
+    template <typename T>
+    bool SetProcessProfiles(uid_t uid, pid_t pid, std::span<const T> profiles, bool use_fd_cache);
+    template <typename T>
+    bool SetTaskProfiles(int tid, std::span<const T> profiles, bool use_fd_cache);
 
   private:
-    std::map<std::string, std::shared_ptr<TaskProfile>> profiles_;
-    std::map<std::string, std::unique_ptr<IProfileAttribute>> attributes_;
-
     TaskProfiles();
 
     bool Load(const CgroupMap& cg_map, const std::string& file_name);
+
+    std::map<std::string, std::shared_ptr<TaskProfile>, std::less<>> profiles_;
+    std::map<std::string, std::unique_ptr<IProfileAttribute>, std::less<>> attributes_;
 };
diff --git a/libstats/pull_lazy/TEST_MAPPING b/libstats/pull_lazy/TEST_MAPPING
index 92f1e6a..0282a03 100644
--- a/libstats/pull_lazy/TEST_MAPPING
+++ b/libstats/pull_lazy/TEST_MAPPING
@@ -4,7 +4,7 @@
       "name" : "libstatspull_lazy_test"
     }
   ],
-  "hwasan-postsubmit" : [
+  "hwasan-presubmit" : [
     {
       "name" : "libstatspull_lazy_test"
     }
diff --git a/libutils/Android.bp b/libutils/Android.bp
index f663671..7939e82 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -68,6 +68,7 @@
         "-Wall",
         "-Werror",
         "-Wno-exit-time-destructors",
+        "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     header_libs: [
         "libbase_headers",
@@ -173,6 +174,10 @@
     min_sdk_version: "apex_inherit",
 
     afdo: true,
+
+    header_abi_checker: {
+        diff_flags: ["-allow-adding-removing-weak-symbols"],
+    },
 }
 
 cc_library {
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 292425a..1a3f34b 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -117,14 +117,15 @@
     int result = pthread_once(& gTLSOnce, initTLSKey);
     LOG_ALWAYS_FATAL_IF(result != 0, "pthread_once failed");
 
-    return (Looper*)pthread_getspecific(gTLSKey);
+    Looper* looper = (Looper*)pthread_getspecific(gTLSKey);
+    return sp<Looper>::fromExisting(looper);
 }
 
 sp<Looper> Looper::prepare(int opts) {
     bool allowNonCallbacks = opts & PREPARE_ALLOW_NON_CALLBACKS;
     sp<Looper> looper = Looper::getForThread();
     if (looper == nullptr) {
-        looper = new Looper(allowNonCallbacks);
+        looper = sp<Looper>::make(allowNonCallbacks);
         Looper::setForThread(looper);
     }
     if (looper->getAllowNonCallbacks() != allowNonCallbacks) {
@@ -425,7 +426,11 @@
 }
 
 int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
-    return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : nullptr, data);
+    sp<SimpleLooperCallback> looperCallback;
+    if (callback) {
+        looperCallback = sp<SimpleLooperCallback>::make(callback);
+    }
+    return addFd(fd, ident, events, looperCallback, data);
 }
 
 int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {
diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp
index d437a9f..819a603 100644
--- a/libutils/NativeHandle.cpp
+++ b/libutils/NativeHandle.cpp
@@ -20,7 +20,7 @@
 namespace android {
 
 sp<NativeHandle> NativeHandle::create(native_handle_t* handle, bool ownsHandle) {
-    return handle ? new NativeHandle(handle, ownsHandle) : nullptr;
+    return handle ? sp<NativeHandle>::make(handle, ownsHandle) : nullptr;
 }
 
 NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 4dacdc6..e756fec 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -673,7 +673,7 @@
     mThread = thread_id_t(-1);
 
     // hold a strong reference on ourself
-    mHoldSelf = this;
+    mHoldSelf = sp<Thread>::fromExisting(this);
 
     mRunning = true;
 
diff --git a/libutils/include/utils/NativeHandle.h b/libutils/include/utils/NativeHandle.h
index 73fe804..f26a1a4 100644
--- a/libutils/include/utils/NativeHandle.h
+++ b/libutils/include/utils/NativeHandle.h
@@ -39,6 +39,8 @@
 private:
     // for access to the destructor
     friend class LightRefBase<NativeHandle>;
+    // for access to the constructor
+    friend class sp<NativeHandle>;
 
     NativeHandle(native_handle_t* handle, bool ownsHandle);
     ~NativeHandle();
diff --git a/rootdir/etc/linker.config.json b/rootdir/etc/linker.config.json
index 780ace5..c88c7ff 100644
--- a/rootdir/etc/linker.config.json
+++ b/rootdir/etc/linker.config.json
@@ -31,5 +31,9 @@
     "libadb_pairing_auth.so",
     "libadb_pairing_connection.so",
     "libadb_pairing_server.so"
+  ],
+  "provideLibs": [
+    "libaptX_encoder.so",
+    "libaptXHD_encoder.so"
   ]
 }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 660f18c..60bf57b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -723,9 +723,13 @@
     # Multi-installed APEXes are selected using persist props.
     # Load persist properties and override properties (if enabled) from /data,
     # before starting apexd.
+    # /data/property should be created before `load_persist_props`
+    mkdir /data/property 0700 root root encryption=Require
     load_persist_props
+
     start logd
     start logd-reinit
+
     # Some existing vendor rc files use 'on load_persist_props_action' to know
     # when persist props are ready. These are difficult to change due to GRF,
     # so continue triggering this action here even though props are already loaded
@@ -852,7 +856,6 @@
     mkdir /data/app-asec 0700 root root encryption=Require
     mkdir /data/app-lib 0771 system system encryption=Require
     mkdir /data/app 0771 system system encryption=Require
-    mkdir /data/property 0700 root root encryption=Require
 
     # create directory for updated font files.
     mkdir /data/fonts/ 0771 root root encryption=Require
diff --git a/set-verity-state/Android.bp b/set-verity-state/Android.bp
index f0df350..f40118b 100644
--- a/set-verity-state/Android.bp
+++ b/set-verity-state/Android.bp
@@ -9,17 +9,18 @@
     srcs: ["set-verity-state.cpp"],
     shared_libs: [
         "libbase",
+        "libbinder",
         "libcrypto",
         "libcrypto_utils",
-        "libcutils",
-        "libfec",
         "libfs_mgr_binder",
-        "liblog",
         "libutils",
     ],
     static_libs: [
         "libavb_user",
     ],
+    header_libs: [
+        "libcutils_headers",
+    ],
 
     cflags: ["-Werror"],
     cppflags: [
diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp
index 52a7f74..de9a452 100644
--- a/set-verity-state/set-verity-state.cpp
+++ b/set-verity-state/set-verity-state.cpp
@@ -14,242 +14,230 @@
  * limitations under the License.
  */
 
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <libavb_user/libavb_user.h>
-#include <stdarg.h>
+#include <getopt.h>
 #include <stdio.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <unistd.h>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr.h>
+#include <binder/ProcessState.h>
+#include <cutils/android_reboot.h>
 #include <fs_mgr_overlayfs.h>
-#include <fstab/fstab.h>
-#include <log/log_properties.h>
+#include <libavb_user/libavb_user.h>
 
-#include "fec/io.h"
+using namespace std::string_literals;
+
+namespace {
+
+void print_usage() {
+  printf(
+      "Usage:\n"
+      "\tdisable-verity\n"
+      "\tenable-verity\n"
+      "\tset-verity-state [0|1]\n"
+      "Options:\n"
+      "\t-h --help\tthis help\n"
+      "\t-R --reboot\tautomatic reboot if needed for new settings to take effect\n"
+      "\t-v --verbose\tbe noisy\n");
+}
 
 #ifdef ALLOW_DISABLE_VERITY
-static const bool kAllowDisableVerity = true;
+const bool kAllowDisableVerity = true;
 #else
-static const bool kAllowDisableVerity = false;
+const bool kAllowDisableVerity = false;
 #endif
 
-using android::base::unique_fd;
-
-static void suggest_run_adb_root() {
-  if (getuid() != 0) printf("Maybe run adb root?\n");
-}
-
-static bool make_block_device_writable(const std::string& dev) {
-  unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
-  if (fd == -1) {
-    return false;
-  }
-
-  int OFF = 0;
-  bool result = (ioctl(fd.get(), BLKROSET, &OFF) != -1);
-  return result;
-}
-
-/* Turn verity on/off */
-static bool set_verity_enabled_state(const char* block_device, const char* mount_point,
-                                     bool enable) {
-  if (!make_block_device_writable(block_device)) {
-    printf("Could not make block device %s writable (%s).\n", block_device, strerror(errno));
-    return false;
-  }
-
-  fec::io fh(block_device, O_RDWR);
-
-  if (!fh) {
-    printf("Could not open block device %s (%s).\n", block_device, strerror(errno));
-    suggest_run_adb_root();
-    return false;
-  }
-
-  fec_verity_metadata metadata;
-
-  if (!fh.get_verity_metadata(metadata)) {
-    printf("Couldn't find verity metadata!\n");
-    return false;
-  }
-
-  if (!enable && metadata.disabled) {
-    printf("Verity already disabled on %s\n", mount_point);
-    return false;
-  }
-
-  if (enable && !metadata.disabled) {
-    printf("Verity already enabled on %s\n", mount_point);
-    return false;
-  }
-
-  if (!fh.set_verity_status(enable)) {
-    printf("Could not set verity %s flag on device %s with error %s\n",
-           enable ? "enabled" : "disabled", block_device, strerror(errno));
-    return false;
-  }
-
-  auto change = false;
-  errno = 0;
-  if (enable ? fs_mgr_overlayfs_teardown(mount_point, &change)
-             : fs_mgr_overlayfs_setup(nullptr, mount_point, &change)) {
-    if (change) {
-      printf("%s overlayfs for %s\n", enable ? "disabling" : "using", mount_point);
-    }
-  } else if (errno) {
-    int expected_errno = enable ? EBUSY : ENOENT;
-    if (errno != expected_errno) {
-      printf("Overlayfs %s for %s failed with error %s\n", enable ? "teardown" : "setup",
-             mount_point, strerror(errno));
-    }
-  }
-  printf("Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
-  return true;
-}
-
 /* Helper function to get A/B suffix, if any. If the device isn't
  * using A/B the empty string is returned. Otherwise either "_a",
  * "_b", ... is returned.
  */
-static std::string get_ab_suffix() {
+std::string get_ab_suffix() {
   return android::base::GetProperty("ro.boot.slot_suffix", "");
 }
 
-static bool is_avb_device_locked() {
+bool is_avb_device_locked() {
   return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
 }
 
-static bool overlayfs_setup(bool enable) {
+bool is_debuggable() {
+  return android::base::GetBoolProperty("ro.debuggable", false);
+}
+
+bool is_using_avb() {
+  // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
+  // contract, androidboot.vbmeta.digest is set by the bootloader
+  // when using AVB).
+  return !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
+}
+
+[[noreturn]] void reboot(const std::string& name) {
+  LOG(INFO) << "Rebooting device for new settings to take effect";
+  ::sync();
+  android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot," + name);
+  ::sleep(60);
+  LOG(ERROR) << "Failed to reboot";
+  ::exit(1);
+}
+
+bool overlayfs_setup(bool enable) {
   auto change = false;
   errno = 0;
-  if (enable ? fs_mgr_overlayfs_teardown(nullptr, &change)
-             : fs_mgr_overlayfs_setup(nullptr, nullptr, &change)) {
+  if (enable ? fs_mgr_overlayfs_setup(nullptr, &change)
+             : fs_mgr_overlayfs_teardown(nullptr, &change)) {
     if (change) {
-      printf("%s overlayfs\n", enable ? "disabling" : "using");
+      LOG(INFO) << (enable ? "Enabled" : "Disabled") << " overlayfs";
     }
-  } else if (errno) {
-    printf("Overlayfs %s failed with error %s\n", enable ? "teardown" : "setup", strerror(errno));
-    suggest_run_adb_root();
+  } else {
+    LOG(ERROR) << "Failed to " << (enable ? "enable" : "disable") << " overlayfs";
   }
   return change;
 }
 
+struct SetVerityStateResult {
+  bool success = false;
+  bool want_reboot = false;
+};
+
 /* Use AVB to turn verity on/off */
-static bool set_avb_verity_enabled_state(AvbOps* ops, bool enable_verity) {
+SetVerityStateResult SetVerityState(bool enable_verity) {
   std::string ab_suffix = get_ab_suffix();
-  bool verity_enabled;
+  bool verity_enabled = false;
 
   if (is_avb_device_locked()) {
-    printf("Device is locked. Please unlock the device first\n");
-    return false;
+    LOG(ERROR) << "Device must be bootloader unlocked to change verity state";
+    return {};
   }
 
-  if (!avb_user_verity_get(ops, ab_suffix.c_str(), &verity_enabled)) {
-    printf("Error getting verity state. Try adb root first?\n");
-    return false;
+  std::unique_ptr<AvbOps, decltype(&avb_ops_user_free)> ops(avb_ops_user_new(), &avb_ops_user_free);
+  if (!ops) {
+    LOG(ERROR) << "Error getting AVB ops";
+    return {};
+  }
+
+  if (!avb_user_verity_get(ops.get(), ab_suffix.c_str(), &verity_enabled)) {
+    LOG(ERROR) << "Error getting verity state";
+    return {};
   }
 
   if ((verity_enabled && enable_verity) || (!verity_enabled && !enable_verity)) {
-    printf("verity is already %s\n", verity_enabled ? "enabled" : "disabled");
-    return false;
+    LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled");
+    return {.success = true, .want_reboot = false};
   }
 
-  if (!avb_user_verity_set(ops, ab_suffix.c_str(), enable_verity)) {
-    printf("Error setting verity\n");
-    return false;
+  if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) {
+    LOG(ERROR) << "Error setting verity state";
+    return {};
   }
 
-  overlayfs_setup(enable_verity);
-  printf("Successfully %s verity\n", enable_verity ? "enabled" : "disabled");
-  return true;
+  LOG(INFO) << "Successfully " << (enable_verity ? "enabled" : "disabled") << " verity";
+  return {.success = true, .want_reboot = true};
 }
 
+class MyLogger {
+ public:
+  explicit MyLogger(bool verbose) : verbose_(verbose) {}
+
+  void operator()(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
+                  const char* file, unsigned int line, const char* message) {
+    // Hide log starting with '[fs_mgr]' unless it's an error.
+    if (verbose_ || severity >= android::base::ERROR || message[0] != '[') {
+      fprintf(stderr, "%s\n", message);
+    }
+    logd_(id, severity, tag, file, line, message);
+  }
+
+ private:
+  android::base::LogdLogger logd_;
+  bool verbose_;
+};
+
+}  // namespace
+
 int main(int argc, char* argv[]) {
-  if (argc == 0) {
-    LOG(FATAL) << "set-verity-state called with empty argv";
-  }
+  bool auto_reboot = false;
+  bool verbose = false;
 
-  std::optional<bool> enable_opt;
-  std::string procname = android::base::Basename(argv[0]);
-  if (procname == "enable-verity") {
-    enable_opt = true;
-  } else if (procname == "disable-verity") {
-    enable_opt = false;
-  }
-
-  if (!enable_opt.has_value()) {
-    if (argc != 2) {
-      printf("usage: %s [1|0]\n", argv[0]);
-      return 1;
-    }
-
-    if (strcmp(argv[1], "1") == 0) {
-      enable_opt = true;
-    } else if (strcmp(argv[1], "0") == 0) {
-      enable_opt = false;
-    } else {
-      printf("usage: %s [1|0]\n", argv[0]);
-      return 1;
+  struct option longopts[] = {
+      {"help", no_argument, nullptr, 'h'},
+      {"reboot", no_argument, nullptr, 'R'},
+      {"verbose", no_argument, nullptr, 'v'},
+      {0, 0, nullptr, 0},
+  };
+  for (int opt; (opt = ::getopt_long(argc, argv, "hRv", longopts, nullptr)) != -1;) {
+    switch (opt) {
+      case 'h':
+        print_usage();
+        return 0;
+      case 'R':
+        auto_reboot = true;
+        break;
+      case 'v':
+        verbose = true;
+        break;
+      default:
+        print_usage();
+        return 1;
     }
   }
 
-  bool enable = enable_opt.value();
+  android::base::InitLogging(argv, MyLogger(verbose));
 
-  bool any_changed = false;
-
-  // Figure out if we're using VB1.0 or VB2.0 (aka AVB) - by
-  // contract, androidboot.vbmeta.digest is set by the bootloader
-  // when using AVB).
-  bool using_avb = !android::base::GetProperty("ro.boot.vbmeta.digest", "").empty();
-
-  // If using AVB, dm-verity is used on any build so we want it to
-  // be possible to disable/enable on any build (except USER). For
-  // VB1.0 dm-verity is only enabled on certain builds.
-  if (!using_avb) {
-    if (!kAllowDisableVerity) {
-      printf("%s only works for userdebug builds\n", argv[0]);
-    }
-
-    if (!android::base::GetBoolProperty("ro.secure", false)) {
-      overlayfs_setup(enable);
-      printf("verity not enabled - ENG build\n");
-      return 0;
-    }
+  bool enable_verity = false;
+  const std::string progname = getprogname();
+  if (progname == "enable-verity") {
+    enable_verity = true;
+  } else if (progname == "disable-verity") {
+    enable_verity = false;
+  } else if (optind < argc && (argv[optind] == "1"s || argv[optind] == "0"s)) {
+    // progname "set-verity-state"
+    enable_verity = (argv[optind] == "1"s);
+  } else {
+    print_usage();
+    return 1;
   }
 
-  // Should never be possible to disable dm-verity on a USER build
-  // regardless of using AVB or VB1.0.
-  if (!__android_log_is_debuggable()) {
-    printf("verity cannot be disabled/enabled - USER build\n");
-    return 0;
+  if (!kAllowDisableVerity || !is_debuggable()) {
+    errno = EPERM;
+    PLOG(ERROR) << "Cannot disable/enable verity on user build";
+    return 1;
   }
 
-  if (using_avb) {
-    // Yep, the system is using AVB.
-    AvbOps* ops = avb_ops_user_new();
-    if (ops == nullptr) {
-      printf("Error getting AVB ops\n");
-      return 1;
+  if (getuid() != 0) {
+    errno = EACCES;
+    PLOG(ERROR) << "Must be running as root (adb root)";
+    return 1;
+  }
+
+  if (!is_using_avb()) {
+    LOG(ERROR) << "Expected AVB device, VB1.0 is no longer supported";
+    return 1;
+  }
+
+  int exit_code = 0;
+  bool want_reboot = false;
+
+  auto ret = SetVerityState(enable_verity);
+  if (ret.success) {
+    want_reboot |= ret.want_reboot;
+  } else {
+    exit_code = 1;
+  }
+
+  // Disable any overlayfs unconditionally if we want verity enabled.
+  // Enable overlayfs only if verity is successfully disabled or is already disabled.
+  if (enable_verity || ret.success) {
+    // Start a threadpool to service waitForService() callbacks as
+    // fs_mgr_overlayfs_* might call waitForService() to get the image service.
+    android::ProcessState::self()->startThreadPool();
+    want_reboot |= overlayfs_setup(!enable_verity);
+  }
+
+  if (want_reboot) {
+    if (auto_reboot) {
+      reboot(progname);
     }
-    if (set_avb_verity_enabled_state(ops, enable)) {
-      any_changed = true;
-    }
-    avb_ops_user_free(ops);
-  }
-  if (!any_changed) any_changed = overlayfs_setup(enable);
-
-  if (any_changed) {
-    printf("Now reboot your device for settings to take effect\n");
+    printf("Reboot the device for new settings to take effect\n");
   }
 
-  return 0;
+  return exit_code;
 }
diff --git a/trusty/apploader/apploader.cpp b/trusty/apploader/apploader.cpp
index 278499f..17d083c 100644
--- a/trusty/apploader/apploader.cpp
+++ b/trusty/apploader/apploader.cpp
@@ -226,6 +226,9 @@
         case APPLOADER_ERR_POLICY_VIOLATION:
             LOG(ERROR) << "Error: loading denied by policy engine";
             break;
+        case APPLOADER_ERR_NOT_ENCRYPTED:
+            LOG(ERROR) << "Error: unmet application encryption requirement";
+            break;
         default:
             LOG(ERROR) << "Unrecognized error: " << resp.error;
             break;
diff --git a/trusty/apploader/apploader_ipc.h b/trusty/apploader/apploader_ipc.h
index 306596e..f037692 100644
--- a/trusty/apploader/apploader_ipc.h
+++ b/trusty/apploader/apploader_ipc.h
@@ -45,6 +45,10 @@
  * @APPLOADER_ERR_INTERNAL:             miscellaneous or internal apploader
  *                                      error not covered by the above
  * @APPLOADER_ERR_INVALID_VERSION:      invalid application version
+ * @APPLOADER_ERR_POLICY_VIOLATION:     signature verification succeeded but
+ *                                      key+manifest combination not allowed
+ *                                      by app loader policy engine
+ * @APPLOADER_ERR_NOT_ENCRYPTED:        unmet application encryption requirement
  */
 enum apploader_error : uint32_t {
     APPLOADER_NO_ERROR = 0,
@@ -57,6 +61,7 @@
     APPLOADER_ERR_INTERNAL,
     APPLOADER_ERR_INVALID_VERSION,
     APPLOADER_ERR_POLICY_VIOLATION,
+    APPLOADER_ERR_NOT_ENCRYPTED,
 };
 
 /**
diff --git a/trusty/utils/acvp/acvp_ipc.h b/trusty/utils/acvp/acvp_ipc.h
index 300e05a..fc1c9d7 100644
--- a/trusty/utils/acvp/acvp_ipc.h
+++ b/trusty/utils/acvp/acvp_ipc.h
@@ -45,7 +45,7 @@
  * This must be at least as long as the longest reply from the ACVP service
  * (currently the reply from getConfig()).
  */
-#define ACVP_MIN_SHARED_MEMORY 16384
+#define ACVP_MIN_SHARED_MEMORY 32768
 
 /**
  * acvp_req - Request for the Trusty ACVP app