Merge "String8: fix infinite loop and segmentation fault in removeAll()" into main
diff --git a/debuggerd/rust/tombstoned_client/src/lib.rs b/debuggerd/rust/tombstoned_client/src/lib.rs
index 5c8abef..d1b5e69 100644
--- a/debuggerd/rust/tombstoned_client/src/lib.rs
+++ b/debuggerd/rust/tombstoned_client/src/lib.rs
@@ -39,20 +39,26 @@
 }
 
 impl TombstonedConnection {
+    /// # Safety
+    ///
+    /// The file descriptors must be valid and open.
     unsafe fn from_raw_fds(
         tombstoned_socket: RawFd,
         text_output_fd: RawFd,
         proto_output_fd: RawFd,
     ) -> Self {
         Self {
-            tombstoned_socket: File::from_raw_fd(tombstoned_socket),
+            // SAFETY: The caller guarantees that the file descriptor is valid and open.
+            tombstoned_socket: unsafe { File::from_raw_fd(tombstoned_socket) },
             text_output: if text_output_fd >= 0 {
-                Some(File::from_raw_fd(text_output_fd))
+                // SAFETY: The caller guarantees that the file descriptor is valid and open.
+                Some(unsafe { File::from_raw_fd(text_output_fd) })
             } else {
                 None
             },
             proto_output: if proto_output_fd >= 0 {
-                Some(File::from_raw_fd(proto_output_fd))
+                // SAFETY: The caller guarantees that the file descriptor is valid and open.
+                Some(unsafe { File::from_raw_fd(proto_output_fd) })
             } else {
                 None
             },
@@ -71,6 +77,8 @@
             &mut proto_output_fd,
             dump_type,
         ) {
+            // SAFETY: If tombstoned_connect_files returns successfully then they file descriptors
+            // are valid and open.
             Ok(unsafe { Self::from_raw_fds(tombstoned_socket, text_output_fd, proto_output_fd) })
         } else {
             Err(Error)
@@ -146,8 +154,6 @@
             .write_all(b"test data")
             .expect("Failed to write to text output FD.");
 
-        connection
-            .notify_completion()
-            .expect("Failed to notify completion.");
+        connection.notify_completion().expect("Failed to notify completion.");
     }
 }
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 2941216..0bd07ed 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -120,6 +120,9 @@
 static std::vector<Image> images = {
         // clang-format off
     { "boot",     "boot.img",         "boot.sig",     "boot",     false, ImageType::BootCritical },
+    { "bootloader",
+                  "bootloader.img",   "",             "bootloader",
+                                                                  true,  ImageType::Extra },
     { "init_boot",
                   "init_boot.img",    "init_boot.sig",
                                                       "init_boot",
@@ -132,6 +135,7 @@
     { "odm_dlkm", "odm_dlkm.img",     "odm_dlkm.sig", "odm_dlkm", true,  ImageType::Normal },
     { "product",  "product.img",      "product.sig",  "product",  true,  ImageType::Normal },
     { "pvmfw",    "pvmfw.img",        "pvmfw.sig",    "pvmfw",    true,  ImageType::BootCritical },
+    { "radio",    "radio.img",        "",             "radio",    true,  ImageType::Extra },
     { "recovery", "recovery.img",     "recovery.sig", "recovery", true,  ImageType::BootCritical },
     { "super",    "super.img",        "super.sig",    "super",    true,  ImageType::Extra },
     { "system",   "system.img",       "system.sig",   "system",   false, ImageType::Normal },
@@ -630,6 +634,9 @@
             " --skip-reboot              Don't reboot device after flashing.\n"
             " --disable-verity           Sets disable-verity when flashing vbmeta.\n"
             " --disable-verification     Sets disable-verification when flashing vbmeta.\n"
+            " --disable-super-optimization\n"
+            "                            Disables optimizations on flashing super partition.\n"
+            " --disable-fastboot-info    Will collects tasks from image list rather than $OUT/fastboot-info.txt.\n"
             " --fs-options=OPTION[,OPTION]\n"
             "                            Enable filesystem features. OPTION supports casefold, projid, compress\n"
             // TODO: remove --unbuffered?
@@ -2213,6 +2220,7 @@
                                       {"disable-verification", no_argument, 0, 0},
                                       {"disable-verity", no_argument, 0, 0},
                                       {"disable-super-optimization", no_argument, 0, 0},
+                                      {"disable-fastboot-info", no_argument, 0, 0},
                                       {"force", no_argument, 0, 0},
                                       {"fs-options", required_argument, 0, 0},
                                       {"header-version", required_argument, 0, 0},
@@ -2253,6 +2261,8 @@
                 g_disable_verity = true;
             } else if (name == "disable-super-optimization") {
                 fp->should_optimize_flash_super = false;
+            } else if (name == "disable-fastboot-info") {
+                fp->should_use_fastboot_info = false;
             } else if (name == "force") {
                 fp->force_flash = true;
             } else if (name == "fs-options") {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 50db25d..f6ffb64 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -97,7 +97,7 @@
     bool skip_secondary = false;
     bool force_flash = false;
     bool should_optimize_flash_super = true;
-    bool should_use_fastboot_info = false;
+    bool should_use_fastboot_info = true;
     uint64_t sparse_limit = 0;
 
     std::string slot_override;
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index bbd068b..0a836e4 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -49,7 +49,6 @@
     sanitize: {
         misc_undefined: ["integer"],
     },
-    local_include_dirs: ["include/"],
     cflags: [
         "-Wall",
         "-Werror",
@@ -60,6 +59,7 @@
     name: "libfs_mgr_defaults",
     defaults: ["fs_mgr_defaults"],
     export_include_dirs: ["include"],
+    local_include_dirs: ["include/"],
     include_dirs: ["system/vold"],
     cflags: [
         "-D_FILE_OFFSET_BITS=64",
@@ -70,8 +70,9 @@
         "fs_mgr.cpp",
         "fs_mgr_format.cpp",
         "fs_mgr_dm_linear.cpp",
-        "fs_mgr_overlayfs.cpp",
         "fs_mgr_roots.cpp",
+        "fs_mgr_overlayfs_control.cpp",
+        "fs_mgr_overlayfs_mount.cpp",
         "fs_mgr_vendor_overlay.cpp",
         ":libfiemap_srcs",
     ],
@@ -187,6 +188,7 @@
     ],
     host_supported: true,
     defaults: ["fs_mgr_defaults"],
+    local_include_dirs: ["include/"],
     srcs: [
         "fs_mgr_fstab.cpp",
         "fs_mgr_boot_config.cpp",
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp
similarity index 60%
rename from fs_mgr/fs_mgr_overlayfs.cpp
rename to fs_mgr/fs_mgr_overlayfs_control.cpp
index 01827d6..69a2ac0 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs_control.cpp
@@ -55,8 +55,9 @@
 #include <liblp/liblp.h>
 #include <storage_literals/storage_literals.h>
 
+#include "fs_mgr_overlayfs_control.h"
+#include "fs_mgr_overlayfs_mount.h"
 #include "fs_mgr_priv.h"
-#include "fs_mgr_priv_overlayfs.h"
 #include "libfiemap/utility.h"
 
 using namespace std::literals;
@@ -69,100 +70,18 @@
 namespace {
 
 constexpr char kDataScratchSizeMbProp[] = "fs_mgr.overlayfs.data_scratch_size_mb";
-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;
-}
-
-const auto kLowerdirOption = "lowerdir="s;
-const auto kUpperdirOption = "upperdir="s;
-
-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");
-}
-
-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;
-    return android::gsi::IsGsiRunning();
-}
-
-// list of acceptable overlayfs backing storage
-const auto kScratchMountPoint = "/mnt/scratch"s;
-const auto kCacheMountPoint = "/cache"s;
-
-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
-    // partitions, which means legacy cache mustn't be used.
-    if (fs_mgr_is_dsu_running()) {
-        return {kScratchMountPoint};
-    }
-
-    // For non-A/B devices prefer cache backing storage if
-    // kPreferCacheBackingStorageProp property set.
-    if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) &&
-        android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) {
-        return {kCacheMountPoint, kScratchMountPoint};
-    }
-
-    return {kScratchMountPoint, kCacheMountPoint};
-}
 
 // Return true if everything is mounted, but before adb is started.  Right
 // after 'trigger load_persist_props_action' is done.
-bool fs_mgr_boot_completed() {
+static bool fs_mgr_boot_completed() {
     return android::base::GetBoolProperty("ro.persistent_properties.ready", false);
 }
 
-bool fs_mgr_is_dir(const std::string& path) {
-    struct stat st;
-    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) {
-    // If we have access issues to find out space remaining, return true
-    // to prevent us trying to override with overlayfs.
-    struct statvfs vst;
-    if (statvfs(mount_point.c_str(), &vst)) {
-        PLOG(ERROR) << "statvfs " << mount_point;
-        return true;
-    }
-
-    static constexpr int kPercentThreshold = 1;                       // 1%
-    static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024;  // 8MB
-
-    return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) &&
-           (static_cast<uint64_t>(vst.f_bfree) * vst.f_frsize) >= kSizeThreshold;
-}
-
-const auto kPhysicalDevice = "/dev/block/by-name/"s;
+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.
-bool ScratchIsOnData() {
+static bool ScratchIsOnData() {
     // The scratch partition of DSU is managed by gsid.
     if (fs_mgr_is_dsu_running()) {
         return false;
@@ -170,97 +89,7 @@
     return fs_mgr_access(kScratchImageMetadata);
 }
 
-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)) {
-        return true;
-    }
-    if (entry->blk_device != "/dev/root") {
-        return false;
-    }
-
-    // special case for system-as-root (taimen and others)
-    auto blk_device = kPhysicalDevice + "system";
-    if (!fs_mgr_access(blk_device)) {
-        blk_device += fs_mgr_get_slot_suffix();
-        if (!fs_mgr_access(blk_device)) {
-            return false;
-        }
-    }
-    entry->blk_device = blk_device;
-    return true;
-}
-
-bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
-    struct statfs fs;
-    if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
-        (fs.f_type != EXT4_SUPER_MAGIC)) {
-        return false;
-    }
-
-    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
-    if (fd < 0) return false;
-
-    struct ext4_super_block sb;
-    if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
-        (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
-        return false;
-    }
-
-    struct fs_info info;
-    if (ext4_parse_sb(&sb, &info) < 0) return false;
-
-    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
-}
-
-#define F2FS_SUPER_OFFSET 1024
-#define F2FS_FEATURE_OFFSET 2180
-#define F2FS_FEATURE_RO 0x4000
-bool fs_mgr_is_read_only_f2fs(const std::string& dev) {
-    if (!fs_mgr_is_f2fs(dev)) return false;
-
-    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
-    if (fd < 0) return false;
-
-    __le32 feat;
-    if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) ||
-        (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) {
-        return false;
-    }
-
-    return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0;
-}
-
-bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
-    // readonly filesystem, can not be mount -o remount,rw
-    // for squashfs, erofs or if free space is (near) zero making such a remount
-    // virtually useless, or if there are shared blocks that prevent remount,rw
-    if (!fs_mgr_filesystem_has_space(entry->mount_point)) {
-        return true;
-    }
-
-    // blk_device needs to be setup so we can check superblock.
-    // If we fail here, because during init first stage and have doubts.
-    if (!fs_mgr_update_blk_device(entry)) {
-        return true;
-    }
-
-    // f2fs read-only mode doesn't support remount,rw
-    if (fs_mgr_is_read_only_f2fs(entry->blk_device)) {
-        return true;
-    }
-
-    // check if ext4 de-dupe
-    auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
-    if (!has_shared_blocks && (entry->mount_point == "/system")) {
-        has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device);
-    }
-    return has_shared_blocks;
-}
-
-bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
+static bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
     if (!dir) {
         if (errno == ENOENT) {
@@ -301,96 +130,6 @@
     return ret;
 }
 
-const auto kUpperName = "upper"s;
-const auto kWorkName = "work"s;
-const auto kOverlayTopDir = "/overlay"s;
-
-std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
-    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 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;
-        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";
-}
-
-// default options for mount_point, returns empty string for none available.
-std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) {
-    const auto mount_point = fs_mgr_mount_point(entry.mount_point);
-    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";
-    }
-    for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
-        if (android::base::StartsWith(flag, "context=")) {
-            ret += "," + flag;
-        }
-    }
-    return ret;
-}
-
-constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
-
-class AutoSetFsCreateCon final {
-  public:
-    AutoSetFsCreateCon() {}
-    AutoSetFsCreateCon(const std::string& context) { Set(context); }
-    ~AutoSetFsCreateCon() { Restore(); }
-
-    bool Ok() const { return ok_; }
-    bool Set(const std::string& context) {
-        if (setfscreatecon(context.c_str())) {
-            PLOG(ERROR) << "setfscreatecon " << context;
-            return false;
-        }
-        ok_ = true;
-        return true;
-    }
-    bool Restore() {
-        if (restored_ || !ok_) {
-            return true;
-        }
-        if (setfscreatecon(nullptr)) {
-            PLOG(ERROR) << "setfscreatecon null";
-            return false;
-        }
-        restored_ = true;
-        return true;
-    }
-
-  private:
-    bool ok_ = false;
-    bool restored_ = false;
-};
-
 std::string fs_mgr_overlayfs_setup_dir(const std::string& dir) {
     auto top = dir + kOverlayTopDir;
 
@@ -452,15 +191,15 @@
     return true;
 }
 
-uint32_t fs_mgr_overlayfs_slot_number() {
+static uint32_t fs_mgr_overlayfs_slot_number() {
     return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
 }
 
-std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
+static std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) {
     return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number);
 }
 
-bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) {
+static bool fs_mgr_overlayfs_has_logical(const Fstab& fstab) {
     for (const auto& entry : fstab) {
         if (entry.fs_mgr_flags.logical) {
             return true;
@@ -469,18 +208,6 @@
     return false;
 }
 
-// Returns true if immediate unmount succeeded and the scratch mount point was
-// removed.
-bool fs_mgr_overlayfs_umount_scratch() {
-    if (umount(kScratchMountPoint.c_str()) != 0) {
-        return false;
-    }
-    if (rmdir(kScratchMountPoint.c_str()) != 0 && errno != ENOENT) {
-        PLOG(ERROR) << "rmdir " << kScratchMountPoint;
-    }
-    return true;
-}
-
 OverlayfsTeardownResult TeardownDataScratch(IImageManager* images,
                                             const std::string& partition_name, bool was_mounted) {
     if (!images) {
@@ -573,7 +300,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.substr(1) + ".teardown"
+    const auto newpath = cleanup_all ? overlay + "/." + (kOverlayTopDir + 1) + ".teardown"
                                      : top + "/." + partition_name + ".teardown";
     auto ret = fs_mgr_rm_all(newpath);
     if (!rename(oldpath.c_str(), newpath.c_str())) {
@@ -619,214 +346,6 @@
     return ret;
 }
 
-bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
-    auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
-                     nullptr);
-    if (ret) {
-        PERROR << "__mount(target=" << mount_point
-               << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
-        // If "/system" doesn't look like a mountpoint, retry with "/".
-        if (errno == EINVAL && mount_point == "/system") {
-            return fs_mgr_overlayfs_set_shared_mount("/", shared_flag);
-        }
-        return false;
-    }
-    return true;
-}
-
-bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
-    auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
-    if (ret) {
-        PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
-        return false;
-    }
-    return true;
-}
-
-struct mount_info {
-    std::string mount_point;
-    bool shared_flag;
-};
-
-std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
-    std::vector<mount_info> info;
-
-    auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
-    if (!file) {
-        PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
-        return info;
-    }
-
-    ssize_t len;
-    size_t alloc_len = 0;
-    char* line = nullptr;
-    while ((len = getline(&line, &alloc_len, file.get())) != -1) {
-        /* if the last character is a newline, shorten the string by 1 byte */
-        if (line[len - 1] == '\n') {
-            line[len - 1] = '\0';
-        }
-
-        static constexpr char delim[] = " \t";
-        char* save_ptr;
-        if (!strtok_r(line, delim, &save_ptr)) {
-            LERROR << "Error parsing mount ID";
-            break;
-        }
-        if (!strtok_r(nullptr, delim, &save_ptr)) {
-            LERROR << "Error parsing parent ID";
-            break;
-        }
-        if (!strtok_r(nullptr, delim, &save_ptr)) {
-            LERROR << "Error parsing mount source";
-            break;
-        }
-        if (!strtok_r(nullptr, delim, &save_ptr)) {
-            LERROR << "Error parsing root";
-            break;
-        }
-
-        char* p;
-        if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
-            LERROR << "Error parsing mount_point";
-            break;
-        }
-        mount_info entry = {p, false};
-
-        if (!strtok_r(nullptr, delim, &save_ptr)) {
-            LERROR << "Error parsing mount_flags";
-            break;
-        }
-
-        while ((p = strtok_r(nullptr, delim, &save_ptr))) {
-            if ((p[0] == '-') && (p[1] == '\0')) break;
-            if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
-        }
-        if (!p) {
-            LERROR << "Error parsing fields";
-            break;
-        }
-        info.emplace_back(std::move(entry));
-    }
-
-    free(line);
-    if (info.empty()) {
-        LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
-    }
-    return info;
-}
-
-bool fs_mgr_overlayfs_mount(const FstabEntry& entry) {
-    const auto mount_point = fs_mgr_mount_point(entry.mount_point);
-    const auto options = fs_mgr_get_overlayfs_options(entry);
-    if (options.empty()) return false;
-
-    auto retval = true;
-
-    struct move_entry {
-        std::string mount_point;
-        std::string dir;
-        bool shared_flag;
-    };
-    std::vector<move_entry> move;
-    auto parent_private = false;
-    auto parent_made_private = false;
-    auto dev_private = false;
-    auto dev_made_private = false;
-    for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
-        if ((entry.mount_point == mount_point) && !entry.shared_flag) {
-            parent_private = true;
-        }
-        if ((entry.mount_point == "/dev") && !entry.shared_flag) {
-            dev_private = true;
-        }
-
-        if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
-            continue;
-        }
-        if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
-                return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
-            }) != move.end()) {
-            continue;
-        }
-
-        // use as the bound directory in /dev.
-        AutoSetFsCreateCon createcon;
-        auto new_context = fs_mgr_get_context(entry.mount_point);
-        if (new_context.empty() || !createcon.Set(new_context)) {
-            continue;
-        }
-        move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
-                                entry.shared_flag};
-        const auto target = mkdtemp(new_entry.dir.data());
-        if (!createcon.Restore()) {
-            return false;
-        }
-        if (!target) {
-            retval = false;
-            PERROR << "temporary directory for MS_BIND";
-            continue;
-        }
-
-        if (!parent_private && !parent_made_private) {
-            parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
-        }
-        if (new_entry.shared_flag) {
-            new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
-        }
-        if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
-            retval = false;
-            if (new_entry.shared_flag) {
-                fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
-            }
-            continue;
-        }
-        move.emplace_back(std::move(new_entry));
-    }
-
-    // hijack __mount() report format to help triage
-    auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
-    const auto opt_list = android::base::Split(options, ",");
-    for (const auto& opt : opt_list) {
-        if (android::base::StartsWith(opt, kUpperdirOption)) {
-            report = report + "," + opt;
-            break;
-        }
-    }
-    report = report + ")=";
-
-    auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
-                     options.c_str());
-    if (ret) {
-        retval = false;
-        PERROR << report << ret;
-    } else {
-        LINFO << report << ret;
-    }
-
-    // Move submounts back.
-    for (const auto& entry : move) {
-        if (!dev_private && !dev_made_private) {
-            dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
-        }
-
-        if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
-            retval = false;
-        } else if (entry.shared_flag &&
-                   !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
-            retval = false;
-        }
-        rmdir(entry.dir.c_str());
-    }
-    if (dev_made_private) {
-        fs_mgr_overlayfs_set_shared_mount("/dev", true);
-    }
-    if (parent_made_private) {
-        fs_mgr_overlayfs_set_shared_mount(mount_point, true);
-    }
-
-    return retval;
-}
-
 // Mount kScratchMountPoint
 bool MountScratch(const std::string& device_path, bool readonly = false) {
     if (readonly) {
@@ -853,7 +372,7 @@
     if (!createcon.Ok()) {
         return false;
     }
-    if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) {
+    if (mkdir(kScratchMountPoint, 0755) && (errno != EEXIST)) {
         PERROR << "create " << kScratchMountPoint;
         return false;
     }
@@ -884,7 +403,7 @@
         return false;
     }
     if (!mounted) {
-        rmdir(kScratchMountPoint.c_str());
+        rmdir(kScratchMountPoint);
         return false;
     }
     return true;
@@ -1010,21 +529,7 @@
         auto partition_size =
                 builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
         if ((partition_size > kMinimumSize) || !partition->size()) {
-            // Leave some space for free space jitter of a few erase
-            // blocks, in case they are needed for any individual updates
-            // to any other partition that needs to be flashed while
-            // overlayfs is in force.  Of course if margin_size is not
-            // enough could normally get a flash failure, so
-            // ResizePartition() will delete the scratch partition in
-            // order to fulfill.  Deleting scratch will destroy all of
-            // the adb remount overrides :-( .
-            auto margin_size = uint64_t(3 * 256 * 1024);
-            BlockDeviceInfo info;
-            if (builder->GetBlockDeviceInfo(fs_mgr_get_super_partition_name(slot_number), &info)) {
-                margin_size = 3 * info.logical_block_size;
-            }
-            partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
-                                      partition_size / 2);
+            partition_size = std::max(std::min(kMinimumSize, partition_size), partition_size / 2);
             if (partition_size > partition->size()) {
                 if (!builder->ResizePartition(partition, partition_size)) {
                     // Try to free up space by deallocating partitions in the other slot.
@@ -1032,8 +537,8 @@
 
                     partition_size =
                             builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
-                    partition_size = std::max(std::min(kMinimumSize, partition_size - margin_size),
-                                              partition_size / 2);
+                    partition_size =
+                            std::max(std::min(kMinimumSize, partition_size), partition_size / 2);
                     if (!builder->ResizePartition(partition, partition_size)) {
                         LERROR << "resize " << partition_name;
                         return false;
@@ -1192,7 +697,7 @@
     // If the partition exists, assume first that it can be mounted.
     if (partition_exists) {
         if (MountScratch(scratch_device)) {
-            if (fs_mgr_access(kScratchMountPoint + kOverlayTopDir) ||
+            if (fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir) ||
                 fs_mgr_filesystem_has_space(kScratchMountPoint)) {
                 return true;
             }
@@ -1212,12 +717,6 @@
     return MountScratch(scratch_device);
 }
 
-#if ALLOW_ADBD_DISABLE_VERITY
-constexpr bool kAllowOverlayfs = true;
-#else
-constexpr bool kAllowOverlayfs = false;
-#endif
-
 // NOTE: OverlayfsSetupAllowed() must be "stricter" than OverlayfsTeardownAllowed().
 // Setup is allowed only if teardown is also allowed.
 bool OverlayfsSetupAllowed(bool verbose = false) {
@@ -1251,114 +750,6 @@
 
 }  // namespace
 
-bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
-    // Don't check entries that are managed by vold.
-    if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
-
-    // *_other doesn't want overlayfs.
-    if (entry->fs_mgr_flags.slot_select_other) return false;
-
-    // Only concerned with readonly partitions.
-    if (!(entry->flags & MS_RDONLY)) return false;
-
-    // If unbindable, do not allow overlayfs as this could expose us to
-    // security issues.  On Android, this could also be used to turn off
-    // the ability to overlay an otherwise acceptable filesystem since
-    // /system and /vendor are never bound(sic) to.
-    if (entry->flags & MS_UNBINDABLE) return false;
-
-    if (!fs_mgr_overlayfs_enabled(entry)) return false;
-
-    return true;
-}
-
-Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
-    android::fs_mgr::Fstab mounts;
-    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
-        PLOG(ERROR) << "Failed to read /proc/mounts";
-        return {};
-    }
-
-    Fstab candidates;
-    for (const auto& entry : fstab) {
-        // Filter out partitions whose type doesn't match what's mounted.
-        // This avoids spammy behavior on devices which can mount different
-        // filesystems for each partition.
-        auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
-        auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
-        if (!mounted || mounted->fs_type != entry.fs_type) {
-            continue;
-        }
-
-        FstabEntry new_entry = entry;
-        if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
-            !fs_mgr_wants_overlayfs(&new_entry)) {
-            continue;
-        }
-        auto new_mount_point = fs_mgr_mount_point(entry.mount_point);
-        auto duplicate_or_more_specific = false;
-        for (auto it = candidates.begin(); it != candidates.end();) {
-            auto it_mount_point = fs_mgr_mount_point(it->mount_point);
-            if ((it_mount_point == new_mount_point) ||
-                (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) {
-                duplicate_or_more_specific = true;
-                break;
-            }
-            if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) {
-                it = candidates.erase(it);
-            } else {
-                ++it;
-            }
-        }
-        if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry));
-    }
-    return candidates;
-}
-
-static void TryMountScratch() {
-    // Note we get the boot scratch device here, which means if scratch was
-    // just created through ImageManager, this could fail. In practice this
-    // should not happen because "remount" detects this scenario (by checking
-    // 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)) {
-        return;
-    }
-    if (!WaitForFile(scratch_device, 10s)) {
-        return;
-    }
-    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) {
-        MountScratch(scratch_device);
-    }
-}
-
-bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
-    if (!OverlayfsSetupAllowed()) {
-        return false;
-    }
-    auto ret = true;
-    auto scratch_can_be_mounted = true;
-    for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
-        if (fs_mgr_is_verity_enabled(entry)) continue;
-        auto mount_point = fs_mgr_mount_point(entry.mount_point);
-        if (fs_mgr_overlayfs_already_mounted(mount_point)) {
-            continue;
-        }
-        if (scratch_can_be_mounted) {
-            scratch_can_be_mounted = false;
-            TryMountScratch();
-        }
-        ret &= fs_mgr_overlayfs_mount(entry);
-    }
-    return ret;
-}
-
 bool fs_mgr_overlayfs_setup(const Fstab& fstab, const char* mount_point, bool* want_reboot,
                             bool just_disabled_verity) {
     if (!OverlayfsSetupAllowed(/*verbose=*/true)) {
@@ -1582,22 +973,6 @@
     return rv;
 }
 
-bool fs_mgr_overlayfs_is_setup() {
-    if (!OverlayfsSetupAllowed()) {
-        return false;
-    }
-    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
-    Fstab fstab;
-    if (!ReadDefaultFstab(&fstab)) {
-        return false;
-    }
-    for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) {
-        if (fs_mgr_is_verity_enabled(entry)) continue;
-        if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true;
-    }
-    return false;
-}
-
 namespace android {
 namespace fs_mgr {
 
@@ -1714,23 +1089,3 @@
 
 }  // namespace fs_mgr
 }  // namespace android
