Merge changes I732e5b8a,I4271909e

* changes:
  libutils: RefBase DEBUG_REF love
  libutils: DEBUG_* modes compile forever
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 45cd3c0..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",
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index df26d85..cc09d09 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -785,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;
@@ -797,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;
     }
@@ -816,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;
@@ -831,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()) {
@@ -854,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_filesystem_available("f2fs")) {
-        return "f2fs";
-    }
-    if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_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() {
@@ -923,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;
@@ -1123,7 +1089,7 @@
     return true;
 }
 
-static bool CanUseSuperPartition(const Fstab& fstab, bool* is_virtual_ab) {
+static bool CanUseSuperPartition(const Fstab& fstab) {
     auto slot_number = fs_mgr_overlayfs_slot_number();
     auto super_device = fs_mgr_overlayfs_super_device(slot_number);
     if (!fs_mgr_rw_access(super_device) || !fs_mgr_overlayfs_has_logical(fstab)) {
@@ -1133,7 +1099,6 @@
     if (!metadata) {
         return false;
     }
-    *is_virtual_ab = !!(metadata->header.flags & LP_HEADER_FLAG_VIRTUAL_AB_DEVICE);
     return true;
 }
 
@@ -1146,23 +1111,15 @@
         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;
+    // Try ImageManager on /data first.
+    bool can_use_data = false;
+    if (FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
+        return CreateScratchOnData(scratch_device, partition_exists);
     }
-
     // If that fails, see if we can land on super.
-    bool is_virtual_ab;
-    if (CanUseSuperPartition(fstab, &is_virtual_ab)) {
-        bool can_use_data = false;
-        if (is_virtual_ab && FilesystemHasReliablePinning("/data", &can_use_data) && can_use_data) {
-            return CreateScratchOnData(scratch_device, partition_exists);
-        }
+    if (CanUseSuperPartition(fstab)) {
         return CreateDynamicScratch(scratch_device, partition_exists);
     }
-
     return false;
 }
 
@@ -1180,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;
@@ -1195,12 +1151,12 @@
         }
     }
 
-    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);
 }
 
 #if ALLOW_ADBD_DISABLE_VERITY
@@ -1319,14 +1275,13 @@
     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);
     }
 }
 
@@ -1565,8 +1520,7 @@
     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);
         }
     }
 
@@ -1687,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);
@@ -1702,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();
         }
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 54c1c2c..2edaaad 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -35,7 +35,6 @@
 #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>
@@ -50,7 +49,7 @@
 
 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"
@@ -62,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) {
@@ -116,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,
@@ -281,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;
@@ -489,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;
@@ -514,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;
@@ -531,8 +518,8 @@
                 break;
             default:
                 LOG(ERROR) << "Bad Argument -" << char(opt);
-                usage(BADARG);
-                break;
+                usage();
+                return 1;
         }
     }
 
@@ -549,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/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/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/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",
     ],
 }