Merge "storageproxyd: Add STORAGE_FILE_GET_MAX_SIZE API on Android side"
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index b478e6e..eed49fa 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -342,6 +342,8 @@
         targets: [
             "dist_files",
             "sdk",
+            "sdk-repo-platform-tools",
+            "sdk_repo",
             "win_sdk",
         ],
     },
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 49761ac..bebf19e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -223,7 +223,6 @@
         "libcutils",
         "libcrypto",
         "libext4_utils",
-        "libfec",
         "libfs_mgr_binder",
         "liblog",
         "liblp",
@@ -254,3 +253,39 @@
         "clean_scratch_files",
     ],
 }
+
+cc_binary {
+    name: "set-verity-state",
+    srcs: ["set-verity-state.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcrypto",
+        "libcrypto_utils",
+        "libfs_mgr_binder",
+        "libutils",
+    ],
+    static_libs: [
+        "libavb_user",
+    ],
+    header_libs: [
+        "libcutils_headers",
+    ],
+
+    cflags: ["-Werror"],
+    cppflags: [
+        "-DALLOW_DISABLE_VERITY=0",
+    ],
+    product_variables: {
+        debuggable: {
+            cppflags: [
+                "-UALLOW_DISABLE_VERITY",
+                "-DALLOW_DISABLE_VERITY=1",
+            ],
+        },
+    },
+    symlinks: [
+        "enable-verity",
+        "disable-verity",
+    ],
+}
diff --git a/fs_mgr/OWNERS b/fs_mgr/OWNERS
index c6f9054..6f1059b 100644
--- a/fs_mgr/OWNERS
+++ b/fs_mgr/OWNERS
@@ -2,3 +2,4 @@
 bowgotsai@google.com
 dvander@google.com
 elsk@google.com
+yochiang@google.com
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 9fe8e18..27137a2 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -22,6 +22,7 @@
 #include <fcntl.h>
 #include <inttypes.h>
 #include <libgen.h>
+#include <selinux/selinux.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -30,6 +31,7 @@
 #include <sys/stat.h>
 #include <sys/swap.h>
 #include <sys/types.h>
+#include <sys/utsname.h>
 #include <sys/wait.h>
 #include <time.h>
 #include <unistd.h>
@@ -2359,3 +2361,49 @@
 
     return true;
 }
+
+bool fs_mgr_filesystem_available(const std::string& filesystem) {
+    std::string filesystems;
+    if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false;
+    return filesystems.find("\t" + filesystem + "\n") != std::string::npos;
+}
+
+std::string fs_mgr_get_context(const std::string& mount_point) {
+    char* ctx = nullptr;
+    if (getfilecon(mount_point.c_str(), &ctx) == -1) {
+        PERROR << "getfilecon " << mount_point;
+        return "";
+    }
+
+    std::string context(ctx);
+    free(ctx);
+    return context;
+}
+
+OverlayfsValidResult fs_mgr_overlayfs_valid() {
+    // Overlayfs available in the kernel, and patched for override_creds?
+    if (access("/sys/module/overlay/parameters/override_creds", F_OK) == 0) {
+        return OverlayfsValidResult::kOverrideCredsRequired;
+    }
+    if (!fs_mgr_filesystem_available("overlay")) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    struct utsname uts;
+    if (uname(&uts) == -1) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    int major, minor;
+    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    if (major < 4) {
+        return OverlayfsValidResult::kOk;
+    }
+    if (major > 4) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    if (minor > 3) {
+        return OverlayfsValidResult::kNotSupported;
+    }
+    return OverlayfsValidResult::kOk;
+}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 1d8a452..6fbccf4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -56,6 +56,7 @@
 #include <storage_literals/storage_literals.h>
 
 #include "fs_mgr_priv.h"
+#include "fs_mgr_priv_overlayfs.h"
 #include "libfiemap/utility.h"
 
 using namespace std::literals;
@@ -71,62 +72,9 @@
     return access(path.c_str(), F_OK) == 0;
 }
 
-// determine if a filesystem is available
-bool fs_mgr_overlayfs_filesystem_available(const std::string& filesystem) {
-    std::string filesystems;
-    if (!android::base::ReadFileToString("/proc/filesystems", &filesystems)) return false;
-    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
-
-bool fs_mgr_wants_overlayfs(FstabEntry*) {
-    return false;
-}
-
-Fstab fs_mgr_overlayfs_candidate_list(const Fstab&) {
-    return {};
-}
-
-bool fs_mgr_overlayfs_mount_all(Fstab*) {
-    return false;
-}
-
-bool fs_mgr_overlayfs_setup(const char*, bool*, bool) {
-    LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
-    return false;
-}
-
-OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char*, bool*) {
-    return OverlayfsTeardownResult::Ok;
-}
-
-bool fs_mgr_overlayfs_is_setup() {
-    return false;
-}
-
-namespace android {
-namespace fs_mgr {
-
-void MapScratchPartitionIfNeeded(Fstab*, const std::function<bool(const std::set<std::string>&)>&) {
-}
-
-void CleanupOldScratchFiles() {}
-
-void TeardownAllOverlayForMountPoint(const std::string&) {}
-
-}  // namespace fs_mgr
-}  // namespace android
-
-#else  // ALLOW_ADBD_DISABLE_VERITY == 0
-
-namespace {
-
 bool fs_mgr_in_recovery() {
     // Check the existence of recovery binary instead of using the compile time
     // __ANDROID_RECOVERY__ macro.
@@ -234,6 +182,28 @@
     return true;
 }
 
+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) ||
+        (fs.f_type != EXT4_SUPER_MAGIC)) {
+        return false;
+    }
+
+    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) return false;
+
+    struct ext4_super_block sb;
+    if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
+        (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
+        return false;
+    }
+
+    struct fs_info info;
+    if (ext4_parse_sb(&sb, &info) < 0) return false;
+
+    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
+
 bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
     // readonly filesystem, can not be mount -o remount,rw
     // for squashfs, erofs or if free space is (near) zero making such a remount
@@ -815,8 +785,7 @@
 }
 
 // Mount kScratchMountPoint
-bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type,
-                                    bool readonly = false) {
+bool MountScratch(const std::string& device_path, bool readonly = false) {
     if (readonly) {
         if (!fs_mgr_access(device_path)) {
             LOG(ERROR) << "Path does not exist: " << device_path;
@@ -827,9 +796,12 @@
         return false;
     }
 
-    auto f2fs = fs_mgr_is_f2fs(device_path);
-    auto ext4 = fs_mgr_is_ext4(device_path);
-    if (!f2fs && !ext4) {
+    std::vector<const char*> filesystem_candidates;
+    if (fs_mgr_is_f2fs(device_path)) {
+        filesystem_candidates = {"f2fs", "ext4"};
+    } else if (fs_mgr_is_ext4(device_path)) {
+        filesystem_candidates = {"ext4", "f2fs"};
+    } else {
         LOG(ERROR) << "Scratch partition is not f2fs or ext4";
         return false;
     }
@@ -846,11 +818,7 @@
     FstabEntry entry;
     entry.blk_device = device_path;
     entry.mount_point = kScratchMountPoint;
-    entry.fs_type = mnt_type;
-    if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4";
-    if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs";
     entry.flags = MS_NOATIME | MS_RDONLY;
-    auto mounted = true;
     if (!readonly) {
         entry.flags &= ~MS_RDONLY;
         entry.flags |= MS_SYNCHRONOUS;
@@ -861,14 +829,12 @@
     if (fs_mgr_overlayfs_already_mounted("/data", false)) {
         entry.fs_mgr_flags.check = true;
     }
-    if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0;
-    if (!mounted) {
-        if ((entry.fs_type == "f2fs") && ext4) {
-            entry.fs_type = "ext4";
-            mounted = fs_mgr_do_mount_one(entry) == 0;
-        } else if ((entry.fs_type == "ext4") && f2fs) {
-            entry.fs_type = "f2fs";
-            mounted = fs_mgr_do_mount_one(entry) == 0;
+    bool mounted = false;
+    for (auto fs_type : filesystem_candidates) {
+        entry.fs_type = fs_type;
+        if (fs_mgr_do_mount_one(entry) == 0) {
+            mounted = true;
+            break;
         }
     }
     if (!createcon.Restore()) {
@@ -884,39 +850,6 @@
 const std::string kMkF2fs("/system/bin/make_f2fs");
 const std::string kMkExt4("/system/bin/mke2fs");
 
-// Only a suggestion for _first_ try during mounting
-std::string fs_mgr_overlayfs_scratch_mount_type() {
-    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("f2fs")) {
-        return "f2fs";
-    }
-    if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_overlayfs_filesystem_available("ext4")) {
-        return "ext4";
-    }
-    return "auto";
-}
-
-// Note: we do not check access() here except for the super partition, since
-// in first-stage init we wouldn't have registed by-name symlinks for "other"
-// partitions that won't be mounted.
-static std::string GetPhysicalScratchDevice() {
-    auto slot_number = fs_mgr_overlayfs_slot_number();
-    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
-    auto path = fs_mgr_overlayfs_super_device(slot_number == 0);
-    if (super_device != path) {
-        return path;
-    }
-    if (fs_mgr_access(super_device)) {
-        // Do not try to use system_other on a DAP device.
-        return "";
-    }
-
-    auto other_slot = fs_mgr_get_other_slot_suffix();
-    if (!other_slot.empty()) {
-        return kPhysicalDevice + "system" + other_slot;
-    }
-    return "";
-}
-
 // Note: The scratch partition of DSU is managed by gsid, and should be initialized during
 // first-stage-mount. Just check if the DM device for DSU scratch partition is created or not.
 static std::string GetDsuScratchDevice() {
@@ -953,27 +886,30 @@
         return device;
     }
 
-    // There is no dynamic scratch, so try and find a physical one.
-    return GetPhysicalScratchDevice();
+    return "";
 }
 
-bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) {
+bool MakeScratchFilesystem(const std::string& scratch_device) {
     // Force mkfs by design for overlay support of adb remount, simplify and
     // thus do not rely on fsck to correct problems that could creep in.
+    auto fs_type = ""s;
     auto command = ""s;
-    if (mnt_type == "f2fs") {
+    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) {
+        fs_type = "f2fs";
         command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint);
-    } else if (mnt_type == "ext4") {
+    } else if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) {
+        fs_type = "ext4";
         command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
     } else {
-        LERROR << mnt_type << " has no mkfs cookbook";
+        LERROR << "No supported mkfs command or filesystem driver available, supported filesystems "
+                  "are: f2fs, ext4";
         return false;
     }
     command += " " + scratch_device + " >/dev/null 2>/dev/null </dev/null";
     fs_mgr_set_blk_ro(scratch_device, false);
     auto ret = system(command.c_str());
     if (ret) {
-        LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret;
+        LERROR << "make " << fs_type << " filesystem on " << scratch_device << " return=" << ret;
         return false;
     }
     return true;
@@ -1176,15 +1112,7 @@
         return *partition_exists;
     }
 
-    // Try a physical partition first.
-    *scratch_device = GetPhysicalScratchDevice();
-    if (!scratch_device->empty() && fs_mgr_rw_access(*scratch_device)) {
-        *partition_exists = true;
-        return true;
-    }
-
-    // If that fails, see if we can land on super.
-    bool is_virtual_ab;
+    bool is_virtual_ab = false;
     if (CanUseSuperPartition(fstab, &is_virtual_ab)) {
         bool can_use_data = false;
         if (is_virtual_ab && FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
@@ -1192,7 +1120,6 @@
         }
         return CreateDynamicScratch(scratch_device, partition_exists);
     }
-
     return false;
 }
 
@@ -1210,9 +1137,8 @@
     }
 
     // If the partition exists, assume first that it can be mounted.
-    auto mnt_type = fs_mgr_overlayfs_scratch_mount_type();
     if (partition_exists) {
-        if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) {
+        if (MountScratch(scratch_device)) {
             if (fs_mgr_access(kScratchMountPoint + kOverlayTopDir) ||
                 fs_mgr_filesystem_has_space(kScratchMountPoint)) {
                 return true;
@@ -1225,19 +1151,49 @@
         }
     }
 
-    if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) {
+    if (!MakeScratchFilesystem(scratch_device)) {
         LOG(ERROR) << "Failed to format scratch partition";
         return false;
     }
 
-    return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type);
+    return MountScratch(scratch_device);
 }
 
