Merge "Add logs in SuperLayoutBuilder::Open when the metadata isn't supported" into main
diff --git a/OWNERS b/OWNERS
index 682a067..96b4f54 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1 +1,2 @@
+# Bug component: 128577
 enh@google.com
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index d20de6b..5393e25 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -188,6 +188,7 @@
 cc_library_static {
     name: "libdebuggerd",
     defaults: ["debuggerd_defaults"],
+    ramdisk_available: true,
     recovery_available: true,
     vendor_ramdisk_available: true,
 
@@ -221,9 +222,6 @@
         "libbase",
         "libcutils",
     ],
-    runtime_libs: [
-        "libdexfile",           // libdexfile_support dependency
-    ],
 
     whole_static_libs: [
         "libasync_safe",
@@ -250,6 +248,19 @@
                 "libdexfile",
             ],
         },
+        ramdisk: {
+            exclude_static_libs: [
+                "libdexfile_support",
+            ],
+            exclude_runtime_libs: [
+                "libdexfile",
+            ],
+        },
+        android: {
+            runtime_libs: [
+                "libdexfile",           // libdexfile_support dependency
+            ],
+        },
     },
 
     product_variables: {
diff --git a/debuggerd/proto/Android.bp b/debuggerd/proto/Android.bp
index 73cf573..804f805 100644
--- a/debuggerd/proto/Android.bp
+++ b/debuggerd/proto/Android.bp
@@ -35,6 +35,7 @@
         "com.android.runtime",
     ],
 
+    ramdisk_available: true,
     recovery_available: true,
     vendor_ramdisk_available: true,
 }
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index f6ffb64..dc57149 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -27,6 +27,7 @@
  */
 #pragma once
 
+#include <functional>
 #include <string>
 #include "fastboot_driver.h"
 #include "fastboot_driver_interface.h"
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 0a836e4..4e4d20e 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -60,7 +60,6 @@
     defaults: ["fs_mgr_defaults"],
     export_include_dirs: ["include"],
     local_include_dirs: ["include/"],
-    include_dirs: ["system/vold"],
     cflags: [
         "-D_FILE_OFFSET_BITS=64",
     ],
@@ -90,8 +89,6 @@
     static_libs: [
         "libavb",
         "libfs_avb",
-        "libfstab",
-        "libdm",
         "libgsi",
     ],
     export_static_lib_headers: [
@@ -174,47 +171,6 @@
     ],
 }
 
-cc_library_static {
-    // Do not ever make this a shared library as long as it is vendor_available.
-    // It does not have a stable interface.
-    name: "libfstab",
-    vendor_available: true,
-    ramdisk_available: true,
-    vendor_ramdisk_available: true,
-    recovery_available: true,
-    apex_available: [
-        "//apex_available:anyapex",
-        "//apex_available:platform",
-    ],
-    host_supported: true,
-    defaults: ["fs_mgr_defaults"],
-    local_include_dirs: ["include/"],
-    srcs: [
-        "fs_mgr_fstab.cpp",
-        "fs_mgr_boot_config.cpp",
-        "fs_mgr_slotselect.cpp",
-    ],
-    target: {
-        darwin: {
-            enabled: false,
-        },
-        vendor: {
-            cflags: [
-                // Skipping entries in fstab should only be done in a system
-                // process as the config file is in /system_ext.
-                // Remove the op from the vendor variant.
-                "-DNO_SKIP_MOUNT",
-            ],
-        },
-    },
-    export_include_dirs: ["include_fstab"],
-    header_libs: [
-        "libbase_headers",
-        "libgsi_headers",
-    ],
-    min_sdk_version: "31",
-}
-
 cc_binary {
     name: "remount",
     defaults: ["fs_mgr_defaults"],
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index e568a9b..d55f8d3 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -2227,8 +2227,8 @@
 }
 
 bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) {
-    auto overlayfs_valid_result = fs_mgr_overlayfs_valid();
-    if (overlayfs_valid_result == OverlayfsValidResult::kNotSupported) {
+    const auto overlayfs_check_result = android::fs_mgr::CheckOverlayfs();
+    if (!overlayfs_check_result.supported) {
         LERROR << __FUNCTION__ << "(): kernel does not support overlayfs";
         return false;
     }
@@ -2280,10 +2280,7 @@
         }
     }
 
-    auto options = "lowerdir=" + lowerdir;
-    if (overlayfs_valid_result == OverlayfsValidResult::kOverrideCredsRequired) {
-        options += ",override_creds=off";
-    }
+    const auto options = "lowerdir=" + lowerdir + overlayfs_check_result.mount_flags;
 
     // Use "overlay-" + entry.blk_device as the mount() source, so that adb-remout-test don't
     // confuse this with adb remount overlay, whose device name is "overlay".
@@ -2339,30 +2336,34 @@
     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;
-    }
+namespace android {
+namespace fs_mgr {
+
+OverlayfsCheckResult CheckOverlayfs() {
     if (!fs_mgr_filesystem_available("overlay")) {
-        return OverlayfsValidResult::kNotSupported;
+        return {.supported = false};
     }
     struct utsname uts;
     if (uname(&uts) == -1) {
-        return OverlayfsValidResult::kNotSupported;
+        return {.supported = false};
     }
     int major, minor;
     if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
-        return OverlayfsValidResult::kNotSupported;
+        return {.supported = false};
     }
-    if (major < 4) {
-        return OverlayfsValidResult::kOk;
+    // Overlayfs available in the kernel, and patched for override_creds?
+    if (access("/sys/module/overlay/parameters/override_creds", F_OK) == 0) {
+        auto mount_flags = ",override_creds=off"s;
+        if (major > 5 || (major == 5 && minor >= 15)) {
+            mount_flags += ",userxattr"s;
+        }
+        return {.supported = true, .mount_flags = mount_flags};
     }
-    if (major > 4) {
-        return OverlayfsValidResult::kNotSupported;
+    if (major < 4 || (major == 4 && minor <= 3)) {
+        return {.supported = true};
     }
-    if (minor > 3) {
-        return OverlayfsValidResult::kNotSupported;
-    }
-    return OverlayfsValidResult::kOk;
+    return {.supported = false};
 }
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp
index 69a2ac0..68576f2 100644
--- a/fs_mgr/fs_mgr_overlayfs_control.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_control.cpp
@@ -18,17 +18,10 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/fs.h>
-#include <selinux/selinux.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/types.h>
-#include <sys/utsname.h>
-#include <sys/vfs.h>
 #include <unistd.h>
 
 #include <algorithm>
@@ -38,13 +31,9 @@
 #include <vector>
 
 #include <android-base/file.h>
-#include <android-base/macros.h>
 #include <android-base/properties.h>
 #include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <ext4_utils/ext4_utils.h>
 #include <fs_mgr.h>
-#include <fs_mgr/file_wait.h>
 #include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
@@ -71,22 +60,25 @@
 
 constexpr char kDataScratchSizeMbProp[] = "fs_mgr.overlayfs.data_scratch_size_mb";
 
+constexpr char kPhysicalDevice[] = "/dev/block/by-name/";
+constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata";
+
+constexpr char kMkF2fs[] = "/system/bin/make_f2fs";
+constexpr char kMkExt4[] = "/system/bin/mke2fs";
+
 // Return true if everything is mounted, but before adb is started.  Right
 // after 'trigger load_persist_props_action' is done.
 static bool fs_mgr_boot_completed() {
     return android::base::GetBoolProperty("ro.persistent_properties.ready", false);
 }
 
-constexpr auto kPhysicalDevice = "/dev/block/by-name/";
-constexpr char kScratchImageMetadata[] = "/metadata/gsi/remount/lp_metadata";
-
 // Note: this is meant only for recovery/first-stage init.
 static bool ScratchIsOnData() {
     // The scratch partition of DSU is managed by gsid.
     if (fs_mgr_is_dsu_running()) {
         return false;
     }
-    return fs_mgr_access(kScratchImageMetadata);
+    return access(kScratchImageMetadata, F_OK) == 0;
 }
 
 static bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
@@ -131,7 +123,7 @@
 }
 
 std::string fs_mgr_overlayfs_setup_dir(const std::string& dir) {
-    auto top = dir + kOverlayTopDir;
+    auto top = dir + "/" + kOverlayTopDir;
 
     AutoSetFsCreateCon createcon(kOverlayfsFileContext);
     if (!createcon.Ok()) {
@@ -195,10 +187,6 @@
     return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
 }
 
-static std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
-    return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number);
-}
-
 static bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) {
     for (const auto& entry : fstab) {
         if (entry.fs_mgr_flags.logical) {
@@ -258,8 +246,8 @@
     }
 
     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)) {
+    const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
+    if (access(super_device.c_str(), R_OK | W_OK)) {
         return OverlayfsTeardownResult::Ok;
     }
 
@@ -290,9 +278,9 @@
 
 bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point,
                                    bool* change, bool* should_destroy_scratch = nullptr) {
-    const auto top = overlay + kOverlayTopDir;
+    const auto top = overlay + "/" + kOverlayTopDir;
 
-    if (!fs_mgr_access(top)) {
+    if (access(top.c_str(), F_OK)) {
         if (should_destroy_scratch) *should_destroy_scratch = true;
         return true;
     }
@@ -300,7 +288,7 @@
     auto cleanup_all = mount_point.empty();
     const auto partition_name = android::base::Basename(mount_point);
     const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name));