-
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
-    Fstab fstab;
-    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
-        return false;
-    }
-    const auto lowerdir = kLowerdirOption + mount_point;
-    for (const auto& entry : fstab) {
-        if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
-        if (mount_point != entry.mount_point) continue;
-        if (!overlay_only) return true;
-        const auto options = android::base::Split(entry.fs_options, ",");
-        for (const auto& opt : options) {
-            if (opt == lowerdir) {
-                return true;
-            }
-        }
-    }
-    return false;
-}
diff --git a/fs_mgr/fs_mgr_overlayfs_control.h b/fs_mgr/fs_mgr_overlayfs_control.h
new file mode 100644
index 0000000..50e83e8
--- /dev/null
+++ b/fs_mgr/fs_mgr_overlayfs_control.h
@@ -0,0 +1,44 @@
+// 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 <string>
+
+#include <fstab/fstab.h>
+
+// If "mount_point" is non-null, set up exactly one overlay.
+//
+// If "mount_point" is null, setup any overlays.
+//
+// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then
+// it will be true on return. The caller is responsible for initializing it.
+bool fs_mgr_overlayfs_setup(const android::fs_mgr::Fstab& fstab, const char* mount_point = nullptr,
+                            bool* want_reboot = nullptr, bool just_disabled_verity = true);
+
+enum class OverlayfsTeardownResult {
+    Ok,
+    Busy,  // Indicates that overlays are still in use.
+    Error
+};
+OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr,
+                                                  bool* want_reboot = nullptr);
+
+namespace android {
+namespace fs_mgr {
+
+void CleanupOldScratchFiles();
+
+}  // namespace fs_mgr
+}  // namespace android
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.cpp b/fs_mgr/fs_mgr_overlayfs_mount.cpp
new file mode 100644
index 0000000..c057c2b
--- /dev/null
+++ b/fs_mgr/fs_mgr_overlayfs_mount.cpp
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2018 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 <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>
+
+#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>
+#include <libdm/dm.h>
+#include <libgsi/libgsi.h>
+#include <storage_literals/storage_literals.h>
+
+#include "fs_mgr_overlayfs_mount.h"
+#include "fs_mgr_priv.h"
+
+using namespace std::literals;
+using namespace android::dm;
+using namespace android::fs_mgr;
+using namespace android::storage_literals;
+
+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;
+}
+
+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");
+}
+
+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;
+    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
+    // partitions, which means legacy cache mustn't be used.
+    if (fs_mgr_is_dsu_running()) {
+        return {kScratchMountPoint};
+    }
+
+    // For non-A/B devices prefer cache backing storage if
+    // kPreferCacheBackingStorageProp property set.
+    if (!IsABDevice() && android::base::GetBoolProperty(kPreferCacheBackingStorageProp, false) &&
+        android::base::GetIntProperty("ro.vendor.api_level", -1) < __ANDROID_API_T__) {
+        return {kCacheMountPoint, kScratchMountPoint};
+    }
+
+    return {kScratchMountPoint, kCacheMountPoint};
+}
+
+static bool fs_mgr_is_dir(const std::string& path) {
+    struct stat st;
+    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) {
+    // If we have access issues to find out space remaining, return true
+    // to prevent us trying to override with overlayfs.
+    struct statvfs vst;
+    if (statvfs(mount_point.c_str(), &vst)) {
+        PLOG(ERROR) << "statvfs " << mount_point;
+        return true;
+    }
+
+    static constexpr int kPercentThreshold = 1;                       // 1%
+    static constexpr unsigned long kSizeThreshold = 8 * 1024 * 1024;  // 8MB
+
+    return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100)) &&
+           (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)) {
+        return true;
+    }
+    if (entry->blk_device != "/dev/root") {
+        return false;
+    }
+
+    // special case for system-as-root (taimen and others)
+    auto blk_device = std::string(kPhysicalDevice) + "system";
+    if (!fs_mgr_access(blk_device)) {
+        blk_device += fs_mgr_get_slot_suffix();
+        if (!fs_mgr_access(blk_device)) {
+            return false;
+        }
+    }
+    entry->blk_device = blk_device;
+    return true;
+}
+
+static bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev) {
+    struct statfs fs;
+    if ((statfs((mount_point + "/lost+found").c_str(), &fs) == -1) ||
+        (fs.f_type != EXT4_SUPER_MAGIC)) {
+        return false;
+    }
+
+    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) return false;
+
+    struct ext4_super_block sb;
+    if ((TEMP_FAILURE_RETRY(lseek64(fd, 1024, SEEK_SET)) < 0) ||
+        (TEMP_FAILURE_RETRY(read(fd, &sb, sizeof(sb))) < 0)) {
+        return false;
+    }
+
+    struct fs_info info;
+    if (ext4_parse_sb(&sb, &info) < 0) return false;
+
+    return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
+}
+
+#define F2FS_SUPER_OFFSET 1024
+#define F2FS_FEATURE_OFFSET 2180
+#define F2FS_FEATURE_RO 0x4000
+static bool fs_mgr_is_read_only_f2fs(const std::string& dev) {
+    if (!fs_mgr_is_f2fs(dev)) return false;
+
+    android::base::unique_fd fd(open(dev.c_str(), O_RDONLY | O_CLOEXEC));
+    if (fd < 0) return false;
+
+    __le32 feat;
+    if ((TEMP_FAILURE_RETRY(lseek64(fd, F2FS_SUPER_OFFSET + F2FS_FEATURE_OFFSET, SEEK_SET)) < 0) ||
+        (TEMP_FAILURE_RETRY(read(fd, &feat, sizeof(feat))) < 0)) {
+        return false;
+    }
+
+    return (feat & cpu_to_le32(F2FS_FEATURE_RO)) != 0;
+}
+
+static bool fs_mgr_overlayfs_enabled(FstabEntry* entry) {
+    // readonly filesystem, can not be mount -o remount,rw
+    // for squashfs, erofs or if free space is (near) zero making such a remount
+    // virtually useless, or if there are shared blocks that prevent remount,rw
+    if (!fs_mgr_filesystem_has_space(entry->mount_point)) {
+        return true;
+    }
+
+    // blk_device needs to be setup so we can check superblock.
+    // If we fail here, because during init first stage and have doubts.
+    if (!fs_mgr_update_blk_device(entry)) {
+        return true;
+    }
+
+    // f2fs read-only mode doesn't support remount,rw
+    if (fs_mgr_is_read_only_f2fs(entry->blk_device)) {
+        return true;
+    }
+
+    // check if ext4 de-dupe
+    auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device);
+    if (!has_shared_blocks && (entry->mount_point == "/system")) {
+        has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device);
+    }
+    return has_shared_blocks;
+}
+
+static std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) {
+    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 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;
+        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";
+}
+
+// default options for mount_point, returns empty string for none available.
+static std::string fs_mgr_get_overlayfs_options(const FstabEntry& entry) {
+    const auto mount_point = fs_mgr_mount_point(entry.mount_point);
+    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";
+    }
+    for (const auto& flag : android::base::Split(entry.fs_options, ",")) {
+        if (android::base::StartsWith(flag, "context=")) {
+            ret += "," + flag;
+        }
+    }
+    return ret;
+}
+
+bool AutoSetFsCreateCon::Set(const std::string& context) {
+    if (setfscreatecon(context.c_str())) {
+        PLOG(ERROR) << "setfscreatecon " << context;
+        return false;
+    }
+    ok_ = true;
+    return true;
+}
+
+bool AutoSetFsCreateCon::Restore() {
+    if (restored_ || !ok_) {
+        return true;
+    }
+    if (setfscreatecon(nullptr)) {
+        PLOG(ERROR) << "setfscreatecon null";
+        return false;
+    }
+    restored_ = true;
+    return true;
+}
+
+// Returns true if immediate unmount succeeded and the scratch mount point was
+// removed.
+bool fs_mgr_overlayfs_umount_scratch() {
+    if (umount(kScratchMountPoint) != 0) {
+        return false;
+    }
+    if (rmdir(kScratchMountPoint) != 0 && errno != ENOENT) {
+        PLOG(ERROR) << "rmdir " << kScratchMountPoint;
+    }
+    return true;
+}
+
+static bool fs_mgr_overlayfs_set_shared_mount(const std::string& mount_point, bool shared_flag) {
+    auto ret = mount(nullptr, mount_point.c_str(), nullptr, shared_flag ? MS_SHARED : MS_PRIVATE,
+                     nullptr);
+    if (ret) {
+        PERROR << "__mount(target=" << mount_point
+               << ",flag=" << (shared_flag ? "MS_SHARED" : "MS_PRIVATE") << ")=" << ret;
+        // If "/system" doesn't look like a mountpoint, retry with "/".
+        if (errno == EINVAL && mount_point == "/system") {
+            return fs_mgr_overlayfs_set_shared_mount("/", shared_flag);
+        }
+        return false;
+    }
+    return true;
+}
+
+static bool fs_mgr_overlayfs_move_mount(const std::string& source, const std::string& target) {
+    auto ret = mount(source.c_str(), target.c_str(), nullptr, MS_MOVE, nullptr);
+    if (ret) {
+        PERROR << "__mount(source=" << source << ",target=" << target << ",flag=MS_MOVE)=" << ret;
+        return false;
+    }
+    return true;
+}
+
+struct mount_info {
+    std::string mount_point;
+    bool shared_flag;
+};
+
+static std::vector<mount_info> ReadMountinfoFromFile(const std::string& path) {
+    std::vector<mount_info> info;
+
+    auto file = std::unique_ptr<FILE, decltype(&fclose)>{fopen(path.c_str(), "re"), fclose};
+    if (!file) {
+        PERROR << __FUNCTION__ << "(): cannot open file: '" << path << "'";
+        return info;
+    }
+
+    ssize_t len;
+    size_t alloc_len = 0;
+    char* line = nullptr;
+    while ((len = getline(&line, &alloc_len, file.get())) != -1) {
+        /* if the last character is a newline, shorten the string by 1 byte */
+        if (line[len - 1] == '\n') {
+            line[len - 1] = '\0';
+        }
+
+        static constexpr char delim[] = " \t";
+        char* save_ptr;
+        if (!strtok_r(line, delim, &save_ptr)) {
+            LERROR << "Error parsing mount ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing parent ID";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount source";
+            break;
+        }
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing root";
+            break;
+        }
+
+        char* p;
+        if (!(p = strtok_r(nullptr, delim, &save_ptr))) {
+            LERROR << "Error parsing mount_point";
+            break;
+        }
+        mount_info entry = {p, false};
+
+        if (!strtok_r(nullptr, delim, &save_ptr)) {
+            LERROR << "Error parsing mount_flags";
+            break;
+        }
+
+        while ((p = strtok_r(nullptr, delim, &save_ptr))) {
+            if ((p[0] == '-') && (p[1] == '\0')) break;
+            if (android::base::StartsWith(p, "shared:")) entry.shared_flag = true;
+        }
+        if (!p) {
+            LERROR << "Error parsing fields";
+            break;
+        }
+        info.emplace_back(std::move(entry));
+    }
+
+    free(line);
+    if (info.empty()) {
+        LERROR << __FUNCTION__ << "(): failed to load mountinfo from : '" << path << "'";
+    }
+    return info;
+}
+
+static bool fs_mgr_overlayfs_mount(const FstabEntry& entry) {
+    const auto mount_point = fs_mgr_mount_point(entry.mount_point);
+    const auto options = fs_mgr_get_overlayfs_options(entry);
+    if (options.empty()) return false;
+
+    auto retval = true;
+
+    struct move_entry {
+        std::string mount_point;
+        std::string dir;
+        bool shared_flag;
+    };
+    std::vector<move_entry> move;
+    auto parent_private = false;
+    auto parent_made_private = false;
+    auto dev_private = false;
+    auto dev_made_private = false;
+    for (auto& entry : ReadMountinfoFromFile("/proc/self/mountinfo")) {
+        if ((entry.mount_point == mount_point) && !entry.shared_flag) {
+            parent_private = true;
+        }
+        if ((entry.mount_point == "/dev") && !entry.shared_flag) {
+            dev_private = true;
+        }
+
+        if (!android::base::StartsWith(entry.mount_point, mount_point + "/")) {
+            continue;
+        }
+        if (std::find_if(move.begin(), move.end(), [&entry](const auto& it) {
+                return android::base::StartsWith(entry.mount_point, it.mount_point + "/");
+            }) != move.end()) {
+            continue;
+        }
+
+        // use as the bound directory in /dev.
+        AutoSetFsCreateCon createcon;
+        auto new_context = fs_mgr_get_context(entry.mount_point);
+        if (new_context.empty() || !createcon.Set(new_context)) {
+            continue;
+        }
+        move_entry new_entry = {std::move(entry.mount_point), "/dev/TemporaryDir-XXXXXX",
+                                entry.shared_flag};
+        const auto target = mkdtemp(new_entry.dir.data());
+        if (!createcon.Restore()) {
+            return false;
+        }
+        if (!target) {
+            retval = false;
+            PERROR << "temporary directory for MS_BIND";
+            continue;
+        }
+
+        if (!parent_private && !parent_made_private) {
+            parent_made_private = fs_mgr_overlayfs_set_shared_mount(mount_point, false);
+        }
+        if (new_entry.shared_flag) {
+            new_entry.shared_flag = fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, false);
+        }
+        if (!fs_mgr_overlayfs_move_mount(new_entry.mount_point, new_entry.dir)) {
+            retval = false;
+            if (new_entry.shared_flag) {
+                fs_mgr_overlayfs_set_shared_mount(new_entry.mount_point, true);
+            }
+            continue;
+        }
+        move.emplace_back(std::move(new_entry));
+    }
+
+    // hijack __mount() report format to help triage
+    auto report = "__mount(source=overlay,target="s + mount_point + ",type=overlay";
+    const auto opt_list = android::base::Split(options, ",");
+    for (const auto& opt : opt_list) {
+        if (android::base::StartsWith(opt, kUpperdirOption)) {
+            report = report + "," + opt;
+            break;
+        }
+    }
+    report = report + ")=";
+
+    auto ret = mount("overlay", mount_point.c_str(), "overlay", MS_RDONLY | MS_NOATIME,
+                     options.c_str());
+    if (ret) {
+        retval = false;
+        PERROR << report << ret;
+    } else {
+        LINFO << report << ret;
+    }
+
+    // Move submounts back.
+    for (const auto& entry : move) {
+        if (!dev_private && !dev_made_private) {
+            dev_made_private = fs_mgr_overlayfs_set_shared_mount("/dev", false);
+        }
+
+        if (!fs_mgr_overlayfs_move_mount(entry.dir, entry.mount_point)) {
+            retval = false;
+        } else if (entry.shared_flag &&
+                   !fs_mgr_overlayfs_set_shared_mount(entry.mount_point, true)) {
+            retval = false;
+        }
+        rmdir(entry.dir.c_str());
+    }
+    if (dev_made_private) {
+        fs_mgr_overlayfs_set_shared_mount("/dev", true);
+    }
+    if (parent_made_private) {
+        fs_mgr_overlayfs_set_shared_mount(mount_point, true);
+    }
+
+    return retval;
+}
+
+// Mount kScratchMountPoint
+static 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() {
+    auto& dm = DeviceMapper::Instance();
+    std::string device;
+    if (dm.GetState(android::gsi::kDsuScratch) != DmDeviceState::INVALID &&
+        dm.GetDmDevicePathByName(android::gsi::kDsuScratch, &device)) {
+        return device;
+    }
+    return "";
+}
+
+// This returns the scratch device that was detected during early boot (first-
+// stage init). If the device was created later, for example during setup for
+// the adb remount command, it can return an empty string since it does not
+// query ImageManager. (Note that ImageManager in first-stage init will always
+// use device-mapper, since /data is not available to use loop devices.)
+static std::string GetBootScratchDevice() {
+    // Note: fs_mgr_is_dsu_running() always returns false in recovery or fastbootd.
+    if (fs_mgr_is_dsu_running()) {
+        return GetDsuScratchDevice();
+    }
+
+    auto& dm = DeviceMapper::Instance();
+
+    // If there is a scratch partition allocated in /data or on super, we
+    // automatically prioritize that over super_other or system_other.
+    // Some devices, for example, have a write-protected eMMC and the
+    // super partition cannot be used even if it exists.
+    std::string device;
+    auto partition_name = android::base::Basename(kScratchMountPoint);
+    if (dm.GetState(partition_name) != DmDeviceState::INVALID &&
+        dm.GetDmDevicePathByName(partition_name, &device)) {
+        return device;
+    }
+
+    return "";
+}
+
+// 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;
+}
+
+bool fs_mgr_wants_overlayfs(FstabEntry* entry) {
+    // Don't check entries that are managed by vold.
+    if (entry->fs_mgr_flags.vold_managed || entry->fs_mgr_flags.recovery_only) return false;
+
+    // *_other doesn't want overlayfs.
+    if (entry->fs_mgr_flags.slot_select_other) return false;
+
+    // Only concerned with readonly partitions.
+    if (!(entry->flags & MS_RDONLY)) return false;
+
+    // If unbindable, do not allow overlayfs as this could expose us to
+    // security issues.  On Android, this could also be used to turn off
+    // the ability to overlay an otherwise acceptable filesystem since
+    // /system and /vendor are never bound(sic) to.
+    if (entry->flags & MS_UNBINDABLE) return false;
+
+    if (!fs_mgr_overlayfs_enabled(entry)) return false;
+
+    return true;
+}
+
+Fstab fs_mgr_overlayfs_candidate_list(const Fstab& fstab) {
+    android::fs_mgr::Fstab mounts;
+    if (!android::fs_mgr::ReadFstabFromFile("/proc/mounts", &mounts)) {
+        PLOG(ERROR) << "Failed to read /proc/mounts";
+        return {};
+    }
+
+    Fstab candidates;
+    for (const auto& entry : fstab) {
+        // Filter out partitions whose type doesn't match what's mounted.
+        // This avoids spammy behavior on devices which can mount different
+        // filesystems for each partition.
+        auto proc_mount_point = (entry.mount_point == "/system") ? "/" : entry.mount_point;
+        auto mounted = GetEntryForMountPoint(&mounts, proc_mount_point);
+        if (!mounted || mounted->fs_type != entry.fs_type) {
+            continue;
+        }
+
+        FstabEntry new_entry = entry;
+        if (!fs_mgr_overlayfs_already_mounted(entry.mount_point) &&
+            !fs_mgr_wants_overlayfs(&new_entry)) {
+            continue;
+        }
+        auto new_mount_point = fs_mgr_mount_point(entry.mount_point);
+        auto duplicate_or_more_specific = false;
+        for (auto it = candidates.begin(); it != candidates.end();) {
+            auto it_mount_point = fs_mgr_mount_point(it->mount_point);
+            if ((it_mount_point == new_mount_point) ||
+                (android::base::StartsWith(new_mount_point, it_mount_point + "/"))) {
+                duplicate_or_more_specific = true;
+                break;
+            }
+            if (android::base::StartsWith(it_mount_point, new_mount_point + "/")) {
+                it = candidates.erase(it);
+            } else {
+                ++it;
+            }
+        }
+        if (!duplicate_or_more_specific) candidates.emplace_back(std::move(new_entry));
+    }
+    return candidates;
+}
+
+static void TryMountScratch() {
+    // Note we get the boot scratch device here, which means if scratch was
+    // just created through ImageManager, this could fail. In practice this
+    // should not happen because "remount" detects this scenario (by checking
+    // 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)) {
+        return;
+    }
+    if (!WaitForFile(scratch_device, 10s)) {
+        return;
+    }
+    if (!MountScratch(scratch_device, true /* readonly */)) {
+        return;
+    }
+    auto has_overlayfs_dir = fs_mgr_access(std::string(kScratchMountPoint) + kOverlayTopDir);
+    fs_mgr_overlayfs_umount_scratch();
+    if (has_overlayfs_dir) {
+        MountScratch(scratch_device);
+    }
+}
+
+bool fs_mgr_overlayfs_mount_all(Fstab* fstab) {
+    if (!OverlayfsSetupAllowed()) {
+        return false;
+    }
+    auto ret = true;
+    auto scratch_can_be_mounted = true;
+    for (const auto& entry : fs_mgr_overlayfs_candidate_list(*fstab)) {
+        if (fs_mgr_is_verity_enabled(entry)) continue;
+        auto mount_point = fs_mgr_mount_point(entry.mount_point);
+        if (fs_mgr_overlayfs_already_mounted(mount_point)) {
+            continue;
+        }
+        if (scratch_can_be_mounted) {
+            scratch_can_be_mounted = false;
+            TryMountScratch();
+        }
+        ret &= fs_mgr_overlayfs_mount(entry);
+    }
+    return ret;
+}
+
+bool fs_mgr_overlayfs_is_setup() {
+    if (!OverlayfsSetupAllowed()) {
+        return false;
+    }
+    if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true;
+    Fstab fstab;
+    if (!ReadDefaultFstab(&fstab)) {
+        return false;
+    }
+    for (const auto& entry : fs_mgr_overlayfs_candidate_list(fstab)) {
+        if (fs_mgr_is_verity_enabled(entry)) continue;
+        if (fs_mgr_overlayfs_already_mounted(fs_mgr_mount_point(entry.mount_point))) return true;
+    }
+    return false;
+}
+
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only) {
+    Fstab fstab;
+    if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+        return false;
+    }
+    const auto lowerdir = kLowerdirOption + mount_point;
+    for (const auto& entry : fstab) {
+        if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue;
+        if (mount_point != entry.mount_point) continue;
+        if (!overlay_only) return true;
+        const auto options = android::base::Split(entry.fs_options, ",");
+        for (const auto& opt : options) {
+            if (opt == lowerdir) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
diff --git a/fs_mgr/fs_mgr_overlayfs_mount.h b/fs_mgr/fs_mgr_overlayfs_mount.h
new file mode 100644
index 0000000..ae3ea84
--- /dev/null
+++ b/fs_mgr/fs_mgr_overlayfs_mount.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <fstab/fstab.h>
+
+bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
+bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
+android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
+
+#if ALLOW_ADBD_DISABLE_VERITY
+constexpr bool kAllowOverlayfs = true;
+#else
+constexpr bool kAllowOverlayfs = false;
+#endif
+
+class AutoSetFsCreateCon final {
+  public:
+    AutoSetFsCreateCon() {}
+    AutoSetFsCreateCon(const std::string& context) { Set(context); }
+    ~AutoSetFsCreateCon() { Restore(); }
+
+    bool Ok() const { return ok_; }
+    bool Set(const std::string& context);
+    bool Restore();
+
+  private:
+    bool ok_ = false;
+    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 fs_mgr_overlayfs_umount_scratch();
+std::vector<const std::string> OverlayMountPoints();
diff --git a/fs_mgr/fs_mgr_priv_overlayfs.h b/fs_mgr/fs_mgr_priv_overlayfs.h
deleted file mode 100644
index 2033701..0000000
--- a/fs_mgr/fs_mgr_priv_overlayfs.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include <fstab/fstab.h>
-
-bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true);
-bool fs_mgr_wants_overlayfs(android::fs_mgr::FstabEntry* entry);
-android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fstab& fstab);
-
-// If "mount_point" is non-null, set up exactly one overlay.
-// If "mount_point" is null, setup any overlays.
-//
-// If |want_reboot| is non-null, and a reboot is needed to apply overlays, then
-// it will be true on return. The caller is responsible for initializing it.
-bool fs_mgr_overlayfs_setup(const android::fs_mgr::Fstab& fstab, const char* mount_point = nullptr,
-                            bool* want_reboot = nullptr, bool just_disabled_verity = true);
-
-enum class OverlayfsTeardownResult {
-    Ok,
-    Busy,  // Indicates that overlays are still in use.
-    Error
-};
-OverlayfsTeardownResult fs_mgr_overlayfs_teardown(const char* mount_point = nullptr,
-                                                  bool* want_reboot = nullptr);
-
-namespace android {
-namespace fs_mgr {
-
-void CleanupOldScratchFiles();
-
-}  // namespace fs_mgr
-}  // namespace android
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 5a9f391..4c45828 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -43,7 +43,8 @@
 #include <libavb_user/libavb_user.h>
 #include <libgsi/libgsid.h>
 
-#include "fs_mgr_priv_overlayfs.h"
+#include "fs_mgr_overlayfs_control.h"
+#include "fs_mgr_overlayfs_mount.h"
 
 using namespace std::literals;
 using android::fs_mgr::Fstab;
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 9d1ce7d..8f35381 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -166,7 +166,6 @@
     header_libs: [
         "libupdate_engine_headers",
     ],
-    export_include_dirs: ["include"],
 }
 
 cc_library_static {
@@ -184,6 +183,7 @@
         "libsnapshot_cow/writer_base.cpp",
         "libsnapshot_cow/writer_v2.cpp",
     ],