-bool fs_mgr_overlayfs_invalid() {
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true;
+#if ALLOW_ADBD_DISABLE_VERITY
+constexpr bool kAllowOverlayfs = true;
+#else
+constexpr bool kAllowOverlayfs = false;
+#endif
 
+// NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed().
+// Setup is allowed only if teardown is also allowed.
+bool OverlayfsSetupAllowed(bool verbose = false) {
+    if (!kAllowOverlayfs) {
+        if (verbose) {
+            LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
+        }
+        return false;
+    }
+    // Check mandatory kernel patches.
+    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
+        if (verbose) {
+            LOG(ERROR) << "Kernel does not support overlayfs";
+        }
+        return false;
+    }
     // in recovery or fastbootd, not allowed!
-    return fs_mgr_in_recovery();
+    if (fs_mgr_in_recovery()) {
+        if (verbose) {
+            LOG(ERROR) << "Unsupported overlayfs setup from recovery";
+        }
+        return false;
+    }
+    return true;
+}
+
+constexpr bool OverlayfsTeardownAllowed() {
+    // Never allow on non-debuggable build.
+    return kAllowOverlayfs;
 }
 
 }  // namespace
@@ -1319,19 +1275,18 @@
     if (!WaitForFile(scratch_device, 10s)) {
         return;
     }
-    const auto mount_type = fs_mgr_overlayfs_scratch_mount_type();
-    if (!fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type, true /* readonly */)) {
+    if (!MountScratch(scratch_device, true /* readonly */)) {
         return;
     }
     auto has_overlayfs_dir = fs_mgr_access(kScratchMountPoint + kOverlayTopDir);
     fs_mgr_overlayfs_umount_scratch();
     if (has_overlayfs_dir) {
-        fs_mgr_overlayfs_mount_scratch(scratch_device, mount_type);
+        MountScratch(scratch_device);
     }
 }
 
 bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
-    if (fs_mgr_overlayfs_invalid()) {
+    if (!OverlayfsSetupAllowed()) {
         return false;
     }
     auto ret = true;
@@ -1352,8 +1307,7 @@
 }
 
 bool fs_mgr_overlayfs_setup(const char* mount_point, bool* want_reboot, bool just_disabled_verity) {
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
-        LOG(ERROR) << "Overlayfs is not supported";
+    if (!OverlayfsSetupAllowed(/*verbose=*/true)) {
         return false;
     }
 
@@ -1523,7 +1477,8 @@
     return true;
 }
 
-OverlayfsTeardownResult TeardownMountsAndScratch(const char* mount_point, bool* want_reboot) {
+static OverlayfsTeardownResult TeardownMountsAndScratch(const char* mount_point,
+                                                        bool* want_reboot) {
     bool should_destroy_scratch = false;
     auto rv = OverlayfsTeardownResult::Ok;
     for (const auto& overlay_mount_point : OverlayMountPoints()) {
@@ -1555,14 +1510,17 @@
 
 // Returns false if teardown not permitted. If something is altered, set *want_reboot.
 OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point, bool* want_reboot) {
+    if (!OverlayfsTeardownAllowed()) {
+        // Nothing to teardown.
+        return OverlayfsTeardownResult::Ok;
+    }
     // If scratch exists, but is not mounted, lets gain access to clean
     // specific override entries.
     auto mount_scratch = false;
     if ((mount_point != nullptr) && !fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) {
         std::string scratch_device = GetBootScratchDevice();
         if (!scratch_device.empty()) {
-            mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device,
-                                                           fs_mgr_overlayfs_scratch_mount_type());
+            mount_scratch = MountScratch(scratch_device);
         }
     }
 
@@ -1577,12 +1535,14 @@
 }
 
 bool fs_mgr_overlayfs_is_setup() {
+    if (!OverlayfsSetupAllowed()) {
+        return false;
+    }
     if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
     Fstab fstab;
     if (!ReadDefaultFstab(&fstab)) {
         return false;
     }
-    if (fs_mgr_overlayfs_invalid()) return 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))) return true;
@@ -1595,7 +1555,7 @@
 
 void MapScratchPartitionIfNeeded(Fstab* fstab,
                                  const std::function<bool(const std::set<std::string>&)>& init) {
-    if (fs_mgr_overlayfs_invalid()) {
+    if (!OverlayfsSetupAllowed()) {
         return;
     }
     if (GetEntryForMountPoint(fstab, kScratchMountPoint) != nullptr) {
@@ -1632,6 +1592,9 @@
 }
 
 void CleanupOldScratchFiles() {
+    if (!OverlayfsTeardownAllowed()) {
+        return;
+    }
     if (!ScratchIsOnData()) {
         return;
     }
@@ -1641,6 +1604,9 @@
 }
 
 void TeardownAllOverlayForMountPoint(const std::string& mount_point) {
+    if (!OverlayfsTeardownAllowed()) {
+        return;
+    }
     if (!fs_mgr_in_recovery()) {
         LERROR << __FUNCTION__ << "(): must be called within recovery.";
         return;
@@ -1675,7 +1641,7 @@
     if (auto info = EnsureScratchMapped(); info.has_value()) {
         // Map scratch device, mount kScratchMountPoint and teardown kScratchMountPoint.
         fs_mgr_overlayfs_umount_scratch();
-        if (fs_mgr_overlayfs_mount_scratch(info->device, fs_mgr_overlayfs_scratch_mount_type())) {
+        if (MountScratch(info->device)) {
             bool should_destroy_scratch = false;
             fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change,
                                           &should_destroy_scratch);
@@ -1690,7 +1656,7 @@
     std::string scratch_device;
     if (MapDsuScratchDevice(&scratch_device)) {
         fs_mgr_overlayfs_umount_scratch();
-        if (fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type())) {
+        if (MountScratch(scratch_device)) {
             fs_mgr_overlayfs_teardown_one(kScratchMountPoint, teardown_dir, ignore_change);
             fs_mgr_overlayfs_umount_scratch();
         }
@@ -1701,8 +1667,6 @@
 }  // namespace fs_mgr
 }  // namespace android
 
-#endif  // ALLOW_ADBD_DISABLE_VERITY != 0
-
 bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
     Fstab fstab;
     if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
@@ -1722,65 +1686,3 @@
     }
     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) ||
-        (fs.f_type != EXT4_SUPER_MAGIC)) {
-        return false;
-    }
-
-    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
-    if (fd < 0) return false;
-
-    struct ext4_super_block sb;
-    if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
-        (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
-        return false;
-    }
-
-    struct fs_info info;
-    if (ext4_parse_sb(&sb, &info) < 0) return false;
-
-    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
-}
-
-std::string fs_mgr_get_context(const std::string& mount_point) {
-    char* ctx = nullptr;
-    if (getfilecon(mount_point.c_str(), &ctx) == -1) {
-        PLOG(ERROR) << "getfilecon " << mount_point;
-        return "";
-    }
-
-    std::string context(ctx);
-    free(ctx);
-    return context;
-}
-
-OverlayfsValidResult fs_mgr_overlayfs_valid() {
-    // Overlayfs available in the kernel, and patched for override_creds?
-    if (fs_mgr_access("/sys/module/overlay/parameters/override_creds")) {
-        return OverlayfsValidResult::kOverrideCredsRequired;
-    }
-    if (!fs_mgr_overlayfs_filesystem_available("overlay")) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    struct utsname uts;
-    if (uname(&uts) == -1) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    int major, minor;
-    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    if (major < 4) {
-        return OverlayfsValidResult::kOk;
-    }
-    if (major > 4) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    if (minor > 3) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    return OverlayfsValidResult::kOk;
-}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index c5e477c..46f54cc 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -99,6 +99,16 @@
 
 bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab);
 