-    const auto newpath = cleanup_all ? overlay + "/." + (kOverlayTopDir + 1) + ".teardown"
+    const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir + ".teardown"
                                      : top + "/." + partition_name + ".teardown";
     auto ret = fs_mgr_rm_all(newpath);
     if (!rename(oldpath.c_str(), newpath.c_str())) {
@@ -346,72 +334,6 @@
     return ret;
 }
 
-// Mount kScratchMountPoint
-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;
-            return false;
-        }
-    } else if (!fs_mgr_rw_access(device_path)) {
-        LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
-        return false;
-    }
-
-    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;
-    }
-
-    AutoSetFsCreateCon createcon(kOverlayfsFileContext);
-    if (!createcon.Ok()) {
-        return false;
-    }
-    if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) {
-        PERROR << "create " << kScratchMountPoint;
-        return false;
-    }
-
-    FstabEntry entry;
-    entry.blk_device = device_path;
-    entry.mount_point = kScratchMountPoint;
-    entry.flags = MS_NOATIME | MS_RDONLY;
-    if (!readonly) {
-        entry.flags &= ~MS_RDONLY;
-        entry.flags |= MS_SYNCHRONOUS;
-        entry.fs_options = "nodiscard";
-        fs_mgr_set_blk_ro(device_path, false);
-    }
-    // check_fs requires apex runtime library
-    if (fs_mgr_overlayfs_already_mounted("/data", false)) {
-        entry.fs_mgr_flags.check = true;
-    }
-    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()) {
-        return false;
-    }
-    if (!mounted) {
-        rmdir(kScratchMountPoint);
-        return false;
-    }
-    return true;
-}
-
-const std::string kMkF2fs("/system/bin/make_f2fs");
-const std::string kMkExt4("/system/bin/mke2fs");
-
 // 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() {
@@ -456,14 +378,14 @@
     // thus do not rely on fsck to correct problems that could creep in.
     auto fs_type = ""s;
     auto command = ""s;