+    export_include_dirs: ["include"],
     host_supported: true,
     recovery_available: true,
     ramdisk_available: true,
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index fbea79b..09d35cf 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -2490,9 +2490,6 @@
         }
         created_devices.EmplaceBack<AutoUnmapDevice>(&dm_, name);
 
-        remaining_time = GetRemainingTime(params.timeout_ms, begin);
-        if (remaining_time.count() < 0) return false;
-
         cow_device = new_cow_device;
     }
 
@@ -2507,6 +2504,9 @@
     // the user-space will not start the merge. We have to explicitly inform the
     // daemon to resume the merge. Check ProcessUpdateState() call stack.
     if (!UpdateUsesUserSnapshots(lock)) {
+        remaining_time = GetRemainingTime(params.timeout_ms, begin);
+        if (remaining_time.count() < 0) return false;
+
         std::string path;
         if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
                          &path)) {
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index 9fe567a..a9b96e2 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -57,18 +57,20 @@
     defaults: [
         "fs_mgr_defaults",
     ],
+    local_include_dirs: ["include/"],
     srcs: [
         "dm-snapshot-merge/snapuserd.cpp",
         "dm-snapshot-merge/snapuserd_worker.cpp",
         "dm-snapshot-merge/snapuserd_readahead.cpp",
         "snapuserd_buffer.cpp",
         "user-space-merge/handler_manager.cpp",
+        "user-space-merge/read_worker.cpp",
         "user-space-merge/snapuserd_core.cpp",
-        "user-space-merge/snapuserd_dm_user.cpp",
         "user-space-merge/snapuserd_merge.cpp",
         "user-space-merge/snapuserd_readahead.cpp",
         "user-space-merge/snapuserd_transitions.cpp",
         "user-space-merge/snapuserd_verify.cpp",
+        "user-space-merge/worker.cpp",
     ],
     static_libs: [
         "libbase",
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
index a6b6a7f..c5ca2b1 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_buffer.h
@@ -36,6 +36,21 @@
     struct dm_user_header* GetHeaderPtr();
     void ResetBufferOffset() { buffer_offset_ = 0; }
     void* GetPayloadBufPtr();
+    loff_t GetPayloadBytesWritten() { return buffer_offset_; }
+
+    // Same as calling GetPayloadBuffer and then UpdateBufferOffset.
+    //
+    // This is preferred over GetPayloadBuffer as it does not require a
+    // separate call to UpdateBufferOffset.
+    void* AcquireBuffer(size_t size) { return AcquireBuffer(size, size); }
+
+    // Same as AcquireBuffer, but separates the requested size from the buffer
+    // offset. This is useful for a situation where a full run of data will be
+    // read, but only a partial amount will be returned.
+    //
+    // If size != to_write, the excess bytes may be reallocated by the next
+    // call to AcquireBuffer.
+    void* AcquireBuffer(size_t size, size_t to_write);
 
   private:
     std::unique_ptr<uint8_t[]> buffer_;
@@ -43,19 +58,5 @@
     size_t buffer_size_;
 };
 
-class XorSink final {
-  public:
-    void Initialize(BufferSink* sink, size_t size);
-    void Reset();
-    void* GetBuffer(size_t requested, size_t* actual);
-    bool ReturnData(void* buffer, size_t len);
-
-  private:
-    BufferSink* bufsink_;
-    std::unique_ptr<uint8_t[]> buffer_;
-    size_t buffer_size_;
-    size_t returned_;
-};
-
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
index ab763ab..35065e6 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_buffer.cpp
@@ -15,6 +15,8 @@
  */
 
 #include <snapuserd/snapuserd_buffer.h>
+
+#include <android-base/logging.h>
 #include <snapuserd/snapuserd_kernel.h>
 
 namespace android {
@@ -26,11 +28,23 @@
     buffer_ = std::make_unique<uint8_t[]>(size);
 }
 
-void* BufferSink::GetPayloadBuffer(size_t size) {
-    if ((buffer_size_ - buffer_offset_) < size) return nullptr;
+void* BufferSink::AcquireBuffer(size_t size, size_t to_write) {
+    CHECK(to_write <= size);
 
+    void* ptr = GetPayloadBuffer(size);
+    if (!ptr) {
+        return nullptr;
+    }
+    UpdateBufferOffset(to_write);
+    return ptr;
+}
+
+void* BufferSink::GetPayloadBuffer(size_t size) {
     char* buffer = reinterpret_cast<char*>(GetBufPtr());
     struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+    if ((buffer_size_ - buffer_offset_ - sizeof(msg->header)) < size) {
+        return nullptr;
+    }
     return (char*)msg->payload.buf + buffer_offset_;
 }
 
@@ -59,38 +73,5 @@
     return msg->payload.buf;
 }
 
-void XorSink::Initialize(BufferSink* sink, size_t size) {
-    bufsink_ = sink;
-    buffer_size_ = size;
-    returned_ = 0;
-    buffer_ = std::make_unique<uint8_t[]>(size);
-}
-
-void XorSink::Reset() {
-    returned_ = 0;
-}
-
-void* XorSink::GetBuffer(size_t requested, size_t* actual) {
-    if (requested > buffer_size_) {
-        *actual = buffer_size_;
-    } else {
-        *actual = requested;
-    }
-    return buffer_.get();
-}
-
-bool XorSink::ReturnData(void* buffer, size_t len) {
-    uint8_t* xor_data = reinterpret_cast<uint8_t*>(buffer);
-    uint8_t* buff = reinterpret_cast<uint8_t*>(bufsink_->GetPayloadBuffer(len + returned_));
-    if (buff == nullptr) {
-        return false;
-    }
-    for (size_t i = 0; i < len; i++) {
-        buff[returned_ + i] ^= xor_data[i];
-    }
-    returned_ += len;
-    return true;
-}
-
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
index bdba5c0..4105b4b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/handler_manager.cpp
@@ -18,7 +18,9 @@
 
 #include <android-base/logging.h>
 
+#include "read_worker.h"
 #include "snapuserd_core.h"
+#include "snapuserd_merge.h"
 
 namespace android {
 namespace snapshot {
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
similarity index 67%
rename from fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
rename to fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
index 0eb2a14..7268fca 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_dm_user.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "read_worker.h"
+
 #include "snapuserd_core.h"
 
 namespace android {
@@ -23,64 +25,24 @@
 using namespace android::dm;
 using android::base::unique_fd;
 
-Worker::Worker(const std::string& cow_device, const std::string& backing_device,
-               const std::string& control_device, const std::string& misc_name,
-               const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd) {
-    cow_device_ = cow_device;
-    backing_store_device_ = backing_device;
-    control_device_ = control_device;
-    misc_name_ = misc_name;
-    base_path_merge_ = base_path_merge;
-    snapuserd_ = snapuserd;
+void ReadWorker::CloseFds() {
+    ctrl_fd_ = {};
+    backing_store_fd_ = {};
+    Worker::CloseFds();
 }
 
-bool Worker::InitializeFds() {
-    backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
-    if (backing_store_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
-        return false;
-    }
-
-    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
-    if (cow_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
-        return false;
-    }
-
-    ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR));
-    if (ctrl_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Unable to open " << control_device_;
-        return false;
-    }
-
-    // Base device used by merge thread
-    base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR));
-    if (base_path_merge_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << base_path_merge_;
-        return false;
-    }
-
-    return true;
-}
-
-bool Worker::InitReader() {
-    reader_ = snapuserd_->CloneReaderForWorker();
-
-    if (!reader_->InitForMerge(std::move(cow_fd_))) {
-        return false;
-    }
-    return true;
-}
+ReadWorker::ReadWorker(const std::string& cow_device, const std::string& backing_device,
+                       const std::string& control_device, const std::string& misc_name,
+                       const std::string& base_path_merge,
+                       std::shared_ptr<SnapshotHandler> snapuserd)
+    : Worker(cow_device, misc_name, base_path_merge, snapuserd),
+      backing_store_device_(backing_device),
+      control_device_(control_device) {}
 
 // Start the replace operation. This will read the
 // internal COW format and if the block is compressed,
 // it will be de-compressed.
-bool Worker::ProcessReplaceOp(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (!buffer) {
-        SNAP_LOG(ERROR) << "ProcessReplaceOp failed to allocate buffer";
-        return false;
-    }
+bool ReadWorker::ProcessReplaceOp(const CowOperation* cow_op, void* buffer) {
     if (!reader_->ReadData(cow_op, buffer, BLOCK_SZ)) {
         SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block;
         return false;
@@ -88,12 +50,7 @@
     return true;
 }
 
-bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
-        return false;
-    }
+bool ReadWorker::ReadFromSourceDevice(const CowOperation* cow_op, void* buffer) {
     uint64_t offset;
     if (!reader_->GetSourceOffset(cow_op, &offset)) {
         SNAP_LOG(ERROR) << "ReadFromSourceDevice: Failed to get source offset";
@@ -118,60 +75,43 @@
 
 // Start the copy operation. This will read the backing
 // block device which is represented by cow_op->source.
-bool Worker::ProcessCopyOp(const CowOperation* cow_op) {
-    if (!ReadFromSourceDevice(cow_op)) {
+bool ReadWorker::ProcessCopyOp(const CowOperation* cow_op, void* buffer) {
+    if (!ReadFromSourceDevice(cow_op, buffer)) {
         return false;
     }
-
     return true;
 }
 
-bool Worker::ProcessXorOp(const CowOperation* cow_op) {
-    if (!ReadFromSourceDevice(cow_op)) {
+bool ReadWorker::ProcessXorOp(const CowOperation* cow_op, void* buffer) {
+    if (!ReadFromSourceDevice(cow_op, buffer)) {
         return false;
     }
 
-    xorsink_.Reset();
-
-    size_t actual = 0;
-    void* buffer = xorsink_.GetBuffer(BLOCK_SZ, &actual);
-    if (!buffer || actual < BLOCK_SZ) {
-        SNAP_LOG(ERROR) << "ProcessXorOp failed to get buffer of " << BLOCK_SZ << " size, got "
-                        << actual;
-        return false;
+    if (xor_buffer_.empty()) {
+        xor_buffer_.resize(BLOCK_SZ);
     }
-    ssize_t size = reader_->ReadData(cow_op, buffer, BLOCK_SZ);
+    CHECK(xor_buffer_.size() == BLOCK_SZ);
+
+    ssize_t size = reader_->ReadData(cow_op, xor_buffer_.data(), xor_buffer_.size());
     if (size != BLOCK_SZ) {
         SNAP_LOG(ERROR) << "ProcessXorOp failed for block " << cow_op->new_block
                         << ", return value: " << size;
         return false;
     }
-    if (!xorsink_.ReturnData(buffer, size)) {
-        SNAP_LOG(ERROR) << "ProcessXorOp failed to return data";
-        return false;
+
+    auto xor_out = reinterpret_cast<uint8_t*>(buffer);
+    for (size_t i = 0; i < BLOCK_SZ; i++) {
+        xor_out[i] ^= xor_buffer_[i];
     }
     return true;
 }
 
-bool Worker::ProcessZeroOp() {
-    // Zero out the entire block
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ProcessZeroOp: Failed to get payload buffer";
-        return false;
-    }
-
+bool ReadWorker::ProcessZeroOp(void* buffer) {
     memset(buffer, 0, BLOCK_SZ);
     return true;
 }
 
-bool Worker::ProcessOrderedOp(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ProcessOrderedOp: Failed to get payload buffer";
-        return false;
-    }
-
+bool ReadWorker::ProcessOrderedOp(const CowOperation* cow_op, void* buffer) {
     MERGE_GROUP_STATE state = snapuserd_->ProcessMergingBlock(cow_op->new_block, buffer);
 
     switch (state) {
@@ -181,7 +121,7 @@
             SNAP_LOG(DEBUG) << "Merge-completed: Reading from base device sector: "
                             << (cow_op->new_block >> SECTOR_SHIFT)
                             << " Block-number: " << cow_op->new_block;
-            if (!ReadDataFromBaseDevice(ChunkToSector(cow_op->new_block), BLOCK_SZ)) {
+            if (!ReadDataFromBaseDevice(ChunkToSector(cow_op->new_block), buffer, BLOCK_SZ)) {
                 SNAP_LOG(ERROR) << "ReadDataFromBaseDevice at sector: "
                                 << (cow_op->new_block >> SECTOR_SHIFT) << " after merge-complete.";
                 return false;
@@ -191,9 +131,9 @@
         case MERGE_GROUP_STATE::GROUP_MERGE_PENDING: {
             bool ret;
             if (cow_op->type == kCowCopyOp) {
-                ret = ProcessCopyOp(cow_op);
+                ret = ProcessCopyOp(cow_op, buffer);
             } else {
-                ret = ProcessXorOp(cow_op);
+                ret = ProcessXorOp(cow_op, buffer);
             }
 
             // I/O is complete - decrement the refcount irrespective of the return
@@ -218,7 +158,7 @@
     return false;
 }
 
-bool Worker::ProcessCowOp(const CowOperation* cow_op) {
+bool ReadWorker::ProcessCowOp(const CowOperation* cow_op, void* buffer) {
     if (cow_op == nullptr) {
         SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op";
         return false;
@@ -226,17 +166,17 @@
 
     switch (cow_op->type) {
         case kCowReplaceOp: {
-            return ProcessReplaceOp(cow_op);
+            return ProcessReplaceOp(cow_op, buffer);
         }
 
         case kCowZeroOp: {
-            return ProcessZeroOp();
+            return ProcessZeroOp(buffer);
         }
 
         case kCowCopyOp:
             [[fallthrough]];
         case kCowXorOp: {
-            return ProcessOrderedOp(cow_op);
+            return ProcessOrderedOp(cow_op, buffer);
         }
 
         default: {
@@ -246,31 +186,26 @@
     return false;
 }
 
-void Worker::InitializeBufsink() {
-    // Allocate the buffer which is used to communicate between
-    // daemon and dm-user. The buffer comprises of header and a fixed payload.
-    // If the dm-user requests a big IO, the IO will be broken into chunks
-    // of PAYLOAD_BUFFER_SZ.
-    size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ;
-    bufsink_.Initialize(buf_size);
-}
-
-bool Worker::Init() {
-    InitializeBufsink();
-    xorsink_.Initialize(&bufsink_, BLOCK_SZ);
-
-    if (!InitializeFds()) {
+bool ReadWorker::Init() {
+    if (!Worker::Init()) {
         return false;
     }
 
-    if (!InitReader()) {
+    backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
+    if (backing_store_fd_ < 0) {
+        SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
         return false;
     }
 
+    ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR));
+    if (ctrl_fd_ < 0) {
+        SNAP_PLOG(ERROR) << "Unable to open " << control_device_;
+        return false;
+    }
     return true;
 }
 
-bool Worker::RunThread() {
+bool ReadWorker::Run() {
     SNAP_LOG(INFO) << "Processing snapshot I/O requests....";
 
     if (setpriority(PRIO_PROCESS, gettid(), kNiceValueForMergeThreads)) {
@@ -290,23 +225,8 @@
     return true;
 }
 
-// Read Header from dm-user misc device. This gives
-// us the sector number for which IO is issued by dm-snapshot device
-bool Worker::ReadDmUserHeader() {
-    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
-        if (errno != ENOTBLK) {
-            SNAP_PLOG(ERROR) << "Control-read failed";
-        }
-
-        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
-        return false;
-    }
-
-    return true;
-}
-
 // Send the payload/data back to dm-user misc device.
-bool Worker::WriteDmUserPayload(size_t size) {
+bool ReadWorker::WriteDmUserPayload(size_t size) {
     size_t payload_size = size;
     void* buf = bufsink_.GetPayloadBufPtr();
     if (header_response_) {
@@ -322,18 +242,15 @@
     // After the first header is sent in response to a request, we cannot
     // send any additional headers.
     header_response_ = false;
+
+    // Reset the buffer for use by the next request.
+    bufsink_.ResetBufferOffset();
     return true;
 }
 
-bool Worker::ReadDataFromBaseDevice(sector_t sector, size_t read_size) {
+bool ReadWorker::ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size) {
     CHECK(read_size <= BLOCK_SZ);
 
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
-        return false;
-    }
-
     loff_t offset = sector << SECTOR_SHIFT;
     if (!android::base::ReadFullyAtOffset(base_path_merge_fd_, buffer, read_size, offset)) {
         SNAP_PLOG(ERROR) << "ReadDataFromBaseDevice failed. fd: " << base_path_merge_fd_
@@ -344,21 +261,16 @@
     return true;
 }
 
-bool Worker::ReadAlignedSector(sector_t sector, size_t sz) {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
+bool ReadWorker::ReadAlignedSector(sector_t sector, size_t sz) {
     size_t remaining_size = sz;
     std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-    bool io_error = false;
     int ret = 0;
 
     do {
         // Process 1MB payload at a time
         size_t read_size = std::min(PAYLOAD_BUFFER_SZ, remaining_size);
 
-        header->type = DM_USER_RESP_SUCCESS;
         size_t total_bytes_read = 0;
-        io_error = false;
-        bufsink_.ResetBufferOffset();
 
         while (read_size) {
             // We need to check every 4k block to verify if it is
@@ -369,93 +281,83 @@
                                        std::make_pair(sector, nullptr), SnapshotHandler::compare);
             bool not_found = (it == chunk_vec.end() || it->first != sector);
 
+            void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, size);
+            if (!buffer) {
+                SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadAlignedSector";
+                return false;
+            }
+
             if (not_found) {
                 // Block not found in map - which means this block was not
                 // changed as per the OTA. Just route the I/O to the base
                 // device.
-                if (!ReadDataFromBaseDevice(sector, size)) {
+                if (!ReadDataFromBaseDevice(sector, buffer, size)) {
                     SNAP_LOG(ERROR) << "ReadDataFromBaseDevice failed";
-                    header->type = DM_USER_RESP_ERROR;
+                    return false;
                 }
 
                 ret = size;
             } else {
                 // We found the sector in mapping. Check the type of COW OP and
                 // process it.
-                if (!ProcessCowOp(it->second)) {
+                if (!ProcessCowOp(it->second, buffer)) {
                     SNAP_LOG(ERROR) << "ProcessCowOp failed";
-                    header->type = DM_USER_RESP_ERROR;
+                    return false;
                 }
 
                 ret = BLOCK_SZ;
             }
 
-            // Just return the header if it is an error
-            if (header->type == DM_USER_RESP_ERROR) {
-                RespondIOError();
-                io_error = true;
-                break;
-            }
-
             read_size -= ret;
             total_bytes_read += ret;
             sector += (ret >> SECTOR_SHIFT);
-            bufsink_.UpdateBufferOffset(ret);
         }
 
-        if (!io_error) {
-            if (!WriteDmUserPayload(total_bytes_read)) {
-                return false;
-            }
-
-            SNAP_LOG(DEBUG) << "WriteDmUserPayload success total_bytes_read: " << total_bytes_read
-                            << " remaining_size: " << remaining_size;
-            remaining_size -= total_bytes_read;
+        if (!SendBufferedIo()) {
+            return false;
         }
-    } while (remaining_size > 0 && !io_error);
+
+        SNAP_LOG(DEBUG) << "SendBufferedIo success total_bytes_read: " << total_bytes_read
+                        << " remaining_size: " << remaining_size;
+        remaining_size -= total_bytes_read;
+    } while (remaining_size > 0);
 
     return true;
 }
 
-int Worker::ReadUnalignedSector(
+int ReadWorker::ReadUnalignedSector(
         sector_t sector, size_t size,
         std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it) {
-    size_t skip_sector_size = 0;
-
     SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size
                     << " Aligned sector: " << it->first;
 
-    if (!ProcessCowOp(it->second)) {
+    int num_sectors_skip = sector - it->first;
+    size_t skip_size = num_sectors_skip << SECTOR_SHIFT;
+    size_t write_size = std::min(size, BLOCK_SZ - skip_size);
+    auto buffer = reinterpret_cast<uint8_t*>(bufsink_.AcquireBuffer(BLOCK_SZ, write_size));
+    if (!buffer) {
+        SNAP_LOG(ERROR) << "ProcessCowOp failed to allocate buffer";
+        return -1;
+    }
+
+    if (!ProcessCowOp(it->second, buffer)) {
         SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size
                         << " Aligned sector: " << it->first;
         return -1;
     }
 
-    int num_sectors_skip = sector - it->first;
-
-    if (num_sectors_skip > 0) {
-        skip_sector_size = num_sectors_skip << SECTOR_SHIFT;
-        char* buffer = reinterpret_cast<char*>(bufsink_.GetBufPtr());
-        struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-
-        if (skip_sector_size == BLOCK_SZ) {
+    if (skip_size) {
+        if (skip_size == BLOCK_SZ) {
             SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector
                             << " Base-sector: " << it->first;
             return -1;
         }
-
-        memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size,
-                (BLOCK_SZ - skip_sector_size));
+        memmove(buffer, buffer + skip_size, write_size);
     }
-
-    bufsink_.ResetBufferOffset();
-    return std::min(size, (BLOCK_SZ - skip_sector_size));
+    return write_size;
 }
 
-bool Worker::ReadUnalignedSector(sector_t sector, size_t size) {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
-    header->type = DM_USER_RESP_SUCCESS;
-    bufsink_.ResetBufferOffset();
+bool ReadWorker::ReadUnalignedSector(sector_t sector, size_t size) {
     std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
 
     auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr),
@@ -524,7 +426,6 @@
     // requested offset in this case is beyond the last mapped COW op size (which
     // is block 1 in this case).
 
-    size_t total_bytes_read = 0;
     size_t remaining_size = size;
     int ret = 0;
     if (!merge_complete && (requested_offset >= final_offset) &&
@@ -538,11 +439,10 @@
         }
 
         remaining_size -= ret;
-        total_bytes_read += ret;
         sector += (ret >> SECTOR_SHIFT);
 
         // Send the data back
-        if (!WriteDmUserPayload(total_bytes_read)) {
+        if (!SendBufferedIo()) {
             return false;
         }
 
@@ -560,26 +460,21 @@
         // Find the diff of the aligned offset
         size_t diff_size = aligned_offset - requested_offset;
         CHECK(diff_size <= BLOCK_SZ);
-        if (remaining_size < diff_size) {
-            if (!ReadDataFromBaseDevice(sector, remaining_size)) {
-                return false;
-            }
-            total_bytes_read += remaining_size;
 
-            if (!WriteDmUserPayload(total_bytes_read)) {
-                return false;
-            }
-        } else {
-            if (!ReadDataFromBaseDevice(sector, diff_size)) {
-                return false;
-            }
+        size_t read_size = std::min(remaining_size, diff_size);
+        void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ, read_size);
+        if (!buffer) {
+            SNAP_LOG(ERROR) << "AcquireBuffer failed in ReadUnalignedSector";
+            return false;
+        }
+        if (!ReadDataFromBaseDevice(sector, buffer, read_size)) {
+            return false;
+        }
+        if (!SendBufferedIo()) {
+            return false;
+        }
 
-            total_bytes_read += diff_size;
-
-            if (!WriteDmUserPayload(total_bytes_read)) {
-                return false;
-            }
-
+        if (remaining_size >= diff_size) {
             remaining_size -= diff_size;
             size_t num_sectors_read = (diff_size >> SECTOR_SHIFT);
             sector += num_sectors_read;
@@ -593,7 +488,7 @@
     return true;
 }
 
-void Worker::RespondIOError() {
+void ReadWorker::RespondIOError() {
     struct dm_user_header* header = bufsink_.GetHeaderPtr();
     header->type = DM_USER_RESP_ERROR;
     // This is an issue with the dm-user interface. There
@@ -610,21 +505,31 @@
     WriteDmUserPayload(0);
 }
 
-bool Worker::DmuserReadRequest() {
+bool ReadWorker::DmuserReadRequest() {
     struct dm_user_header* header = bufsink_.GetHeaderPtr();
 
     // Unaligned I/O request
     if (!IsBlockAligned(header->sector << SECTOR_SHIFT)) {
-        return ReadUnalignedSector(header->sector, header->len) != -1;
+        return ReadUnalignedSector(header->sector, header->len);
     }
 
     return ReadAlignedSector(header->sector, header->len);
 }
 
-bool Worker::ProcessIORequest() {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
+bool ReadWorker::SendBufferedIo() {
+    return WriteDmUserPayload(bufsink_.GetPayloadBytesWritten());
+}
 
-    if (!ReadDmUserHeader()) {
+bool ReadWorker::ProcessIORequest() {
+    // Read Header from dm-user misc device. This gives
+    // us the sector number for which IO is issued by dm-snapshot device
+    struct dm_user_header* header = bufsink_.GetHeaderPtr();
+    if (!android::base::ReadFully(ctrl_fd_, header, sizeof(*header))) {
+        if (errno != ENOTBLK) {
+            SNAP_PLOG(ERROR) << "Control-read failed";
+        }
+
+        SNAP_PLOG(DEBUG) << "ReadDmUserHeader failed....";
         return false;
     }
 
@@ -634,26 +539,37 @@
     SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
     SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
 
+    // Use the same header buffer as the response header.
+    int request_type = header->type;
+    header->type = DM_USER_RESP_SUCCESS;
     header_response_ = true;
 
-    switch (header->type) {
-        case DM_USER_REQ_MAP_READ: {
-            if (!DmuserReadRequest()) {
-                return false;
-            }
-            break;
-        }
+    // Reset the output buffer.
+    bufsink_.ResetBufferOffset();
 
-        case DM_USER_REQ_MAP_WRITE: {
+    bool ok;
+    switch (request_type) {
+        case DM_USER_REQ_MAP_READ:
+            ok = DmuserReadRequest();
+            break;
+
+        case DM_USER_REQ_MAP_WRITE:
             // TODO: We should not get any write request
             // to dm-user as we mount all partitions
             // as read-only. Need to verify how are TRIM commands
             // handled during mount.
-            return false;
-        }
+            ok = false;
+            break;
+
+        default:
+            ok = false;
+            break;
     }
 
-    return true;
+    if (!ok && header->type != DM_USER_RESP_ERROR) {
+        RespondIOError();
+    }
+    return ok;
 }
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
new file mode 100644
index 0000000..8d6f663
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.h
@@ -0,0 +1,71 @@
+// 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 <utility>
+#include <vector>
+
+#include "worker.h"
+
+namespace android {
+namespace snapshot {
+
+class ReadWorker : public Worker {
+  public:
+    ReadWorker(const std::string& cow_device, const std::string& backing_device,
+               const std::string& control_device, const std::string& misc_name,
+               const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd);
+
+    bool Run();
+    bool Init() override;
+    void CloseFds() override;
+
+  private:
+    // Functions interacting with dm-user
+    bool ProcessIORequest();
+    bool WriteDmUserPayload(size_t size);
+    bool DmuserReadRequest();
+    bool SendBufferedIo();
+    void RespondIOError();
+
+    bool ProcessCowOp(const CowOperation* cow_op, void* buffer);
+    bool ProcessXorOp(const CowOperation* cow_op, void* buffer);
+    bool ProcessOrderedOp(const CowOperation* cow_op, void* buffer);
+    bool ProcessCopyOp(const CowOperation* cow_op, void* buffer);
+    bool ProcessReplaceOp(const CowOperation* cow_op, void* buffer);
+    bool ProcessZeroOp(void* buffer);
+
+    bool ReadAlignedSector(sector_t sector, size_t sz);
+    bool ReadUnalignedSector(sector_t sector, size_t size);
+    int ReadUnalignedSector(sector_t sector, size_t size,
+                            std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it);
+    bool ReadFromSourceDevice(const CowOperation* cow_op, void* buffer);
+    bool ReadDataFromBaseDevice(sector_t sector, void* buffer, size_t read_size);
+
+    constexpr bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); }
+    constexpr sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
+
+    std::string backing_store_device_;
+    unique_fd backing_store_fd_;
+
+    std::string control_device_;
+    unique_fd ctrl_fd_;
+
+    bool header_response_ = false;
+    std::basic_string<uint8_t> xor_buffer_;
+};
+
+}  // namespace snapshot
+}  // namespace android
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 8e1212b..e52d752 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -23,6 +23,9 @@
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 
+#include "read_worker.h"
+#include "snapuserd_merge.h"
+
 namespace android {
 namespace snapshot {
 
@@ -46,9 +49,8 @@
 
 bool SnapshotHandler::InitializeWorkers() {
     for (int i = 0; i < num_worker_threads_; i++) {
-        std::unique_ptr<Worker> wt =
-                std::make_unique<Worker>(cow_device_, backing_store_device_, control_device_,
-                                         misc_name_, base_path_merge_, GetSharedPtr());
+        auto wt = std::make_unique<ReadWorker>(cow_device_, backing_store_device_, control_device_,
+                                               misc_name_, base_path_merge_, GetSharedPtr());
         if (!wt->Init()) {
             SNAP_LOG(ERROR) << "Thread initialization failed";
             return false;
@@ -57,8 +59,8 @@
         worker_threads_.push_back(std::move(wt));
     }
 
-    merge_thread_ = std::make_unique<Worker>(cow_device_, backing_store_device_, control_device_,
-                                             misc_name_, base_path_merge_, GetSharedPtr());
+    merge_thread_ = std::make_unique<MergeWorker>(cow_device_, misc_name_, base_path_merge_,
+                                                  GetSharedPtr());
 
     read_ahead_thread_ = std::make_unique<ReadAhead>(cow_device_, backing_store_device_, misc_name_,
                                                      GetSharedPtr());
@@ -312,11 +314,11 @@
     // Launch worker threads
     for (int i = 0; i < worker_threads_.size(); i++) {
         threads.emplace_back(
-                std::async(std::launch::async, &Worker::RunThread, worker_threads_[i].get()));
+                std::async(std::launch::async, &ReadWorker::Run, worker_threads_[i].get()));
     }
 
     std::future<bool> merge_thread =
-            std::async(std::launch::async, &Worker::RunMergeThread, merge_thread_.get());
+            std::async(std::launch::async, &MergeWorker::Run, merge_thread_.get());
 
     // Now that the worker threads are up, scan the partitions.
     if (perform_verification_) {
@@ -452,5 +454,11 @@
     return update_verify_->CheckPartitionVerification();
 }
 
+void SnapshotHandler::FreeResources() {
+    worker_threads_.clear();
+    read_ahead_thread_ = nullptr;
+    merge_thread_ = nullptr;
+}
+
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index 7cffc1c..cdc38c0 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -75,7 +75,8 @@
     READ_AHEAD_FAILURE,
 };
 
-class SnapshotHandler;
+class MergeWorker;
+class ReadWorker;
 
 enum class MERGE_GROUP_STATE {
     GROUP_MERGE_PENDING,
@@ -98,103 +99,6 @@
         : merge_state_(state), num_ios_in_progress(n_ios) {}
 };
 
-class Worker {
-  public:
-    Worker(const std::string& cow_device, const std::string& backing_device,
-           const std::string& control_device, const std::string& misc_name,
-           const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd);
-    bool RunThread();
-    bool RunMergeThread();
-    bool Init();
-
-  private:
-    // Initialization
-    void InitializeBufsink();
-    bool InitializeFds();
-    bool InitReader();
-    void CloseFds() {
-        ctrl_fd_ = {};
-        backing_store_fd_ = {};
-        base_path_merge_fd_ = {};
-    }
-
-    // Functions interacting with dm-user
-    bool ReadDmUserHeader();
-    bool WriteDmUserPayload(size_t size);
-    bool DmuserReadRequest();
-
-    // IO Path
-    bool ProcessIORequest();
-    bool IsBlockAligned(size_t size) { return ((size & (BLOCK_SZ - 1)) == 0); }
-
-    bool ReadDataFromBaseDevice(sector_t sector, size_t read_size);
-    bool ReadFromSourceDevice(const CowOperation* cow_op);
-
-    bool ReadAlignedSector(sector_t sector, size_t sz);
-    bool ReadUnalignedSector(sector_t sector, size_t size);
-    int ReadUnalignedSector(sector_t sector, size_t size,
-                            std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it);
-    void RespondIOError();
-
-    // Processing COW operations
-    bool ProcessCowOp(const CowOperation* cow_op);
-    bool ProcessReplaceOp(const CowOperation* cow_op);
-    bool ProcessZeroOp();
-
-    // Handles Copy and Xor
-    bool ProcessCopyOp(const CowOperation* cow_op);
-    bool ProcessXorOp(const CowOperation* cow_op);
-    bool ProcessOrderedOp(const CowOperation* cow_op);
-
-    // Merge related ops
-    bool Merge();
-    bool AsyncMerge();
-    bool SyncMerge();
-    bool MergeOrderedOps();
-    bool MergeOrderedOpsAsync();
-    bool MergeReplaceZeroOps();
-    int PrepareMerge(uint64_t* source_offset, int* pending_ops,
-                     std::vector<const CowOperation*>* replace_zero_vec = nullptr);
-
-    sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
-    chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
-
-    bool InitializeIouring();
-    void FinalizeIouring();
-
-    std::unique_ptr<CowReader> reader_;
-    BufferSink bufsink_;
-    XorSink xorsink_;
-
-    std::string cow_device_;
-    std::string backing_store_device_;
-    std::string control_device_;
-    std::string misc_name_;
-    std::string base_path_merge_;
-
-    unique_fd cow_fd_;
-    unique_fd backing_store_fd_;
-    unique_fd base_path_merge_fd_;
-    unique_fd ctrl_fd_;
-    bool header_response_ = false;
-
-    std::unique_ptr<ICowOpIter> cowop_iter_;
-    size_t ra_block_index_ = 0;
-    uint64_t blocks_merged_in_group_ = 0;
-    bool merge_async_ = false;
-    // Queue depth of 8 seems optimal. We don't want
-    // to have a huge depth as it may put more memory pressure
-    // on the kernel worker threads given that we use
-    // IOSQE_ASYNC flag - ASYNC flags can potentially
-    // result in EINTR; Since we don't restart
-    // syscalls and fallback to synchronous I/O, we
-    // don't want huge queue depth
-    int queue_depth_ = 8;
-    std::unique_ptr<struct io_uring> ring_;
-
-    std::shared_ptr<SnapshotHandler> snapuserd_;
-};
-
 class SnapshotHandler : public std::enable_shared_from_this<SnapshotHandler> {
   public:
     SnapshotHandler(std::string misc_name, std::string cow_device, std::string backing_device,
@@ -213,11 +117,7 @@
     bool CommitMerge(int num_merge_ops);
 
     void CloseFds() { cow_fd_ = {}; }
-    void FreeResources() {
-        worker_threads_.clear();
-        read_ahead_thread_ = nullptr;
-        merge_thread_ = nullptr;
-    }
+    void FreeResources();
 
     bool InitializeWorkers();
     std::unique_ptr<CowReader> CloneReaderForWorker();
@@ -316,7 +216,7 @@
     void* mapped_addr_;
     size_t total_mapped_addr_length_;
 
-    std::vector<std::unique_ptr<Worker>> worker_threads_;
+    std::vector<std::unique_ptr<ReadWorker>> worker_threads_;
     // Read-ahead related
     bool populate_data_from_cow_ = false;
     bool ra_thread_ = false;
@@ -331,7 +231,7 @@
     // Merge Block state
     std::vector<std::unique_ptr<MergeGroupState>> merge_blk_state_;
 
-    std::unique_ptr<Worker> merge_thread_;
+    std::unique_ptr<MergeWorker> merge_thread_;
     double merge_completion_percentage_;
 
     bool merge_initiated_ = false;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
index ce95b76..517148d 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.cpp
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "snapuserd_merge.h"
 
 #include "snapuserd_core.h"
 
@@ -23,8 +24,13 @@
 using namespace android::dm;
 using android::base::unique_fd;
 
-int Worker::PrepareMerge(uint64_t* source_offset, int* pending_ops,
-                         std::vector<const CowOperation*>* replace_zero_vec) {
+MergeWorker::MergeWorker(const std::string& cow_device, const std::string& misc_name,
+                         const std::string& base_path_merge,
+                         std::shared_ptr<SnapshotHandler> snapuserd)
+    : Worker(cow_device, misc_name, base_path_merge, snapuserd) {}
+
+int MergeWorker::PrepareMerge(uint64_t* source_offset, int* pending_ops,
+                              std::vector<const CowOperation*>* replace_zero_vec) {
     int num_ops = *pending_ops;
     int nr_consecutive = 0;
     bool checkOrderedOp = (replace_zero_vec == nullptr);
@@ -70,7 +76,7 @@
     return nr_consecutive;
 }
 
-bool Worker::MergeReplaceZeroOps() {
+bool MergeWorker::MergeReplaceZeroOps() {
     // Flush after merging 2MB. Since all ops are independent and there is no
     // dependency between COW ops, we will flush the data and the number
     // of ops merged in COW block device. If there is a crash, we will
@@ -99,20 +105,21 @@
 
         for (size_t i = 0; i < replace_zero_vec.size(); i++) {
             const CowOperation* cow_op = replace_zero_vec[i];
+
+            void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ);
+            if (!buffer) {
+                SNAP_LOG(ERROR) << "AcquireBuffer failed in MergeReplaceOps";
+                return false;
+            }
             if (cow_op->type == kCowReplaceOp) {
-                if (!ProcessReplaceOp(cow_op)) {
-                    SNAP_LOG(ERROR) << "Merge - ReplaceOp failed for block: " << cow_op->new_block;
+                if (!reader_->ReadData(cow_op, buffer, BLOCK_SZ)) {
+                    SNAP_LOG(ERROR) << "Failed to read COW in merge";
                     return false;
                 }
             } else {
                 CHECK(cow_op->type == kCowZeroOp);
-                if (!ProcessZeroOp()) {
-                    SNAP_LOG(ERROR) << "Merge ZeroOp failed.";
-                    return false;
-                }
+                memset(buffer, 0, BLOCK_SZ);
             }
-
-            bufsink_.UpdateBufferOffset(BLOCK_SZ);
         }
 
         size_t io_size = linear_blocks * BLOCK_SZ;
@@ -149,7 +156,7 @@
 
         if (snapuserd_->IsIOTerminated()) {
             SNAP_LOG(ERROR)
-                    << "MergeReplaceZeroOps: Worker threads terminated - shutting down merge";
+                    << "MergeReplaceZeroOps: MergeWorker threads terminated - shutting down merge";
             return false;
         }
     }
@@ -173,7 +180,7 @@
     return true;
 }
 
-bool Worker::MergeOrderedOpsAsync() {
+bool MergeWorker::MergeOrderedOpsAsync() {
     void* mapped_addr = snapuserd_->GetMappedAddr();
     void* read_ahead_buffer =
             static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
@@ -354,7 +361,7 @@
     return true;
 }
 
-bool Worker::MergeOrderedOps() {
+bool MergeWorker::MergeOrderedOps() {
     void* mapped_addr = snapuserd_->GetMappedAddr();
     void* read_ahead_buffer =
             static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
@@ -439,7 +446,7 @@
     return true;
 }
 
-bool Worker::AsyncMerge() {
+bool MergeWorker::AsyncMerge() {
     if (!MergeOrderedOpsAsync()) {
         SNAP_LOG(ERROR) << "MergeOrderedOpsAsync failed - Falling back to synchronous I/O";
         // Reset the iter so that we retry the merge
@@ -455,7 +462,7 @@
     return true;
 }
 
-bool Worker::SyncMerge() {
+bool MergeWorker::SyncMerge() {
     if (!MergeOrderedOps()) {
         SNAP_LOG(ERROR) << "Merge failed for ordered ops";
         return false;
@@ -465,7 +472,7 @@
     return true;
 }
 
-bool Worker::Merge() {
+bool MergeWorker::Merge() {
     cowop_iter_ = reader_->GetOpIter(true);
 
     bool retry = false;
@@ -511,7 +518,7 @@
     return true;
 }
 
-bool Worker::InitializeIouring() {
+bool MergeWorker::InitializeIouring() {
     if (!snapuserd_->IsIouringSupported()) {
         return false;
     }
@@ -530,13 +537,13 @@
     return true;
 }
 
-void Worker::FinalizeIouring() {
+void MergeWorker::FinalizeIouring() {
     if (merge_async_) {
         io_uring_queue_exit(ring_.get());
     }
 }
 
-bool Worker::RunMergeThread() {
+bool MergeWorker::Run() {
     SNAP_LOG(DEBUG) << "Waiting for merge begin...";
     if (!snapuserd_->WaitForMergeBegin()) {
         SNAP_LOG(ERROR) << "Merge terminated early...";
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h
new file mode 100644
index 0000000..f35147f
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_merge.h
@@ -0,0 +1,58 @@
+// 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 "worker.h"
+
+#include <liburing.h>
+
+namespace android {
+namespace snapshot {
+
+class MergeWorker : public Worker {
+  public:
+    MergeWorker(const std::string& cow_device, const std::string& misc_name,
+                const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd);
+    bool Run();
+
+  private:
+    int PrepareMerge(uint64_t* source_offset, int* pending_ops,
+                     std::vector<const CowOperation*>* replace_zero_vec = nullptr);
+    bool MergeReplaceZeroOps();
+    bool MergeOrderedOps();
+    bool MergeOrderedOpsAsync();
+    bool Merge();
+    bool AsyncMerge();
+    bool SyncMerge();
+    bool InitializeIouring();
+    void FinalizeIouring();
+
+  private:
+    std::unique_ptr<ICowOpIter> cowop_iter_;
+    std::unique_ptr<struct io_uring> ring_;
+    size_t ra_block_index_ = 0;
+    uint64_t blocks_merged_in_group_ = 0;
+    bool merge_async_ = false;
+    // Queue depth of 8 seems optimal. We don't want
+    // to have a huge depth as it may put more memory pressure
+    // on the kernel worker threads given that we use
+    // IOSQE_ASYNC flag - ASYNC flags can potentially
+    // result in EINTR; Since we don't restart
+    // syscalls and fallback to synchronous I/O, we
+    // don't want huge queue depth
+    int queue_depth_ = 8;
+};
+
+}  // namespace snapshot
+}  // namespace android
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 399f7b8..3e9588b 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp
@@ -492,7 +492,7 @@
         if (xor_op_index < xor_op_vec.size()) {
             const CowOperation* xor_op = xor_op_vec[xor_op_index];
             if (xor_op->new_block == new_block) {
-                void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
+                void* buffer = bufsink_.AcquireBuffer(BLOCK_SZ);
                 if (!buffer) {
                     SNAP_LOG(ERROR) << "ReadAhead - failed to allocate buffer for block: "
                                     << xor_op->new_block;
@@ -506,7 +506,6 @@
                 }
 
                 xor_op_index += 1;
-                bufsink_.UpdateBufferOffset(BLOCK_SZ);
             }
         }
         block_index += 1;
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp
new file mode 100644
index 0000000..aa15630
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.cpp
@@ -0,0 +1,80 @@
+// 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.
+
+#include "worker.h"
+
+#include "snapuserd_core.h"
+
+namespace android {
+namespace snapshot {
+
+Worker::Worker(const std::string& cow_device, const std::string& misc_name,
+               const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd) {
+    cow_device_ = cow_device;
+    misc_name_ = misc_name;
+    base_path_merge_ = base_path_merge;
+    snapuserd_ = snapuserd;
+}
+
+void Worker::InitializeBufsink() {
+    // Allocate the buffer which is used to communicate between
+    // daemon and dm-user. The buffer comprises of header and a fixed payload.
+    // If the dm-user requests a big IO, the IO will be broken into chunks
+    // of PAYLOAD_BUFFER_SZ.
+    size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_BUFFER_SZ;
+    bufsink_.Initialize(buf_size);
+}
+
+bool Worker::Init() {
+    InitializeBufsink();
+
+    if (!InitializeFds()) {
+        return false;
+    }
+
+    if (!InitReader()) {
+        return false;
+    }
+
+    return true;
+}
+
+bool Worker::InitReader() {
+    reader_ = snapuserd_->CloneReaderForWorker();
+
+    if (!reader_->InitForMerge(std::move(cow_fd_))) {
+        return false;
+    }
+    return true;
+}
+
+bool Worker::InitializeFds() {
+    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
+    if (cow_fd_ < 0) {
+        SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
+        return false;
+    }
+
+    // Base device used by merge thread
+    base_path_merge_fd_.reset(open(base_path_merge_.c_str(), O_RDWR));
+    if (base_path_merge_fd_ < 0) {
+        SNAP_PLOG(ERROR) << "Open Failed: " << base_path_merge_;
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h
new file mode 100644
index 0000000..813b159
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/worker.h
@@ -0,0 +1,65 @@
+// 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 <stddef.h>
+
+#include <memory>
+#include <string>
+
+#include <android-base/unique_fd.h>
+#include <libsnapshot/cow_reader.h>
+#include <snapuserd/snapuserd_buffer.h>
+#include <snapuserd/snapuserd_kernel.h>
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+
+class SnapshotHandler;
+
+class Worker {
+  public:
+    Worker(const std::string& cow_device, const std::string& misc_name,
+           const std::string& base_path_merge, std::shared_ptr<SnapshotHandler> snapuserd);
+    virtual ~Worker() = default;
+
+    virtual bool Init();
+
+  protected:
+    // Initialization
+    void InitializeBufsink();
+    bool InitializeFds();
+    bool InitReader();
+    virtual void CloseFds() { base_path_merge_fd_ = {}; }
+
+    std::unique_ptr<CowReader> reader_;
+    BufferSink bufsink_;
+
+    std::string misc_name_;  // Needed for SNAP_LOG.
+
+    unique_fd base_path_merge_fd_;
+
+    std::shared_ptr<SnapshotHandler> snapuserd_;
+
+  private:
+    std::string cow_device_;
+    std::string base_path_merge_;
+    unique_fd cow_fd_;
+};
+
+}  // namespace snapshot
+}  // namespace android
diff --git a/init/Android.bp b/init/Android.bp
index 1af398a..4416b9d 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -166,11 +166,9 @@
         "libbootloader_message",
         "libc++fs",
         "libcgrouprc_format",
-        "libfsverity_init",
         "liblmkd_utils",
         "liblz4",
         "libzstd",
-        "libmini_keyctl_static",
         "libmodprobe",
         "libprocinfo",
         "libprotobuf-cpp-lite",
diff --git a/init/selinux.cpp b/init/selinux.cpp
index e0ef491..51093d8 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -74,10 +74,8 @@
 #include <android-base/unique_fd.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr.h>
-#include <fsverity_init.h>
 #include <libgsi/libgsi.h>
 #include <libsnapshot/snapshot.h>
-#include <mini_keyctl_utils.h>
 #include <selinux/android.h>
 #include <ziparchive/zip_archive.h>
 
@@ -510,7 +508,6 @@
 
 constexpr const char* kSigningCertRelease =
         "/system/etc/selinux/com.android.sepolicy.cert-release.der";
-constexpr const char* kFsVerityProcPath = "/proc/sys/fs/verity";
 const std::string kSepolicyApexMetadataDir = "/metadata/sepolicy/";
 const std::string kSepolicyApexSystemDir = "/system/etc/selinux/apex/";
 const std::string kSepolicyZip = "SEPolicy.zip";
@@ -614,24 +611,6 @@
     return {};
 }
 
-Result<void> LoadSepolicyApexCerts() {
-    key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
-    if (keyring_id < 0) {
-        return Error() << "Failed to find .fs-verity keyring id";
-    }
-
-    // TODO(b/199914227) the release key should always exist. Once it's checked in, start
-    // throwing an error here if it doesn't exist.
-    if (access(kSigningCertRelease, F_OK) == 0) {
-        LoadKeyFromFile(keyring_id, "fsv_sepolicy_apex_release", kSigningCertRelease);
-    }
-    return {};
-}
-
-Result<void> SepolicyFsVerityCheck() {
-    return Error() << "TODO implement support for fsverity SEPolicy.";
-}
-
 Result<void> SepolicyCheckSignature(const std::string& dir) {
     std::string signature;
     if (!android::base::ReadFileToString(dir + kSepolicySignature, &signature)) {
@@ -654,18 +633,7 @@
     return verifySignature(sepolicyStr, signature, *releaseKey);
 }
 
-Result<void> SepolicyVerify(const std::string& dir, bool supportsFsVerity) {
-    if (supportsFsVerity) {
-        auto fsVerityCheck = SepolicyFsVerityCheck();
-        if (fsVerityCheck.ok()) {
-            return fsVerityCheck;
-        }
-        // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail to
-        // boot and not carry on. For now, fallback to a signature checkuntil the fsverity
-        // logic is implemented.
-        LOG(INFO) << "Falling back to standard signature check. " << fsVerityCheck.error();
-    }
-
+Result<void> SepolicyVerify(const std::string& dir) {
     auto sepolicySignature = SepolicyCheckSignature(dir);
     if (!sepolicySignature.ok()) {
         return Error() << "Apex SEPolicy failed signature check";
@@ -698,23 +666,19 @@
 // 6. Sets selinux into enforcing mode and continues normal booting.
 //
 void PrepareApexSepolicy() {
-    bool supportsFsVerity = access(kFsVerityProcPath, F_OK) == 0;
-    if (supportsFsVerity) {
-        auto loadSepolicyApexCerts = LoadSepolicyApexCerts();
-        if (!loadSepolicyApexCerts.ok()) {
-            // TODO(b/199914227) If the device supports fsverity, but we fail here, we should fail
-            // to boot and not carry on. For now, fallback to a signature checkuntil the fsverity
-            // logic is implemented.
-            LOG(INFO) << loadSepolicyApexCerts.error();
-        }
-    }
     // If apex sepolicy zip exists in /metadata/sepolicy, use that, otherwise use version on
-    // /system.
-    auto dir = (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0)
-                       ? kSepolicyApexMetadataDir
-                       : kSepolicyApexSystemDir;
+    // /system. If neither exists, do nothing.
+    std::string dir;
+    if (access((kSepolicyApexMetadataDir + kSepolicyZip).c_str(), F_OK) == 0) {
+        dir = kSepolicyApexMetadataDir;
+    } else if (access((kSepolicyApexSystemDir + kSepolicyZip).c_str(), F_OK) == 0) {
+        dir = kSepolicyApexSystemDir;
+    } else {
+        LOG(INFO) << "APEX Sepolicy not found";
+        return;
+    }
 
-    auto sepolicyVerify = SepolicyVerify(dir, supportsFsVerity);
+    auto sepolicyVerify = SepolicyVerify(dir);
     if (!sepolicyVerify.ok()) {
         LOG(INFO) << "Error: " << sepolicyVerify.error();
         // If signature verification fails, fall back to version on /system.
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0b5c125..92486e3 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -219,11 +219,19 @@
             exclude_srcs: [
                 "qtaguid.cpp",
             ],
+            header_abi_checker: {
+                enabled: true,
+                ref_dump_dirs: ["abi-dumps"],
+            },
         },
         product: {
             exclude_srcs: [
                 "qtaguid.cpp",
             ],
+            header_abi_checker: {
+                enabled: true,
+                ref_dump_dirs: ["abi-dumps"],
+            },
         },
     },
 
diff --git a/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
new file mode 100644
index 0000000..333e61c
--- /dev/null
+++ b/libcutils/abi-dumps/arm64/source-based/libcutils.so.lsdump
@@ -0,0 +1,2690 @@
+{
+ "array_types" :
+ [
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIA0_i",
+   "name" : "int[0]",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIA0_i",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  }
+ ],
+ "builtin_types" :
+ [
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIa",
+   "name" : "signed char",
+   "referenced_type" : "_ZTIa",
+   "self_type" : "_ZTIa",
+   "size" : 1
+  },
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIb",
+   "name" : "bool",
+   "referenced_type" : "_ZTIb",
+   "self_type" : "_ZTIb",
+   "size" : 1
+  },
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIc",
+   "name" : "char",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIc",
+   "size" : 1
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIf",
+   "name" : "float",
+   "referenced_type" : "_ZTIf",
+   "self_type" : "_ZTIf",
+   "size" : 4
+  },
+  {
+   "alignment" : 4,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIi",
+   "name" : "int",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIi",
+   "size" : 4
+  },
+  {
+   "alignment" : 4,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIj",
+   "name" : "unsigned int",
+   "referenced_type" : "_ZTIj",
+   "self_type" : "_ZTIj",
+   "size" : 4
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIl",
+   "name" : "long",
+   "referenced_type" : "_ZTIl",
+   "self_type" : "_ZTIl",
+   "size" : 8
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIm",
+   "name" : "unsigned long",
+   "referenced_type" : "_ZTIm",
+   "self_type" : "_ZTIm",
+   "size" : 8
+  },
+  {
+   "linker_set_key" : "_ZTIv",
+   "name" : "void",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIv"
+  }
+ ],
+ "elf_functions" :
+ [
+  {
+   "name" : "_Z23socket_make_sockaddr_unPKciP11sockaddr_unPj"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPcl"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc"
+  },
+  {
+   "name" : "android_get_control_file"
+  },
+  {
+   "name" : "android_get_control_socket"
+  },
+  {
+   "name" : "android_get_ioprio"
+  },
+  {
+   "name" : "android_reboot"
+  },
+  {
+   "name" : "android_set_ioprio"
+  },
+  {
+   "name" : "ashmem_create_region"
+  },
+  {
+   "name" : "ashmem_get_size_region"
+  },
+  {
+   "name" : "ashmem_pin_region"
+  },
+  {
+   "name" : "ashmem_set_prot_region"
+  },
+  {
+   "name" : "ashmem_unpin_region"
+  },
+  {
+   "name" : "ashmem_valid"
+  },
+  {
+   "name" : "atrace_async_begin_body"
+  },
+  {
+   "name" : "atrace_async_end_body"
+  },
+  {
+   "name" : "atrace_async_for_track_begin_body"
+  },
+  {
+   "name" : "atrace_async_for_track_end_body"
+  },
+  {
+   "name" : "atrace_begin_body"
+  },
+  {
+   "name" : "atrace_end_body"
+  },
+  {
+   "name" : "atrace_get_enabled_tags"
+  },
+  {
+   "name" : "atrace_init"
+  },
+  {
+   "name" : "atrace_instant_body"
+  },
+  {
+   "name" : "atrace_instant_for_track_body"
+  },
+  {
+   "name" : "atrace_int64_body"
+  },
+  {
+   "name" : "atrace_int_body"
+  },
+  {
+   "name" : "atrace_set_tracing_enabled"
+  },
+  {
+   "name" : "atrace_setup"
+  },
+  {
+   "name" : "atrace_update_tags"
+  },
+  {
+   "name" : "canned_fs_config"
+  },
+  {
+   "name" : "config_bool"
+  },
+  {
+   "name" : "config_find"
+  },
+  {
+   "name" : "config_free"
+  },
+  {
+   "name" : "config_load"
+  },
+  {
+   "name" : "config_load_file"
+  },
+  {
+   "name" : "config_node"
+  },
+  {
+   "name" : "config_set"
+  },
+  {
+   "name" : "config_str"
+  },
+  {
+   "name" : "fs_config"
+  },
+  {
+   "name" : "fs_mkdirs"
+  },
+  {
+   "name" : "fs_prepare_dir"
+  },
+  {
+   "name" : "fs_prepare_dir_strict"
+  },
+  {
+   "name" : "fs_prepare_file_strict"
+  },
+  {
+   "name" : "fs_read_atomic_int"
+  },
+  {
+   "name" : "fs_write_atomic_int"
+  },
+  {
+   "name" : "hashmapCreate"
+  },
+  {
+   "name" : "hashmapForEach"
+  },
+  {
+   "name" : "hashmapFree"
+  },
+  {
+   "name" : "hashmapGet"
+  },
+  {
+   "name" : "hashmapHash"
+  },
+  {
+   "name" : "hashmapLock"
+  },
+  {
+   "name" : "hashmapPut"
+  },
+  {
+   "name" : "hashmapRemove"
+  },
+  {
+   "name" : "hashmapUnlock"
+  },
+  {
+   "name" : "klog_set_level"
+  },
+  {
+   "name" : "klog_write"
+  },
+  {
+   "name" : "klog_writev"
+  },
+  {
+   "name" : "load_canned_fs_config"
+  },
+  {
+   "name" : "load_file"
+  },
+  {
+   "name" : "multiuser_convert_sdk_sandbox_to_app_uid"
+  },
+  {
+   "name" : "multiuser_get_app_id"
+  },
+  {
+   "name" : "multiuser_get_cache_gid"
+  },
+  {
+   "name" : "multiuser_get_ext_cache_gid"
+  },
+  {
+   "name" : "multiuser_get_ext_gid"
+  },
+  {
+   "name" : "multiuser_get_sdk_sandbox_uid"
+  },
+  {
+   "name" : "multiuser_get_shared_app_gid"
+  },
+  {
+   "name" : "multiuser_get_shared_gid"
+  },
+  {
+   "name" : "multiuser_get_uid"
+  },
+  {
+   "name" : "multiuser_get_user_id"
+  },
+  {
+   "name" : "native_handle_clone"
+  },
+  {
+   "name" : "native_handle_close"
+  },
+  {
+   "name" : "native_handle_close_with_tag"
+  },
+  {
+   "name" : "native_handle_create"
+  },
+  {
+   "name" : "native_handle_delete"
+  },
+  {
+   "name" : "native_handle_init"
+  },
+  {
+   "name" : "native_handle_set_fdsan_tag"
+  },
+  {
+   "name" : "native_handle_unset_fdsan_tag"
+  },
+  {
+   "name" : "partition_wiped"
+  },
+  {
+   "name" : "property_get"
+  },
+  {
+   "name" : "property_get_bool"
+  },
+  {
+   "name" : "property_get_int32"
+  },
+  {
+   "name" : "property_get_int64"
+  },
+  {
+   "name" : "property_list"
+  },
+  {
+   "name" : "property_set"
+  },
+  {
+   "name" : "record_stream_free"
+  },
+  {
+   "name" : "record_stream_get_next"
+  },
+  {
+   "name" : "record_stream_new"
+  },
+  {
+   "name" : "socket_close"
+  },
+  {
+   "name" : "socket_get_local_port"
+  },
+  {
+   "name" : "socket_inaddr_any_server"
+  },
+  {
+   "name" : "socket_local_client"
+  },
+  {
+   "name" : "socket_local_client_connect"
+  },
+  {
+   "name" : "socket_local_server"
+  },
+  {
+   "name" : "socket_local_server_bind"
+  },
+  {
+   "name" : "socket_network_client"
+  },
+  {
+   "name" : "socket_network_client_timeout"
+  },
+  {
+   "name" : "socket_send_buffers"
+  },
+  {
+   "name" : "str_parms_add_float"
+  },
+  {
+   "name" : "str_parms_add_int"
+  },
+  {
+   "name" : "str_parms_add_str"
+  },
+  {
+   "name" : "str_parms_create"
+  },
+  {
+   "name" : "str_parms_create_str"
+  },
+  {
+   "name" : "str_parms_del"
+  },
+  {
+   "name" : "str_parms_destroy"
+  },
+  {
+   "name" : "str_parms_dump"
+  },
+  {
+   "name" : "str_parms_get_float"
+  },
+  {
+   "name" : "str_parms_get_int"
+  },
+  {
+   "name" : "str_parms_get_str"
+  },
+  {
+   "name" : "str_parms_has_key"
+  },
+  {
+   "name" : "str_parms_to_str"
+  },
+  {
+   "name" : "uevent_kernel_multicast_recv"
+  },
+  {
+   "name" : "uevent_kernel_multicast_uid_recv"
+  },
+  {
+   "name" : "uevent_kernel_recv"
+  },
+  {
+   "name" : "uevent_open_socket"
+  }
+ ],
+ "elf_objects" :
+ [
+  {
+   "binding" : "weak",
+   "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "name" : "atrace_enabled_tags"
+  },
+  {
+   "name" : "atrace_is_ready"
+  },
+  {
+   "name" : "atrace_marker_fd"
+  }
+ ],
+ "enum_types" :
+ [
+  {
+   "alignment" : 4,
+   "enum_fields" :
+   [
+    {
+     "enum_field_value" : 0,
+     "name" : "IoSchedClass_NONE"
+    },
+    {
+     "enum_field_value" : 1,
+     "name" : "IoSchedClass_RT"
+    },
+    {
+     "enum_field_value" : 2,
+     "name" : "IoSchedClass_BE"
+    },
+    {
+     "enum_field_value" : 3,
+     "name" : "IoSchedClass_IDLE"
+    }
+   ],
+   "linker_set_key" : "_ZTI12IoSchedClass",
+   "name" : "IoSchedClass",
+   "referenced_type" : "_ZTI12IoSchedClass",
+   "self_type" : "_ZTI12IoSchedClass",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h",
+   "underlying_type" : "_ZTIj"
+  }
+ ],
+ "function_types" :
+ [
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFbPvS_E",
+   "name" : "bool (void *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFbPvS_E",
+   "return_type" : "_ZTIb",
+   "self_type" : "_ZTIFbPvS_E",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFbPvS_S_E",
+   "name" : "bool (void *, void *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFbPvS_S_E",
+   "return_type" : "_ZTIb",
+   "self_type" : "_ZTIFbPvS_S_E",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFiPvE",
+   "name" : "int (void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFiPvE",
+   "return_type" : "_ZTIi",
+   "self_type" : "_ZTIFiPvE",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFvPKcS0_PvE",
+   "name" : "void (const char *, const char *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFvPKcS0_PvE",
+   "return_type" : "_ZTIv",
+   "self_type" : "_ZTIFvPKcS0_PvE",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  }
+ ],
+ "functions" :
+ [
+  {
+   "function_name" : "android_get_control_file",
+   "linker_set_key" : "android_get_control_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/android_get_control_file.h"
+  },
+  {
+   "function_name" : "android_get_control_socket",
+   "linker_set_key" : "android_get_control_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "android_get_ioprio",
+   "linker_set_key" : "android_get_ioprio",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIP12IoSchedClass"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "function_name" : "android_reboot",
+   "linker_set_key" : "android_reboot",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/android_reboot.h"
+  },
+  {
+   "function_name" : "android_set_ioprio",
+   "linker_set_key" : "android_set_ioprio",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTI12IoSchedClass"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "function_name" : "ashmem_create_region",
+   "linker_set_key" : "ashmem_create_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_get_size_region",
+   "linker_set_key" : "ashmem_get_size_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_pin_region",
+   "linker_set_key" : "ashmem_pin_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_set_prot_region",
+   "linker_set_key" : "ashmem_set_prot_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_unpin_region",
+   "linker_set_key" : "ashmem_unpin_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_valid",
+   "linker_set_key" : "ashmem_valid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "atrace_async_begin_body",
+   "linker_set_key" : "atrace_async_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_end_body",
+   "linker_set_key" : "atrace_async_end_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_for_track_begin_body",
+   "linker_set_key" : "atrace_async_for_track_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_for_track_end_body",
+   "linker_set_key" : "atrace_async_for_track_end_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_begin_body",
+   "linker_set_key" : "atrace_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_end_body",
+   "linker_set_key" : "atrace_end_body",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_get_enabled_tags",
+   "linker_set_key" : "atrace_get_enabled_tags",
+   "return_type" : "_ZTIm",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_init",
+   "linker_set_key" : "atrace_init",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_instant_body",
+   "linker_set_key" : "atrace_instant_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_instant_for_track_body",
+   "linker_set_key" : "atrace_instant_for_track_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_int64_body",
+   "linker_set_key" : "atrace_int64_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIl"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_int_body",
+   "linker_set_key" : "atrace_int_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_set_tracing_enabled",
+   "linker_set_key" : "atrace_set_tracing_enabled",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_setup",
+   "linker_set_key" : "atrace_setup",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_update_tags",
+   "linker_set_key" : "atrace_update_tags",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "canned_fs_config",
+   "linker_set_key" : "canned_fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPm"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
+  },
+  {
+   "function_name" : "config_bool",
+   "linker_set_key" : "config_bool",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_find",
+   "linker_set_key" : "config_find",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP5cnode",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_free",
+   "linker_set_key" : "config_free",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_load",
+   "linker_set_key" : "config_load",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_load_file",
+   "linker_set_key" : "config_load_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_node",
+   "linker_set_key" : "config_node",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP5cnode",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_set",
+   "linker_set_key" : "config_set",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_str",
+   "linker_set_key" : "config_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIPKc",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "fs_config",
+   "linker_set_key" : "fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPm"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/private/fs_config.h"
+  },
+  {
+   "function_name" : "fs_mkdirs",
+   "linker_set_key" : "fs_mkdirs",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_dir",
+   "linker_set_key" : "fs_prepare_dir",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_dir_strict",
+   "linker_set_key" : "fs_prepare_dir_strict",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_file_strict",
+   "linker_set_key" : "fs_prepare_file_strict",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_read_atomic_int",
+   "linker_set_key" : "fs_read_atomic_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_write_atomic_int",
+   "linker_set_key" : "fs_write_atomic_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "hashmapCreate",
+   "linker_set_key" : "hashmapCreate",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIm"
+    },
+    {
+     "referenced_type" : "_ZTIPFiPvE"
+    },
+    {
+     "referenced_type" : "_ZTIPFbPvS_E"
+    }
+   ],
+   "return_type" : "_ZTIP7Hashmap",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapForEach",
+   "linker_set_key" : "hashmapForEach",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPFbPvS_S_E"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapFree",
+   "linker_set_key" : "hashmapFree",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapGet",
+   "linker_set_key" : "hashmapGet",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapHash",
+   "linker_set_key" : "hashmapHash",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapLock",
+   "linker_set_key" : "hashmapLock",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapPut",
+   "linker_set_key" : "hashmapPut",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapRemove",
+   "linker_set_key" : "hashmapRemove",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapUnlock",
+   "linker_set_key" : "hashmapUnlock",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "klog_set_level",
+   "linker_set_key" : "klog_set_level",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "klog_write",
+   "linker_set_key" : "klog_write",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "klog_writev",
+   "linker_set_key" : "klog_writev",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPK5iovec"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "load_canned_fs_config",
+   "linker_set_key" : "load_canned_fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
+  },
+  {
+   "function_name" : "load_file",
+   "linker_set_key" : "load_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  },
+  {
+   "function_name" : "multiuser_convert_sdk_sandbox_to_app_uid",
+   "linker_set_key" : "multiuser_convert_sdk_sandbox_to_app_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_app_id",
+   "linker_set_key" : "multiuser_get_app_id",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_cache_gid",
+   "linker_set_key" : "multiuser_get_cache_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_ext_cache_gid",
+   "linker_set_key" : "multiuser_get_ext_cache_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_ext_gid",
+   "linker_set_key" : "multiuser_get_ext_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_sdk_sandbox_uid",
+   "linker_set_key" : "multiuser_get_sdk_sandbox_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_shared_app_gid",
+   "linker_set_key" : "multiuser_get_shared_app_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_shared_gid",
+   "linker_set_key" : "multiuser_get_shared_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_uid",
+   "linker_set_key" : "multiuser_get_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_user_id",
+   "linker_set_key" : "multiuser_get_user_id",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "native_handle_clone",
+   "linker_set_key" : "native_handle_clone",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_close",
+   "linker_set_key" : "native_handle_close",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_close_with_tag",
+   "linker_set_key" : "native_handle_close_with_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_create",
+   "linker_set_key" : "native_handle_create",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_delete",
+   "linker_set_key" : "native_handle_delete",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_init",
+   "linker_set_key" : "native_handle_init",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_set_fdsan_tag",
+   "linker_set_key" : "native_handle_set_fdsan_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_unset_fdsan_tag",
+   "linker_set_key" : "native_handle_unset_fdsan_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "partition_wiped",
+   "linker_set_key" : "partition_wiped",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/partition_utils.h"
+  },
+  {
+   "function_name" : "property_get",
+   "linker_set_key" : "property_get",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_bool",
+   "linker_set_key" : "property_get_bool",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIa"
+    }
+   ],
+   "return_type" : "_ZTIa",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_int32",
+   "linker_set_key" : "property_get_int32",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_int64",
+   "linker_set_key" : "property_get_int64",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIl"
+    }
+   ],
+   "return_type" : "_ZTIl",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_list",
+   "linker_set_key" : "property_list",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPFvPKcS0_PvE"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_set",
+   "linker_set_key" : "property_set",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "record_stream_free",
+   "linker_set_key" : "record_stream_free",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP12RecordStream"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "record_stream_get_next",
+   "linker_set_key" : "record_stream_get_next",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP12RecordStream"
+    },
+    {
+     "referenced_type" : "_ZTIPPv"
+    },
+    {
+     "referenced_type" : "_ZTIPm"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "record_stream_new",
+   "linker_set_key" : "record_stream_new",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIP12RecordStream",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "socket_close",
+   "linker_set_key" : "socket_close",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_get_local_port",
+   "linker_set_key" : "socket_get_local_port",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_inaddr_any_server",
+   "linker_set_key" : "socket_inaddr_any_server",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_client",
+   "linker_set_key" : "socket_local_client",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_client_connect",
+   "linker_set_key" : "socket_local_client_connect",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_server",
+   "linker_set_key" : "socket_local_server",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_server_bind",
+   "linker_set_key" : "socket_local_server_bind",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_network_client",
+   "linker_set_key" : "socket_network_client",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_network_client_timeout",
+   "linker_set_key" : "socket_network_client_timeout",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_send_buffers",
+   "linker_set_key" : "socket_send_buffers",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPK22cutils_socket_buffer_t"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIl",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "str_parms_add_float",
+   "linker_set_key" : "str_parms_add_float",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIf"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_add_int",
+   "linker_set_key" : "str_parms_add_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_add_str",
+   "linker_set_key" : "str_parms_add_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_create",
+   "linker_set_key" : "str_parms_create",
+   "return_type" : "_ZTIP9str_parms",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_create_str",
+   "linker_set_key" : "str_parms_create_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP9str_parms",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_del",
+   "linker_set_key" : "str_parms_del",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_destroy",
+   "linker_set_key" : "str_parms_destroy",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_dump",
+   "linker_set_key" : "str_parms_dump",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_float",
+   "linker_set_key" : "str_parms_get_float",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPf"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_int",
+   "linker_set_key" : "str_parms_get_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_str",
+   "linker_set_key" : "str_parms_get_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_has_key",
+   "linker_set_key" : "str_parms_has_key",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_to_str",
+   "linker_set_key" : "str_parms_to_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIPc",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "uevent_kernel_multicast_recv",
+   "linker_set_key" : "uevent_kernel_multicast_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "return_type" : "_ZTIl",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_kernel_multicast_uid_recv",
+   "linker_set_key" : "uevent_kernel_multicast_uid_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIl",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_kernel_recv",
+   "linker_set_key" : "uevent_kernel_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIm"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIl",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_open_socket",
+   "linker_set_key" : "uevent_open_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  }
+ ],
+ "global_vars" :
+ [
+  {
+   "linker_set_key" : "atrace_enabled_tags",
+   "name" : "atrace_enabled_tags",
+   "referenced_type" : "_ZTIm",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "linker_set_key" : "atrace_is_ready",
+   "name" : "atrace_is_ready",
+   "referenced_type" : "_ZTINSt3__16atomicIbEE",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "linker_set_key" : "atrace_marker_fd",
+   "name" : "atrace_marker_fd",
+   "referenced_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  }
+ ],
+ "lvalue_reference_types" : [],
+ "pointer_types" :
+ [
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP12IoSchedClass",
+   "name" : "IoSchedClass *",
+   "referenced_type" : "_ZTI12IoSchedClass",
+   "self_type" : "_ZTIP12IoSchedClass",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP12RecordStream",
+   "name" : "RecordStream *",
+   "referenced_type" : "_ZTI12RecordStream",
+   "self_type" : "_ZTIP12RecordStream",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP13native_handle",
+   "name" : "native_handle *",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTIP13native_handle",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP5cnode",
+   "name" : "cnode *",
+   "referenced_type" : "_ZTI5cnode",
+   "self_type" : "_ZTIP5cnode",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP7Hashmap",
+   "name" : "Hashmap *",
+   "referenced_type" : "_ZTI7Hashmap",
+   "self_type" : "_ZTIP7Hashmap",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIP9str_parms",
+   "name" : "str_parms *",
+   "referenced_type" : "_ZTI9str_parms",
+   "self_type" : "_ZTIP9str_parms",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPFbPvS_E",
+   "name" : "bool (*)(void *, void *)",
+   "referenced_type" : "_ZTIFbPvS_E",
+   "self_type" : "_ZTIPFbPvS_E",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPFbPvS_S_E",
+   "name" : "bool (*)(void *, void *, void *)",
+   "referenced_type" : "_ZTIFbPvS_S_E",
+   "self_type" : "_ZTIPFbPvS_S_E",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPFiPvE",
+   "name" : "int (*)(void *)",
+   "referenced_type" : "_ZTIFiPvE",
+   "self_type" : "_ZTIPFiPvE",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPFvPKcS0_PvE",
+   "name" : "void (*)(const char *, const char *, void *)",
+   "referenced_type" : "_ZTIFvPKcS0_PvE",
+   "self_type" : "_ZTIPFvPKcS0_PvE",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPK13native_handle",
+   "name" : "const native_handle *",
+   "referenced_type" : "_ZTIK13native_handle",
+   "self_type" : "_ZTIPK13native_handle",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t",
+   "name" : "const cutils_socket_buffer_t *",
+   "referenced_type" : "_ZTIK22cutils_socket_buffer_t",
+   "self_type" : "_ZTIPK22cutils_socket_buffer_t",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPK5iovec",
+   "name" : "const iovec *",
+   "referenced_type" : "_ZTIK5iovec",
+   "self_type" : "_ZTIPK5iovec",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPKc",
+   "name" : "const char *",
+   "referenced_type" : "_ZTIKc",
+   "self_type" : "_ZTIPKc",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPKv",
+   "name" : "const void *",
+   "referenced_type" : "_ZTIKv",
+   "self_type" : "_ZTIPKv",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPPv",
+   "name" : "void **",
+   "referenced_type" : "_ZTIPv",
+   "self_type" : "_ZTIPPv",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPc",
+   "name" : "char *",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIPc",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPf",
+   "name" : "float *",
+   "referenced_type" : "_ZTIf",
+   "self_type" : "_ZTIPf",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPi",
+   "name" : "int *",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIPi",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPj",
+   "name" : "unsigned int *",
+   "referenced_type" : "_ZTIj",
+   "self_type" : "_ZTIPj",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPm",
+   "name" : "unsigned long *",
+   "referenced_type" : "_ZTIm",
+   "self_type" : "_ZTIPm",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "alignment" : 8,
+   "linker_set_key" : "_ZTIPv",
+   "name" : "void *",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIPv",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  }
+ ],
+ "qualified_types" :
+ [
+  {
+   "alignment" : 4,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK13native_handle",
+   "name" : "const native_handle",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTIK13native_handle",
+   "size" : 12,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 8,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK22cutils_socket_buffer_t",
+   "name" : "const cutils_socket_buffer_t",
+   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
+   "self_type" : "_ZTIK22cutils_socket_buffer_t",
+   "size" : 16,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 8,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK5iovec",
+   "name" : "const iovec",
+   "referenced_type" : "_ZTI5iovec",
+   "self_type" : "_ZTIK5iovec",
+   "size" : 16,
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "alignment" : 1,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIKc",
+   "name" : "const char",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIKc",
+   "size" : 1,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "is_const" : true,
+   "linker_set_key" : "_ZTIKv",
+   "name" : "const void",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIKv",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  }
+ ],
+ "record_types" :
+ [
+  {
+   "alignment" : 4,
+   "fields" :
+   [
+    {
+     "field_name" : "version",
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "numFds",
+     "field_offset" : 32,
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "numInts",
+     "field_offset" : 64,
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "data",
+     "field_offset" : 96,
+     "referenced_type" : "_ZTIA0_i"
+    }
+   ],
+   "linker_set_key" : "_ZTI13native_handle",
+   "name" : "native_handle",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTI13native_handle",
+   "size" : 12,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 8,
+   "fields" :
+   [
+    {
+     "field_name" : "data",
+     "referenced_type" : "_ZTIPKv"
+    },
+    {
+     "field_name" : "length",
+     "field_offset" : 64,
+     "referenced_type" : "_ZTIm"
+    }
+   ],
+   "linker_set_key" : "_ZTI22cutils_socket_buffer_t",
+   "name" : "cutils_socket_buffer_t",
+   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
+   "self_type" : "_ZTI22cutils_socket_buffer_t",
+   "size" : 16,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 8,
+   "fields" :
+   [
+    {
+     "field_name" : "next",
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "first_child",
+     "field_offset" : 64,
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "last_child",
+     "field_offset" : 128,
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "name",
+     "field_offset" : 192,
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "field_name" : "value",
+     "field_offset" : 256,
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "linker_set_key" : "_ZTI5cnode",
+   "name" : "cnode",
+   "referenced_type" : "_ZTI5cnode",
+   "self_type" : "_ZTI5cnode",
+   "size" : 40,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  }
+ ],
+ "rvalue_reference_types" : []
+}
diff --git a/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
new file mode 100644
index 0000000..f612fb9
--- /dev/null
+++ b/libcutils/abi-dumps/arm_arm64/source-based/libcutils.so.lsdump
@@ -0,0 +1,2700 @@
+{
+ "array_types" :
+ [
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIA0_i",
+   "name" : "int[0]",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIA0_i",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  }
+ ],
+ "builtin_types" :
+ [
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIa",
+   "name" : "signed char",
+   "referenced_type" : "_ZTIa",
+   "self_type" : "_ZTIa",
+   "size" : 1
+  },
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIb",
+   "name" : "bool",
+   "referenced_type" : "_ZTIb",
+   "self_type" : "_ZTIb",
+   "size" : 1
+  },
+  {
+   "alignment" : 1,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIc",
+   "name" : "char",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIc",
+   "size" : 1
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIf",
+   "name" : "float",
+   "referenced_type" : "_ZTIf",
+   "self_type" : "_ZTIf",
+   "size" : 4
+  },
+  {
+   "alignment" : 4,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIi",
+   "name" : "int",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIi",
+   "size" : 4
+  },
+  {
+   "alignment" : 4,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIj",
+   "name" : "unsigned int",
+   "referenced_type" : "_ZTIj",
+   "self_type" : "_ZTIj",
+   "size" : 4
+  },
+  {
+   "alignment" : 2,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIt",
+   "name" : "unsigned short",
+   "referenced_type" : "_ZTIt",
+   "self_type" : "_ZTIt",
+   "size" : 2
+  },
+  {
+   "linker_set_key" : "_ZTIv",
+   "name" : "void",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIv"
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "linker_set_key" : "_ZTIx",
+   "name" : "long long",
+   "referenced_type" : "_ZTIx",
+   "self_type" : "_ZTIx",
+   "size" : 8
+  },
+  {
+   "alignment" : 8,
+   "is_integral" : true,
+   "is_unsigned" : true,
+   "linker_set_key" : "_ZTIy",
+   "name" : "unsigned long long",
+   "referenced_type" : "_ZTIy",
+   "self_type" : "_ZTIy",
+   "size" : 8
+  }
+ ],
+ "elf_functions" :
+ [
+  {
+   "name" : "_Z23socket_make_sockaddr_unPKciP11sockaddr_unPi"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZN7android4base4TrimIRNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_OT_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE4syncEv"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE5imbueERKNS_6localeE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE6setbufEPci"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekoffExNS_8ios_base7seekdirEj"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE7seekposENS_4fposI9mbstate_tEEj"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE8overflowEi"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9pbackfailEi"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEE9underflowEv"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEEC2Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED0Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__113basic_filebufIcNS_11char_traitsIcEEED2Ev"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_j"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__16vectorI5EntryNS_9allocatorIS1_EEE24__emplace_back_slow_pathIJS1_EEEvDpOT_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__17getlineIcNS_11char_traitsIcEENS_9allocatorIcEEEERNS_13basic_istreamIT_T0_EES9_RNS_12basic_stringIS6_S7_T1_EES6_"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc"
+  },
+  {
+   "name" : "android_get_control_file"
+  },
+  {
+   "name" : "android_get_control_socket"
+  },
+  {
+   "name" : "android_get_ioprio"
+  },
+  {
+   "name" : "android_reboot"
+  },
+  {
+   "name" : "android_set_ioprio"
+  },
+  {
+   "name" : "ashmem_create_region"
+  },
+  {
+   "name" : "ashmem_get_size_region"
+  },
+  {
+   "name" : "ashmem_pin_region"
+  },
+  {
+   "name" : "ashmem_set_prot_region"
+  },
+  {
+   "name" : "ashmem_unpin_region"
+  },
+  {
+   "name" : "ashmem_valid"
+  },
+  {
+   "name" : "atrace_async_begin_body"
+  },
+  {
+   "name" : "atrace_async_end_body"
+  },
+  {
+   "name" : "atrace_async_for_track_begin_body"
+  },
+  {
+   "name" : "atrace_async_for_track_end_body"
+  },
+  {
+   "name" : "atrace_begin_body"
+  },
+  {
+   "name" : "atrace_end_body"
+  },
+  {
+   "name" : "atrace_get_enabled_tags"
+  },
+  {
+   "name" : "atrace_init"
+  },
+  {
+   "name" : "atrace_instant_body"
+  },
+  {
+   "name" : "atrace_instant_for_track_body"
+  },
+  {
+   "name" : "atrace_int64_body"
+  },
+  {
+   "name" : "atrace_int_body"
+  },
+  {
+   "name" : "atrace_set_tracing_enabled"
+  },
+  {
+   "name" : "atrace_setup"
+  },
+  {
+   "name" : "atrace_update_tags"
+  },
+  {
+   "name" : "canned_fs_config"
+  },
+  {
+   "name" : "config_bool"
+  },
+  {
+   "name" : "config_find"
+  },
+  {
+   "name" : "config_free"
+  },
+  {
+   "name" : "config_load"
+  },
+  {
+   "name" : "config_load_file"
+  },
+  {
+   "name" : "config_node"
+  },
+  {
+   "name" : "config_set"
+  },
+  {
+   "name" : "config_str"
+  },
+  {
+   "name" : "fs_config"
+  },
+  {
+   "name" : "fs_mkdirs"
+  },
+  {
+   "name" : "fs_prepare_dir"
+  },
+  {
+   "name" : "fs_prepare_dir_strict"
+  },
+  {
+   "name" : "fs_prepare_file_strict"
+  },
+  {
+   "name" : "fs_read_atomic_int"
+  },
+  {
+   "name" : "fs_write_atomic_int"
+  },
+  {
+   "name" : "hashmapCreate"
+  },
+  {
+   "name" : "hashmapForEach"
+  },
+  {
+   "name" : "hashmapFree"
+  },
+  {
+   "name" : "hashmapGet"
+  },
+  {
+   "name" : "hashmapHash"
+  },
+  {
+   "name" : "hashmapLock"
+  },
+  {
+   "name" : "hashmapPut"
+  },
+  {
+   "name" : "hashmapRemove"
+  },
+  {
+   "name" : "hashmapUnlock"
+  },
+  {
+   "name" : "klog_set_level"
+  },
+  {
+   "name" : "klog_write"
+  },
+  {
+   "name" : "klog_writev"
+  },
+  {
+   "name" : "load_canned_fs_config"
+  },
+  {
+   "name" : "load_file"
+  },
+  {
+   "name" : "multiuser_convert_sdk_sandbox_to_app_uid"
+  },
+  {
+   "name" : "multiuser_get_app_id"
+  },
+  {
+   "name" : "multiuser_get_cache_gid"
+  },
+  {
+   "name" : "multiuser_get_ext_cache_gid"
+  },
+  {
+   "name" : "multiuser_get_ext_gid"
+  },
+  {
+   "name" : "multiuser_get_sdk_sandbox_uid"
+  },
+  {
+   "name" : "multiuser_get_shared_app_gid"
+  },
+  {
+   "name" : "multiuser_get_shared_gid"
+  },
+  {
+   "name" : "multiuser_get_uid"
+  },
+  {
+   "name" : "multiuser_get_user_id"
+  },
+  {
+   "name" : "native_handle_clone"
+  },
+  {
+   "name" : "native_handle_close"
+  },
+  {
+   "name" : "native_handle_close_with_tag"
+  },
+  {
+   "name" : "native_handle_create"
+  },
+  {
+   "name" : "native_handle_delete"
+  },
+  {
+   "name" : "native_handle_init"
+  },
+  {
+   "name" : "native_handle_set_fdsan_tag"
+  },
+  {
+   "name" : "native_handle_unset_fdsan_tag"
+  },
+  {
+   "name" : "partition_wiped"
+  },
+  {
+   "name" : "property_get"
+  },
+  {
+   "name" : "property_get_bool"
+  },
+  {
+   "name" : "property_get_int32"
+  },
+  {
+   "name" : "property_get_int64"
+  },
+  {
+   "name" : "property_list"
+  },
+  {
+   "name" : "property_set"
+  },
+  {
+   "name" : "record_stream_free"
+  },
+  {
+   "name" : "record_stream_get_next"
+  },
+  {
+   "name" : "record_stream_new"
+  },
+  {
+   "name" : "socket_close"
+  },
+  {
+   "name" : "socket_get_local_port"
+  },
+  {
+   "name" : "socket_inaddr_any_server"
+  },
+  {
+   "name" : "socket_local_client"
+  },
+  {
+   "name" : "socket_local_client_connect"
+  },
+  {
+   "name" : "socket_local_server"
+  },
+  {
+   "name" : "socket_local_server_bind"
+  },
+  {
+   "name" : "socket_network_client"
+  },
+  {
+   "name" : "socket_network_client_timeout"
+  },
+  {
+   "name" : "socket_send_buffers"
+  },
+  {
+   "name" : "str_parms_add_float"
+  },
+  {
+   "name" : "str_parms_add_int"
+  },
+  {
+   "name" : "str_parms_add_str"
+  },
+  {
+   "name" : "str_parms_create"
+  },
+  {
+   "name" : "str_parms_create_str"
+  },
+  {
+   "name" : "str_parms_del"
+  },
+  {
+   "name" : "str_parms_destroy"
+  },
+  {
+   "name" : "str_parms_dump"
+  },
+  {
+   "name" : "str_parms_get_float"
+  },
+  {
+   "name" : "str_parms_get_int"
+  },
+  {
+   "name" : "str_parms_get_str"
+  },
+  {
+   "name" : "str_parms_has_key"
+  },
+  {
+   "name" : "str_parms_to_str"
+  },
+  {
+   "name" : "uevent_kernel_multicast_recv"
+  },
+  {
+   "name" : "uevent_kernel_multicast_uid_recv"
+  },
+  {
+   "name" : "uevent_kernel_recv"
+  },
+  {
+   "name" : "uevent_open_socket"
+  }
+ ],
+ "elf_objects" :
+ [
+  {
+   "binding" : "weak",
+   "name" : "_ZTCNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE0_NS_13basic_istreamIcS2_EE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTTNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTVNSt3__113basic_filebufIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "binding" : "weak",
+   "name" : "_ZTVNSt3__114basic_ifstreamIcNS_11char_traitsIcEEEE"
+  },
+  {
+   "name" : "atrace_enabled_tags"
+  },
+  {
+   "name" : "atrace_is_ready"
+  },
+  {
+   "name" : "atrace_marker_fd"
+  }
+ ],
+ "enum_types" :
+ [
+  {
+   "alignment" : 4,
+   "enum_fields" :
+   [
+    {
+     "enum_field_value" : 0,
+     "name" : "IoSchedClass_NONE"
+    },
+    {
+     "enum_field_value" : 1,
+     "name" : "IoSchedClass_RT"
+    },
+    {
+     "enum_field_value" : 2,
+     "name" : "IoSchedClass_BE"
+    },
+    {
+     "enum_field_value" : 3,
+     "name" : "IoSchedClass_IDLE"
+    }
+   ],
+   "linker_set_key" : "_ZTI12IoSchedClass",
+   "name" : "IoSchedClass",
+   "referenced_type" : "_ZTI12IoSchedClass",
+   "self_type" : "_ZTI12IoSchedClass",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h",
+   "underlying_type" : "_ZTIj"
+  }
+ ],
+ "function_types" :
+ [
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFbPvS_E",
+   "name" : "bool (void *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFbPvS_E",
+   "return_type" : "_ZTIb",
+   "self_type" : "_ZTIFbPvS_E",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFbPvS_S_E",
+   "name" : "bool (void *, void *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFbPvS_S_E",
+   "return_type" : "_ZTIb",
+   "self_type" : "_ZTIFbPvS_S_E",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFiPvE",
+   "name" : "int (void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFiPvE",
+   "return_type" : "_ZTIi",
+   "self_type" : "_ZTIFiPvE",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIFvPKcS0_PvE",
+   "name" : "void (const char *, const char *, void *)",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "referenced_type" : "_ZTIFvPKcS0_PvE",
+   "return_type" : "_ZTIv",
+   "self_type" : "_ZTIFvPKcS0_PvE",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  }
+ ],
+ "functions" :
+ [
+  {
+   "function_name" : "android_get_control_file",
+   "linker_set_key" : "android_get_control_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/android_get_control_file.h"
+  },
+  {
+   "function_name" : "android_get_control_socket",
+   "linker_set_key" : "android_get_control_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "android_get_ioprio",
+   "linker_set_key" : "android_get_ioprio",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIP12IoSchedClass"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "function_name" : "android_reboot",
+   "linker_set_key" : "android_reboot",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/android_reboot.h"
+  },
+  {
+   "function_name" : "android_set_ioprio",
+   "linker_set_key" : "android_set_ioprio",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTI12IoSchedClass"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "function_name" : "ashmem_create_region",
+   "linker_set_key" : "ashmem_create_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_get_size_region",
+   "linker_set_key" : "ashmem_get_size_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_pin_region",
+   "linker_set_key" : "ashmem_pin_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_set_prot_region",
+   "linker_set_key" : "ashmem_set_prot_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_unpin_region",
+   "linker_set_key" : "ashmem_unpin_region",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "ashmem_valid",
+   "linker_set_key" : "ashmem_valid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/ashmem.h"
+  },
+  {
+   "function_name" : "atrace_async_begin_body",
+   "linker_set_key" : "atrace_async_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_end_body",
+   "linker_set_key" : "atrace_async_end_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_for_track_begin_body",
+   "linker_set_key" : "atrace_async_for_track_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_async_for_track_end_body",
+   "linker_set_key" : "atrace_async_for_track_end_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_begin_body",
+   "linker_set_key" : "atrace_begin_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_end_body",
+   "linker_set_key" : "atrace_end_body",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_get_enabled_tags",
+   "linker_set_key" : "atrace_get_enabled_tags",
+   "return_type" : "_ZTIy",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_init",
+   "linker_set_key" : "atrace_init",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_instant_body",
+   "linker_set_key" : "atrace_instant_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_instant_for_track_body",
+   "linker_set_key" : "atrace_instant_for_track_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_int64_body",
+   "linker_set_key" : "atrace_int64_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIx"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_int_body",
+   "linker_set_key" : "atrace_int_body",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_set_tracing_enabled",
+   "linker_set_key" : "atrace_set_tracing_enabled",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_setup",
+   "linker_set_key" : "atrace_setup",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "atrace_update_tags",
+   "linker_set_key" : "atrace_update_tags",
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "function_name" : "canned_fs_config",
+   "linker_set_key" : "canned_fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPy"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
+  },
+  {
+   "function_name" : "config_bool",
+   "linker_set_key" : "config_bool",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_find",
+   "linker_set_key" : "config_find",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP5cnode",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_free",
+   "linker_set_key" : "config_free",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_load",
+   "linker_set_key" : "config_load",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_load_file",
+   "linker_set_key" : "config_load_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_node",
+   "linker_set_key" : "config_node",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP5cnode",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_set",
+   "linker_set_key" : "config_set",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "config_str",
+   "linker_set_key" : "config_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIPKc",
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "function_name" : "fs_config",
+   "linker_set_key" : "fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    },
+    {
+     "referenced_type" : "_ZTIPy"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/private/fs_config.h"
+  },
+  {
+   "function_name" : "fs_mkdirs",
+   "linker_set_key" : "fs_mkdirs",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIt"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_dir",
+   "linker_set_key" : "fs_prepare_dir",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIt"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_dir_strict",
+   "linker_set_key" : "fs_prepare_dir_strict",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIt"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_prepare_file_strict",
+   "linker_set_key" : "fs_prepare_file_strict",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIt"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_read_atomic_int",
+   "linker_set_key" : "fs_read_atomic_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "fs_write_atomic_int",
+   "linker_set_key" : "fs_write_atomic_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/fs.h"
+  },
+  {
+   "function_name" : "hashmapCreate",
+   "linker_set_key" : "hashmapCreate",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIPFiPvE"
+    },
+    {
+     "referenced_type" : "_ZTIPFbPvS_E"
+    }
+   ],
+   "return_type" : "_ZTIP7Hashmap",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapForEach",
+   "linker_set_key" : "hashmapForEach",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPFbPvS_S_E"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapFree",
+   "linker_set_key" : "hashmapFree",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapGet",
+   "linker_set_key" : "hashmapGet",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapHash",
+   "linker_set_key" : "hashmapHash",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapLock",
+   "linker_set_key" : "hashmapLock",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapPut",
+   "linker_set_key" : "hashmapPut",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapRemove",
+   "linker_set_key" : "hashmapRemove",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "hashmapUnlock",
+   "linker_set_key" : "hashmapUnlock",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP7Hashmap"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "function_name" : "klog_set_level",
+   "linker_set_key" : "klog_set_level",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "klog_write",
+   "linker_set_key" : "klog_write",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "klog_writev",
+   "linker_set_key" : "klog_writev",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPK5iovec"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "function_name" : "load_canned_fs_config",
+   "linker_set_key" : "load_canned_fs_config",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
+  },
+  {
+   "function_name" : "load_file",
+   "linker_set_key" : "load_file",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIPv",
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  },
+  {
+   "function_name" : "multiuser_convert_sdk_sandbox_to_app_uid",
+   "linker_set_key" : "multiuser_convert_sdk_sandbox_to_app_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_app_id",
+   "linker_set_key" : "multiuser_get_app_id",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_cache_gid",
+   "linker_set_key" : "multiuser_get_cache_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_ext_cache_gid",
+   "linker_set_key" : "multiuser_get_ext_cache_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_ext_gid",
+   "linker_set_key" : "multiuser_get_ext_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_sdk_sandbox_uid",
+   "linker_set_key" : "multiuser_get_sdk_sandbox_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_shared_app_gid",
+   "linker_set_key" : "multiuser_get_shared_app_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_shared_gid",
+   "linker_set_key" : "multiuser_get_shared_gid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_uid",
+   "linker_set_key" : "multiuser_get_uid",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "multiuser_get_user_id",
+   "linker_set_key" : "multiuser_get_user_id",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIj",
+   "source_file" : "system/core/libcutils/include/cutils/multiuser.h"
+  },
+  {
+   "function_name" : "native_handle_clone",
+   "linker_set_key" : "native_handle_clone",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_close",
+   "linker_set_key" : "native_handle_close",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_close_with_tag",
+   "linker_set_key" : "native_handle_close_with_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_create",
+   "linker_set_key" : "native_handle_create",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_delete",
+   "linker_set_key" : "native_handle_delete",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_init",
+   "linker_set_key" : "native_handle_init",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIP13native_handle",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_set_fdsan_tag",
+   "linker_set_key" : "native_handle_set_fdsan_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "native_handle_unset_fdsan_tag",
+   "linker_set_key" : "native_handle_unset_fdsan_tag",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPK13native_handle"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "function_name" : "partition_wiped",
+   "linker_set_key" : "partition_wiped",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/partition_utils.h"
+  },
+  {
+   "function_name" : "property_get",
+   "linker_set_key" : "property_get",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_bool",
+   "linker_set_key" : "property_get_bool",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIa"
+    }
+   ],
+   "return_type" : "_ZTIa",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_int32",
+   "linker_set_key" : "property_get_int32",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_get_int64",
+   "linker_set_key" : "property_get_int64",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIx"
+    }
+   ],
+   "return_type" : "_ZTIx",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_list",
+   "linker_set_key" : "property_list",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPFvPKcS0_PvE"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "property_set",
+   "linker_set_key" : "property_set",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "function_name" : "record_stream_free",
+   "linker_set_key" : "record_stream_free",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP12RecordStream"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "record_stream_get_next",
+   "linker_set_key" : "record_stream_get_next",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP12RecordStream"
+    },
+    {
+     "referenced_type" : "_ZTIPPv"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "record_stream_new",
+   "linker_set_key" : "record_stream_new",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIP12RecordStream",
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "function_name" : "socket_close",
+   "linker_set_key" : "socket_close",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_get_local_port",
+   "linker_set_key" : "socket_get_local_port",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_inaddr_any_server",
+   "linker_set_key" : "socket_inaddr_any_server",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_client",
+   "linker_set_key" : "socket_local_client",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_client_connect",
+   "linker_set_key" : "socket_local_client_connect",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_server",
+   "linker_set_key" : "socket_local_server",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_local_server_bind",
+   "linker_set_key" : "socket_local_server_bind",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_network_client",
+   "linker_set_key" : "socket_network_client",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_network_client_timeout",
+   "linker_set_key" : "socket_network_client_timeout",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "socket_send_buffers",
+   "linker_set_key" : "socket_send_buffers",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPK22cutils_socket_buffer_t"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "function_name" : "str_parms_add_float",
+   "linker_set_key" : "str_parms_add_float",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIf"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_add_int",
+   "linker_set_key" : "str_parms_add_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_add_str",
+   "linker_set_key" : "str_parms_add_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_create",
+   "linker_set_key" : "str_parms_create",
+   "return_type" : "_ZTIP9str_parms",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_create_str",
+   "linker_set_key" : "str_parms_create_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIP9str_parms",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_del",
+   "linker_set_key" : "str_parms_del",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_destroy",
+   "linker_set_key" : "str_parms_destroy",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_dump",
+   "linker_set_key" : "str_parms_dump",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIv",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_float",
+   "linker_set_key" : "str_parms_get_float",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPf"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_int",
+   "linker_set_key" : "str_parms_get_int",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_get_str",
+   "linker_set_key" : "str_parms_get_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "referenced_type" : "_ZTIPc"
+    },
+    {
+     "referenced_type" : "_ZTIi"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_has_key",
+   "linker_set_key" : "str_parms_has_key",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    },
+    {
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "str_parms_to_str",
+   "linker_set_key" : "str_parms_to_str",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIP9str_parms"
+    }
+   ],
+   "return_type" : "_ZTIPc",
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "function_name" : "uevent_kernel_multicast_recv",
+   "linker_set_key" : "uevent_kernel_multicast_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_kernel_multicast_uid_recv",
+   "linker_set_key" : "uevent_kernel_multicast_uid_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_kernel_recv",
+   "linker_set_key" : "uevent_kernel_recv",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIPv"
+    },
+    {
+     "referenced_type" : "_ZTIj"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    },
+    {
+     "referenced_type" : "_ZTIPj"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  },
+  {
+   "function_name" : "uevent_open_socket",
+   "linker_set_key" : "uevent_open_socket",
+   "parameters" :
+   [
+    {
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "referenced_type" : "_ZTIb"
+    }
+   ],
+   "return_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/uevent.h"
+  }
+ ],
+ "global_vars" :
+ [
+  {
+   "linker_set_key" : "atrace_enabled_tags",
+   "name" : "atrace_enabled_tags",
+   "referenced_type" : "_ZTIy",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "linker_set_key" : "atrace_is_ready",
+   "name" : "atrace_is_ready",
+   "referenced_type" : "_ZTINSt3__16atomicIbEE",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  },
+  {
+   "linker_set_key" : "atrace_marker_fd",
+   "name" : "atrace_marker_fd",
+   "referenced_type" : "_ZTIi",
+   "source_file" : "system/core/libcutils/include/cutils/trace.h"
+  }
+ ],
+ "lvalue_reference_types" : [],
+ "pointer_types" :
+ [
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP12IoSchedClass",
+   "name" : "IoSchedClass *",
+   "referenced_type" : "_ZTI12IoSchedClass",
+   "self_type" : "_ZTIP12IoSchedClass",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP12RecordStream",
+   "name" : "RecordStream *",
+   "referenced_type" : "_ZTI12RecordStream",
+   "self_type" : "_ZTIP12RecordStream",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP13native_handle",
+   "name" : "native_handle *",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTIP13native_handle",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP5cnode",
+   "name" : "cnode *",
+   "referenced_type" : "_ZTI5cnode",
+   "self_type" : "_ZTIP5cnode",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP7Hashmap",
+   "name" : "Hashmap *",
+   "referenced_type" : "_ZTI7Hashmap",
+   "self_type" : "_ZTIP7Hashmap",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIP9str_parms",
+   "name" : "str_parms *",
+   "referenced_type" : "_ZTI9str_parms",
+   "self_type" : "_ZTIP9str_parms",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPFbPvS_E",
+   "name" : "bool (*)(void *, void *)",
+   "referenced_type" : "_ZTIFbPvS_E",
+   "self_type" : "_ZTIPFbPvS_E",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPFbPvS_S_E",
+   "name" : "bool (*)(void *, void *, void *)",
+   "referenced_type" : "_ZTIFbPvS_S_E",
+   "self_type" : "_ZTIPFbPvS_S_E",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPFiPvE",
+   "name" : "int (*)(void *)",
+   "referenced_type" : "_ZTIFiPvE",
+   "self_type" : "_ZTIPFiPvE",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/hashmap.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPFvPKcS0_PvE",
+   "name" : "void (*)(const char *, const char *, void *)",
+   "referenced_type" : "_ZTIFvPKcS0_PvE",
+   "self_type" : "_ZTIPFvPKcS0_PvE",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/properties.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPK13native_handle",
+   "name" : "const native_handle *",
+   "referenced_type" : "_ZTIK13native_handle",
+   "self_type" : "_ZTIPK13native_handle",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPK22cutils_socket_buffer_t",
+   "name" : "const cutils_socket_buffer_t *",
+   "referenced_type" : "_ZTIK22cutils_socket_buffer_t",
+   "self_type" : "_ZTIPK22cutils_socket_buffer_t",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPK5iovec",
+   "name" : "const iovec *",
+   "referenced_type" : "_ZTIK5iovec",
+   "self_type" : "_ZTIPK5iovec",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPKc",
+   "name" : "const char *",
+   "referenced_type" : "_ZTIKc",
+   "self_type" : "_ZTIPKc",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPKv",
+   "name" : "const void *",
+   "referenced_type" : "_ZTIKv",
+   "self_type" : "_ZTIPKv",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPPv",
+   "name" : "void **",
+   "referenced_type" : "_ZTIPv",
+   "self_type" : "_ZTIPPv",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/record_stream.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPc",
+   "name" : "char *",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIPc",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPf",
+   "name" : "float *",
+   "referenced_type" : "_ZTIf",
+   "self_type" : "_ZTIPf",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/str_parms.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPi",
+   "name" : "int *",
+   "referenced_type" : "_ZTIi",
+   "self_type" : "_ZTIPi",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/iosched_policy.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPj",
+   "name" : "unsigned int *",
+   "referenced_type" : "_ZTIj",
+   "self_type" : "_ZTIPj",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPv",
+   "name" : "void *",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIPv",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/cutils/misc.h"
+  },
+  {
+   "alignment" : 4,
+   "linker_set_key" : "_ZTIPy",
+   "name" : "unsigned long long *",
+   "referenced_type" : "_ZTIy",
+   "self_type" : "_ZTIPy",
+   "size" : 4,
+   "source_file" : "system/core/libcutils/include/private/canned_fs_config.h"
+  }
+ ],
+ "qualified_types" :
+ [
+  {
+   "alignment" : 4,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK13native_handle",
+   "name" : "const native_handle",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTIK13native_handle",
+   "size" : 12,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 4,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK22cutils_socket_buffer_t",
+   "name" : "const cutils_socket_buffer_t",
+   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
+   "self_type" : "_ZTIK22cutils_socket_buffer_t",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 4,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIK5iovec",
+   "name" : "const iovec",
+   "referenced_type" : "_ZTI5iovec",
+   "self_type" : "_ZTIK5iovec",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/klog.h"
+  },
+  {
+   "alignment" : 1,
+   "is_const" : true,
+   "linker_set_key" : "_ZTIKc",
+   "name" : "const char",
+   "referenced_type" : "_ZTIc",
+   "self_type" : "_ZTIKc",
+   "size" : 1,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  },
+  {
+   "is_const" : true,
+   "linker_set_key" : "_ZTIKv",
+   "name" : "const void",
+   "referenced_type" : "_ZTIv",
+   "self_type" : "_ZTIKv",
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  }
+ ],
+ "record_types" :
+ [
+  {
+   "alignment" : 4,
+   "fields" :
+   [
+    {
+     "field_name" : "version",
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "numFds",
+     "field_offset" : 32,
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "numInts",
+     "field_offset" : 64,
+     "referenced_type" : "_ZTIi"
+    },
+    {
+     "field_name" : "data",
+     "field_offset" : 96,
+     "referenced_type" : "_ZTIA0_i"
+    }
+   ],
+   "linker_set_key" : "_ZTI13native_handle",
+   "name" : "native_handle",
+   "referenced_type" : "_ZTI13native_handle",
+   "self_type" : "_ZTI13native_handle",
+   "size" : 12,
+   "source_file" : "system/core/libcutils/include/cutils/native_handle.h"
+  },
+  {
+   "alignment" : 4,
+   "fields" :
+   [
+    {
+     "field_name" : "data",
+     "referenced_type" : "_ZTIPKv"
+    },
+    {
+     "field_name" : "length",
+     "field_offset" : 32,
+     "referenced_type" : "_ZTIj"
+    }
+   ],
+   "linker_set_key" : "_ZTI22cutils_socket_buffer_t",
+   "name" : "cutils_socket_buffer_t",
+   "referenced_type" : "_ZTI22cutils_socket_buffer_t",
+   "self_type" : "_ZTI22cutils_socket_buffer_t",
+   "size" : 8,
+   "source_file" : "system/core/libcutils/include/cutils/sockets.h"
+  },
+  {
+   "alignment" : 4,
+   "fields" :
+   [
+    {
+     "field_name" : "next",
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "first_child",
+     "field_offset" : 32,
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "last_child",
+     "field_offset" : 64,
+     "referenced_type" : "_ZTIP5cnode"
+    },
+    {
+     "field_name" : "name",
+     "field_offset" : 96,
+     "referenced_type" : "_ZTIPKc"
+    },
+    {
+     "field_name" : "value",
+     "field_offset" : 128,
+     "referenced_type" : "_ZTIPKc"
+    }
+   ],
+   "linker_set_key" : "_ZTI5cnode",
+   "name" : "cnode",
+   "referenced_type" : "_ZTI5cnode",
+   "self_type" : "_ZTI5cnode",
+   "size" : 20,
+   "source_file" : "system/core/libcutils/include/cutils/config_utils.h"
+  }
+ ],
+ "rvalue_reference_types" : []
+}
diff --git a/libcutils/include/cutils/threads.h b/libcutils/include/cutils/threads.h
index 0082c6c..1886184 100644
--- a/libcutils/include/cutils/threads.h
+++ b/libcutils/include/cutils/threads.h
@@ -31,7 +31,7 @@
 //
 // Deprecated: use android::base::GetThreadId instead, which doesn't truncate on Mac/Windows.
 //
-#if !defined(__GLIBC__) || __GLIBC__ >= 2 && __GLIBC_MINOR__ < 32
+#if !defined(__GLIBC__) || __GLIBC__ >= 2 && __GLIBC_MINOR__ < 30
 extern pid_t gettid();
 #endif
 
diff --git a/libcutils/threads.cpp b/libcutils/threads.cpp
index 6ece7a3..2638720 100644
--- a/libcutils/threads.cpp
+++ b/libcutils/threads.cpp
@@ -25,9 +25,9 @@
 #include <windows.h>
 #endif
 
-#if defined(__BIONIC__) || defined(__GLIBC__) && __GLIBC_MINOR__ >= 32
+#if defined(__BIONIC__) || defined(__GLIBC__) && __GLIBC_MINOR__ >= 30
 // No definition needed for Android because we'll just pick up bionic's copy.
-// No definition needed for Glibc >= 2.32 because it exposes its own copy.
+// No definition needed for Glibc >= 2.30 because it exposes its own copy.
 #else
 pid_t gettid() {
 #if defined(__APPLE__)
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1f29040..06d386f 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -223,6 +223,13 @@
         std::this_thread::sleep_for(5ms);
     }
 
+    if (!ret && uid >= AID_ISOLATED_START && uid <= AID_ISOLATED_END) {
+        // Isolated UIDs are unlikely to be reused soon after removal,
+        // so free up the kernel resources for the UID level cgroup.
+        const auto uid_path = ConvertUidToPath(cgroup, uid);
+        ret = rmdir(uid_path.c_str());
+    }
+
     return ret;
 }
 
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index 819066e..c5c1934 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -26,7 +26,7 @@
 cc_defaults {
     name: "libstatspush_compat_defaults",
     srcs: [
-        "statsd_writer.c",
+        "statsd_writer.cpp",
         "stats_event_list.c",
         "StatsEventCompat.cpp"
     ],
diff --git a/libstats/push_compat/statsd_writer.c b/libstats/push_compat/statsd_writer.cpp
similarity index 97%
rename from libstats/push_compat/statsd_writer.c
rename to libstats/push_compat/statsd_writer.cpp
index 4818d11..a3600f3 100644
--- a/libstats/push_compat/statsd_writer.c
+++ b/libstats/push_compat/statsd_writer.cpp
@@ -15,9 +15,9 @@
  */
 #include "statsd_writer.h"
 
+#include <android-base/threads.h>
 #include <cutils/fs.h>
 #include <cutils/sockets.h>
-#include <cutils/threads.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
@@ -108,7 +108,7 @@
                     case -ECONNREFUSED:
                     case -ENOENT:
                         i = atomic_exchange(&statsdLoggerWrite.sock, ret);
-                    /* FALLTHRU */
+                        break;
                     default:
                         break;
                 }
@@ -188,7 +188,7 @@
      *  };
      */
 
-    header.tid = gettid();
+    header.tid = android::base::GetThreadId();
     header.realtime.tv_sec = ts->tv_sec;
     header.realtime.tv_nsec = ts->tv_nsec;
 
@@ -272,7 +272,7 @@
             if (ret < 0) {
                 ret = -errno;
             }
-        /* FALLTHRU */
+            break;
         default:
             break;
     }
diff --git a/libstats/push_compat/statsd_writer.h b/libstats/push_compat/statsd_writer.h
index fe2d37c..f030b96 100644
--- a/libstats/push_compat/statsd_writer.h
+++ b/libstats/push_compat/statsd_writer.h
@@ -21,6 +21,8 @@
 #include <stdatomic.h>
 #include <sys/socket.h>
 
+__BEGIN_DECLS
+
 /**
  * Internal lock should not be exposed. This is bad design.
  * TODO: rewrite it in c++ code and encapsulate the functionality in a
@@ -42,4 +44,6 @@
     void (*noteDrop)(int error, int tag);
 };
 
+__END_DECLS
+
 #endif  // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index faf49b6..e5dcd31 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -45,6 +45,8 @@
                     str1->toLower();
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+                    if (str2->size() == 0) return;
+
                     str1->removeAll(str2->c_str());
                 },
                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4f3959f..d2499ef 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -604,8 +604,8 @@
     chmod 0700 /metadata/vold
     mkdir /metadata/password_slots 0771 root system
     mkdir /metadata/bootstat 0750 system log
-    mkdir /metadata/ota 0700 root system
-    mkdir /metadata/ota/snapshots 0700 root system
+    mkdir /metadata/ota 0750 root system
+    mkdir /metadata/ota/snapshots 0750 root system
     mkdir /metadata/userspacereboot 0770 root system
     mkdir /metadata/watchdog 0770 root system
 
@@ -1021,13 +1021,9 @@
     # Must start after 'derive_classpath' to have *CLASSPATH variables set.
     start odsign
 
-    # Before we can lock keys and proceed to the next boot stage, wait for
-    # odsign to be done with the key
+    # Wait for odsign to be done with the key.
     wait_for_prop odsign.key.done 1
 
-    # Lock the fs-verity keyring, so no more keys can be added
-    exec -- /system/bin/fsverity_init --lock
-
     # Bump the boot level to 1000000000; this prevents further on-device signing.
     # This is a special value that shuts down the thread which listens for
     # further updates.
@@ -1059,7 +1055,7 @@
 on zygote-start
     wait_for_prop odsign.verification.done 1
     # A/B update verifier that marks a successful boot.
-    exec_start update_verifier_nonencrypted
+    exec_start update_verifier
     start statsd
     start netd
     start zygote