+bool fs_mgr_filesystem_available(const std::string& filesystem);
+std::string fs_mgr_get_context(const std::string& mount_point);
+
+enum class OverlayfsValidResult {
+    kNotSupported = 0,
+    kOk,
+    kOverrideCredsRequired,
+};
+OverlayfsValidResult fs_mgr_overlayfs_valid();
+
 namespace android {
 namespace fs_mgr {
 bool UnmapDevice(const std::string& name);
diff --git a/fs_mgr/fs_mgr_priv_overlayfs.h b/fs_mgr/fs_mgr_priv_overlayfs.h
new file mode 100644
index 0000000..45b954d
--- /dev/null
+++ b/fs_mgr/fs_mgr_priv_overlayfs.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <fstab/fstab.h>
+
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
+bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
+android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
+
+// If "mount_point" is non-null, set up exactly one overlay.
+// If "mount_point" is null, setup any overlays.
+//
+// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then
+// it will be true on return. The caller is responsible for initializing it.
+bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* want_reboot = nullptr,
+                            bool just_disabled_verity = true);
+
+enum class OverlayfsTeardownResult {
+    Ok,
+    Busy,  // Indicates that overlays are still in use.
+    Error
+};
+OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr,
+                                                  bool* want_reboot = nullptr);
+
+namespace android {
+namespace fs_mgr {
+
+void CleanupOldScratchFiles();
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index a78f945..2edaaad 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -35,20 +35,21 @@
 #include <binder/IServiceManager.h>
 #include <bootloader_message/bootloader_message.h>
 #include <cutils/android_reboot.h>
-#include <fec/io.h>
 #include <fs_mgr_overlayfs.h>
 #include <fs_mgr_priv.h>
 #include <fstab/fstab.h>
 #include <libavb_user/libavb_user.h>
 #include <libgsi/libgsid.h>
 
+#include "fs_mgr_priv_overlayfs.h"
+
 using namespace std::literals;
 using android::fs_mgr::Fstab;
 using android::fs_mgr::FstabEntry;
 
 namespace {
 
-[[noreturn]] void usage(int exit_status) {
+void usage() {
     LOG(INFO) << getprogname()
               << " [-h] [-R] [-T fstab_file] [partition]...\n"
                  "\t-h --help\tthis help\n"
@@ -60,8 +61,6 @@
                  "-R notwithstanding, verity must be disabled on partition(s).\n"
                  "-R within a DSU guest system reboots into the DSU instead of the host system,\n"
                  "this command would enable DSU (one-shot) if not already enabled.";
-
-    ::exit(exit_status);
 }
 
 const std::string system_mount_point(const android::fs_mgr::FstabEntry& entry) {
@@ -114,15 +113,9 @@
 
 }  // namespace
 
-using namespace std::chrono_literals;
-
 enum RemountStatus {
     REMOUNT_SUCCESS = 0,
-    NOT_USERDEBUG,
-    BADARG,
-    NOT_ROOT,
-    NO_FSTAB,
-    UNKNOWN_PARTITION,
+    UNKNOWN_PARTITION = 5,
     INVALID_PARTITION,
     VERITY_PARTITION,
     BAD_OVERLAY,
@@ -279,23 +272,13 @@
     if (!fs_mgr_is_verity_enabled(entry)) {
         return REMOUNT_SUCCESS;
     }
-    if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
-        return VERITY_PARTITION;
-    }
-
-    bool ok = false;
 
     std::unique_ptr<AvbOps, decltype(&::avb_ops_user_free)> ops(avb_ops_user_new(),
                                                                 &::avb_ops_user_free);
-    if (ops) {
-        auto suffix = android::base::GetProperty("ro.boot.slot_suffix", "");
-        ok = avb_user_verity_set(ops.get(), suffix.c_str(), false);
+    if (!ops) {
+        return VERITY_PARTITION;
     }
-    if (!ok && fs_mgr_set_blk_ro(entry.blk_device, false)) {
-        fec::io fh(entry.blk_device.c_str(), O_RDWR);
-        ok = fh && fh.set_verity_status(false);
-    }
-    if (!ok) {
+    if (!avb_user_verity_set(ops.get(), fs_mgr_get_slot_suffix().c_str(), false)) {
         return VERITY_PARTITION;
     }
     result->disabled_verity = true;
@@ -487,15 +470,20 @@
     // Make sure we are root.
     if (::getuid() != 0) {
         LOG(ERROR) << "Not running as root. Try \"adb root\" first.";
-        return NOT_ROOT;
+        return 1;
     }
 
     // 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;
+    if (!ALLOW_ADBD_DISABLE_VERITY || !android::base::GetBoolProperty("ro.debuggable", false)) {
+        LOG(ERROR) << "Device must be userdebug build";
+        return 1;
+    }
+
+    if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked") {
+        LOG(ERROR) << "Device must be bootloader unlocked";
+        return 1;
     }
 
     const char* fstab_file = nullptr;
@@ -512,15 +500,16 @@
     for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
         switch (opt) {
             case 'h':
-                usage(SUCCESS);
-                break;
+                usage();
+                return 0;
             case 'R':
                 auto_reboot = true;
                 break;
             case 'T':
                 if (fstab_file) {
                     LOG(ERROR) << "Cannot supply two fstabs: -T " << fstab_file << " -T" << optarg;
-                    usage(BADARG);
+                    usage();
+                    return 1;
                 }
                 fstab_file = optarg;
                 break;
@@ -529,8 +518,8 @@
                 break;
             default:
                 LOG(ERROR) << "Bad Argument -" << char(opt);
-                usage(BADARG);
-                break;
+                usage();
+                return 1;
         }
     }
 
@@ -547,7 +536,7 @@
     Fstab fstab;
     if (!ReadFstab(fstab_file, &fstab) || fstab.empty()) {
         PLOG(ERROR) << "Failed to read fstab";
-        return NO_FSTAB;
+        return 1;
     }
 
     RemountCheckResult check_result;
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index 1372511..6b32b4d 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -25,7 +25,6 @@
 
 #include <android-base/logging.h>
 #include <android-base/properties.h>
-#include <fs_mgr_overlayfs.h>
 #include <fs_mgr_vendor_overlay.h>
 #include <fstab/fstab.h>
 
diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h
index 4d9b13f..bdaabbf 100644
--- a/fs_mgr/include/fs_mgr_overlayfs.h
+++ b/fs_mgr/include/fs_mgr_overlayfs.h
@@ -17,51 +17,21 @@
 #pragma once
 
 #include <functional>
+#include <set>
+#include <string>
 
 #include <fstab/fstab.h>
 
-#include <set>
-#include <string>
-#include <vector>
+// Keep the list short and only add interfaces that must be exported public.
 
-android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
-
-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_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);
-
-// If "mount_point" is non-null, set up exactly one overlay.
-// If "mount_point" is null, setup any overlays.
-//
-// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then
-// it will be true on return. The caller is responsible for initializing it.
-bool fs_mgr_overlayfs_setup(const char* mount_point = nullptr, bool* want_reboot = nullptr,
-                            bool just_disabled_verity = true);
-
-enum class OverlayfsTeardownResult {
-    Ok,
-    Busy,  // Indicates that overlays are still in use.
-    Error
-};
-OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr,
-                                                  bool* want_reboot = nullptr);
-
-enum class OverlayfsValidResult {
-    kNotSupported = 0,
-    kOk,
-    kOverrideCredsRequired,
-};
-OverlayfsValidResult fs_mgr_overlayfs_valid();
 
 namespace android {
 namespace fs_mgr {
 
 void MapScratchPartitionIfNeeded(Fstab* fstab,
                                  const std::function<bool(const std::set<std::string>&)>& init);
-void CleanupOldScratchFiles();
 
 // Teardown overlays of all sources (cache dir, scratch device, DSU) for |mount_point|.
 // Teardown all overlays if |mount_point| is empty.
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 34c7baf..cdff06e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -332,10 +332,13 @@
     // Helper function for second stage init to restorecon on the rollback indicator.
     static std::string GetGlobalRollbackIndicatorPath();
 
-    // Detach dm-user devices from the current snapuserd, and populate
-    // |snapuserd_argv| with the necessary arguments to restart snapuserd
-    // and reattach them.
-    bool DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv);
+    // Populate |snapuserd_argv| with the necessary arguments to restart snapuserd
+    // after loading selinux policy.
+    bool PrepareSnapuserdArgsForSelinux(std::vector<std::string>* snapuserd_argv);
+
+    // Detach dm-user devices from the first stage snapuserd. Load
+    // new dm-user tables after loading selinux policy.
+    bool DetachFirstStageSnapuserdForSelinux();
 
     // Perform the transition from the selinux stage of snapuserd into the
     // second-stage of snapuserd. This process involves re-creating the dm-user
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 59abd6f..6fed09c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1746,13 +1746,6 @@
 
         auto misc_name = user_cow_name;
 
-        DmTable table;
-        table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
-        if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
-            LOG(ERROR) << "Unable to swap tables for " << misc_name;
-            continue;
-        }
-
         std::string source_device_name;
         if (snapshot_status.old_partition_size() > 0) {
             source_device_name = GetSourceDeviceName(snapshot);
@@ -1780,13 +1773,6 @@
             continue;
         }
 
-        // Wait for ueventd to acknowledge and create the control device node.
-        std::string control_device = "/dev/dm-user/" + misc_name;
-        if (!WaitForDevice(control_device, 10s)) {
-            LOG(ERROR) << "dm-user control device no found:  " << misc_name;
-            continue;
-        }
-
         if (transition == InitTransition::SELINUX_DETACH) {
             if (!UpdateUsesUserSnapshots(lock.get())) {
                 auto message = misc_name + "," + cow_image_device + "," + source_device;
@@ -1804,6 +1790,20 @@
             continue;
         }
 
+        DmTable table;
+        table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
+        if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
+            LOG(ERROR) << "Unable to swap tables for " << misc_name;
+            continue;
+        }
+
+        // Wait for ueventd to acknowledge and create the control device node.
+        std::string control_device = "/dev/dm-user/" + misc_name;
+        if (!WaitForDevice(control_device, 10s)) {
+            LOG(ERROR) << "dm-user control device no found:  " << misc_name;
+            continue;
+        }
+
         uint64_t base_sectors;
         if (!UpdateUsesUserSnapshots(lock.get())) {
             base_sectors =
@@ -4136,10 +4136,71 @@
     return status.state() != UpdateState::None && status.using_snapuserd();
 }
 
-bool SnapshotManager::DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv) {
+bool SnapshotManager::PrepareSnapuserdArgsForSelinux(std::vector<std::string>* snapuserd_argv) {
     return PerformInitTransition(InitTransition::SELINUX_DETACH, snapuserd_argv);
 }
 
+bool SnapshotManager::DetachFirstStageSnapuserdForSelinux() {
+    LOG(INFO) << "Detaching first stage snapuserd";
+
+    auto lock = LockExclusive();
+    if (!lock) return false;
+
+    std::vector<std::string> snapshots;
+    if (!ListSnapshots(lock.get(), &snapshots)) {
+        LOG(ERROR) << "Failed to list snapshots.";
+        return false;
+    }
+
+    size_t num_cows = 0;
+    size_t ok_cows = 0;
+    for (const auto& snapshot : snapshots) {
+        std::string user_cow_name = GetDmUserCowName(snapshot, GetSnapshotDriver(lock.get()));
+
+        if (dm_.GetState(user_cow_name) == DmDeviceState::INVALID) {
+            continue;
+        }
+
+        DeviceMapper::TargetInfo target;
+        if (!GetSingleTarget(user_cow_name, TableQuery::Table, &target)) {
+            continue;
+        }
+
+        auto target_type = DeviceMapper::GetTargetType(target.spec);
+        if (target_type != "user") {
+            LOG(ERROR) << "Unexpected target type for " << user_cow_name << ": " << target_type;
+            continue;
+        }
+
+        num_cows++;
+        auto misc_name = user_cow_name;
+
+        DmTable table;
+        table.Emplace<DmTargetUser>(0, target.spec.length, misc_name);
+        if (!dm_.LoadTableAndActivate(user_cow_name, table)) {
+            LOG(ERROR) << "Unable to swap tables for " << misc_name;
+            continue;
+        }
+
+        // Wait for ueventd to acknowledge and create the control device node.
+        std::string control_device = "/dev/dm-user/" + misc_name;
+        if (!WaitForDevice(control_device, 10s)) {
+            LOG(ERROR) << "dm-user control device no found:  " << misc_name;
+            continue;
+        }
+
+        ok_cows++;
+        LOG(INFO) << "control device is ready: " << control_device;
+    }
+
+    if (ok_cows != num_cows) {
+        LOG(ERROR) << "Could not transition all snapuserd consumers.";
+        return false;
+    }
+
+    return true;
+}
+
 bool SnapshotManager::PerformSecondStageInitTransition() {
     return PerformInitTransition(InitTransition::SECOND_STAGE);
 }
diff --git a/fs_mgr/set-verity-state.cpp b/fs_mgr/set-verity-state.cpp
new file mode 100644
index 0000000..84ee01f
--- /dev/null
+++ b/fs_mgr/set-verity-state.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <binder/ProcessState.h>
+#include <cutils/android_reboot.h>
+#include <fs_mgr_overlayfs.h>
+#include <libavb_user/libavb_user.h>
+
+#include "fs_mgr_priv_overlayfs.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
+const bool kAllowDisableVerity = true;
+#else
+const bool kAllowDisableVerity = false;
+#endif
+
+static bool SetupOrTeardownOverlayfs(bool enable) {
+    bool want_reboot = false;
+    if (enable) {
+        if (!fs_mgr_overlayfs_setup(nullptr, &want_reboot)) {
+            LOG(ERROR) << "Overlayfs setup failed.";
+            return want_reboot;
+        }
+        if (want_reboot) {
+            printf("enabling overlayfs\n");
+        }
+    } else {
+        auto rv = fs_mgr_overlayfs_teardown(nullptr, &want_reboot);
+        if (rv == OverlayfsTeardownResult::Error) {
+            LOG(ERROR) << "Overlayfs teardown failed.";
+            return want_reboot;
+        }
+        if (rv == OverlayfsTeardownResult::Busy) {
+            LOG(ERROR) << "Overlayfs is still active until reboot.";
+            return true;
+        }
+        if (want_reboot) {
+            printf("disabling overlayfs\n");
+        }
+    }
+    return want_reboot;
+}
+
+/* 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.
+ */
+std::string get_ab_suffix() {
+    return android::base::GetProperty("ro.boot.slot_suffix", "");
+}
+
+bool is_avb_device_locked() {
+    return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
+}
+
+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);
+}
+
+struct SetVerityStateResult {
+    bool success = false;
+    bool want_reboot = false;
+};
+
+/* Use AVB to turn verity on/off */
+SetVerityStateResult SetVerityState(bool enable_verity) {
+    std::string ab_suffix = get_ab_suffix();
+    bool verity_enabled = false;
+
+    if (is_avb_device_locked()) {
+        LOG(ERROR) << "Device must be bootloader unlocked to change verity state";
+        return {};
+    }
+
+    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)) {
+        LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled");
+        return {.success = true, .want_reboot = false};
+    }
+
+    if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) {
+        LOG(ERROR) << "Error setting verity state";
+        return {};
+    }
+
+    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[]) {
+    bool auto_reboot = false;
+    bool verbose = false;
+
+    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;
+        }
+    }
+
+    android::base::InitLogging(argv, MyLogger(verbose));
+
+    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;
+    }
+
+    if (!kAllowDisableVerity || !is_debuggable()) {
+        errno = EPERM;
+        PLOG(ERROR) << "Cannot disable/enable verity on user build";
+        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 |= SetupOrTeardownOverlayfs(!enable_verity);
+    }
+
+    if (want_reboot) {
+        if (auto_reboot) {
+            reboot(progname);
+        }
+        printf("Reboot the device for new settings to take effect\n");
+    }
+
+    return exit_code;
+}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index a6bdd6c..eba4f6e 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -1241,40 +1241,45 @@
 adb_sh grep -q " /vendor [^ ]* rw," /proc/mounts </dev/null ||
   die -t "${T}" "/vendor is not RW"
 