-    if (!access(kMkF2fs.c_str(), X_OK) && fs_mgr_filesystem_available("f2fs")) {
+    if (!access(kMkF2fs, X_OK) && fs_mgr_filesystem_available("f2fs")) {
         fs_type = "f2fs";
-        command = kMkF2fs + " -w ";
+        command = kMkF2fs + " -w "s;
         command += std::to_string(getpagesize());
         command += " -f -d1 -l" + android::base::Basename(kScratchMountPoint);
-    } else if (!access(kMkExt4.c_str(), X_OK) && fs_mgr_filesystem_available("ext4")) {
+    } else if (!access(kMkExt4, X_OK) && fs_mgr_filesystem_available("ext4")) {
         fs_type = "ext4";
-        command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint;
+        command = kMkExt4 + " -F -b 4096 -t ext4 -m 0 -O has_journal -M "s + kScratchMountPoint;
     } else {
         LERROR << "No supported mkfs command or filesystem driver available, supported filesystems "
                   "are: f2fs, ext4";
@@ -506,7 +428,7 @@
 
     auto partition_create = !*partition_exists;
     auto slot_number = fs_mgr_overlayfs_slot_number();
-    auto super_device = fs_mgr_overlayfs_super_device(slot_number);
+    const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
     auto builder = MetadataBuilder::New(super_device, slot_number);
     if (!builder) {
         LERROR << "open " << super_device << " metadata";
@@ -646,8 +568,8 @@
 
 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)) {
+    const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
+    if (access(super_device.c_str(), R_OK | W_OK) || !fs_mgr_overlayfs_has_logical(fstab)) {
         return false;
     }
     auto metadata = ReadMetadata(super_device, slot_number);
@@ -697,8 +619,8 @@
     // If the partition exists, assume first that it can be mounted.
     if (partition_exists) {
         if (MountScratch(scratch_device)) {
-            if (fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir) ||
-                fs_mgr_filesystem_has_space(kScratchMountPoint)) {
+            const auto top = kScratchMountPoint + "/"s + kOverlayTopDir;
+            if (access(top.c_str(), F_OK) == 0 || fs_mgr_filesystem_has_space(kScratchMountPoint)) {
                 return true;
             }
             // declare it useless, no overrides and no free space
@@ -717,32 +639,6 @@
     return MountScratch(scratch_device);
 }
 
-// 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!
-    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;
@@ -844,7 +740,7 @@
     if (!info.device.empty()) {
         return {std::move(info)};
     }
-    if (!fs_mgr_in_recovery()) {
+    if (!InRecovery()) {
         return {};
     }
 
@@ -867,8 +763,7 @@
     }
 
     // Avoid uart spam by first checking for a scratch partition.
-    auto metadata_slot = fs_mgr_overlayfs_slot_number();
-    auto super_device = fs_mgr_overlayfs_super_device(metadata_slot);
+    const auto super_device = kPhysicalDevice + fs_mgr_get_super_partition_name();
     auto metadata = ReadCurrentMetadata(super_device);
     if (!metadata) {
         return {};
@@ -1030,7 +925,7 @@
     if (!OverlayfsTeardownAllowed()) {
         return;
     }
-    if (!fs_mgr_in_recovery()) {
+    if (!InRecovery()) {
         LERROR << __FUNCTION__ << "(): must be called within recovery.";
         return;
     }
diff --git a/fs_mgr/fs_mgr_overlayfs_control.h b/fs_mgr/fs_mgr_overlayfs_control.h
index 50e83e8..b175101 100644
--- a/fs_mgr/fs_mgr_overlayfs_control.h
+++ b/fs_mgr/fs_mgr_overlayfs_control.h
@@ -14,8 +14,6 @@
 
 #pragma once
 
-#include <string>
-
 #include <fstab/fstab.h>
 
 // If "mount_point" is non-null, set up exactly one overlay.
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
index c057c2b..8fb63b1 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -14,26 +14,20 @@
  * limitations under the License.
  */
 
-#include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/fs.h>
 #include <selinux/selinux.h>
-#include <stdio.h>
 #include <stdlib.h>
-#include <string.h>
 #include <sys/mount.h>
-#include <sys/param.h>
 #include <sys/stat.h>
 #include <sys/statvfs.h>
 #include <sys/types.h>
-#include <sys/utsname.h>
 #include <sys/vfs.h>
 #include <unistd.h>
 
 #include <algorithm>
 #include <memory>
-#include <optional>
 #include <string>
 #include <vector>
 
@@ -45,7 +39,6 @@
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr.h>
 #include <fs_mgr/file_wait.h>
-#include <fs_mgr_dm_linear.h>
 #include <fs_mgr_overlayfs.h>
 #include <fstab/fstab.h>
 #include <libdm/dm.h>
@@ -62,39 +55,21 @@
 
 constexpr char kPreferCacheBackingStorageProp[] = "fs_mgr.overlayfs.prefer_cache_backing_storage";
 
-bool fs_mgr_access(const std::string& path) {
-    return access(path.c_str(), F_OK) == 0;
-}
+constexpr char kCacheMountPoint[] = "/cache";
+constexpr char kPhysicalDevice[] = "/dev/block/by-name/";
 
-const auto kLowerdirOption = "lowerdir=";
-const auto kUpperdirOption = "upperdir=";
-
-bool fs_mgr_in_recovery() {
-    // Check the existence of recovery binary instead of using the compile time
-    // __ANDROID_RECOVERY__ macro.
-    // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot
-    // mode would use the same init binary, which would mean during normal boot
-    // the '/init' binary is actually a symlink pointing to
-    // init_second_stage.recovery, which would be compiled with
-    // __ANDROID_RECOVERY__ defined.
-    return fs_mgr_access("/system/bin/recovery");
-}
+constexpr char kLowerdirOption[] = "lowerdir=";
+constexpr char kUpperdirOption[] = "upperdir=";
 
 bool fs_mgr_is_dsu_running() {
     // Since android::gsi::CanBootIntoGsi() or android::gsi::MarkSystemAsGsi() is
     // never called in recovery, the return value of android::gsi::IsGsiRunning()
     // is not well-defined. In this case, just return false as being in recovery
     // implies not running a DSU system.
-    if (fs_mgr_in_recovery()) return false;
+    if (InRecovery()) return false;
     return android::gsi::IsGsiRunning();
 }
 
-const auto kCacheMountPoint = "/cache";
-
-static bool IsABDevice() {
-    return !android::base::GetProperty("ro.boot.slot_suffix", "").empty();
-}
-
 std::vector<const std::string> OverlayMountPoints() {
     // Never fallback to legacy cache mount point if within a DSU system,
     // because running a DSU system implies the device supports dynamic
@@ -105,7 +80,8 @@
 
     // For non-A/B devices prefer cache backing storage if
     // kPreferCacheBackingStorageProp property set.
-    if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) &&
+    if (fs_mgr_get_slot_suffix().empty() &&
+        android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) &&
         android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) {
         return {kCacheMountPoint, kScratchMountPoint};
     }
@@ -118,11 +94,6 @@
     return !stat(path.c_str(), &st) && S_ISDIR(st.st_mode);
 }
 
-bool fs_mgr_rw_access(const std::string& path) {
-    if (path.empty()) return false;
-    return access(path.c_str(), R_OK | W_OK) == 0;
-}
-
 // At less than 1% or 8MB of free space return value of false,
 // means we will try to wrap with overlayfs.
 bool fs_mgr_filesystem_has_space(const std::string& mount_point) {
@@ -141,13 +112,11 @@
            (static_cast<uint64_t>(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold;
 }
 
-const auto kPhysicalDevice = "/dev/block/by-name/";
-
 static bool fs_mgr_update_blk_device(FstabEntry* entry) {
     if (entry->fs_mgr_flags.logical) {
         fs_mgr_update_logical_partition(entry);
     }
-    if (fs_mgr_access(entry->blk_device)) {
+    if (access(entry->blk_device.c_str(), F_OK) == 0) {
         return true;
     }
     if (entry->blk_device != "/dev/root") {
@@ -155,10 +124,10 @@
     }
 
     // special case for system-as-root (taimen and others)
-    auto blk_device = std::string(kPhysicalDevice) + "system";
-    if (!fs_mgr_access(blk_device)) {
+    auto blk_device = kPhysicalDevice + "system"s;
+    if (access(blk_device.c_str(), F_OK)) {
         blk_device += fs_mgr_get_slot_suffix();
-        if (!fs_mgr_access(blk_device)) {
+        if (access(blk_device.c_str(), F_OK)) {
             return false;
         }
     }
@@ -237,28 +206,17 @@
     if (!fs_mgr_is_dir(mount_point)) return "";
     const auto base = android::base::Basename(mount_point) + "/";
     for (const auto& overlay_mount_point : OverlayMountPoints()) {
-        auto dir = overlay_mount_point + kOverlayTopDir + "/" + base;
+        auto dir = overlay_mount_point + "/" + kOverlayTopDir + "/" + base;
         auto upper = dir + kUpperName;
         if (!fs_mgr_is_dir(upper)) continue;
         auto work = dir + kWorkName;
         if (!fs_mgr_is_dir(work)) continue;
-        if (!fs_mgr_rw_access(work)) continue;
+        if (access(work.c_str(), R_OK | W_OK)) continue;
         return dir;
     }
     return "";
 }
 
-static inline bool KernelSupportsUserXattrs() {
-    struct utsname uts;
-    uname(&uts);
-
-    int major, minor;
-    if (sscanf(uts.release, "%d.%d", &major, &minor) != 2) {
-        return false;
-    }
-    return major > 5 || (major == 5 && minor >= 15);
-}
-
 const std::string fs_mgr_mount_point(const std::string& mount_point) {
     if ("/"s != mount_point) return mount_point;
     return "/system";
@@ -270,13 +228,7 @@
     auto candidate = fs_mgr_get_overlayfs_candidate(mount_point);
     if (candidate.empty()) return "";
     auto ret = kLowerdirOption + mount_point + "," + kUpperdirOption + candidate + kUpperName +
-               ",workdir=" + candidate + kWorkName;
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
-        ret += ",override_creds=off";
-    }
-    if (KernelSupportsUserXattrs()) {
-        ret += ",userxattr";
-    }
+               ",workdir=" + candidate + kWorkName + android::fs_mgr::CheckOverlayfs().mount_flags;
     for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
         if (android::base::StartsWith(flag, "context=")) {
             ret += "," + flag;
@@ -527,13 +479,13 @@
 }
 
 // Mount kScratchMountPoint
-static bool MountScratch(const std::string& device_path, bool readonly = false) {
+bool MountScratch(const std::string& device_path, bool readonly) {
     if (readonly) {
-        if (!fs_mgr_access(device_path)) {
+        if (access(device_path.c_str(), F_OK)) {
             LOG(ERROR) << "Path does not exist: " << device_path;
             return false;
         }
-    } else if (!fs_mgr_rw_access(device_path)) {
+    } else if (access(device_path.c_str(), R_OK | W_OK)) {
         LOG(ERROR) << "Path does not exist or is not readwrite: " << device_path;
         return false;
     }
@@ -589,9 +541,6 @@
     return true;
 }
 
-const std::string kMkF2fs("/system/bin/make_f2fs");
-const std::string kMkExt4("/system/bin/mke2fs");
-
 // 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() {
@@ -633,7 +582,7 @@
 
 // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed().
 // Setup is allowed only if teardown is also allowed.
-bool OverlayfsSetupAllowed(bool verbose = false) {
+bool OverlayfsSetupAllowed(bool verbose) {
     if (!kAllowOverlayfs) {
         if (verbose) {
             LOG(ERROR) << "Overlayfs remounts can only be used in debuggable builds";
@@ -641,14 +590,14 @@
         return false;
     }
     // Check mandatory kernel patches.
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
+    if (!android::fs_mgr::CheckOverlayfs().supported) {
         if (verbose) {
             LOG(ERROR) << "Kernel does not support overlayfs";
         }
         return false;
     }
     // in recovery or fastbootd, not allowed!
-    if (fs_mgr_in_recovery()) {
+    if (InRecovery()) {
         if (verbose) {
             LOG(ERROR) << "Unsupported overlayfs setup from recovery";
         }
@@ -728,7 +677,7 @@
     // if verity is still disabled, i.e. no reboot occurred), and skips calling
     // fs_mgr_overlayfs_mount_all().
     auto scratch_device = GetBootScratchDevice();
-    if (!fs_mgr_rw_access(scratch_device)) {
+    if (access(scratch_device.c_str(), R_OK | W_OK)) {
         return;
     }
     if (!WaitForFile(scratch_device, 10s)) {
@@ -737,7 +686,8 @@
     if (!MountScratch(scratch_device, true /* readonly */)) {
         return;
     }
-    auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir);
+    const auto top = kScratchMountPoint + "/"s + kOverlayTopDir;
+    const bool has_overlayfs_dir = access(top.c_str(), F_OK) == 0;
     fs_mgr_overlayfs_umount_scratch();
     if (has_overlayfs_dir) {
         MountScratch(scratch_device);
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h
index ae3ea84..f0afac1 100644
--- a/fs_mgr/fs_mgr_overlayfs_mount.h
+++ b/fs_mgr/fs_mgr_overlayfs_mount.h
@@ -20,9 +20,12 @@
 
 #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);
+constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
+
+constexpr char kScratchMountPoint[] = "/mnt/scratch";
+constexpr char kOverlayTopDir[] = "overlay";
+constexpr char kUpperName[] = "upper";
+constexpr char kWorkName[] = "work";
 
 #if ALLOW_ADBD_DISABLE_VERITY
 constexpr bool kAllowOverlayfs = true;
@@ -45,18 +48,13 @@
     bool restored_ = false;
 };
 
-constexpr auto kScratchMountPoint = "/mnt/scratch";
-constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
-
-constexpr auto kUpperName = "upper";
-constexpr auto kWorkName = "work";
-constexpr auto kOverlayTopDir = "/overlay";
-
 bool fs_mgr_is_dsu_running();
-bool fs_mgr_in_recovery();
-bool fs_mgr_access(const std::string& path);
-bool fs_mgr_rw_access(const std::string& path);
 bool fs_mgr_filesystem_has_space(const std::string& mount_point);
 const std::string fs_mgr_mount_point(const std::string& mount_point);
+bool OverlayfsSetupAllowed(bool verbose = false);
+bool MountScratch(const std::string& device_path, bool readonly = false);
 bool fs_mgr_overlayfs_umount_scratch();
 std::vector<const std::string> OverlayMountPoints();
+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);
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 46cdb62..7e4d5e5 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -23,15 +23,7 @@
 #include <fs_mgr.h>
 #include <fstab/fstab.h>
 
-#include "fs_mgr_priv_boot_config.h"
-
-/* The CHECK() in logging.h will use program invocation name as the tag.
- * Thus, the log will have prefix "init: " when libfs_mgr is statically
- * linked in the init process. This might be opaque when debugging.
- * Appends "in libfs_mgr" at the end of the abort message to explicitly
- * indicate the check happens in fs_mgr.
- */
-#define FS_MGR_CHECK(x) CHECK(x) << "in libfs_mgr "
+#include "libfstab/fstab_priv.h"
 
 #define FS_MGR_TAG "[libfs_mgr] "
 
@@ -89,28 +81,25 @@
 using namespace std::chrono_literals;
 
 bool fs_mgr_set_blk_ro(const std::string& blockdev, bool readonly = true);
-bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab);
 bool fs_mgr_is_device_unlocked();
-const std::string& get_android_dt_dir();
-bool is_dt_compatible();
 
 bool fs_mgr_is_ext4(const std::string& blk_device);
 bool fs_mgr_is_f2fs(const std::string& blk_device);
 
-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);
+
+struct OverlayfsCheckResult {
+    bool supported;
+    std::string mount_flags;
+};
+
+OverlayfsCheckResult CheckOverlayfs();
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/fs_mgr_vendor_overlay.cpp b/fs_mgr/fs_mgr_vendor_overlay.cpp
index 6b32b4d..bacfa4b 100644
--- a/fs_mgr/fs_mgr_vendor_overlay.cpp
+++ b/fs_mgr/fs_mgr_vendor_overlay.cpp
@@ -85,10 +85,8 @@
         return false;
     }
 
-    auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point;
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kOverrideCredsRequired) {
-        options += ",override_creds=off";
-    }
+    const auto options = kLowerdirOption + source_directory + ":" + vendor_mount_point +
+                         android::fs_mgr::CheckOverlayfs().mount_flags;
     auto report = "__mount(source=overlay,target="s + vendor_mount_point + ",type=overlay," +
                   options + ")=";
     auto ret = mount("overlay", vendor_mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
@@ -120,7 +118,7 @@
 
     const auto vendor_overlay_dirs = fs_mgr_get_vendor_overlay_dirs(vndk_version);
     if (vendor_overlay_dirs.empty()) return true;
-    if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) {
+    if (!android::fs_mgr::CheckOverlayfs().supported) {
         LINFO << "vendor overlay: kernel does not support overlayfs";
         return false;
     }
diff --git a/fs_mgr/include_fstab b/fs_mgr/include_fstab
new file mode 120000
index 0000000..728737f
--- /dev/null
+++ b/fs_mgr/include_fstab
@@ -0,0 +1 @@
+libfstab/include
\ No newline at end of file
diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp
index bd97a78..c37329c 100644
--- a/fs_mgr/libfiemap/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp
@@ -27,6 +27,7 @@
 #include <sys/vfs.h>
 #include <unistd.h>
 
+#include <cstring>
 #include <string>
 #include <utility>
 
@@ -518,7 +519,8 @@
         ASSERT_EQ(ret, 0);
 
         // mount the file system
-        ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0);
+        ASSERT_EQ(mount(loop_dev.device().c_str(), mntpoint_.c_str(), "f2fs", 0, nullptr), 0)
+                << strerror(errno);
     }
 
     void TearDown() override {
diff --git a/fs_mgr/libfstab/Android.bp b/fs_mgr/libfstab/Android.bp
new file mode 100644
index 0000000..df0269c
--- /dev/null
+++ b/fs_mgr/libfstab/Android.bp
@@ -0,0 +1,62 @@
+//
+// Copyright (C) 2023 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: [
+        "Android-Apache-2.0",
+        "system_core_fs_mgr_license",
+    ],
+}
+
+cc_library_static {
+    // Do not ever make this a shared library as long as it is vendor_available.
+    // It does not have a stable interface.
+    name: "libfstab",
+    vendor_available: true,
+    ramdisk_available: true,
+    vendor_ramdisk_available: true,
+    recovery_available: true,
+    host_supported: true,
+    defaults: ["fs_mgr_defaults"],
+    export_include_dirs: ["include"],
+    header_libs: [
+        "libbase_headers",
+        "libgsi_headers",
+    ],
+    srcs: [
+        "fstab.cpp",
+        "boot_config.cpp",
+        "slotselect.cpp",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        vendor: {
+            cflags: [
+                // Skipping entries in fstab should only be done in a system
+                // process as the config file is in /system_ext.
+                // Remove the op from the vendor variant.
+                "-DNO_SKIP_MOUNT",
+            ],
+        },
+    },
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
+    min_sdk_version: "31",
+}
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp
similarity index 82%
rename from fs_mgr/fs_mgr_boot_config.cpp
rename to fs_mgr/libfstab/boot_config.cpp
index 75d1e0d..fee4015 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/libfstab/boot_config.cpp
@@ -20,11 +20,39 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
-#include <android-base/properties.h>
 
-#include "fs_mgr_priv.h"
+#include "fstab_priv.h"
+#include "logging_macros.h"
+
+namespace android {
+namespace fs_mgr {
+
+const std::string& GetAndroidDtDir() {
+    // Set once and saves time for subsequent calls to this function
+    static const std::string kAndroidDtDir = [] {
+        std::string android_dt_dir;
+        if ((fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) ||
+             fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) &&
+            !android_dt_dir.empty()) {
+            // Ensure the returned path ends with a /
+            if (android_dt_dir.back() != '/') {
+                android_dt_dir.push_back('/');
+            }
+        } else {
+            // Fall back to the standard procfs-based path
+            android_dt_dir = "/proc/device-tree/firmware/android/";
+        }
+        LINFO << "Using Android DT directory " << android_dt_dir;
+        return android_dt_dir;
+    }();
+    return kAndroidDtDir;
+}
+
+}  // namespace fs_mgr
+}  // namespace android
 
 std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline) {
     static constexpr char quote = '"';
@@ -84,7 +112,7 @@
 
 bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig,
                                             const std::string& android_key, std::string* out_val) {
-    FS_MGR_CHECK(out_val != nullptr);
+    FSTAB_CHECK(out_val != nullptr);
 
     const std::string bootconfig_key("androidboot." + android_key);
     for (const auto& [key, value] : fs_mgr_parse_proc_bootconfig(bootconfig)) {
@@ -100,7 +128,7 @@
 
 bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key,
                                         std::string* out_val) {
-    FS_MGR_CHECK(out_val != nullptr);
+    FSTAB_CHECK(out_val != nullptr);
 
     const std::string cmdline_key("androidboot." + android_key);
     for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
@@ -140,11 +168,11 @@
 // kernel cmdline (in that order).  Returns 'true' if successfully
 // found, 'false' otherwise.
 bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
-    FS_MGR_CHECK(out_val != nullptr);
+    FSTAB_CHECK(out_val != nullptr);
 
     // firstly, check the device tree
     if (is_dt_compatible()) {
-        std::string file_name = get_android_dt_dir() + "/" + key;
+        std::string file_name = android::fs_mgr::GetAndroidDtDir() + key;
         if (android::base::ReadFileToString(file_name, out_val)) {
             if (!out_val->empty()) {
                 out_val->pop_back();  // Trims the trailing '\0' out.
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/libfstab/fstab.cpp
similarity index 94%
rename from fs_mgr/fs_mgr_fstab.cpp
rename to fs_mgr/libfstab/fstab.cpp
index c85e831..86ba031 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -36,7 +36,8 @@
 #include <android-base/strings.h>
 #include <libgsi/libgsi.h>
 
-#include "fs_mgr_priv.h"
+#include "fstab_priv.h"
+#include "logging_macros.h"
 
 using android::base::EndsWith;
 using android::base::ParseByteCount;
@@ -50,11 +51,10 @@
 namespace fs_mgr {
 namespace {
 
-constexpr char kDefaultAndroidDtDir[] = "/proc/device-tree/firmware/android";
 constexpr char kProcMountsPath[] = "/proc/mounts";
 
 struct FlagList {
-    const char *name;
+    const char* name;
     uint64_t flag;
 };
 
@@ -80,7 +80,7 @@
 off64_t CalculateZramSize(int percentage) {
     off64_t total;
 
-    total  = sysconf(_SC_PHYS_PAGES);
+    total = sysconf(_SC_PHYS_PAGES);
     total *= percentage;
     total /= 100;
 
@@ -328,8 +328,7 @@
     // some recovery fstabs still contain the FDE options since they didn't do
     // anything in recovery mode anyway (except possibly to cause the
     // reservation of a crypto footer) and thus never got removed.
-    if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed &&
-        access("/system/bin/recovery", F_OK) != 0) {
+    if (entry->fs_mgr_flags.crypt && !entry->fs_mgr_flags.vold_managed && !InRecovery()) {
         LERROR << "FDE is no longer supported; 'encryptable' can only be used for adoptable "
                   "storage";
         return false;
@@ -337,25 +336,14 @@
     return true;
 }
 
-std::string InitAndroidDtDir() {
-    std::string android_dt_dir;
-    // The platform may specify a custom Android DT path in kernel cmdline
-    if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) &&
-        !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) {
-        // Fall back to the standard procfs-based path
-        android_dt_dir = kDefaultAndroidDtDir;
-    }
-    return android_dt_dir;
-}
-
 bool IsDtFstabCompatible() {
     std::string dt_value;
-    std::string file_name = get_android_dt_dir() + "/fstab/compatible";
+    std::string file_name = GetAndroidDtDir() + "fstab/compatible";
 
     if (ReadDtFile(file_name, &dt_value) && dt_value == "android,fstab") {
         // If there's no status property or its set to "ok" or "okay", then we use the DT fstab.
         std::string status_value;
-        std::string status_file_name = get_android_dt_dir() + "/fstab/status";
+        std::string status_file_name = GetAndroidDtDir() + "fstab/status";
         return !ReadDtFile(status_file_name, &status_value) || status_value == "ok" ||
                status_value == "okay";
     }
@@ -368,7 +356,7 @@
         return {};
     }
 
-    std::string fstabdir_name = get_android_dt_dir() + "/fstab";
+    std::string fstabdir_name = GetAndroidDtDir() + "fstab";
     std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
     if (!fstabdir) return {};
 
@@ -401,7 +389,7 @@
 
         std::string mount_point;
         file_name =
-            android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
+                android::base::StringPrintf("%s/%s/mnt_point", fstabdir_name.c_str(), dp->d_name);
         if (ReadDtFile(file_name, &value)) {
             LINFO << "dt_fstab: Using a specified mount point " << value << " for " << dp->d_name;
             mount_point = value;
@@ -417,14 +405,16 @@
         }
         fstab_entry.push_back(value);
 
-        file_name = android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
+        file_name =
+                android::base::StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
         if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
             return {};
         }
         fstab_entry.push_back(value);
 
-        file_name = android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
+        file_name =
+                android::base::StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
         if (!ReadDtFile(file_name, &value)) {
             LERROR << "dt_fstab: Failed to find type for partition " << dp->d_name;
             return {};
@@ -520,6 +510,9 @@
 // ramdisk's copy of the fstab had to be located in the root directory, but now
 // the system/etc directory is supported too and is the preferred location.
 std::string GetFstabPath() {
+    if (InRecovery()) {
+        return "/etc/recovery.fstab";
+    }
     for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {
         std::string suffix;
 
@@ -835,15 +828,8 @@
     fstab->clear();
     ReadFstabFromDt(fstab, false /* verbose */);
 
-    std::string default_fstab_path;
-    // Use different fstab paths for normal boot and recovery boot, respectively
-    if ((access("/sbin/recovery", F_OK) == 0) || (access("/system/bin/recovery", F_OK) == 0)) {
-        default_fstab_path = "/etc/recovery.fstab";
-    } else {  // normal boot
-        default_fstab_path = GetFstabPath();
-    }
-
     Fstab default_fstab;
+    const std::string default_fstab_path = GetFstabPath();
     if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
         for (auto&& entry : default_fstab) {
             fstab->emplace_back(std::move(entry));
@@ -878,7 +864,7 @@
 
 std::set<std::string> GetBootDevices() {
     // First check bootconfig, then kernel commandline, then the device tree
-    std::string dt_file_name = get_android_dt_dir() + "/boot_devices";
+    std::string dt_file_name = GetAndroidDtDir() + "boot_devices";
     std::string value;
     if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) ||
         fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) {
@@ -936,18 +922,22 @@
     return base_device + "-verity";
 }
 
+bool InRecovery() {
+    // Check the existence of recovery binary instead of using the compile time
+    // __ANDROID_RECOVERY__ macro.
+    // If BOARD_USES_RECOVERY_AS_BOOT is true, both normal and recovery boot
+    // mode would use the same init binary, which would mean during normal boot
+    // the '/init' binary is actually a symlink pointing to
+    // init_second_stage.recovery, which would be compiled with
+    // __ANDROID_RECOVERY__ defined.
+    return access("/system/bin/recovery", F_OK) == 0 || access("/sbin/recovery", F_OK) == 0;
+}
+
 }  // namespace fs_mgr
 }  // namespace android
 
-// FIXME: The same logic is duplicated in system/core/init/
-const std::string& get_android_dt_dir() {
-    // Set once and saves time for subsequent calls to this function
-    static const std::string kAndroidDtDir = android::fs_mgr::InitAndroidDtDir();
-    return kAndroidDtDir;
-}
-
 bool is_dt_compatible() {
-    std::string file_name = get_android_dt_dir() + "/compatible";
+    std::string file_name = android::fs_mgr::GetAndroidDtDir() + "compatible";
     std::string dt_value;
     if (android::fs_mgr::ReadDtFile(file_name, &dt_value)) {
         if (dt_value == "android,firmware") {
diff --git a/fs_mgr/fs_mgr_priv_boot_config.h b/fs_mgr/libfstab/fstab_priv.h
similarity index 70%
rename from fs_mgr/fs_mgr_priv_boot_config.h
rename to fs_mgr/libfstab/fstab_priv.h
index 6a38401..5d226f8 100644
--- a/fs_mgr/fs_mgr_priv_boot_config.h
+++ b/fs_mgr/libfstab/fstab_priv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2023 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.
@@ -14,16 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef __CORE_FS_MGR_PRIV_BOOTCONFIG_H
-#define __CORE_FS_MGR_PRIV_BOOTCONFIG_H
+#pragma once
 
-#include <sys/cdefs.h>
 #include <string>
 #include <utility>
 #include <vector>
 
-std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline);
+#include <fstab/fstab.h>
 
+// Do not include logging_macros.h here as this header is used by fs_mgr, too.
+
+std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline);
 bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key,
                                         std::string* out_val);
 bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val);
@@ -34,4 +35,16 @@
                                             std::string* out_val);
 bool fs_mgr_get_boot_config_from_bootconfig_source(const std::string& key, std::string* out_val);
 
-#endif /* __CORE_FS_MGR_PRIV_BOOTCONFIG_H */
+bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab);
+bool is_dt_compatible();
+
+namespace android {
+namespace fs_mgr {
+
+bool InRecovery();
+bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out);
+bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose);
+std::string GetFstabPath();
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fuzz/Android.bp b/fs_mgr/libfstab/fuzz/Android.bp
similarity index 100%
rename from fs_mgr/fuzz/Android.bp
rename to fs_mgr/libfstab/fuzz/Android.bp
diff --git a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp b/fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp
similarity index 97%
rename from fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
rename to fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp
index b5fdad4..b09b273 100644
--- a/fs_mgr/fuzz/fs_mgr_fstab_fuzzer.cpp
+++ b/fs_mgr/libfstab/fuzz/fs_mgr_fstab_fuzzer.cpp
@@ -20,6 +20,8 @@
 #include <fstab/fstab.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include "../fstab_priv.h"
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     FuzzedDataProvider fdp(data, size);
 
diff --git a/fs_mgr/fuzz/fstab.dict b/fs_mgr/libfstab/fuzz/fstab.dict
similarity index 100%
rename from fs_mgr/fuzz/fstab.dict
rename to fs_mgr/libfstab/fuzz/fstab.dict
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
similarity index 91%
rename from fs_mgr/include_fstab/fstab/fstab.h
rename to fs_mgr/libfstab/include/fstab/fstab.h
index 9cb1546..0a45fe8 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -93,13 +93,6 @@
 // Unless explicitly requested, a lookup on mount point should always return the 1st one.
 using Fstab = std::vector<FstabEntry>;
 
-// Exported for testability. Regular users should use ReadFstabFromFile().
-bool ParseFstabFromString(const std::string& fstab_str, bool proc_mounts, Fstab* fstab_out);
-// Exported for testability. Regular users should use ReadDefaultFstab().
-std::string GetFstabPath();
-// Exported for testability.
-bool SkipMountWithConfig(const std::string& skip_config, Fstab* fstab, bool verbose);
-
 bool ReadFstabFromFile(const std::string& path, Fstab* fstab);
 bool ReadFstabFromProcMounts(Fstab* fstab);
 bool ReadFstabFromDt(Fstab* fstab, bool verbose = true);
@@ -131,5 +124,9 @@
 // expected name.
 std::string GetVerityDeviceName(const FstabEntry& entry);
 
+// Returns the Android Device Tree directory as specified in the kernel bootconfig or cmdline.
+// If the platform does not configure a custom DT path, returns the standard one (based in procfs).
+const std::string& GetAndroidDtDir();
+
 }  // namespace fs_mgr
 }  // namespace android
diff --git a/fs_mgr/libfstab/logging_macros.h b/fs_mgr/libfstab/logging_macros.h
new file mode 100644
index 0000000..7ea1b77
--- /dev/null
+++ b/fs_mgr/libfstab/logging_macros.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2023 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 <android-base/logging.h>
+
+#define FSTAB_TAG "[libfstab] "
+
+/* The CHECK() in logging.h will use program invocation name as the tag.
+ * Thus, the log will have prefix "init: " when libfs_mgr is statically
+ * linked in the init process. This might be opaque when debugging.
+ * Append a library name tag at the end of the abort message to aid debugging.
+ */
+#define FSTAB_CHECK(x) CHECK(x) << "in " << FSTAB_TAG
+
+// Logs a message to kernel
+#define LINFO LOG(INFO) << FSTAB_TAG
+#define LWARNING LOG(WARNING) << FSTAB_TAG
+#define LERROR LOG(ERROR) << FSTAB_TAG
+#define LFATAL LOG(FATAL) << FSTAB_TAG
+
+// Logs a message with strerror(errno) at the end
+#define PINFO PLOG(INFO) << FSTAB_TAG
+#define PWARNING PLOG(WARNING) << FSTAB_TAG
+#define PERROR PLOG(ERROR) << FSTAB_TAG
+#define PFATAL PLOG(FATAL) << FSTAB_TAG
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/libfstab/slotselect.cpp
similarity index 97%
rename from fs_mgr/fs_mgr_slotselect.cpp
rename to fs_mgr/libfstab/slotselect.cpp
index 09c1b7e..97b2ba1 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/libfstab/slotselect.cpp
@@ -18,8 +18,8 @@
 
 #include <string>
 
-#include "fs_mgr.h"
-#include "fs_mgr_priv.h"
+#include "fstab_priv.h"
+#include "logging_macros.h"
 
 // Realistically, this file should be part of the android::fs_mgr namespace;
 using namespace android::fs_mgr;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 8f35381..bd017ff 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -101,7 +101,7 @@
 }
 
 cc_library_static {
-    name: "libsnapshot",
+    name: "libsnapshot_static",
     defaults: [
         "libsnapshot_defaults",
         "libsnapshot_hal_deps",
@@ -112,6 +112,25 @@
     ],
 }
 
+cc_library {
+    name: "libsnapshot",
+    defaults: [
+        "libsnapshot_defaults",
+        "libsnapshot_cow_defaults",
+        "libsnapshot_hal_deps",
+    ],
+    srcs: [":libsnapshot_sources"],
+    shared_libs: [
+        "libfs_mgr_binder",
+        "liblp",
+        "libprotobuf-cpp-lite",
+    ],
+    static_libs: [
+        "libc++fs",
+        "libsnapshot_cow",
+    ]
+}
+
 cc_library_static {
     name: "libsnapshot_init",
     native_coverage : true,
@@ -247,7 +266,7 @@
         "libgsi",
         "libgmock",
         "liblp",
-        "libsnapshot",
+        "libsnapshot_static",
         "libsnapshot_cow",
         "libsnapshot_test_helpers",
         "libsparse",
@@ -330,8 +349,6 @@
         "libbrotli",
         "libc++fs",
         "libfstab",
-        "libsnapshot",
-        "libsnapshot_cow",
         "libz",
         "update_metadata-protos",
     ],
@@ -344,6 +361,7 @@
         "liblog",
         "liblp",
         "libprotobuf-cpp-lite",
+        "libsnapshot",
         "libstatslog",
         "libutils",
     ],
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
index 489669a..f37aed1 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp
@@ -310,9 +310,34 @@
 bool CowReader::VerifyMergeOps() {
     auto itr = GetMergeOpIter(true);
     std::unordered_map<uint64_t, const CowOperation*> overwritten_blocks;
+    bool non_ordered_op_found = false;
+
     while (!itr->AtEnd()) {
         const auto& op = itr->Get();
         uint64_t offset;
+
+        // Op should not be a metadata
+        if (IsMetadataOp(*op)) {
+            LOG(ERROR) << "Metadata op: " << op << " found during merge sequence";
+            return false;
+        }
+
+        // Sequence ops should contain all the ordered ops followed
+        // by Replace and Zero ops. If we find the first op which
+        // is not ordered, that means all ordered ops processing
+        // has been completed.
+        if (!IsOrderedOp(*op)) {
+            non_ordered_op_found = true;
+        }
+
+        // Since, all ordered ops processing has been completed,
+        // check that the subsequent ops are not ordered.
+        if (non_ordered_op_found && IsOrderedOp(*op)) {
+            LOG(ERROR) << "Invalid sequence - non-ordered and ordered ops"
+                       << " cannot be mixed during sequence generation";
+            return false;
+        }
+
         if (!GetSourceOffset(op, &offset)) {
             itr->Next();
             continue;
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
index 978a7f2..71664bf 100644
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
@@ -734,8 +734,8 @@
     off_t offset = 0;
 
     for (int i = 0; i < num_threads; i++) {
-        std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device,
-                   partition_name, offset, read_sz_per_thread);
+        (void)std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device,
+                         partition_name, offset, read_sz_per_thread);
 
         offset += read_sz_per_thread;
     }
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
index 7268fca..7d2e3a6 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
@@ -305,7 +305,7 @@
                     return false;
                 }
 
-                ret = BLOCK_SZ;
+                ret = std::min(BLOCK_SZ, read_size);
             }
 
             read_size -= ret;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index e52d752..2dd2ec0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -308,7 +308,7 @@
         ra_thread_status =
                 std::async(std::launch::async, &ReadAhead::RunThread, read_ahead_thread_.get());
 
-        SNAP_LOG(INFO) << "Read-ahead thread started...";
+        SNAP_LOG(INFO) << "Read-ahead thread started";
     }
 
     // Launch worker threads
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
index 3e9588b..8755820 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -592,7 +592,7 @@
             // Check if this block is an XOR op
             if (xor_op->new_block == new_block) {
                 // Read the xor'ed data from COW
-                void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
+                void* buffer = bufsink.GetPayloadBuffer(BLOCK_SZ);
                 if (!buffer) {
                     SNAP_LOG(ERROR) << "ReadAhead - failed to allocate buffer";
                     return false;
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index b9bae25..b7f792f 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -38,7 +38,6 @@
     ],
     static_libs: [
         "libfs_mgr",
-        "libfstab",
     ],
     srcs: [
         "file_wait_test.cpp",
@@ -109,7 +108,6 @@
     ],
     static_libs: [
         "libfs_mgr",
-        "libfstab",
         "libgmock",
         "libgtest",
     ],
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 5f889ca..c51df2a 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -31,7 +31,7 @@
 #include <fstab/fstab.h>
 #include <gtest/gtest.h>
 
-#include "../fs_mgr_priv_boot_config.h"
+#include "../fs_mgr_priv.h"
 
 using namespace android::fs_mgr;
 
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 4d771fa..32947b5 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -23,6 +23,8 @@
 #include <gtest/gtest.h>
 #include <libdm/dm.h>
 
+#include "../fs_mgr_priv.h"
+
 using testing::Contains;
 using testing::Not;
 
diff --git a/init/Android.bp b/init/Android.bp
index 4416b9d..d4852d6 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -392,6 +392,10 @@
     ],
 
     static_executable: true,
+    lto: {
+        // b/169004486 ThinLTO breaks x86 static executables.
+        never: true,
+    },
     system_shared_libs: [],
 
     cflags: [
@@ -535,6 +539,7 @@
         "libprotobuf-cpp-lite",
     ],
     static_libs: [
+        "libfs_mgr",
         "libhidl-gen-utils",
     ],
 }
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2176233..fa5e36d 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1297,7 +1297,6 @@
         return create_dirs.error();
     }
     auto parse_configs = ParseApexConfigs(/*apex_name=*/"");
-    ServiceList::GetInstance().MarkServicesUpdate();
     if (!parse_configs.ok()) {
         return parse_configs.error();
     }
@@ -1307,6 +1306,8 @@
         return update_linker_config.error();
     }
 
+    // Now start delayed services
+    ServiceList::GetInstance().MarkServicesUpdate();
     return {};
 }
 