+scratch_on_super=false
 if ${overlayfs_needed}; then
-  is_overlayfs_mounted || die -t "${T}" "expected overlay takeover"
-else
-  is_overlayfs_mounted && die -t "${T}" "unexpected overlay takeover"
-fi
+  is_overlayfs_mounted /system ||
+    die -t "${T}" "expected overlay to takeover /system after remount"
 
-# If scratch_partition && uses_dynamic_scratch, then scratch is on super.
-# If scratch_partition && !uses_dynamic_scratch, then scratch is super_other, system_other.
-# If !scratch_partition, then scratch is on /data via image_manager.
-uses_dynamic_scratch=false
-scratch_partition=
-virtual_ab=$(get_property ro.virtual_ab.enabled)
-if ${overlayfs_needed}; then
+  # Collect information about the scratch device if we have one
   M=$(adb_sh cat /proc/mounts </dev/null |
       awk '$2 == "/mnt/scratch" { print $1, $3; exit }')
-  [ -z "${M}" ] && die "cannot find any scratch device mounted on /mnt/scratch"
+  if [ -n "${M}" ]; then
+    scratch_device=$(echo "${M}" | awk '{ print $1 }')
+    scratch_filesystem=$(echo "${M}" | awk '{ print $2 }')
+    scratch_size=$(adb_sh df -k "${scratch_device}" </dev/null |
+                  tail +2 | head -1 | awk '{ print $2 }')
+    [ -z "${scratch_size}" ] && die "cannot get size of scratch device (${scratch_device})"
 
-  scratch_device=$(echo "${M}" | awk '{ print $1 }')
-  scratch_filesystem=$(echo "${M}" | awk '{ print $2 }')
-  scratch_size=$(adb_sh df -k "${scratch_device}" </dev/null |
-                 tail +2 | head -1 | awk '{ print $2 }')
-  [ -z "${scratch_size}" ] && die "cannot get size of scratch device (${scratch_device})"
+    # Detect scratch partition backed by super?
+    for b in "/dev/block/by-name/super"{,_${ACTIVE_SLOT}}; do
+      if adb_test -e "${b}"; then
+        device=$(adb_su realpath "${b}")
+        D=$(adb_su stat -c '0x%t 0x%T' "${device}")
+        major=$(echo "${D}" | awk '{ print $1 }')
+        minor=$(echo "${D}" | awk '{ print $2 }')
+        super_devt=$(( major )):$(( minor ))
+        if adb_su dmctl table scratch | tail +2 | grep -q -w "${super_devt}"; then
+          scratch_on_super=true
+        fi
+        break
+      fi
+    done
 