diff --git a/init/devices.cpp b/init/devices.cpp
index d29ffd6..7c23492 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -568,6 +568,8 @@
         return;
     } else if (uevent.subsystem == "misc" && StartsWith(uevent.device_name, "dm-user/")) {
         devpath = "/dev/dm-user/" + uevent.device_name.substr(8);
+    } else if (uevent.subsystem == "misc" && uevent.device_name == "vfio/vfio") {
+        devpath = "/dev/" + uevent.device_name;
     } else {
         devpath = "/dev/" + Basename(uevent.path);
     }
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 8da6982..0e82022 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -57,6 +57,7 @@
 #include <android-base/result.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <fs_mgr.h>
 #include <property_info_parser/property_info_parser.h>
 #include <property_info_serializer/property_info_serializer.h>
 #include <selinux/android.h>
@@ -1317,7 +1318,8 @@
         return;
     }
 
-    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);
+    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(android::fs_mgr::GetAndroidDtDir().c_str()),
+                                            closedir);
     if (!dir) return;
 
     std::string dt_file;
@@ -1328,7 +1330,7 @@
             continue;
         }
 
-        std::string file_name = get_android_dt_dir() + dp->d_name;
+        std::string file_name = android::fs_mgr::GetAndroidDtDir() + dp->d_name;
 
         android::base::ReadFileToString(file_name, &dt_file);
         std::replace(dt_file.begin(), dt_file.end(), ',', '.');
diff --git a/init/util.cpp b/init/util.cpp
index d0478e8..61d59a4 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -42,6 +42,10 @@
 #include <cutils/sockets.h>
 #include <selinux/android.h>
 
+#if defined(__ANDROID__)
+#include <fs_mgr.h>
+#endif
+
 #ifdef INIT_FULL_SOURCES
 #include <android/api-level.h>
 #include <sys/system_properties.h>
@@ -60,8 +64,6 @@
 namespace android {
 namespace init {
 
-const std::string kDefaultAndroidDtDir("/proc/device-tree/firmware/android/");
-
 const std::string kDataDirPrefix("/data/");
 
 void (*trigger_shutdown)(const std::string& command) = nullptr;
@@ -375,45 +377,18 @@
     return dst;
 }
 
-static std::string init_android_dt_dir() {
-    // Use the standard procfs-based path by default
-    std::string android_dt_dir = kDefaultAndroidDtDir;
-    // The platform may specify a custom Android DT path in kernel cmdline
-    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
-        if (key == "androidboot.android_dt_dir") {
-            android_dt_dir = value;
-        }
-    });
-    // ..Or bootconfig
-    if (android_dt_dir == kDefaultAndroidDtDir) {
-        ImportBootconfig([&](const std::string& key, const std::string& value) {
-            if (key == "androidboot.android_dt_dir") {
-                android_dt_dir = value;
-            }
-        });
-    }
-
-    LOG(INFO) << "Using Android DT directory " << android_dt_dir;
-    return android_dt_dir;
-}
-
-// FIXME: The same logic is duplicated in system/core/fs_mgr/
-const std::string& get_android_dt_dir() {
-    // Set once and saves time for subsequent calls to this function
-    static const std::string kAndroidDtDir = init_android_dt_dir();
-    return kAndroidDtDir;
-}
-
 // Reads the content of device tree file under the platform's Android DT directory.
 // Returns true if the read is success, false otherwise.
 bool read_android_dt_file(const std::string& sub_path, std::string* dt_content) {
-    const std::string file_name = get_android_dt_dir() + sub_path;
+#if defined(__ANDROID__)
+    const std::string file_name = android::fs_mgr::GetAndroidDtDir() + sub_path;
     if (android::base::ReadFileToString(file_name, dt_content)) {
         if (!dt_content->empty()) {
             dt_content->pop_back();  // Trims the trailing '\0' out.
             return true;
         }
     }
+#endif
     return false;
 }
 