-  if [ -n "${virtual_ab}" ]; then
-    LOG INFO "using dynamic scratch partition on /data (VAB device)"
-  elif [[ "${scratch_device}" == /dev/block/by-name/* ]]; then
-    scratch_partition="${scratch_device##/dev/block/by-name/}"
-    LOG INFO "using physical scratch partition ${scratch_partition}"
+    if ${scratch_on_super}; then
+      LOG INFO "using dynamic scratch partition on super"
+    else
+      LOG INFO "using dynamic scratch partition on /data (VAB device)"
+    fi
+    LOG INFO "scratch device ${scratch_device} filesystem ${scratch_filesystem} size ${scratch_size}KiB"
   else
-    uses_dynamic_scratch=true
-    scratch_partition=scratch
-    LOG INFO "using dynamic scratch partition on super"
+    LOG INFO "cannot find any scratch device mounted on /mnt/scratch, using scratch on /cache"
   fi
-  LOG INFO "scratch device ${scratch_device} filesystem ${scratch_filesystem} size ${scratch_size}KiB"
 
   for d in ${OVERLAYFS_BACKING}; do
     if adb_test -d /${d}/overlay/system/upper; then
@@ -1283,8 +1288,6 @@
   done
 
   data_device=$(adb_sh awk '$2 == "/data" { print $1; exit }' /proc/mounts)
-  is_overlayfs_mounted /system 2>/dev/null ||
-    die -t "${T}" "expected overlay to takeover /system after remount"
   # KISS (we do not support sub-mounts for system partitions currently)
   adb_sh grep "^overlay " /proc/mounts </dev/null |
     grep -vE "^overlay.* /(apex|system|vendor)/[^ ]" |
@@ -1312,6 +1315,8 @@
       die "remount overlayfs missed a spot (rw)"
     fi
   done
+else
+  is_overlayfs_mounted && die -t "${T}" "unexpected overlay takeover"
 fi
 
 LOG OK "adb remount RW"
@@ -1455,31 +1460,18 @@
 
   fastboot_getvar is-userspace yes &&
     is_userspace_fastboot=true
-  # check ${scratch_partition} via fastboot
-  if [ -n "${scratch_partition}" ]; then
-    fastboot_getvar partition-type:${scratch_partition} raw ||
-      ( fastboot reboot && false) ||
-      die "fastboot can not see ${scratch_partition} parameters"
-    if ${uses_dynamic_scratch}; then
-      fastboot_getvar has-slot:${scratch_partition} no &&
-        fastboot_getvar is-logical:${scratch_partition} yes ||
-        ( fastboot reboot && false) ||
-        die "fastboot can not see ${scratch_partition} parameters"
-      LOG INFO "expect fastboot erase ${scratch_partition} to fail"
-      fastboot erase ${scratch_partition} &&
-        ( fastboot reboot || true) &&
-        die "fastboot can erase ${scratch_partition}"
-    else
-      fastboot_getvar is-logical:${scratch_partition} no ||
-        ( fastboot reboot && false) ||
-        die "fastboot can not see ${scratch_partition} parameters"
-      fastboot reboot-bootloader ||
-        die "fastboot reboot bootloader"
-    fi
-    LOG INFO "expect fastboot format ${scratch_partition} to fail"
-    fastboot format ${scratch_partition} &&
-      ( fastboot reboot || true) &&
-      die "fastboot can format ${scratch_partition}"
+
+  if ${scratch_on_super}; then
+    fastboot_getvar partition-type:scratch raw ||
+      die "fastboot cannot see parameter partition-type:scratch"
+    fastboot_getvar has-slot:scratch no ||
+      die "fastboot cannot see parameter has-slot:scratch"
+    fastboot_getvar is-logical:scratch yes ||
+      die "fastboot cannot see parameter is-logical:scratch"
+    LOG INFO "expect fastboot erase scratch to fail"
+    fastboot erase scratch && die "fastboot can erase scratch"
+    LOG INFO "expect fastboot format scratch to fail"
+    fastboot format scratch && die "fastboot can format scratch"
   fi
 
   fastboot reboot || die "cannot reboot out of fastboot"
@@ -1539,9 +1531,9 @@
 done
 
 ################################################################################
-if ${is_bootloader_fastboot} && [ -n "${scratch_partition}" ]; then
+if ${is_bootloader_fastboot} && ${scratch_on_super}; then
 
-  LOG RUN "test fastboot flash to ${scratch_partition} recovery"
+  LOG RUN "test fastboot flash to scratch recovery"
 
   avc_check
   adb reboot fastboot </dev/null ||
@@ -1550,15 +1542,15 @@
   dd if=/dev/zero of=${img} bs=4096 count=16 2>/dev/null &&
     fastboot_wait ${FASTBOOT_WAIT} ||
     die "reboot into fastboot to flash scratch `usb_status`"
-  fastboot flash --force ${scratch_partition} ${img}
+  fastboot flash --force scratch ${img}
   err=${?}
   fastboot reboot ||
     die "can not reboot out of fastboot"
   [ 0 -eq ${err} ] ||
-    die "fastboot flash ${scratch_partition}"
+    die "fastboot flash scratch"
   adb_wait ${ADB_WAIT} &&
     adb_root ||
-    die "did not reboot after flashing empty ${scratch_partition} `usb_status`"
+    die "did not reboot after flashing empty scratch $(usb_status)"
   T=`adb_date`
   D=`adb disable-verity 2>&1`
   err=${?}
@@ -1578,7 +1570,7 @@
   [ ${err} = 0 ] &&
     [ X"${D}" = X"${D##*setup failed}" ] &&
     [ X"${D}" != X"${D##*[Uu]sing overlayfs}" ] &&
-    LOG OK "${scratch_partition} recreated" ||
+    LOG OK "recreated scratch" ||
     die -t ${T} "setup for overlayfs"
   adb remount >&2 ||
     die -t ${T} "remount failed"
diff --git a/init/Android.bp b/init/Android.bp
index f0e362c..f6f1e8c 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -308,7 +308,7 @@
     name: "init_first_stage_cc_defaults",
     module_type: "cc_defaults",
     config_namespace: "ANDROID",
-    bool_variables: ["BOARD_BUILD_SYSTEM_ROOT_IMAGE", "BOARD_USES_RECOVERY_AS_BOOT"],
+    bool_variables: ["BOARD_USES_RECOVERY_AS_BOOT"],
     properties: ["installable"],
 }
 
@@ -317,9 +317,6 @@
 init_first_stage_cc_defaults {
     name: "init_first_stage_defaults",
     soong_config_variables: {
-        BOARD_BUILD_SYSTEM_ROOT_IMAGE: {
-            installable: false,
-        },
         BOARD_USES_RECOVERY_AS_BOOT: {
             installable: false,
         },
diff --git a/init/Android.mk b/init/Android.mk
index c08fe03..4b85c15 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -8,11 +8,9 @@
 LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
 LOCAL_LICENSE_CONDITIONS := notice
 LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-ifneq ($(BOARD_BUILD_SYSTEM_ROOT_IMAGE),true)
 ifneq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
 LOCAL_REQUIRED_MODULES := \
    init_first_stage \
 
 endif  # BOARD_USES_RECOVERY_AS_BOOT
-endif  # BOARD_BUILD_SYSTEM_ROOT_IMAGE
 include $(BUILD_PHONY_PACKAGE)
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
new file mode 100644
index 0000000..c21a196
--- /dev/null
+++ b/init/fuzzer/Android.bp
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+package {
+    default_applicable_licenses: ["system_core_init_license"],
+}
+
+cc_defaults {
+    name: "libinit_defaults",
+    static_libs: [
+        "libc++fs",
+        "liblmkd_utils",
+        "libmodprobe",
+        "libprotobuf-cpp-lite",
+        "libpropertyinfoparser",
+        "libsnapshot_init",
+        "libinit",
+    ],
+    shared_libs: [
+        "libbase",
+        "libfs_mgr",
+        "libhidl-gen-utils",
+        "libkeyutils",
+        "liblog",
+        "libprocessgroup",
+        "libselinux",
+    ],
+    header_libs: ["libinit_headers"],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+    },
+}
+
+cc_fuzz {
+    name: "init_parser_fuzzer",
+    srcs: [
+        "init_parser_fuzzer.cpp",
+    ],
+    shared_libs: ["libhidlmetadata",],
+    defaults: [
+        "libinit_defaults",
+    ],
+}
+
+cc_fuzz {
+    name: "init_property_fuzzer",
+    srcs: [
+        "init_property_fuzzer.cpp",
+    ],
+    defaults: ["libinit_defaults"],
+}
+
+cc_fuzz {
+    name: "init_ueventHandler_fuzzer",
+    srcs: [
+        "init_ueventHandler_fuzzer.cpp",
+    ],
+    defaults: [
+        "libinit_defaults",
+    ],
+}
diff --git a/init/fuzzer/README.md b/init/fuzzer/README.md
new file mode 100644
index 0000000..fc9a6a6
--- /dev/null
+++ b/init/fuzzer/README.md
@@ -0,0 +1,98 @@
+# Fuzzers for libinit
+
+## Table of contents
++ [init_parser_fuzzer](#InitParser)
++ [init_property_fuzzer](#InitProperty)
++ [init_ueventHandler_fuzzer](#InitUeventHandler)
+
+# <a name="InitParser"></a> Fuzzer for InitParser
+
+InitParser supports the following parameters:
+1. ValidPathNames (parameter name: "kValidPaths")
+2. ValidParseInputs (parameter name: "kValidInputs")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kValidPaths`| 0.`/system/etc/init/hw/init.rc`,<br/> 1.`/system/etc/init` |Value obtained from FuzzedDataProvider|
+|`kValidInputs`| 0.`{"","cpu", "10", "10"}`,<br/> 1.`{"","RLIM_CPU", "10", "10"}`,<br/> 2.`{"","12", "unlimited", "10"}`,<br/> 3.`{"","13", "-1", "10"}`,<br/> 4.`{"","14", "10", "unlimited"}`,<br/> 5.`{"","15", "10", "-1"}` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) init_parser_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/init_parser_fuzzer/init_parser_fuzzer
+```
+
+# <a name="InitProperty"></a> Fuzzer for InitProperty
+
+InitProperty supports the following parameters:
+  PropertyType (parameter name: "PropertyType")
+
+| Parameter| Valid Values |Configured Value|
+|-------------|----------|----- |
+|`PropertyType`| 0.`STRING`,<br/> 1.`BOOL`,<br/> 2.`INT`,<br/> 3.`UINT`,<br/> 4.`DOUBLE`,<br/> 5.`SIZE`,<br/>6.`ENUM`,<br/>7.`RANDOM`|Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+  $ mm -j$(nproc) init_property_fuzzer
+```
+2. Run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/arm64/init_property_fuzzer/init_property_fuzzer
+```
+
+# <a name="InitUeventHandler"></a> Fuzzer for InitUeventHandler
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+InitUeventHandler supports the following parameters:
+1. Major (parameter name: `major`)
+2. Minor (parameter name: `minor`)
+3. PartitionNum (parameter name: `partition_num`)
+4. Uid (parameter name: `uid`)
+5. Gid (parameter name: `gid`)
+6. Action (parameter name: `action`)
+7. Path (parameter name: `path`)
+8. Subsystem (parameter name: `subsystem`)
+9. PartitionName (parameter name: `partition_name`)
+10. DeviceName (parameter name: `device_name`)
+11. Modalias (parameter name: `modalias`)
+12. DevPath (parameter name: `devPath`)
+13. HandlerPath (parameter name: `handlerPath`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `major` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `minor` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `partition_num ` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `uid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `gid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `action` | `String` | Value obtained from FuzzedDataProvider|
+| `path` | `String` | Value obtained from FuzzedDataProvider|
+| `subsystem` | `String` | Value obtained from FuzzedDataProvider|
+| `partition_name` | `String` | Value obtained from FuzzedDataProvider|
+| `device_name` | `String` | Value obtained from FuzzedDataProvider|
+| `modalias` | `String` | Value obtained from FuzzedDataProvider|
+| `devPath` | `String` | Value obtained from FuzzedDataProvider|
+| `handlerPath` | `String` | Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) init_ueventHandler_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/init_ueventHandler_fuzzer/init_ueventHandler_fuzzer
+```
diff --git a/init/fuzzer/init_parser_fuzzer.cpp b/init/fuzzer/init_parser_fuzzer.cpp
new file mode 100644
index 0000000..e6a78a2
--- /dev/null
+++ b/init/fuzzer/init_parser_fuzzer.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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 <fuzzer/FuzzedDataProvider.h>
+#include <hidl/metadata.h>
+#include <import_parser.h>
+#include <interface_utils.h>
+#include <rlimit_parser.h>
+
+using namespace android;
+using namespace android::init;
+
+const std::vector<std::string> kValidInputs[] = {
+        {"", "cpu", "10", "10"}, {"", "RLIM_CPU", "10", "10"},  {"", "12", "unlimited", "10"},
+        {"", "13", "-1", "10"},  {"", "14", "10", "unlimited"}, {"", "15", "10", "-1"},
+};
+
+const std::string kValidPaths[] = {
+        "/system/etc/init/hw/init.rc",
+        "/system/etc/init",
+};
+
+const int32_t kMaxBytes = 256;
+const std::string kValidInterfaces = "android.frameworks.vr.composer@2.0::IVrComposerClient";
+
+class InitParserFuzzer {
+  public:
+    InitParserFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+    void Process();
+
+  private:
+    void InvokeParser();
+    void InvokeLimitParser();
+    void InvokeInterfaceUtils();
+    InterfaceInheritanceHierarchyMap GenerateHierarchyMap();
+    std::vector<HidlInterfaceMetadata> GenerateInterfaceMetadata();
+
+    FuzzedDataProvider fdp_;
+};
+
+void InitParserFuzzer::InvokeLimitParser() {
+    if (fdp_.ConsumeBool()) {
+        std::vector<std::string> input;
+        input.push_back("");
+        input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+        input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+        input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+        ParseRlimit(input);
+    } else {
+        ParseRlimit(fdp_.PickValueInArray(kValidInputs));
+    }
+}
+
+std::vector<HidlInterfaceMetadata> InitParserFuzzer::GenerateInterfaceMetadata() {
+    std::vector<HidlInterfaceMetadata> random_interface;
+    for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+        HidlInterfaceMetadata metadata;
+        metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
+        for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral<size_t>(); ++idx1) {
+            metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+        }
+        random_interface.push_back(metadata);
+    }
+    return random_interface;
+}
+
+InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
+    InterfaceInheritanceHierarchyMap result;
+    std::vector<HidlInterfaceMetadata> random_interface;
+    if (fdp_.ConsumeBool()) {
+        random_interface = GenerateInterfaceMetadata();
+    } else {
+        random_interface = HidlInterfaceMetadata::all();
+    }
+
+    for (const HidlInterfaceMetadata& iface : random_interface) {
+        std::set<FQName> inherited_interfaces;
+        for (const std::string& intf : iface.inherited) {
+            FQName fqname;
+            (void)fqname.setTo(intf);
+            inherited_interfaces.insert(fqname);
+        }
+        FQName fqname;
+        (void)fqname.setTo(iface.name);
+        result[fqname] = inherited_interfaces;
+    }
+    return result;
+}
+
+void InitParserFuzzer::InvokeInterfaceUtils() {
+    InterfaceInheritanceHierarchyMap hierarchy_map = GenerateHierarchyMap();
+    SetKnownInterfaces(hierarchy_map);
+    IsKnownInterface(fdp_.ConsumeRandomLengthString(kMaxBytes));
+    std::set<std::string> interface_set;
+    for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+        auto set_interface_values = fdp_.PickValueInArray<const std::function<void()>>({
+                [&]() {
+                    interface_set.insert(("aidl/" + fdp_.ConsumeRandomLengthString(kMaxBytes)));
+                },
+                [&]() { interface_set.insert(fdp_.ConsumeRandomLengthString(kMaxBytes)); },
+                [&]() { interface_set.insert(kValidInterfaces); },
+        });
+        set_interface_values();
+    }
+    CheckInterfaceInheritanceHierarchy(interface_set, hierarchy_map);
+}
+
+void InitParserFuzzer::InvokeParser() {
+    Parser parser;
+    std::string name = fdp_.ConsumeBool() ? fdp_.ConsumeRandomLengthString(kMaxBytes) : "import";
+    parser.AddSectionParser(name, std::make_unique<ImportParser>(&parser));
+    std::string path = fdp_.ConsumeBool() ? fdp_.PickValueInArray(kValidPaths)
+                                          : fdp_.ConsumeRandomLengthString(kMaxBytes);
+    parser.ParseConfig(path);
+    parser.ParseConfigFileInsecure(path);
+}
+
+void InitParserFuzzer::Process() {
+    while (fdp_.remaining_bytes()) {
+        auto invoke_parser_fuzzer = fdp_.PickValueInArray<const std::function<void()>>({
+                [&]() { InvokeParser(); },
+                [&]() { InvokeInterfaceUtils(); },
+                [&]() { InvokeLimitParser(); },
+        });
+        invoke_parser_fuzzer();
+    }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    InitParserFuzzer init_parser_fuzzer(data, size);
+    init_parser_fuzzer.Process();
+    return 0;
+}
diff --git a/init/fuzzer/init_property_fuzzer.cpp b/init/fuzzer/init_property_fuzzer.cpp
new file mode 100644
index 0000000..22df375
--- /dev/null
+++ b/init/fuzzer/init_property_fuzzer.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 <persistent_properties.h>
+#include <property_type.h>
+#include <sys/stat.h>
+#include <fstream>
+#include "fuzzer/FuzzedDataProvider.h"
+
+using namespace android;
+using namespace android::init;
+using android::init::persistent_property_filename;
+
+const std::string kTempDir = "/data/local/tmp/";
+const std::string kFuzzerPropertyFile = kTempDir + "persistent_properties";
+constexpr int32_t kMaxPropertyLength = 10;
+const std::string kPrefix = "persist.";
+const std::string kPropertyName = kPrefix + "sys.timezone";
+const std::string kPropertyValue = "America/Los_Angeles";
+const std::string kLegacyPropertyFile = "/data/property/persist.properties";
+const std::string kSizeSuffix[3] = {"g", "k", "m"};
+constexpr int32_t kMinNumStrings = 1;
+constexpr int32_t kMaxNumStrings = 10;
+
+enum PropertyType { STRING, BOOL, INT, UINT, DOUBLE, SIZE, ENUM, RANDOM, kMaxValue = RANDOM };
+
+class InitPropertyFuzzer {
+  public:
+    InitPropertyFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+    void process();
+
+  private:
+    void InvokeCheckType();
+    void InvokeWritePersistentProperty();
+    void RemoveFiles();
+    void CreateFuzzerPropertyFile(const std::string property_file);
+    FuzzedDataProvider fdp_;
+};
+
+void InitPropertyFuzzer::InvokeCheckType() {
+    std::string property_type;
+    std::string value;
+    int type = fdp_.ConsumeEnum<PropertyType>();
+    switch (type) {
+        case STRING:
+            value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+            property_type = "string";
+            break;
+        case BOOL:
+            value = fdp_.ConsumeBool();
+            property_type = "bool";
+            break;
+        case INT:
+            value = fdp_.ConsumeIntegral<int>();
+            property_type = "int";
+            break;
+        case UINT:
+            value = fdp_.ConsumeIntegral<uint_t>();
+            property_type = "uint";
+            break;
+        case DOUBLE:
+            value = fdp_.ConsumeFloatingPoint<double>();
+            property_type = "double";
+            break;
+        case SIZE:
+            value = fdp_.ConsumeIntegral<uint_t>();
+            value = value.append(fdp_.PickValueInArray(kSizeSuffix));
+            property_type = "size";
+            break;
+        case ENUM:
+            value = fdp_.ConsumeIntegral<uint_t>();
+            property_type = "enum";
+            break;
+        case RANDOM:
+            value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+            property_type = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+            break;
+    }
+
+    CheckType(property_type, value);
+}
+
+void InitPropertyFuzzer::InvokeWritePersistentProperty() {
+    if (fdp_.ConsumeBool()) {
+        WritePersistentProperty(kPropertyName, kPropertyValue);
+    } else {
+        WritePersistentProperty((kPrefix + fdp_.ConsumeRandomLengthString(kMaxPropertyLength)),
+                                fdp_.ConsumeRandomLengthString(kMaxPropertyLength));
+    }
+}
+
+void InitPropertyFuzzer::RemoveFiles() {
+    remove(kFuzzerPropertyFile.c_str());
+    remove(kLegacyPropertyFile.c_str());
+}
+
+void InitPropertyFuzzer::CreateFuzzerPropertyFile(const std::string property_file) {
+    std::ofstream out;
+    out.open(property_file, std::ios::binary | std::ofstream::trunc);
+    chmod(property_file.c_str(), S_IRWXU);
+    const int32_t numStrings = fdp_.ConsumeIntegralInRange(kMinNumStrings, kMaxNumStrings);
+    for (int32_t i = 0; i < numStrings; ++i) {
+        out << fdp_.ConsumeRandomLengthString(kMaxPropertyLength) << "\n";
+    }
+    out.close();
+}
+
+void InitPropertyFuzzer::process() {
+    persistent_property_filename = kFuzzerPropertyFile;
+    /* Property and legacy files are created using createFuzzerPropertyFile() and */
+    /* are used in the below APIs. Hence createFuzzerPropertyFile() is not a part */
+    /* of the lambda construct. */
+    CreateFuzzerPropertyFile(kFuzzerPropertyFile);
+    CreateFuzzerPropertyFile(kLegacyPropertyFile);
+    auto property_type = fdp_.PickValueInArray<const std::function<void()>>({
+            [&]() { InvokeCheckType(); },
+            [&]() { InvokeWritePersistentProperty(); },
+            [&]() { LoadPersistentProperties(); },
+    });
+    property_type();
+    RemoveFiles();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    InitPropertyFuzzer initPropertyFuzzer(data, size);
+    initPropertyFuzzer.process();
+    return 0;
+}
diff --git a/init/fuzzer/init_ueventHandler_fuzzer.cpp b/init/fuzzer/init_ueventHandler_fuzzer.cpp
new file mode 100644
index 0000000..b6d5f8a
--- /dev/null
+++ b/init/fuzzer/init_ueventHandler_fuzzer.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 <devices.h>
+#include <firmware_handler.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <modalias_handler.h>
+#include <sys/stat.h>
+#include <util.h>
+#include <fstream>
+
+using namespace android;
+using namespace android::init;
+constexpr int32_t kMaxBytes = 100;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 1;
+
+/*'HandleUevent' prefixes the path with '/sys' and hence this is required to point
+ * to'/data/local/tmp' dir.*/
+const std::string kPath = "/../data/local/tmp/";
+const std::string kPathPrefix = "/..";
+
+void MakeFile(FuzzedDataProvider* fdp, std::string s) {
+    std::ofstream out;
+    out.open(s, std::ios::binary | std::ofstream::trunc);
+    for (int32_t idx = 0; idx < fdp->ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
+        out << fdp->ConsumeRandomLengthString(kMaxBytes) << "\n";
+    }
+    out.close();
+}
+
+void CreateDir(std::string Directory, FuzzedDataProvider* fdp) {
+    std::string tmp = Directory.substr(kPathPrefix.length());
+    mkdir_recursive(android::base::Dirname(tmp.c_str()),
+                    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+    MakeFile(fdp, tmp + "/data");
+    MakeFile(fdp, tmp + "/loading");
+}
+
+std::string SelectRandomString(FuzzedDataProvider* fdp, std::string s) {
+    if (fdp->ConsumeBool()) {
+        if (fdp->ConsumeBool()) {
+            return fdp->ConsumeRandomLengthString(kMaxBytes);
+        } else {
+            return s;
+        }
+    }
+    return "";
+}
+
+Uevent CreateUevent(FuzzedDataProvider* fdp) {
+    Uevent uevent;
+    uevent.action = SelectRandomString(fdp, "add");
+    uevent.subsystem = SelectRandomString(fdp, "firmware");
+    uevent.path = SelectRandomString(fdp, kPath + fdp->ConsumeRandomLengthString(kMaxBytes));
+    uevent.firmware = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+    uevent.partition_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+    uevent.device_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+    uevent.modalias = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+    uevent.partition_num = fdp->ConsumeIntegral<int32_t>();
+    uevent.major = fdp->ConsumeIntegral<int32_t>();
+    uevent.minor = fdp->ConsumeIntegral<int32_t>();
+    return uevent;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    while (fdp.remaining_bytes()) {
+        auto invoke_uevent_handler_fuzzer = fdp.PickValueInArray<const std::function<void()>>({
+                [&]() {
+                    std::vector<std::string> modalias_vector;
+                    for (size_t idx = 0;
+                         idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+                        modalias_vector.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+                    }
+                    ModaliasHandler modalias_handler = ModaliasHandler(modalias_vector);
+                    modalias_handler.HandleUevent(CreateUevent(&fdp));
+                },
+                [&]() {
+                    std::vector<ExternalFirmwareHandler> external_handlers;
+                    std::vector<std::string> firmware_directories;
+                    for (size_t idx = 0;
+                         idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+                        std::string devPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+                        uid_t uid = fdp.ConsumeIntegral<uid_t>();
+                        gid_t gid = fdp.ConsumeIntegral<gid_t>();
+                        std::string handlerPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+                        ExternalFirmwareHandler externalFirmwareHandler =
+                                ExternalFirmwareHandler(devPath, uid, gid, handlerPath);
+                        external_handlers.push_back(externalFirmwareHandler);
+                        firmware_directories.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+                    }
+                    FirmwareHandler firmware_handler =
+                            FirmwareHandler(firmware_directories, external_handlers);
+                    Uevent uevent = CreateUevent(&fdp);
+                    if (fdp.ConsumeBool() && uevent.path.size() != 0 &&
+                        uevent.path.find(kPath) == 0) {
+                        CreateDir(uevent.path, &fdp);
+                        firmware_handler.HandleUevent(uevent);
+                        std::string s = uevent.path.substr(kPathPrefix.length());
+                        remove(s.c_str());
+                    } else {
+                        firmware_handler.HandleUevent(uevent);
+                    }
+                },
+        });
+        invoke_uevent_handler_fuzzer();
+    }
+    return 0;
+}
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 880674c..4c27a56 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -608,7 +608,7 @@
     if (sem_init(&reboot_semaphore, false, 0) == -1) {
         // These should never fail, but if they do, skip the graceful reboot and reboot immediately.
         LOG(ERROR) << "sem_init() fail and RebootSystem() return!";
-        RebootSystem(cmd, reboot_target);
+        RebootSystem(cmd, reboot_target, reason);
     }
 
     // Start a thread to monitor init shutdown process
@@ -636,7 +636,7 @@
     // worry about unmounting it.
     if (!IsDataMounted("*")) {
         sync();
-        RebootSystem(cmd, reboot_target);
+        RebootSystem(cmd, reboot_target, reason);
         abort();
     }
 
@@ -769,7 +769,7 @@
             LOG(INFO) << "Shutdown /data";
         }
     }
-    RebootSystem(cmd, reboot_target);
+    RebootSystem(cmd, reboot_target, reason);
     abort();
 }
 
diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp
index f8e1de0..e6b868e 100644
--- a/init/reboot_utils.cpp
+++ b/init/reboot_utils.cpp
@@ -106,7 +106,8 @@
     return value == CAP_SET;
 }
 
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
+void __attribute__((noreturn))
+RebootSystem(unsigned int cmd, const std::string& rebootTarget, const std::string& reboot_reason) {
     LOG(INFO) << "Reboot ending, jumping to kernel";
 
     if (!IsRebootCapable()) {
@@ -127,10 +128,12 @@
 
         case ANDROID_RB_THERMOFF:
             if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
+                std::string reason = "shutdown,thermal";
+                if (!reboot_reason.empty()) reason = reboot_reason;
+
                 LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
-                static constexpr const char kThermalShutdownTarget[] = "shutdown,thermal";
                 syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
-                        LINUX_REBOOT_CMD_RESTART2, kThermalShutdownTarget);
+                        LINUX_REBOOT_CMD_RESTART2, reason.c_str());
             } else {
                 reboot(RB_POWER_OFF);
             }
diff --git a/init/reboot_utils.h b/init/reboot_utils.h
index a0023b9..09e87ef 100644
--- a/init/reboot_utils.h
+++ b/init/reboot_utils.h
@@ -29,7 +29,8 @@
 // so if any of the attempts to determine this fail, it will still return true.
 bool IsRebootCapable();
 // This is a wrapper around the actual reboot calls.