diff --git a/init/util.h b/init/util.h
index 3f0a4e0..1c00a3e 100644
--- a/init/util.h
+++ b/init/util.h
@@ -60,9 +60,6 @@
 bool is_dir(const char* pathname);
 Result<std::string> ExpandProps(const std::string& src);
 
-// Returns the platform's Android DT directory as specified in the kernel cmdline.
-// If the platform does not configure a custom DT path, returns the standard one (based in procfs).
-const std::string& get_android_dt_dir();
 // Reads or compares the content of device tree file under the platform's Android DT directory.
 bool read_android_dt_file(const std::string& sub_path, std::string* dt_content);
 bool is_android_dt_value_expected(const std::string& sub_path, const std::string& expected_content);
diff --git a/libcutils/OWNERS b/libcutils/OWNERS
index 7529cb9..e1cbe4a 100644
--- a/libcutils/OWNERS
+++ b/libcutils/OWNERS
@@ -1 +1,2 @@
+# Bug component: 128577
 include platform/system/core:/janitors/OWNERS
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 06d386f..4506439 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -206,11 +206,11 @@
 }
 
 static std::string ConvertUidToPath(const char* cgroup, uid_t uid) {
-    return StringPrintf("%s/uid_%d", cgroup, uid);
+    return StringPrintf("%s/uid_%u", cgroup, uid);
 }
 
 static std::string ConvertUidPidToPath(const char* cgroup, uid_t uid, int pid) {
-    return StringPrintf("%s/uid_%d/pid_%d", cgroup, uid, pid);
+    return StringPrintf("%s/uid_%u/pid_%d", cgroup, uid, pid);
 }
 
 static int RemoveProcessGroup(const char* cgroup, uid_t uid, int pid, unsigned int retries) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 44dba2a..f51b076 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -114,9 +114,26 @@
 
 IProfileAttribute::~IProfileAttribute() = default;
 