-void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target);
+void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target,
+                                            const std::string& reboot_reason = "");
 void __attribute__((noreturn)) InitFatalReboot(int signal_number);
 void InstallRebootSignalHandlers();
 
diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp
index 5c821b0..6972f30 100644
--- a/init/snapuserd_transition.cpp
+++ b/init/snapuserd_transition.cpp
@@ -226,12 +226,9 @@
 
     argv_.emplace_back("snapuserd");
     argv_.emplace_back("-no_socket");
-    if (!sm_->DetachSnapuserdForSelinux(&argv_)) {
+    if (!sm_->PrepareSnapuserdArgsForSelinux(&argv_)) {
         LOG(FATAL) << "Could not perform selinux transition";
     }
-
-    // Make sure the process is gone so we don't have any selinux audits.
-    KillFirstStageSnapuserd(old_pid_);
 }
 
 void SnapuserdSelinuxHelper::FinishTransition() {
@@ -301,6 +298,12 @@
 }
 
 void SnapuserdSelinuxHelper::RelaunchFirstStageSnapuserd() {
+    if (!sm_->DetachFirstStageSnapuserdForSelinux()) {
+        LOG(FATAL) << "Could not perform selinux transition";
+    }
+
+    KillFirstStageSnapuserd(old_pid_);
+
     auto fd = GetRamdiskSnapuserdFd();
     if (!fd) {
         LOG(FATAL) << "Environment variable " << kSnapuserdFirstStageFdVar << " was not set!";
diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp
index a3ef131..85a38f8 100644
--- a/libstats/pull_rust/Android.bp
+++ b/libstats/pull_rust/Android.bp
@@ -51,6 +51,7 @@
     min_sdk_version: "apex_inherit",
     apex_available: [
         "//apex_available:platform",
+        "com.android.resolv",
         "com.android.virt",
     ],
 }
diff --git a/libutils/Android.bp b/libutils/Android.bp
index c744b53..26e1597 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -58,10 +58,6 @@
     vendor_available: true,
     product_available: true,
     recovery_available: true,
-    vndk: {
-        enabled: true,
-        support_system_process: true,
-    },
     host_supported: true,
 
     cflags: [
@@ -126,8 +122,8 @@
     },
 }
 