-void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name) {
+const std::string& ProfileAttribute::file_name() const {
+    if (controller()->version() == 2 && !file_v2_name_.empty()) return file_v2_name_;
+    return file_name_;
+}
+
+void ProfileAttribute::Reset(const CgroupController& controller, const std::string& file_name,
+                             const std::string& file_v2_name) {
     controller_ = controller;
     file_name_ = file_name;
+    file_v2_name_ = file_v2_name;
+}
+
+bool ProfileAttribute::GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const {
+    if (controller()->version() == 2) {
+        // all cgroup v2 attributes use the same process group hierarchy
+        *path = StringPrintf("%s/uid_%u/pid_%d/%s", controller()->path(), uid, pid,
+                             file_name().c_str());
+        return true;
+    }
+    return GetPathForTask(pid, path);
 }
 
 bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const {
@@ -129,12 +146,11 @@
         return true;
     }
 
-    const std::string& file_name =
-            controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
     if (subgroup.empty()) {
-        *path = StringPrintf("%s/%s", controller()->path(), file_name.c_str());
+        *path = StringPrintf("%s/%s", controller()->path(), file_name().c_str());
     } else {
-        *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), file_name.c_str());
+        *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(),
+                             file_name().c_str());
     }
     return true;
 }
@@ -144,9 +160,7 @@
         return true;
     }
 
-    const std::string& file_name =
-            controller()->version() == 2 && !file_v2_name_.empty() ? file_v2_name_ : file_name_;
-    *path = StringPrintf("%s/uid_%d/%s", controller()->path(), uid, file_name.c_str());
+    *path = StringPrintf("%s/uid_%u/%s", controller()->path(), uid, file_name().c_str());
     return true;
 }
 