-cc_library {
-    name: "libutils",
+cc_defaults {
+    name: "libutils_impl_defaults",
     defaults: ["libutils_defaults"],
     native_bridge_supported: true,
 
@@ -181,11 +177,39 @@
 }
 
 cc_library {
+    name: "libutils",
+    defaults: ["libutils_impl_defaults"],
+
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
+}
+
+cc_library {
+    name: "libutils_test_compile",
+    defaults: ["libutils_impl_defaults"],
+
+    cflags: [
+        "-DCALLSTACKS=1",
+        "-DDEBUG_POLL_AND_WAKE=1",
+        "-DDEBUG_REFS=1",
+        "-DDEBUG_TOKENIZER=1",
+    ],
+
+    visibility: [":__subpackages__"],
+}
+
+cc_library {
     name: "libutilscallstack",
     defaults: ["libutils_defaults"],
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     min_sdk_version: "29",
+    vndk: {
+        enabled: true,
+        support_system_process: true,
+    },
 
     srcs: [
         "CallStack.cpp",
diff --git a/libutils/Looper.cpp b/libutils/Looper.cpp
index 1a3f34b..402e43c 100644
--- a/libutils/Looper.cpp
+++ b/libutils/Looper.cpp
@@ -8,10 +8,14 @@
 //#define LOG_NDEBUG 0
 
 // Debugs poll and wake interactions.
+#ifndef DEBUG_POLL_AND_WAKE
 #define DEBUG_POLL_AND_WAKE 0
+#endif
 
 // Debugs callback registration and invocation.
+#ifndef DEBUG_CALLBACKS
 #define DEBUG_CALLBACKS 0
+#endif
 
 #include <utils/Looper.h>
 
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index ed5b2a9..ab122c7 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -21,9 +21,11 @@
 
 #include <android-base/macros.h>
 
+#include <fcntl.h>
 #include <log/log.h>
 
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 
 #include <utils/Mutex.h>
 
@@ -32,7 +34,9 @@
 #endif
 
 // Compile with refcounting debugging enabled.
+#ifndef DEBUG_REFS
 #define DEBUG_REFS 0
+#endif
 
 // The following three are ignored unless DEBUG_REFS is set.
 
@@ -45,7 +49,11 @@
 
 // folder where stack traces are saved when DEBUG_REFS is enabled
 // this folder needs to exist and be writable
+#ifdef __ANDROID__
 #define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+#else
+#define DEBUG_REFS_CALLSTACK_PATH "."
+#endif
 
 // log all reference counting operations
 #define PRINT_REFS 0
@@ -320,11 +328,11 @@
             char name[100];
             snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
                      this);
-            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
+            int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 0644);
             if (rc >= 0) {
                 (void)write(rc, text.string(), text.length());
                 close(rc);
-                ALOGD("STACK TRACE for %p saved in %s", this, name);
+                ALOGI("STACK TRACE for %p saved in %s", this, name);
             }
             else ALOGE("FAILED TO PRINT STACK TRACE for %p in %s: %s", this,
                       name, strerror(errno));
diff --git a/libutils/Tokenizer.cpp b/libutils/Tokenizer.cpp
index 98dd2fd..c3ec165 100644
--- a/libutils/Tokenizer.cpp
+++ b/libutils/Tokenizer.cpp
@@ -21,9 +21,10 @@
 #include <sys/stat.h>
 #include <utils/Log.h>
 
+#ifndef DEBUG_TOKENIZER
 // Enables debug output for the tokenizer.
 #define DEBUG_TOKENIZER 0
-
+#endif
 
 namespace android {
 
diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt
index 82196e4..ea1e234 100644
--- a/rootdir/etc/public.libraries.wear.txt
+++ b/rootdir/etc/public.libraries.wear.txt
@@ -10,6 +10,7 @@
 libGLESv1_CM.so
 libGLESv2.so
 libGLESv3.so
+libicu.so
 libicui18n.so
 libicuuc.so
 libjnigraphics.so
diff --git a/set-verity-state/.clang-format b/set-verity-state/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/set-verity-state/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/set-verity-state/Android.bp b/set-verity-state/Android.bp
deleted file mode 100644
index f40118b..0000000
--- a/set-verity-state/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2019 The Android Open Source Project
-
-package {
-    default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-cc_binary {
-    name: "set-verity-state",
-    srcs: ["set-verity-state.cpp"],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "libcrypto",
-        "libcrypto_utils",
-        "libfs_mgr_binder",
-        "libutils",
-    ],
-    static_libs: [
-        "libavb_user",
-    ],
-    header_libs: [
-        "libcutils_headers",
-    ],
-
-    cflags: ["-Werror"],
-    cppflags: [
-        "-DALLOW_DISABLE_VERITY=0",
-    ],
-    product_variables: {
-        debuggable: {
-            cppflags: [
-                "-UALLOW_DISABLE_VERITY",
-                "-DALLOW_DISABLE_VERITY=1",
-            ],
-        },
-    },
-    symlinks: [
-        "enable-verity",
-        "disable-verity",
-    ],
-}
diff --git a/set-verity-state/OWNERS b/set-verity-state/OWNERS
deleted file mode 100644
index e849450..0000000
--- a/set-verity-state/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-dvander@google.com
-yochiang@google.com
-bowgotsai@google.com
diff --git a/set-verity-state/set-verity-state.cpp b/set-verity-state/set-verity-state.cpp
deleted file mode 100644
index 2b9c0ca..0000000
--- a/set-verity-state/set-verity-state.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <getopt.h>
-#include <stdio.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <binder/ProcessState.h>
-#include <cutils/android_reboot.h>
-#include <fs_mgr_overlayfs.h>
-#include <libavb_user/libavb_user.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
-const bool kAllowDisableVerity = true;
-#else
-const bool kAllowDisableVerity = false;
-#endif
-
-static bool SetupOrTeardownOverlayfs(bool enable) {
-  bool want_reboot = false;
-  if (enable) {
-    if (!fs_mgr_overlayfs_setup(nullptr, &want_reboot)) {
-      LOG(ERROR) << "Overlayfs setup failed.";
-      return want_reboot;
-    }
-    if (want_reboot) {
-      printf("enabling overlayfs\n");
-    }
-  } else {
-    auto rv = fs_mgr_overlayfs_teardown(nullptr, &want_reboot);
-    if (rv == OverlayfsTeardownResult::Error) {
-      LOG(ERROR) << "Overlayfs teardown failed.";
-      return want_reboot;
-    }
-    if (rv == OverlayfsTeardownResult::Busy) {
-      LOG(ERROR) << "Overlayfs is still active until reboot.";
-      return true;
-    }
-    if (want_reboot) {
-      printf("disabling overlayfs\n");
-    }
-  }
-  return want_reboot;
-}
-
-/* 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.
- */
-std::string get_ab_suffix() {
-  return android::base::GetProperty("ro.boot.slot_suffix", "");
-}
-
-bool is_avb_device_locked() {
-  return android::base::GetProperty("ro.boot.vbmeta.device_state", "") == "locked";
-}
-
-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);
-}
-
-struct SetVerityStateResult {
-  bool success = false;
-  bool want_reboot = false;
-};
-
-/* Use AVB to turn verity on/off */
-SetVerityStateResult SetVerityState(bool enable_verity) {
-  std::string ab_suffix = get_ab_suffix();
-  bool verity_enabled = false;
-
-  if (is_avb_device_locked()) {
-    LOG(ERROR) << "Device must be bootloader unlocked to change verity state";
-    return {};
-  }
-
-  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)) {
-    LOG(INFO) << "Verity is already " << (verity_enabled ? "enabled" : "disabled");
-    return {.success = true, .want_reboot = false};
-  }
-
-  if (!avb_user_verity_set(ops.get(), ab_suffix.c_str(), enable_verity)) {
-    LOG(ERROR) << "Error setting verity state";
-    return {};
-  }
-
-  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[]) {
-  bool auto_reboot = false;
-  bool verbose = false;
-
-  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;
-    }
-  }
-
-  android::base::InitLogging(argv, MyLogger(verbose));
-
-  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;
-  }
-
-  if (!kAllowDisableVerity || !is_debuggable()) {
-    errno = EPERM;
-    PLOG(ERROR) << "Cannot disable/enable verity on user build";
-    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 |= SetupOrTeardownOverlayfs(!enable_verity);
-  }
-
-  if (want_reboot) {
-    if (auto_reboot) {
-      reboot(progname);
-    }
-    printf("Reboot the device for new settings to take effect\n");
-  }
-
-  return exit_code;
-}