@@ -205,18 +219,7 @@
 
 #endif
 
-bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const {
-    return ExecuteForTask(pid);
-}
-
-bool SetAttributeAction::ExecuteForTask(int tid) const {
-    std::string path;
-
-    if (!attribute_->GetPathForTask(tid, &path)) {
-        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
-        return false;
-    }
-
+bool SetAttributeAction::WriteValueToFile(const std::string& path) const {
     if (!WriteStringToFile(value_, path)) {
         if (access(path.c_str(), F_OK) < 0) {
             if (optional_) {
@@ -236,6 +239,28 @@
     return true;
 }
 
+bool SetAttributeAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
+    std::string path;
+
+    if (!attribute_->GetPathForProcess(uid, pid, &path)) {
+        LOG(ERROR) << "Failed to find cgroup for uid " << uid << " pid " << pid;
+        return false;
+    }
+
+    return WriteValueToFile(path);
+}
+
+bool SetAttributeAction::ExecuteForTask(int tid) const {
+    std::string path;
+
+    if (!attribute_->GetPathForTask(tid, &path)) {
+        LOG(ERROR) << "Failed to find cgroup for tid " << tid;
+        return false;
+    }
+
+    return WriteValueToFile(path);
+}
+
 bool SetAttributeAction::ExecuteForUID(uid_t uid) const {
     std::string path;
 
@@ -816,7 +841,7 @@
                 attributes_[name] =
                         std::make_unique<ProfileAttribute>(controller, file_attr, file_v2_attr);
             } else {
-                iter->second->Reset(controller, file_attr);
+                iter->second->Reset(controller, file_attr, file_v2_attr);
             }
         } else {
             LOG(WARNING) << "Controller " << controller_name << " is not found";
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index a62c5b0..4663f64 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -32,9 +32,11 @@
 class IProfileAttribute {
   public:
     virtual ~IProfileAttribute() = 0;
-    virtual void Reset(const CgroupController& controller, const std::string& file_name) = 0;
+    virtual void Reset(const CgroupController& controller, const std::string& file_name,
+                       const std::string& file_v2_name) = 0;
     virtual const CgroupController* controller() const = 0;
     virtual const std::string& file_name() const = 0;
+    virtual bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const = 0;
     virtual bool GetPathForTask(int tid, std::string* path) const = 0;
     virtual bool GetPathForUID(uid_t uid, std::string* path) const = 0;
 };
@@ -50,9 +52,11 @@
     ~ProfileAttribute() = default;
 
     const CgroupController* controller() const override { return &controller_; }
-    const std::string& file_name() const override { return file_name_; }
-    void Reset(const CgroupController& controller, const std::string& file_name) override;
+    const std::string& file_name() const override;
+    void Reset(const CgroupController& controller, const std::string& file_name,
+               const std::string& file_v2_name) override;
 
+    bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override;
     bool GetPathForTask(int tid, std::string* path) const override;
     bool GetPathForUID(uid_t uid, std::string* path) const override;
 
@@ -131,6 +135,8 @@
     const IProfileAttribute* attribute_;
     std::string value_;
     bool optional_;
+
+    bool WriteValueToFile(const std::string& path) const;
 };
 
 // Set cgroup profile element
diff --git a/libprocessgroup/task_profiles_test.cpp b/libprocessgroup/task_profiles_test.cpp
index eadbe76..99d819a 100644
--- a/libprocessgroup/task_profiles_test.cpp
+++ b/libprocessgroup/task_profiles_test.cpp
@@ -102,7 +102,8 @@
   public:
     ProfileAttributeMock(const std::string& file_name) : file_name_(file_name) {}
     ~ProfileAttributeMock() override = default;
-    void Reset(const CgroupController& controller, const std::string& file_name) override {
+    void Reset(const CgroupController& controller, const std::string& file_name,
+               const std::string& file_v2_name) override {
         CHECK(false);
     }
     const CgroupController* controller() const override {
@@ -110,6 +111,9 @@
         return {};
     }
     const std::string& file_name() const override { return file_name_; }
+    bool GetPathForProcess(uid_t uid, pid_t pid, std::string* path) const override {
+        return GetPathForTask(pid, path);
+    }
     bool GetPathForTask(int tid, std::string* path) const override {
 #ifdef __ANDROID__
         CHECK(CgroupGetControllerPath(CGROUPV2_CONTROLLER_NAME, path));
@@ -125,9 +129,7 @@
         return true;
     };
 
-    bool GetPathForUID(uid_t, std::string*) const override {
-        return false;
-    }
+    bool GetPathForUID(uid_t, std::string*) const override { return false; }
 
   private:
     const std::string file_name_;
diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs
index 09b2623..d188b5f 100644
--- a/libstats/pull_rust/stats_pull.rs
+++ b/libstats/pull_rust/stats_pull.rs
@@ -111,7 +111,9 @@
     static ref COOKIES: Mutex<HashMap<i32, fn() -> StatsPullResult>> = Mutex::new(HashMap::new());
 }
 
-// Safety: We store our callbacks in the global so they are valid.
+/// # Safety
+///
+/// `data` must be a valid pointer with no aliases.
 unsafe extern "C" fn callback_wrapper(
     atom_tag: i32,
     data: *mut AStatsEventList,
@@ -126,7 +128,8 @@
                 let stats = cb();
                 let result = stats
                     .iter()
-                    .map(|stat| stat.add_astats_event(&mut *data))
+                    // Safety: The caller promises that `data` is valid and unaliased.
+                    .map(|stat| stat.add_astats_event(unsafe { &mut *data }))
                     .collect::<Result<Vec<()>, StatsError>>();
                 match result {
                     Ok(_) => {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index d2499ef..8f01d93 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -997,7 +997,7 @@
     perform_apex_config
 
     # Create directories for boot animation.
-    mkdir /data/bootanim 0755 system system encryption=DeleteIfNecessary
+    mkdir /data/misc/bootanim 0755 system system encryption=DeleteIfNecessary
 
     exec_start derive_sdk
 
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 0b7ffb8..60dcc2a 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -23,6 +23,11 @@
 subsystem dma_heap
    devname uevent_devpath
    dirname /dev/dma_heap
+
+subsystem vfio
+    devname uevent_devpath
+    dirname /dev/vfio
+
 # ueventd can only set permissions on device nodes and their associated
 # sysfs attributes, not on arbitrary paths.
 #
@@ -43,6 +48,7 @@
 /dev/binder               0666   root       root
 /dev/hwbinder             0666   root       root
 /dev/vndbinder            0666   root       root
+/dev/vfio/*               0666   root       root
 
 /dev/pmsg0                0222   root       log
 /dev/dma_heap/system      0444   system     system
diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp
index c19ebbd..19dcc98 100644
--- a/trusty/keymint/Android.bp
+++ b/trusty/keymint/Android.bp
@@ -35,6 +35,7 @@
         "liblibc",
         "liblog_rust",
     ],
+    prefer_rlib: true,
     required: [
         "android.hardware.hardware_keystore.xml",
     ],
diff --git a/trusty/libtrusty-rs/src/lib.rs b/trusty/libtrusty-rs/src/lib.rs
index 28ea075..22b894a 100644
--- a/trusty/libtrusty-rs/src/lib.rs
+++ b/trusty/libtrusty-rs/src/lib.rs
@@ -102,6 +102,8 @@
         let file = File::options().read(true).write(true).open(device)?;
 
         let srv_name = CString::new(service).expect("Service name contained null bytes");
+        // SAFETY: The file descriptor is valid because it came from a `File`, and the name is a
+        // valid C string because it came from a `CString`.
         unsafe {
             tipc_connect(file.as_raw_fd(), srv_name.as_ptr())?;
         }
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
index 3b744ec..67e935e 100644
--- a/trusty/storage/proxy/proxy.c
+++ b/trusty/storage/proxy/proxy.c
@@ -243,9 +243,12 @@
      * Start binder threadpool. At least one extra binder thread is needed to
      * connect to the wakelock service without relying on polling. If we poll on
      * the main thread we end up pausing for at least 1s even if the service
-     * starts faster.
+     * starts faster. We set the max thread count to 0 because startThreadPool
+     * "Starts one thread, PLUS those requested in setThreadPoolMaxThreadCount,
+     * PLUS those manually requested in joinThreadPool." We only need a single
+     * binder thread to receive notifications on.
      */
-    ABinderProcess_setThreadPoolMaxThreadCount(1);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
     ABinderProcess_startThreadPool();
 
     /* initialize secure storage directory */