Merge "SF: Fix jank after folding due to power sequence" into udc-qpr-dev am: 507c115dde

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/native/+/24372572

Change-Id: I1dcab0e3bba67b4a3fb23702d73131645eb9669a
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index f1d8c72..fc0801c 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -228,10 +228,6 @@
     chmod 0666 /sys/kernel/debug/tracing/events/thermal/cdev_update/enable
     chmod 0666 /sys/kernel/tracing/events/thermal/cdev_update/enable
 
-# Tracing disabled by default
-    write /sys/kernel/debug/tracing/tracing_on 0
-    write /sys/kernel/tracing/tracing_on 0
-
 # Read and truncate the kernel trace.
     chmod 0666 /sys/kernel/debug/tracing/trace
     chmod 0666 /sys/kernel/tracing/trace
@@ -310,18 +306,9 @@
     chmod 0666 /sys/kernel/tracing/events/synthetic/suspend_resume_minimal/enable
     chmod 0666 /sys/kernel/debug/tracing/events/synthetic/suspend_resume_minimal/enable
 
-on late-init && property:ro.boot.fastboot.boottrace=enabled
-    setprop debug.atrace.tags.enableflags 802922
-    setprop persist.traced.enable 0
-    write /sys/kernel/tracing/events/binder/binder_transaction/enable 1
-    write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 1
-    write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 1
-    write /sys/kernel/tracing/events/binder/binder_set_priority/enable 1
-    write /sys/kernel/tracing/events/binder/binder_lock/enable 1
-    write /sys/kernel/tracing/events/binder/binder_locked/enable 1
-    write /sys/kernel/tracing/events/binder/binder_unlock/enable 1
-    write /sys/kernel/debug/tracing/tracing_on 1
-    write /sys/kernel/tracing/tracing_on 1
+on late-init && property:ro.boot.fastboot.boottrace=
+    write /sys/kernel/debug/tracing/tracing_on 0
+    write /sys/kernel/tracing/tracing_on 0
 
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
@@ -534,7 +521,6 @@
     chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/host_mem_abort/id
     chmod 0440 /sys/kernel/tracing/hyp/events/hyp/host_mem_abort/id
 
-
 on property:persist.debug.atrace.boottrace=1
     start boottrace
 
@@ -543,17 +529,3 @@
     user root
     disabled
     oneshot
-
-on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled
-    setprop debug.atrace.tags.enableflags 0
-    setprop persist.traced.enable 1
-    write /sys/kernel/tracing/events/binder/binder_transaction/enable 0
-    write /sys/kernel/tracing/events/binder/binder_transaction_received/enable 0
-    write /sys/kernel/tracing/events/binder/binder_transaction_alloc_buf/enable 0
-    write /sys/kernel/tracing/events/binder/binder_set_priority/enable 0
-    write /sys/kernel/tracing/events/binder/binder_lock/enable 0
-    write /sys/kernel/tracing/events/binder/binder_locked/enable 0
-    write /sys/kernel/tracing/events/binder/binder_unlock/enable 0
-    write /sys/kernel/debug/tracing/tracing_on 0
-    write /sys/kernel/tracing/tracing_on 0
-
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 4842312..615701c 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -207,9 +207,7 @@
 int PropertiesHelper::dry_run_ = -1;
 int PropertiesHelper::unroot_ = -1;
 int PropertiesHelper::parallel_run_ = -1;
-#if !defined(__ANDROID_VNDK__)
 int PropertiesHelper::strict_run_ = -1;
-#endif
 
 bool PropertiesHelper::IsUserBuild() {
     if (build_type_.empty()) {
@@ -240,7 +238,6 @@
     return parallel_run_ == 1;
 }
 
-#if !defined(__ANDROID_VNDK__)
 bool PropertiesHelper::IsStrictRun() {
     if (strict_run_ == -1) {
         // Defaults to using stricter timeouts.
@@ -248,7 +245,6 @@
     }
     return strict_run_ == 1;
 }
-#endif
 
 int DumpFileToFd(int out_fd, const std::string& title, const std::string& path) {
     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
diff --git a/cmds/dumpstate/DumpstateUtil.h b/cmds/dumpstate/DumpstateUtil.h
index 6049e3e..9e955e3 100644
--- a/cmds/dumpstate/DumpstateUtil.h
+++ b/cmds/dumpstate/DumpstateUtil.h
@@ -198,18 +198,14 @@
      * will default to true. This results in shortened timeouts for flaky
      * sections.
      */
-#if !defined(__ANDROID_VNDK__)
     static bool IsStrictRun();
-#endif
 
   private:
     static std::string build_type_;
     static int dry_run_;
     static int unroot_;
     static int parallel_run_;
-#if !defined(__ANDROID_VNDK__)
     static int strict_run_;
-#endif
 };
 
 /*
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e93b46c..e132b35 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1420,12 +1420,12 @@
     auto ret = sm->list([&](const auto& interfaces) {
         for (const std::string& interface : interfaces) {
             std::string cleanName = interface;
-            std::replace_if(cleanName.begin(),
-                            cleanName.end(),
-                            [](char c) {
-                                return !isalnum(c) &&
-                                    std::string("@-_:.").find(c) == std::string::npos;
-                            }, '_');
+            std::replace_if(
+                cleanName.begin(), cleanName.end(),
+                [](char c) {
+                    return !isalnum(c) && std::string("@-_.").find(c) == std::string::npos;
+                },
+                '_');
             const std::string path = ds.bugreport_internal_dir_ + "/lshal_debug_" + cleanName;
 
             bool empty = false;
@@ -1758,6 +1758,20 @@
 
     RunCommand("SYSTEM PROPERTIES", {"getprop"});
 
+    DumpFile("SYSTEM BUILD-TIME RELEASE FLAGS", "/system/etc/build_flags.json");
+    DumpFile("SYSTEM_EXT BUILD-TIME RELEASE FLAGS", "/system_ext/etc/build_flags.json");
+    DumpFile("PRODUCT BUILD-TIME RELEASE FLAGS", "/product/etc/build_flags.json");
+    DumpFile("VENDOR BUILD-TIME RELEASE FLAGS", "/vendor/etc/build_flags.json");
+
+    DumpFile("SYSTEM BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)",
+            "/system/etc/aconfig_flags.textproto");
+    DumpFile("SYSTEM_EXT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime"
+            " values)", "/system_ext/etc/aconfig_flags.textproto");
+    DumpFile("PRODUCT BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)",
+            "/product/etc/aconfig_flags.textproto");
+    DumpFile("VENDOR BUILD-TIME ACONFIG FLAGS (check dumpstate build_config for runtime values)",
+            "/vendor/etc/aconfig_flags.textproto");
+
     RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});
 
     RunCommand("FILESYSTEMS & FREE SPACE", {"df"});
diff --git a/cmds/installd/CrateManager.cpp b/cmds/installd/CrateManager.cpp
index b17cba1..fd1df35 100644
--- a/cmds/installd/CrateManager.cpp
+++ b/cmds/installd/CrateManager.cpp
@@ -29,9 +29,10 @@
 #include <sys/xattr.h>
 #include <unistd.h>
 
-#include <fstream>
-#include <string>
 #include <utils.h>
+#include <fstream>
+#include <functional>
+#include <string>
 
 #include "utils.h"
 
diff --git a/cmds/installd/CrateManager.h b/cmds/installd/CrateManager.h
index 1f30b5d..d9b590f 100644
--- a/cmds/installd/CrateManager.h
+++ b/cmds/installd/CrateManager.h
@@ -25,6 +25,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <functional>
 #include <optional>
 #include <string>
 #include <vector>
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index bb6639e..b302f52 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -236,6 +236,16 @@
     }                                                       \
 }
 
+// we could have tighter checks, but this is only to avoid hard errors. Negative values are defined
+// in UserHandle.java and carry specific meanings that may not be handled by certain APIs here.
+#define ENFORCE_VALID_USER(userId)                                     \
+    {                                                                  \
+        if (static_cast<uid_t>(std::abs(userId)) >=                    \
+            std::numeric_limits<uid_t>::max() / AID_USER_OFFSET) {     \
+            return error("userId invalid: " + std::to_string(userId)); \
+        }                                                              \
+    }
+
 #define CHECK_ARGUMENT_UUID(uuid) {                         \
     binder::Status status = checkArgumentUuid((uuid));      \
     if (!status.isOk()) {                                   \
@@ -416,10 +426,12 @@
  */
 static int restorecon_app_data_lazy(const std::string& path, const std::string& seInfo, uid_t uid,
         bool existing) {
+    ScopedTrace tracer("restorecon-lazy");
     int res = 0;
     char* before = nullptr;
     char* after = nullptr;
     if (!existing) {
+        ScopedTrace tracer("new-path");
         if (selinux_android_restorecon_pkgdir(path.c_str(), seInfo.c_str(), uid,
                 SELINUX_ANDROID_RESTORECON_RECURSE) < 0) {
             PLOG(ERROR) << "Failed recursive restorecon for " << path;
@@ -446,6 +458,7 @@
     // If the initial top-level restorecon above changed the label, then go
     // back and restorecon everything recursively
     if (strcmp(before, after)) {
+        ScopedTrace tracer("label-change");
         if (existing) {
             LOG(DEBUG) << "Detected label change from " << before << " to " << after << " at "
                     << path << "; running recursive restorecon";
@@ -480,11 +493,15 @@
 
 static int prepare_app_dir(const std::string& path, mode_t target_mode, uid_t uid, gid_t gid,
                            long project_id) {
-    if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
-        PLOG(ERROR) << "Failed to prepare " << path;
-        return -1;
+    {
+        ScopedTrace tracer("prepare-dir");
+        if (fs_prepare_dir_strict(path.c_str(), target_mode, uid, gid) != 0) {
+            PLOG(ERROR) << "Failed to prepare " << path;
+            return -1;
+        }
     }
     if (internal_storage_has_project_id()) {
+        ScopedTrace tracer("set-quota");
         return set_quota_project_id(path, project_id, true);
     }
     return 0;
@@ -493,14 +510,20 @@
 static int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t target_mode,
                                  uid_t uid, gid_t gid, long project_id) {
     auto path = StringPrintf("%s/%s", parent.c_str(), name);
-    int ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+    int ret;
+    {
+        ScopedTrace tracer("prepare-cache-dir");
+        ret = prepare_app_cache_dir(parent, name, target_mode, uid, gid);
+    }
     if (ret == 0 && internal_storage_has_project_id()) {
+        ScopedTrace tracer("set-quota-cache-dir");
         return set_quota_project_id(path, project_id, true);
     }
     return ret;
 }
 
 static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) {
+    ScopedTrace tracer("prepare-app-profile");
     int32_t uid = multiuser_get_uid(userId, appId);
     int shared_app_gid = multiuser_get_shared_gid(userId, appId);
     if (shared_app_gid == -1) {
@@ -633,6 +656,7 @@
                                         int32_t previousUid, int32_t cacheGid,
                                         const std::string& seInfo, mode_t targetMode,
                                         long projectIdApp, long projectIdCache) {
+    ScopedTrace tracer("create-dirs");
     struct stat st{};
     bool parent_dir_exists = (stat(path.c_str(), &st) == 0);
 
@@ -682,6 +706,7 @@
         int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
         int32_t targetSdkVersion, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -709,6 +734,7 @@
     long projectIdCache = get_project_id(uid, PROJECT_ID_APP_CACHE_START);
 
     if (flags & FLAG_STORAGE_CE) {
+        ScopedTrace tracer("ce");
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
 
         auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
@@ -735,6 +761,7 @@
         }
     }
     if (flags & FLAG_STORAGE_DE) {
+        ScopedTrace tracer("de");
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
 
         auto status = createAppDataDirs(path, uid, uid, previousUid, cacheGid, seInfo, targetMode,
@@ -752,13 +779,14 @@
     }
 
     if (flags & FLAG_STORAGE_SDK) {
+        ScopedTrace tracer("sdk");
         // Safe to ignore status since we can retry creating this by calling reconcileSdkData
         auto ignore = createSdkSandboxDataPackageDirectory(uuid, packageName, userId, appId, flags);
         if (!ignore.isOk()) {
             PLOG(WARNING) << "Failed to create sdk data package directory for " << packageName;
         }
-
     } else {
+        ScopedTrace tracer("destroy-sdk");
         // Package does not need sdk storage. Remove it.
         destroySdkSandboxDataPackageDirectory(uuid, packageName, userId, flags);
     }
@@ -773,6 +801,8 @@
 binder::Status InstalldNativeService::createSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t appId, int32_t flags) {
+    ENFORCE_VALID_USER(userId);
+
     int32_t sdkSandboxUid = multiuser_get_sdk_sandbox_uid(userId, appId);
     if (sdkSandboxUid == -1) {
         // There no valid sdk sandbox process for this app. Skip creation of data directory
@@ -811,6 +841,7 @@
         int32_t flags, int32_t appId, int32_t previousAppId, const std::string& seInfo,
         int32_t targetSdkVersion, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -822,6 +853,7 @@
         const android::os::CreateAppDataArgs& args,
         android::os::CreateAppDataResult* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(args.userId);
     // Locking is performed depeer in the callstack.
 
     int64_t ceDataInode = -1;
@@ -837,6 +869,10 @@
         const std::vector<android::os::CreateAppDataArgs>& args,
         std::vector<android::os::CreateAppDataResult>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    for (const auto& arg : args) {
+        ENFORCE_VALID_USER(arg.userId);
+    }
+
     // Locking is performed depeer in the callstack.
 
     std::vector<android::os::CreateAppDataResult> results;
@@ -851,6 +887,7 @@
 
 binder::Status InstalldNativeService::reconcileSdkData(
         const android::os::ReconcileSdkDataArgs& args) {
+    ENFORCE_VALID_USER(args.userId);
     // Locking is performed depeer in the callstack.
 
     return reconcileSdkData(args.uuid, args.packageName, args.subDirNames, args.userId, args.appId,
@@ -874,6 +911,7 @@
                                                        int userId, int appId, int previousAppId,
                                                        const std::string& seInfo, int flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -957,6 +995,7 @@
 binder::Status InstalldNativeService::migrateAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1024,6 +1063,7 @@
 binder::Status InstalldNativeService::clearAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1115,6 +1155,7 @@
 binder::Status InstalldNativeService::clearSdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags) {
+    ENFORCE_VALID_USER(userId);
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
 
@@ -1201,6 +1242,7 @@
 binder::Status InstalldNativeService::destroyAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int64_t ceDataInode) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1271,6 +1313,8 @@
 binder::Status InstalldNativeService::destroySdkSandboxDataPackageDirectory(
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags) {
+    ENFORCE_VALID_USER(userId);
+
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     const char* pkgname = packageName.c_str();
 
@@ -1418,6 +1462,7 @@
                                                       int32_t userId, int32_t snapshotId,
                                                       int32_t storageFlags, int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1552,6 +1597,7 @@
         const int32_t appId, const std::string& seInfo, const int32_t userId,
         const int32_t snapshotId, int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1624,6 +1670,7 @@
         const int32_t userId, const int64_t ceSnapshotInode, const int32_t snapshotId,
         int32_t storageFlags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -1657,6 +1704,7 @@
         const std::optional<std::string>& volumeUuid, const int32_t userId,
         const std::vector<int32_t>& retainSnapshotIds) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID_IS_TEST_OR_NULL(volumeUuid);
     LOCK_USER();
 
@@ -1847,9 +1895,12 @@
 binder::Status InstalldNativeService::createUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t userSerial ATTRIBUTE_UNUSED, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     LOCK_USER();
 
+    ScopedTrace tracer("create-user-data");
+
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     if (flags & FLAG_STORAGE_DE) {
         if (uuid_ == nullptr) {
@@ -1865,6 +1916,7 @@
 binder::Status InstalldNativeService::destroyUserData(const std::optional<std::string>& uuid,
         int32_t userId, int32_t flags) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     LOCK_USER();
 
@@ -2355,11 +2407,15 @@
         p->fts_number = p->fts_parent->fts_number;
         switch (p->fts_info) {
         case FTS_D:
-            if (p->fts_level == 4
+            if (p->fts_level == 3
+                    && !strcmp(p->fts_parent->fts_name, "obb")
+                    && !strcmp(p->fts_parent->fts_parent->fts_name, "Android")) {
+                p->fts_number = 1;
+            } else if (p->fts_level == 4
                     && !strcmp(p->fts_name, "cache")
                     && !strcmp(p->fts_parent->fts_parent->fts_name, "data")
                     && !strcmp(p->fts_parent->fts_parent->fts_parent->fts_name, "Android")) {
-                p->fts_number = 1;
+                p->fts_number = 2;
             }
             [[fallthrough]]; // to count the directory
         case FTS_DEFAULT:
@@ -2368,9 +2424,13 @@
         case FTS_SLNONE:
             int64_t size = (p->fts_statp->st_blocks * 512);
             if (p->fts_number == 1) {
-                stats->cacheSize += size;
+                stats->codeSize += size;
+            } else {
+                if (p->fts_number == 2) {
+                    stats->cacheSize += size;
+                }
+                stats->dataSize += size;
             }
-            stats->dataSize += size;
             break;
         }
     }
@@ -2644,6 +2704,7 @@
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     // NOTE: Locking is relaxed on this method, since it's limited to
     // read-only measurements without mutation.
@@ -2716,11 +2777,6 @@
         extStats.dataSize = dataSize;
         atrace_pm_end();
     } else {
-        atrace_pm_begin("obb");
-        auto obbPath = create_data_path(uuid_) + "/media/obb";
-        calculate_tree_size(obbPath, &extStats.codeSize);
-        atrace_pm_end();
-
         atrace_pm_begin("code");
         calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize);
         atrace_pm_end();
@@ -2751,9 +2807,10 @@
         atrace_pm_begin("external");
         auto dataMediaPath = create_data_media_path(uuid_, userId);
         collectManualExternalStatsForUser(dataMediaPath, &extStats);
+
 #if MEASURE_DEBUG
         LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache "
-                << extStats.cacheSize;
+                << extStats.cacheSize << " code " << extStats.codeSize;
 #endif
         atrace_pm_end();
 
@@ -2783,6 +2840,7 @@
         int32_t userId, int32_t flags, const std::vector<int32_t>& appIds,
         std::vector<int64_t>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     // NOTE: Locking is relaxed on this method, since it's limited to
     // read-only measurements without mutation.
@@ -2903,6 +2961,7 @@
         const std::vector<std::string>& packageNames, int32_t userId,
         std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     for (const auto& packageName : packageNames) {
         CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -2952,6 +3011,7 @@
         const std::optional<std::string>& uuid, int32_t userId,
         std::optional<std::vector<std::optional<CrateMetadata>>>* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
 #ifdef ENABLE_STORAGE_CRATES
     LOCK_USER();
@@ -2995,6 +3055,7 @@
 binder::Status InstalldNativeService::setAppQuota(const std::optional<std::string>& uuid,
         int32_t userId, int32_t appId, int64_t cacheQuota) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
 
@@ -3238,6 +3299,7 @@
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     LOCK_PACKAGE_USER();
@@ -3248,6 +3310,7 @@
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags, int32_t appId, const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -3279,6 +3342,7 @@
         const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId,
         int32_t flags, int32_t appId, const std::string& seInfo) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
 
@@ -3555,22 +3619,22 @@
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
 
     std::string mirrorVolCePath(StringPrintf("%s/%s", kDataMirrorCePath, uuid_));
-    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+    if (fs_prepare_dir(mirrorVolCePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) {
         return error("Failed to create CE data mirror");
     }
 
     std::string mirrorVolDePath(StringPrintf("%s/%s", kDataMirrorDePath, uuid_));
-    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+    if (fs_prepare_dir(mirrorVolDePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) {
         return error("Failed to create DE data mirror");
     }
 
     std::string mirrorVolMiscCePath(StringPrintf("%s/%s", kMiscMirrorCePath, uuid_));
-    if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+    if (fs_prepare_dir(mirrorVolMiscCePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) {
         return error("Failed to create CE misc mirror");
     }
 
     std::string mirrorVolMiscDePath(StringPrintf("%s/%s", kMiscMirrorDePath, uuid_));
-    if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0711, AID_SYSTEM, AID_SYSTEM) != 0) {
+    if (fs_prepare_dir(mirrorVolMiscDePath.c_str(), 0511, AID_SYSTEM, AID_SYSTEM) != 0) {
         return error("Failed to create DE misc mirror");
     }
 
@@ -3730,6 +3794,7 @@
         int32_t userId, int32_t appId, const std::string& profileName, const std::string& codePath,
         const std::optional<std::string>& dexMetadata, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
+    ENFORCE_VALID_USER(userId);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     CHECK_ARGUMENT_PATH(codePath);
     LOCK_PACKAGE_USER();
@@ -3752,6 +3817,7 @@
 
 binder::Status InstalldNativeService::cleanupInvalidPackageDirs(
         const std::optional<std::string>& uuid, int32_t userId, int32_t flags) {
+    ENFORCE_VALID_USER(userId);
     const char* uuid_cstr = uuid ? uuid->c_str() : nullptr;
 
     if (flags & FLAG_STORAGE_CE) {
diff --git a/cmds/installd/SysTrace.h b/cmds/installd/SysTrace.h
index 18506a9..0deaeb4 100644
--- a/cmds/installd/SysTrace.h
+++ b/cmds/installd/SysTrace.h
@@ -19,4 +19,16 @@
 namespace android::installd {
 void atrace_pm_begin(const char*);
 void atrace_pm_end();
+
+class ScopedTrace {
+public:
+    explicit ScopedTrace(const char* label) { atrace_pm_begin(label); }
+    ~ScopedTrace() { atrace_pm_end(); }
+
+private:
+    ScopedTrace(const ScopedTrace&) = delete;
+    ScopedTrace& operator=(const ScopedTrace&) = delete;
+    ScopedTrace(ScopedTrace&&) = delete;
+    ScopedTrace& operator=(ScopedTrace&&) = delete;
+};
 } /* namespace android::installd */
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5cf402c..df02588 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -18,6 +18,7 @@
 #define DEXOPT_H_
 
 #include "installd_constants.h"
+#include "unique_file.h"
 
 #include <sys/types.h>
 
@@ -156,6 +157,10 @@
 // artifacts.
 int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir);
 
+UniqueFile maybe_open_reference_profile(const std::string& pkgname, const std::string& dex_path,
+                                        const char* profile_name, bool profile_guided,
+                                        bool is_public, int uid, bool is_secondary_dex);
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 7cabdb0..27ae8f6 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -14,20 +14,21 @@
  ** limitations under the License.
  */
 
-#include <algorithm>
 #include <inttypes.h>
-#include <limits>
-#include <random>
-#include <regex>
 #include <selinux/android.h>
 #include <selinux/avc.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
+#include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
-#include <sys/mman.h>
 #include <sys/wait.h>
+#include <algorithm>
+#include <iterator>
+#include <limits>
+#include <random>
+#include <regex>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -47,6 +48,7 @@
 #include "otapreopt_parameters.h"
 #include "otapreopt_utils.h"
 #include "system_properties.h"
+#include "unique_file.h"
 #include "utils.h"
 
 #ifndef LOG_TAG
@@ -87,6 +89,9 @@
 static_assert(DEXOPT_MASK           == (0x3dfe | DEXOPT_IDLE_BACKGROUND_JOB),
               "DEXOPT_MASK unexpected.");
 
+constexpr const char* kAotCompilerFilters[]{
+        "space-profile", "space", "speed-profile", "speed", "everything-profile", "everything",
+};
 
 template<typename T>
 static constexpr bool IsPowerOfTwo(T x) {
@@ -415,6 +420,32 @@
         return (strcmp(arg, "!") == 0) ? nullptr : arg;
     }
 
+    bool IsAotCompilation() const {
+        if (std::find(std::begin(kAotCompilerFilters), std::end(kAotCompilerFilters),
+                      parameters_.compiler_filter) == std::end(kAotCompilerFilters)) {
+            return false;
+        }
+
+        int dexopt_flags = parameters_.dexopt_flags;
+        bool profile_guided = (dexopt_flags & DEXOPT_PROFILE_GUIDED) != 0;
+        bool is_secondary_dex = (dexopt_flags & DEXOPT_SECONDARY_DEX) != 0;
+        bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0;
+
+        if (profile_guided) {
+            UniqueFile reference_profile =
+                    maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path,
+                                                 parameters_.profile_name, profile_guided,
+                                                 is_public, parameters_.uid, is_secondary_dex);
+            struct stat sbuf;
+            if (reference_profile.fd() == -1 ||
+                (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     bool ShouldSkipPreopt() const {
         // There's one thing we have to be careful about: we may/will be asked to compile an app
         // living in the system image. This may be a valid request - if the app wasn't compiled,
@@ -439,9 +470,12 @@
         //       (This is ugly as it's the only thing where we need to understand the contents
         //        of parameters_, but it beats postponing the decision or using the call-
         //        backs to do weird things.)
+
+        // In addition, no need to preopt for "verify". The existing vdex files in the OTA package
+        // and the /data partition will still be usable after the OTA update is applied.
         const char* apk_path = parameters_.apk_path;
         CHECK(apk_path != nullptr);
-        if (StartsWith(apk_path, android_root_)) {
+        if (StartsWith(apk_path, android_root_) || !IsAotCompilation()) {
             const char* last_slash = strrchr(apk_path, '/');
             if (last_slash != nullptr) {
                 std::string path(apk_path, last_slash - apk_path + 1);
@@ -471,13 +505,18 @@
     // TODO(calin): embed the profile name in the parameters.
     int Dexopt() {
         std::string error;
+
+        int dexopt_flags = parameters_.dexopt_flags;
+        // Make sure dex2oat is run with background priority.
+        dexopt_flags |= DEXOPT_BOOTCOMPLETE | DEXOPT_IDLE_BACKGROUND_JOB;
+
         int res = dexopt(parameters_.apk_path,
                          parameters_.uid,
                          parameters_.pkgName,
                          parameters_.instruction_set,
                          parameters_.dexopt_needed,
                          parameters_.oat_dir,
-                         parameters_.dexopt_flags,
+                         dexopt_flags,
                          parameters_.compiler_filter,
                          parameters_.volume_uuid,
                          parameters_.shared_libraries,
@@ -521,61 +560,6 @@
         return Dexopt();
     }
 
-    ////////////////////////////////////
-    // Helpers, mostly taken from ART //
-    ////////////////////////////////////
-
-    // Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
-    static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
-        constexpr size_t kPageSize = PAGE_SIZE;
-        static_assert(IsPowerOfTwo(kPageSize), "page size must be power of two");
-        CHECK_EQ(min_delta % kPageSize, 0u);
-        CHECK_EQ(max_delta % kPageSize, 0u);
-        CHECK_LT(min_delta, max_delta);
-
-        std::default_random_engine generator;
-        generator.seed(GetSeed());
-        std::uniform_int_distribution<int32_t> distribution(min_delta, max_delta);
-        int32_t r = distribution(generator);
-        if (r % 2 == 0) {
-            r = RoundUp(r, kPageSize);
-        } else {
-            r = RoundDown(r, kPageSize);
-        }
-        CHECK_LE(min_delta, r);
-        CHECK_GE(max_delta, r);
-        CHECK_EQ(r % kPageSize, 0u);
-        return r;
-    }
-
-    static uint64_t GetSeed() {
-#ifdef __BIONIC__
-        // Bionic exposes arc4random, use it.
-        uint64_t random_data;
-        arc4random_buf(&random_data, sizeof(random_data));
-        return random_data;
-#else
-#error "This is only supposed to run with bionic. Otherwise, implement..."
-#endif
-    }
-
-    void AddCompilerOptionFromSystemProperty(const char* system_property,
-            const char* prefix,
-            bool runtime,
-            std::vector<std::string>& out) const {
-        const std::string* value = system_properties_.GetProperty(system_property);
-        if (value != nullptr) {
-            if (runtime) {
-                out.push_back("--runtime-arg");
-            }
-            if (prefix != nullptr) {
-                out.push_back(StringPrintf("%s%s", prefix, value->c_str()));
-            } else {
-                out.push_back(*value);
-            }
-        }
-    }
-
     static constexpr const char* kBootClassPathPropertyName = "BOOTCLASSPATH";
     static constexpr const char* kAndroidRootPathPropertyName = "ANDROID_ROOT";
     static constexpr const char* kAndroidDataPathPropertyName = "ANDROID_DATA";
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index c86993c..c40caf5 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -19,9 +19,12 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
+#include <unistd.h>
 
+#include <algorithm>
 #include <array>
 #include <fstream>
+#include <iostream>
 #include <sstream>
 
 #include <android-base/file.h>
@@ -29,6 +32,7 @@
 #include <android-base/macros.h>
 #include <android-base/scopeguard.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <libdm/dm.h>
 #include <selinux/android.h>
@@ -37,7 +41,7 @@
 #include "otapreopt_utils.h"
 
 #ifndef LOG_TAG
-#define LOG_TAG "otapreopt"
+#define LOG_TAG "otapreopt_chroot"
 #endif
 
 using android::base::StringPrintf;
@@ -49,20 +53,22 @@
 // so just try the possibilities one by one.
 static constexpr std::array kTryMountFsTypes = {"ext4", "erofs"};
 
-static void CloseDescriptor(int fd) {
-    if (fd >= 0) {
-        int result = close(fd);
-        UNUSED(result);  // Ignore result. Printing to logcat will open a new descriptor
-                         // that we do *not* want.
-    }
-}
-
 static void CloseDescriptor(const char* descriptor_string) {
     int fd = -1;
     std::istringstream stream(descriptor_string);
     stream >> fd;
     if (!stream.fail()) {
-        CloseDescriptor(fd);
+        if (fd >= 0) {
+            if (close(fd) < 0) {
+                PLOG(ERROR) << "Failed to close " << fd;
+            }
+        }
+    }
+}
+
+static void SetCloseOnExec(int fd) {
+    if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
+        PLOG(ERROR) << "Failed to set FD_CLOEXEC on " << fd;
     }
 }
 
@@ -129,24 +135,39 @@
 }
 
 // Entry for otapreopt_chroot. Expected parameters are:
-//   [cmd] [status-fd] [target-slot] "dexopt" [dexopt-params]
-// The file descriptor denoted by status-fd will be closed. The rest of the parameters will
-// be passed on to otapreopt in the chroot.
+//
+//   [cmd] [status-fd] [target-slot-suffix]
+//
+// The file descriptor denoted by status-fd will be closed. Dexopt commands on
+// the form
+//
+//   "dexopt" [dexopt-params]
+//
+// are then read from stdin until EOF and passed on to /system/bin/otapreopt one
+// by one. After each call a line with the current command count is written to
+// stdout and flushed.
 static int otapreopt_chroot(const int argc, char **arg) {
     // Validate arguments
-    // We need the command, status channel and target slot, at a minimum.
-    if(argc < 3) {
-        PLOG(ERROR) << "Not enough arguments.";
+    if (argc == 2 && std::string_view(arg[1]) == "--version") {
+        // Accept a single --version flag, to allow the script to tell this binary
+        // from the earlier one.
+        std::cout << "2" << std::endl;
+        return 0;
+    }
+    if (argc != 3) {
+        LOG(ERROR) << "Wrong number of arguments: " << argc;
         exit(208);
     }
-    // Close all file descriptors. They are coming from the caller, we do not want to pass them
-    // on across our fork/exec into a different domain.
-    // 1) Default descriptors.
-    CloseDescriptor(STDIN_FILENO);
-    CloseDescriptor(STDOUT_FILENO);
-    CloseDescriptor(STDERR_FILENO);
-    // 2) The status channel.
-    CloseDescriptor(arg[1]);
+    const char* status_fd = arg[1];
+    const char* slot_suffix = arg[2];
+
+    // Set O_CLOEXEC on standard fds. They are coming from the caller, we do not
+    // want to pass them on across our fork/exec into a different domain.
+    SetCloseOnExec(STDIN_FILENO);
+    SetCloseOnExec(STDOUT_FILENO);
+    SetCloseOnExec(STDERR_FILENO);
+    // Close the status channel.
+    CloseDescriptor(status_fd);
 
     // We need to run the otapreopt tool from the postinstall partition. As such, set up a
     // mount namespace and change root.
@@ -185,20 +206,20 @@
     //  2) We're in a mount namespace here, so when we die, this will be cleaned up.
     //  3) Ignore errors. Printing anything at this stage will open a file descriptor
     //     for logging.
-    if (!ValidateTargetSlotSuffix(arg[2])) {
-        LOG(ERROR) << "Target slot suffix not legal: " << arg[2];
+    if (!ValidateTargetSlotSuffix(slot_suffix)) {
+        LOG(ERROR) << "Target slot suffix not legal: " << slot_suffix;
         exit(207);
     }
-    TryExtraMount("vendor", arg[2], "/postinstall/vendor");
+    TryExtraMount("vendor", slot_suffix, "/postinstall/vendor");
 
     // Try to mount the product partition. update_engine doesn't do this for us, but we
     // want it for product APKs. Same notes as vendor above.
-    TryExtraMount("product", arg[2], "/postinstall/product");
+    TryExtraMount("product", slot_suffix, "/postinstall/product");
 
     // Try to mount the system_ext partition. update_engine doesn't do this for
     // us, but we want it for system_ext APKs. Same notes as vendor and product
     // above.
-    TryExtraMount("system_ext", arg[2], "/postinstall/system_ext");
+    TryExtraMount("system_ext", slot_suffix, "/postinstall/system_ext");
 
     constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
     // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
@@ -329,30 +350,37 @@
         exit(218);
     }
 
-    // Now go on and run otapreopt.
+    // Now go on and read dexopt lines from stdin and pass them on to otapreopt.
 
-    // Incoming:  cmd + status-fd + target-slot + cmd...      | Incoming | = argc
-    // Outgoing:  cmd             + target-slot + cmd...      | Outgoing | = argc - 1
-    std::vector<std::string> cmd;
-    cmd.reserve(argc);
-    cmd.push_back("/system/bin/otapreopt");
+    int count = 1;
+    for (std::array<char, 1000> linebuf;
+         std::cin.clear(), std::cin.getline(&linebuf[0], linebuf.size()); ++count) {
+        // Subtract one from gcount() since getline() counts the newline.
+        std::string line(&linebuf[0], std::cin.gcount() - 1);
 
-    // The first parameter is the status file descriptor, skip.
-    for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
-        cmd.push_back(arg[i]);
+        if (std::cin.fail()) {
+            LOG(ERROR) << "Command exceeds max length " << linebuf.size() << " - skipped: " << line;
+            continue;
+        }
+
+        std::vector<std::string> tokenized_line = android::base::Tokenize(line, " ");
+        std::vector<std::string> cmd{"/system/bin/otapreopt", slot_suffix};
+        std::move(tokenized_line.begin(), tokenized_line.end(), std::back_inserter(cmd));
+
+        LOG(INFO) << "Command " << count << ": " << android::base::Join(cmd, " ");
+
+        // Fork and execute otapreopt in its own process.
+        std::string error_msg;
+        bool exec_result = Exec(cmd, &error_msg);
+        if (!exec_result) {
+            LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+        }
+
+        // Print the count to stdout and flush to indicate progress.
+        std::cout << count << std::endl;
     }
 
-    // Fork and execute otapreopt in its own process.
-    std::string error_msg;
-    bool exec_result = Exec(cmd, &error_msg);
-    if (!exec_result) {
-        LOG(ERROR) << "Running otapreopt failed: " << error_msg;
-    }
-
-    if (!exec_result) {
-        exit(213);
-    }
-
+    LOG(INFO) << "No more dexopt commands";
     return 0;
 }
 
diff --git a/cmds/installd/otapreopt_script.sh b/cmds/installd/otapreopt_script.sh
index db5c34e..28bd793 100644
--- a/cmds/installd/otapreopt_script.sh
+++ b/cmds/installd/otapreopt_script.sh
@@ -16,7 +16,9 @@
 # limitations under the License.
 #
 
-# This script will run as a postinstall step to drive otapreopt.
+# This script runs as a postinstall step to drive otapreopt. It comes with the
+# OTA package, but runs /system/bin/otapreopt_chroot in the (old) active system
+# image. See system/extras/postinst/postinst.sh for some docs.
 
 TARGET_SLOT="$1"
 STATUS_FD="$2"
@@ -31,12 +33,11 @@
 
 BOOT_COMPLETE=$(getprop $BOOT_PROPERTY_NAME)
 if [ "$BOOT_COMPLETE" != "1" ] ; then
-  echo "Error: boot-complete not detected."
+  echo "$0: Error: boot-complete not detected."
   # We must return 0 to not block sideload.
   exit 0
 fi
 
-
 # Compute target slot suffix.
 # TODO: Once bootctl is not restricted, we should query from there. Or get this from
 #       update_engine as a parameter.
@@ -45,45 +46,63 @@
 elif [ "$TARGET_SLOT" = "1" ] ; then
   TARGET_SLOT_SUFFIX="_b"
 else
-  echo "Unknown target slot $TARGET_SLOT"
+  echo "$0: Unknown target slot $TARGET_SLOT"
   exit 1
 fi
 
+if [ "$(/system/bin/otapreopt_chroot --version)" != 2 ]; then
+  # We require an updated chroot wrapper that reads dexopt commands from stdin.
+  # Even if we kept compat with the old binary, the OTA preopt wouldn't work due
+  # to missing sepolicy rules, so there's no use spending time trying to dexopt
+  # (b/291974157).
+  echo "$0: Current system image is too old to work with OTA preopt - skipping."
+  exit 0
+fi
 
 PREPARE=$(cmd otadexopt prepare)
 # Note: Ignore preparation failures. Step and done will fail and exit this.
 #       This is necessary to support suspends - the OTA service will keep
 #       the state around for us.
 
-PROGRESS=$(cmd otadexopt progress)
-print -u${STATUS_FD} "global_progress $PROGRESS"
-
-i=0
-while ((i<MAXIMUM_PACKAGES)) ; do
+# Create an array with all dexopt commands in advance, to know how many there are.
+otadexopt_cmds=()
+while (( ${#otadexopt_cmds[@]} < MAXIMUM_PACKAGES )) ; do
   DONE=$(cmd otadexopt done)
   if [ "$DONE" = "OTA complete." ] ; then
     break
   fi
-
-  DEXOPT_PARAMS=$(cmd otadexopt next)
-
-  /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX $DEXOPT_PARAMS >&- 2>&-
-
-  PROGRESS=$(cmd otadexopt progress)
-  print -u${STATUS_FD} "global_progress $PROGRESS"
-
-  sleep 1
-  i=$((i+1))
+  otadexopt_cmds+=("$(cmd otadexopt next)")
 done
 
 DONE=$(cmd otadexopt done)
+cmd otadexopt cleanup
+
+echo "$0: Using streaming otapreopt_chroot on ${#otadexopt_cmds[@]} packages"
+
+function print_otadexopt_cmds {
+  for cmd in "${otadexopt_cmds[@]}" ; do
+    print "$cmd"
+  done
+}
+
+function report_progress {
+  while read count ; do
+    # mksh can't do floating point arithmetic, so emulate a fixed point calculation.
+    (( permilles = 1000 * count / ${#otadexopt_cmds[@]} ))
+    printf 'global_progress %d.%03d\n' $((permilles / 1000)) $((permilles % 1000)) >&${STATUS_FD}
+  done
+}
+
+print_otadexopt_cmds | \
+  /system/bin/otapreopt_chroot $STATUS_FD $TARGET_SLOT_SUFFIX | \
+  report_progress
+
 if [ "$DONE" = "OTA incomplete." ] ; then
-  echo "Incomplete."
+  echo "$0: Incomplete."
 else
-  echo "Complete or error."
+  echo "$0: Complete or error."
 fi
 
 print -u${STATUS_FD} "global_progress 1.0"
-cmd otadexopt cleanup
 
 exit 0
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index 07f73b9..61fe316 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -77,10 +77,8 @@
     },
 }
 
-cc_test {
-    name: "installd_service_test",
-    test_suites: ["device-tests"],
-    srcs: ["installd_service_test.cpp"],
+cc_defaults {
+    name: "installd_service_test_defaults",
     cflags: [
         "-Wall",
         "-Werror",
@@ -106,8 +104,6 @@
         "liblogwrap",
         "libc++fs",
     ],
-    test_config: "installd_service_test.xml",
-
     product_variables: {
         arc: {
             exclude_srcs: [
@@ -125,6 +121,14 @@
 }
 
 cc_test {
+    name: "installd_service_test",
+    test_suites: ["device-tests"],
+    srcs: ["installd_service_test.cpp"],
+    defaults: ["installd_service_test_defaults"],
+    test_config: "installd_service_test.xml",
+}
+
+cc_test {
     name: "installd_dexopt_test",
     test_suites: ["device-tests"],
     srcs: ["installd_dexopt_test.cpp"],
@@ -209,3 +213,19 @@
         "liblog",
     ],
 }
+
+cc_fuzz {
+    name: "installd_service_fuzzer",
+    defaults: [
+        "service_fuzzer_defaults",
+        "fuzzer_disable_leaks",
+        "installd_service_test_defaults",
+    ],
+    srcs: ["fuzzers/InstalldServiceFuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "android-package-manager-team@google.com",
+        ],
+        triage_assignee: "waghpawan@google.com",
+    },
+}
diff --git a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
new file mode 100644
index 0000000..b1c6940
--- /dev/null
+++ b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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 <fuzzbinder/libbinder_driver.h>
+
+#include "InstalldNativeService.h"
+#include "dexopt.h"
+
+using ::android::fuzzService;
+using ::android::sp;
+using ::android::installd::InstalldNativeService;
+
+namespace android {
+namespace installd {
+
+bool calculate_oat_file_path(char path[PKG_PATH_MAX], const char* oat_dir, const char* apk_path,
+                             const char* instruction_set) {
+    return calculate_oat_file_path_default(path, oat_dir, apk_path, instruction_set);
+}
+
+bool calculate_odex_file_path(char path[PKG_PATH_MAX], const char* apk_path,
+                              const char* instruction_set) {
+    return calculate_odex_file_path_default(path, apk_path, instruction_set);
+}
+
+bool create_cache_path(char path[PKG_PATH_MAX], const char* src, const char* instruction_set) {
+    return create_cache_path_default(path, src, instruction_set);
+}
+
+bool force_compile_without_image() {
+    return false;
+}
+
+} // namespace installd
+} // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto service = sp<InstalldNativeService>::make();
+    fuzzService(service, FuzzedDataProvider(data, size));
+    return 0;
+}
\ No newline at end of file
diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h
index ecea1d2..c43fdbd 100644
--- a/cmds/installd/utils.h
+++ b/cmds/installd/utils.h
@@ -18,6 +18,7 @@
 #ifndef UTILS_H_
 #define UTILS_H_
 
+#include <functional>
 #include <string>
 #include <vector>
 
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
index af85666..d0e4b74 100644
--- a/cmds/lshal/libprocpartition/Android.bp
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -37,4 +37,8 @@
         "include",
     ],
     min_sdk_version: "30",
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.neuralnetworks",
+    ],
 }
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index fb69513..d73a30b 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -93,22 +93,9 @@
         libfuzzer_options: [
             "max_len=50000",
         ],
-    },
-}
-
-// Adding this new fuzzer to test the corpus generated by record_binder
-cc_fuzz {
-    name: "servicemanager_test_fuzzer",
-    defaults: [
-        "servicemanager_defaults",
-        "service_fuzzer_defaults",
-    ],
-    host_supported: true,
-    srcs: ["fuzzers/ServiceManagerTestFuzzer.cpp"],
-    fuzz_config: {
-        libfuzzer_options: [
-            "max_len=50000",
+        cc: [
+            "smoreland@google.com",
+            "waghpawan@google.com",
         ],
     },
-    corpus: ["fuzzers/servicemamanager_fuzzer_corpus/*"],
 }
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 63f3821..f6e4ec3 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -301,7 +301,7 @@
     }
 
     if (!out && startIfNotFound) {
-        tryStartService(name);
+        tryStartService(ctx, name);
     }
 
     if (out) {
@@ -372,8 +372,10 @@
     }
 
     auto it = mNameToService.find(name);
+    bool prevClients = false;
     if (it != mNameToService.end()) {
         const Service& existing = it->second;
+        prevClients = existing.hasClients;
 
         // We could do better than this because if the other service dies, it
         // may not have an entry here. However, this case is unlikely. We are
@@ -401,12 +403,14 @@
             .binder = binder,
             .allowIsolated = allowIsolated,
             .dumpPriority = dumpPriority,
+            .hasClients = prevClients, // see b/279898063, matters if existing callbacks
+            .guaranteeClient = false,
             .ctx = ctx,
     };
 
     if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) {
-        // See also getService - handles case where client never gets the service,
-        // we want the service to quit.
+        // If someone is currently waiting on the service, notify the service that
+        // we're waiting and flush it to the service.
         mNameToService[name].guaranteeClient = true;
         CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false));
         mNameToService[name].guaranteeClient = true;
@@ -633,6 +637,14 @@
 void ServiceManager::binderDied(const wp<IBinder>& who) {
     for (auto it = mNameToService.begin(); it != mNameToService.end();) {
         if (who == it->second.binder) {
+            // TODO: currently, this entry contains the state also
+            // associated with mNameToClientCallback. If we allowed
+            // other processes to register client callbacks, we
+            // would have to preserve hasClients (perhaps moving
+            // that state into mNameToClientCallback, which is complicated
+            // because those callbacks are associated w/ particular binder
+            // objects, though they are indexed by name now, they may
+            // need to be indexed by binder at that point).
             it = mNameToService.erase(it);
         } else {
             ++it;
@@ -648,10 +660,11 @@
     }
 }
 
-void ServiceManager::tryStartService(const std::string& name) {
-    ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not "
-          "configured to be a lazy service, it may be stuck starting or still starting).",
-          name.c_str());
+void ServiceManager::tryStartService(const Access::CallingContext& ctx, const std::string& name) {
+    ALOGI("Since '%s' could not be found (requested by debug pid %d), trying to start it as a lazy "
+          "AIDL service. (if it's not configured to be a lazy service, it may be stuck starting or "
+          "still starting).",
+          name.c_str(), ctx.debugPid);
 
     std::thread([=] {
         if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
@@ -700,13 +713,21 @@
         return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
     }
 
-    // make sure all callbacks have been told about a consistent state - b/278038751
+    // WARNING: binderDied makes an assumption about this. If we open up client
+    // callbacks to other services, certain race conditions may lead to services
+    // getting extra client callback notifications.
+    // Make sure all callbacks have been told about a consistent state - b/278038751
     if (serviceIt->second.hasClients) {
         cb->onClients(service, true);
     }
 
     mNameToClientCallback[name].push_back(cb);
 
+    // Flush updated info to client callbacks (especially if guaranteeClient
+    // and !hasClient, see b/285202885). We may or may not have clients at
+    // this point, so ignore the return value.
+    (void)handleServiceClientCallback(2 /* sm + transaction */, name, false);
+
     return Status::ok();
 }
 
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 3aa6731..3b925a4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -67,7 +67,7 @@
     void clear();
 
 protected:
-    virtual void tryStartService(const std::string& name);
+    virtual void tryStartService(const Access::CallingContext& ctx, const std::string& name);
 
 private:
     struct Service {
diff --git a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp b/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
deleted file mode 100644
index e19b6eb..0000000
--- a/cmds/servicemanager/fuzzers/ServiceManagerTestFuzzer.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 <fuzzbinder/libbinder_driver.h>
-#include <utils/StrongPointer.h>
-
-#include "Access.h"
-#include "ServiceManager.h"
-
-using ::android::Access;
-using ::android::Parcel;
-using ::android::ServiceManager;
-using ::android::sp;
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    FuzzedDataProvider provider(data, size);
-    auto accessPtr = std::make_unique<Access>();
-    auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
-
-    // Reserved bytes
-    provider.ConsumeBytes<uint8_t>(8);
-    uint32_t code = provider.ConsumeIntegral<uint32_t>();
-    uint32_t flag = provider.ConsumeIntegral<uint32_t>();
-    std::vector<uint8_t> parcelData = provider.ConsumeRemainingBytes<uint8_t>();
-
-    Parcel inputParcel;
-    inputParcel.setData(parcelData.data(), parcelData.size());
-
-    Parcel reply;
-    serviceManager->transact(code, inputParcel, &reply, flag);
-
-    serviceManager->clear();
-
-    return 0;
-}
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_1
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_10
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_11
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_12
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_13
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_14
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_15
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_16
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_17
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_18
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_19
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
deleted file mode 100644
index e69ab49..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_2
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_20
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_21
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_22
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_23
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_24
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_25
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_26
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_27
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_28
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_29
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_3
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_30
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_31
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_32
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_33
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_34
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_35
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
deleted file mode 100644
index 88ad474..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_36
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
deleted file mode 100644
index fae15a2..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_37
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_38
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
deleted file mode 100644
index b326907..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_39
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
deleted file mode 100644
index 05b27bf..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_4
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_40
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
deleted file mode 100644
index b326907..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_41
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
deleted file mode 100644
index cdaa1f0..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_42
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
deleted file mode 100644
index ff0941b..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_43
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
deleted file mode 100644
index cdaa1f0..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_44
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_45
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
deleted file mode 100644
index 7e5f948..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_46
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_5
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_6
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_7
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
deleted file mode 100644
index 07319f8..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_8
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9 b/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
deleted file mode 100644
index 39e5104..0000000
--- a/cmds/servicemanager/fuzzers/servicemanager_fuzzer_corpus/Transaction_9
+++ /dev/null
Binary files differ
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index c1a04dd..86a45e61 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -131,7 +131,9 @@
     }
 
     IPCThreadState::self()->setTheContextObject(manager);
-    ps->becomeContextManager();
+    if (!ps->becomeContextManager()) {
+        LOG(FATAL) << "Could not become context manager";
+    }
 
     sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
 
diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc
index b927c01..6354fd7 100644
--- a/cmds/servicemanager/servicemanager.recovery.rc
+++ b/cmds/servicemanager/servicemanager.recovery.rc
@@ -1,5 +1,6 @@
 service servicemanager /system/bin/servicemanager
     disabled
     group system readproc
+    user root
     onrestart setprop servicemanager.ready false
     seclabel u:r:servicemanager:s0
diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp
index cae32e3..97e500d 100644
--- a/cmds/servicemanager/test_sm.cpp
+++ b/cmds/servicemanager/test_sm.cpp
@@ -27,11 +27,14 @@
 #include "Access.h"
 #include "ServiceManager.h"
 
-using android::sp;
 using android::Access;
 using android::BBinder;
 using android::IBinder;
 using android::ServiceManager;
+using android::sp;
+using android::base::EndsWith;
+using android::base::GetProperty;
+using android::base::StartsWith;
 using android::binder::Status;
 using android::os::BnServiceCallback;
 using android::os::IServiceManager;
@@ -62,7 +65,7 @@
 class MockServiceManager : public ServiceManager {
  public:
     MockServiceManager(std::unique_ptr<Access>&& access) : ServiceManager(std::move(access)) {}
-    MOCK_METHOD1(tryStartService, void(const std::string& name));
+    MOCK_METHOD2(tryStartService, void(const Access::CallingContext&, const std::string& name));
 };
 
 static sp<ServiceManager> getPermissiveServiceManager() {
@@ -77,9 +80,11 @@
     return sm;
 }
 
-static bool isCuttlefish() {
-    return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""),
-                                     "vsoc_");
+// Determines if test device is a cuttlefish phone device
+static bool isCuttlefishPhone() {
+    auto device = GetProperty("ro.product.vendor.device", "");
+    auto product = GetProperty("ro.product.vendor.name", "");
+    return StartsWith(device, "vsoc_") && EndsWith(product, "_phone");
 }
 
 TEST(AddService, HappyHappy) {
@@ -314,7 +319,7 @@
 }
 
 TEST(Vintf, UpdatableViaApex) {
-    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+    if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices";
 
     auto sm = getPermissiveServiceManager();
     std::optional<std::string> updatableViaApex;
@@ -326,7 +331,7 @@
 }
 
 TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) {
-    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+    if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices";
 
     auto sm = getPermissiveServiceManager();
     std::optional<std::string> updatableViaApex;
@@ -337,7 +342,7 @@
 }
 
 TEST(Vintf, GetUpdatableNames) {
-    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+    if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices";
 
     auto sm = getPermissiveServiceManager();
     std::vector<std::string> names;
@@ -348,7 +353,7 @@
 }
 
 TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) {
-    if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices";
+    if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices";
 
     auto sm = getPermissiveServiceManager();
     std::vector<std::string> names;
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 226cae1..4327e28 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -263,6 +263,12 @@
 }
 
 prebuilt_etc {
+    name: "android.hardware.thread_network.prebuilt.xml",
+    src: "android.hardware.thread_network.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "android.hardware.usb.accessory.prebuilt.xml",
     src: "android.hardware.usb.accessory.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.thread_network.xml b/data/etc/android.hardware.thread_network.xml
new file mode 100644
index 0000000..b116ed6
--- /dev/null
+++ b/data/etc/android.hardware.thread_network.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<!-- Adds the feature indicating support for the Thread networking protocol -->
+<permissions>
+    <feature name="android.hardware.thread_network" />
+</permissions>
diff --git a/libs/arect/Android.bp b/libs/arect/Android.bp
index 5e539f2..1a9766d 100644
--- a/libs/arect/Android.bp
+++ b/libs/arect/Android.bp
@@ -72,6 +72,7 @@
         "//apex_available:platform",
         "com.android.media",
         "com.android.media.swcodec",
+        "com.android.neuralnetworks",
     ],
 
 }
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 49dd9c7..6c2b313 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -144,10 +144,6 @@
         "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
     ],
     product_variables: {
-        binder32bit: {
-            cflags: ["-DBINDER_IPC_32BIT=1"],
-        },
-
         debuggable: {
             cflags: [
                 "-DBINDER_RPC_DEV_SERVERS",
@@ -194,6 +190,9 @@
         "-performance-move-const-arg", // b/273486801
         "portability*",
     ],
+    lto: {
+        thin: true,
+    },
 }
 
 cc_library_headers {
@@ -285,14 +284,6 @@
     cflags: [
         "-DBINDER_WITH_KERNEL_IPC",
     ],
-    arch: {
-        // TODO(b/254713216): undefined symbol in BufferedTextOutput::getBuffer
-        riscv64: {
-            lto: {
-                thin: false,
-            },
-        },
-    },
 }
 
 cc_library {
@@ -531,7 +522,6 @@
         "libbase",
         "libbinder",
         "libbinder_ndk",
-        "libcutils_sockets",
         "liblog",
         "libutils",
     ],
@@ -548,6 +538,7 @@
         ":__subpackages__",
         "//packages/modules/Virtualization/javalib/jni",
         "//packages/modules/Virtualization/vm_payload",
+        "//packages/modules/Virtualization/demo_native",
         "//device/google/cuttlefish/shared/minidroid:__subpackages__",
         "//system/software_defined_vehicle:__subpackages__",
     ],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 3e49656..0f4a6ca 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -58,15 +58,15 @@
 
 // global b/c b/230079120 - consistent symbol table
 #ifdef BINDER_RPC_DEV_SERVERS
-bool kEnableRpcDevServers = true;
+constexpr bool kEnableRpcDevServers = true;
 #else
-bool kEnableRpcDevServers = false;
+constexpr bool kEnableRpcDevServers = false;
 #endif
 
 #ifdef BINDER_ENABLE_RECORDING
-bool kEnableRecording = true;
+constexpr bool kEnableRecording = true;
 #else
-bool kEnableRecording = false;
+constexpr bool kEnableRecording = false;
 #endif
 
 // Log any reply transactions for which the data exceeds this size
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index f66993f..7644806 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -324,6 +324,10 @@
     return *registrarInstance;
 }
 
+LazyServiceRegistrar LazyServiceRegistrar::createExtraTestInstance() {
+    return LazyServiceRegistrar();
+}
+
 status_t LazyServiceRegistrar::registerService(const sp<IBinder>& service, const std::string& name,
                                                bool allowIsolated, int dumpFlags) {
     if (!mClientCC->registerService(service, name, allowIsolated, dumpFlags)) {
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 8fe1d2b..3da06ba 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -78,7 +78,7 @@
         if (SEAL_FLAGS && (fcntl(fd, F_ADD_SEALS, SEAL_FLAGS) == -1)) {
             ALOGE("MemoryHeapBase: MemFD %s sealing with flags %x failed with error  %s", name,
                   SEAL_FLAGS, strerror(errno));
-            munmap(mBase, mSize);
+            if (mNeedUnmap) munmap(mBase, mSize);
             mBase = nullptr;
             mSize = 0;
             close(fd);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 0aca163..9b685f9 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -947,7 +947,10 @@
         threadState->setCallingWorkSourceUidWithoutPropagation(workSource);
         // vendor header
         int32_t header = readInt32();
-        if (header != kHeader) {
+
+        // fuzzers skip this check, because it is for protecting the underlying ABI, but
+        // we don't want it to reduce our coverage
+        if (header != kHeader && !mServiceFuzzing) {
             ALOGE("Expecting header 0x%x but found 0x%x. Mixing copies of libbinder?", kHeader,
                   header);
             return false;
@@ -966,10 +969,18 @@
             (!len || !memcmp(parcel_interface, interface, len * sizeof (char16_t)))) {
         return true;
     } else {
-        ALOGW("**** enforceInterface() expected '%s' but read '%s'",
-              String8(interface, len).string(),
-              String8(parcel_interface, parcel_interface_len).string());
-        return false;
+        if (mServiceFuzzing) {
+            // ignore. Theoretically, this could cause a few false positives, because
+            // people could assume things about getInterfaceDescriptor if they pass
+            // this point, but it would be extremely fragile. It's more important that
+            // we fuzz with the above things read from the Parcel.
+            return true;
+        } else {
+            ALOGW("**** enforceInterface() expected '%s' but read '%s'",
+                  String8(interface, len).string(),
+                  String8(parcel_interface, parcel_interface_len).string());
+            return false;
+        }
     }
 }
 
@@ -977,6 +988,14 @@
     mEnforceNoDataAvail = enforceNoDataAvail;
 }
 
+void Parcel::setServiceFuzzing() {
+    mServiceFuzzing = true;
+}
+
+bool Parcel::isServiceFuzzing() const {
+    return mServiceFuzzing;
+}
+
 binder::Status Parcel::enforceNoDataAvail() const {
     if (!mEnforceNoDataAvail) {
         return binder::Status::ok();
@@ -1722,7 +1741,9 @@
             do {
                 if (mDataPos < kernelFields->mObjects[nextObject] + sizeof(flat_binder_object)) {
                     // Requested info overlaps with an object
-                    ALOGE("Attempt to read from protected data in Parcel %p", this);
+                    if (!mServiceFuzzing) {
+                        ALOGE("Attempt to read from protected data in Parcel %p", this);
+                    }
                     return PERMISSION_DENIED;
                 }
                 nextObject++;
@@ -2092,7 +2113,11 @@
     size_t len;
     const char* str = readString8Inplace(&len);
     if (str) return String8(str, len);
-    ALOGE("Reading a NULL string not supported here.");
+
+    if (!mServiceFuzzing) {
+        ALOGE("Reading a NULL string not supported here.");
+    }
+
     return String8();
 }
 
@@ -2132,7 +2157,11 @@
     size_t len;
     const char16_t* str = readString16Inplace(&len);
     if (str) return String16(str, len);
-    ALOGE("Reading a NULL string not supported here.");
+
+    if (!mServiceFuzzing) {
+        ALOGE("Reading a NULL string not supported here.");
+    }
+
     return String16();
 }
 
@@ -2172,7 +2201,9 @@
 {
     status_t status = readNullableStrongBinder(val);
     if (status == OK && !val->get()) {
-        ALOGW("Expecting binder but got null!");
+        if (!mServiceFuzzing) {
+            ALOGW("Expecting binder but got null!");
+        }
         status = UNEXPECTED_NULL;
     }
     return status;
@@ -2237,9 +2268,11 @@
     if (const auto* rpcFields = maybeRpcFields()) {
         if (!std::binary_search(rpcFields->mObjectPositions.begin(),
                                 rpcFields->mObjectPositions.end(), mDataPos)) {
-            ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in the "
-                  "object list",
-                  this, mDataPos);
+            if (!mServiceFuzzing) {
+                ALOGW("Attempt to read file descriptor from Parcel %p at offset %zu that is not in "
+                      "the object list",
+                      this, mDataPos);
+            }
             return BAD_TYPE;
         }
 
@@ -2497,8 +2530,11 @@
                 return obj;
             }
         }
-        ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object list",
-             this, DPOS);
+        if (!mServiceFuzzing) {
+            ALOGW("Attempt to read object from Parcel %p at offset %zu that is not in the object "
+                  "list",
+                  this, DPOS);
+        }
     }
     return nullptr;
 }
@@ -3093,6 +3129,7 @@
     mDeallocZero = false;
     mOwner = nullptr;
     mEnforceNoDataAvail = true;
+    mServiceFuzzing = false;
 }
 
 void Parcel::scanForFds() const {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 5f1f506..02b0447 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -104,14 +104,7 @@
     return access("/vendor/bin/vndservicemanager", R_OK) == 0;
 }
 
-sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
-{
-#ifdef BINDER_IPC_32BIT
-    LOG_ALWAYS_FATAL("32-bit binder IPC is not supported for new devices starting in Android P. If "
-                     "you do need to use this mode, please see b/232423610 or file an issue with "
-                     "AOSP upstream as otherwise this will be removed soon.");
-#endif
-
+sp<ProcessState> ProcessState::init(const char* driver, bool requireDefault) {
     if (driver == nullptr) {
         std::lock_guard<std::mutex> l(gProcessMutex);
         if (gProcess) {
@@ -199,6 +192,7 @@
     AutoMutex _l(mLock);
     if (!mThreadPoolStarted) {
         if (mMaxThreads == 0) {
+            // see also getThreadPoolMaxTotalThreadCount
             ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
                   "*startThreadPool when zero threads are requested.");
         }
@@ -414,6 +408,11 @@
         mKernelStartedThreads++;
         pthread_mutex_unlock(&mThreadCountLock);
     }
+    // TODO: if startThreadPool is called on another thread after the process
+    // starts up, the kernel might think that it already requested those
+    // binder threads, and additional won't be started. This is likely to
+    // cause deadlocks, and it will also cause getThreadPoolMaxTotalThreadCount
+    // to return too high of a value.
 }
 
 status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
@@ -433,12 +432,32 @@
     pthread_mutex_lock(&mThreadCountLock);
     base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); };
 
-    // may actually be one more than this, if join is called
     if (mThreadPoolStarted) {
-        return mCurrentThreads < mKernelStartedThreads
-                ? mMaxThreads
-                : mMaxThreads + mCurrentThreads - mKernelStartedThreads;
+        LOG_ALWAYS_FATAL_IF(mKernelStartedThreads > mMaxThreads + 1,
+                            "too many kernel-started threads: %zu > %zu + 1", mKernelStartedThreads,
+                            mMaxThreads);
+
+        // calling startThreadPool starts a thread
+        size_t threads = 1;
+
+        // the kernel is configured to start up to mMaxThreads more threads
+        threads += mMaxThreads;
+
+        // Users may call IPCThreadState::joinThreadPool directly. We don't
+        // currently have a way to count this directly (it could be added by
+        // adding a separate private joinKernelThread method in IPCThreadState).
+        // So, if we are in a race between the kernel thread variable being
+        // incremented in this file and mCurrentThreads being incremented
+        // in IPCThreadState, temporarily forget about the extra join threads.
+        // This is okay, because most callers of this method only care about
+        // having 0, 1, or more threads.
+        if (mCurrentThreads > mKernelStartedThreads) {
+            threads += mCurrentThreads - mKernelStartedThreads;
+        }
+
+        return threads;
     }
+
     // must not be initialized or maybe has poll thread setup, we
     // currently don't track this in libbinder
     LOG_ALWAYS_FATAL_IF(mKernelStartedThreads != 0,
diff --git a/libs/binder/RecordedTransaction.cpp b/libs/binder/RecordedTransaction.cpp
index 1c76135..44a9e3b 100644
--- a/libs/binder/RecordedTransaction.cpp
+++ b/libs/binder/RecordedTransaction.cpp
@@ -161,17 +161,6 @@
 constexpr uint32_t kMaxChunkDataSize = 0xfffffff0;
 typedef uint64_t transaction_checksum_t;
 
-static android::status_t readChunkDescriptor(borrowed_fd fd, ChunkDescriptor* chunkOut,
-                                             transaction_checksum_t* sum) {
-    if (!android::base::ReadFully(fd, chunkOut, sizeof(ChunkDescriptor))) {
-        LOG(ERROR) << "Failed to read Chunk Descriptor from fd " << fd.get();
-        return android::UNKNOWN_ERROR;
-    }
-
-    *sum ^= *reinterpret_cast<transaction_checksum_t*>(chunkOut);
-    return android::NO_ERROR;
-}
-
 std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) {
     RecordedTransaction t;
     ChunkDescriptor chunk;
@@ -192,11 +181,13 @@
             LOG(ERROR) << "Not enough file remains to contain expected chunk descriptor";
             return std::nullopt;
         }
-        transaction_checksum_t checksum = 0;
-        if (NO_ERROR != readChunkDescriptor(fd, &chunk, &checksum)) {
-            LOG(ERROR) << "Failed to read chunk descriptor.";
+
+        if (!android::base::ReadFully(fd, &chunk, sizeof(ChunkDescriptor))) {
+            LOG(ERROR) << "Failed to read ChunkDescriptor from fd " << fd.get() << ". "
+                       << strerror(errno);
             return std::nullopt;
         }
+        transaction_checksum_t checksum = *reinterpret_cast<transaction_checksum_t*>(&chunk);
 
         fdCurrentPosition = lseek(fd.get(), 0, SEEK_CUR);
         if (fdCurrentPosition == -1) {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 9282856..55fc16d 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -81,6 +81,7 @@
     auto aiStart = InetSocketAddress::getAddrInfo(address, port);
     if (aiStart == nullptr) return UNKNOWN_ERROR;
     for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+        if (ai->ai_addr == nullptr) continue;
         InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
         if (status_t status = setupSocketServer(socketAddress); status != OK) {
             continue;
@@ -123,8 +124,13 @@
     return mMaxThreads;
 }
 
-void RpcServer::setProtocolVersion(uint32_t version) {
+bool RpcServer::setProtocolVersion(uint32_t version) {
+    if (!RpcState::validateProtocolVersion(version)) {
+        return false;
+    }
+
     mProtocolVersion = version;
+    return true;
 }
 
 void RpcServer::setSupportedFileDescriptorTransportModes(
@@ -148,7 +154,7 @@
     mRootObjectWeak = binder;
 }
 void RpcServer::setPerSessionRootObject(
-        std::function<sp<IBinder>(const void*, size_t)>&& makeObject) {
+        std::function<sp<IBinder>(wp<RpcSession> session, const void*, size_t)>&& makeObject) {
     RpcMutexLockGuard _l(mLock);
     mRootObject.clear();
     mRootObjectWeak.clear();
@@ -161,6 +167,12 @@
     mConnectionFilter = std::move(filter);
 }
 
+void RpcServer::setServerSocketModifier(std::function<void(base::borrowed_fd)>&& modifier) {
+    RpcMutexLockGuard _l(mLock);
+    LOG_ALWAYS_FATAL_IF(mServer.fd != -1, "Already started");
+    mServerSocketModifier = std::move(modifier);
+}
+
 sp<IBinder> RpcServer::getRootObject() {
     RpcMutexLockGuard _l(mLock);
     bool hasWeak = mRootObjectWeak.unsafe_get();
@@ -335,6 +347,8 @@
         mJoinThread.reset();
     }
 
+    mServer = RpcTransportFd();
+
     LOG_RPC_DETAIL("Finished waiting on shutdown.");
 
     mShutdownTrigger = nullptr;
@@ -501,7 +515,8 @@
             // if null, falls back to server root
             sp<IBinder> sessionSpecificRoot;
             if (server->mRootObjectFactory != nullptr) {
-                sessionSpecificRoot = server->mRootObjectFactory(addr.data(), addrLen);
+                sessionSpecificRoot =
+                        server->mRootObjectFactory(wp<RpcSession>(session), addr.data(), addrLen);
                 if (sessionSpecificRoot == nullptr) {
                     ALOGE("Warning: server returned null from root object factory");
                 }
@@ -556,6 +571,14 @@
         ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
         return -savedErrno;
     }
+
+    {
+        RpcMutexLockGuard _l(mLock);
+        if (mServerSocketModifier != nullptr) {
+            mServerSocketModifier(socket_fd);
+        }
+    }
+
     if (0 != TEMP_FAILURE_RETRY(bind(socket_fd.get(), addr.addr(), addr.addrSize()))) {
         int savedErrno = errno;
         ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index fbad0f7..c3dee16 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -104,11 +104,7 @@
 }
 
 bool RpcSession::setProtocolVersionInternal(uint32_t version, bool checkStarted) {
-    if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
-        version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
-        ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
-              "is %u).",
-              version, RPC_WIRE_PROTOCOL_VERSION);
+    if (!RpcState::validateProtocolVersion(version)) {
         return false;
     }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 03fa699..bac2808 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -34,6 +34,10 @@
 
 #include <inttypes.h>
 
+#ifdef __ANDROID__
+#include <cutils/properties.h>
+#endif
+
 namespace android {
 
 using base::StringPrintf;
@@ -59,6 +63,7 @@
         case RpcSession::FileDescriptorTransportMode::TRUSTY:
             return true;
     }
+    LOG_ALWAYS_FATAL("Invalid FileDescriptorTransportMode: %d", static_cast<int>(mode));
 }
 
 RpcState::RpcState() {}
@@ -398,6 +403,31 @@
     return OK;
 }
 
+bool RpcState::validateProtocolVersion(uint32_t version) {
+    if (version == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+#if defined(__ANDROID__)
+        char codename[PROPERTY_VALUE_MAX];
+        property_get("ro.build.version.codename", codename, "");
+        if (!strcmp(codename, "REL")) {
+            ALOGE("Cannot use experimental RPC binder protocol on a release branch.");
+            return false;
+        }
+#else
+        // don't restrict on other platforms, though experimental should
+        // only really be used for testing, we don't have a good way to see
+        // what is shipping outside of Android
+#endif
+    } else if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT) {
+        ALOGE("Cannot use RPC binder protocol version %u which is unknown (current protocol "
+              "version "
+              "is %u).",
+              version, RPC_WIRE_PROTOCOL_VERSION);
+        return false;
+    }
+
+    return true;
+}
+
 status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
                                           const sp<RpcSession>& session, uint32_t* version) {
     RpcNewSessionResponse response;
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 0e23ea7..1fe71a5 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -63,6 +63,8 @@
     RpcState();
     ~RpcState();
 
+    [[nodiscard]] static bool validateProtocolVersion(uint32_t version);
+
     [[nodiscard]] status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
                                                   const sp<RpcSession>& session, uint32_t* version);
     [[nodiscard]] status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index cd067bf..f3575cc 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -29,8 +29,6 @@
 
 namespace android {
 
-namespace {
-
 // RpcTransport with TLS disabled.
 class RpcTransportRaw : public RpcTransport {
 public:
@@ -96,8 +94,6 @@
     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
 };
 
-} // namespace
-
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
     return std::make_unique<RpcTransportCtxRaw>();
 }
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index d5a6da2..0c81d83 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -31,8 +31,6 @@
 
 namespace android {
 
-namespace {
-
 // RpcTransport for writing Trusty IPC clients in Android.
 class RpcTransportTipcAndroid : public RpcTransport {
 public:
@@ -217,8 +215,6 @@
     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
 };
 
-} // namespace
-
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcAndroid::newServerCtx() const {
     return std::make_unique<RpcTransportCtxTipcAndroid>();
 }
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 3e98ecc..785f6ce 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -275,6 +275,8 @@
     bssl::UniquePtr<SSL> mSsl;
 };
 
+} // namespace
+
 class RpcTransportTls : public RpcTransport {
 public:
     RpcTransportTls(RpcTransportFd socket, Ssl ssl)
@@ -411,7 +413,8 @@
 }
 
 // For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|.
-bool setFdAndDoHandshake(Ssl* ssl, const android::RpcTransportFd& socket, FdTrigger* fdTrigger) {
+static bool setFdAndDoHandshake(Ssl* ssl, const android::RpcTransportFd& socket,
+                                FdTrigger* fdTrigger) {
     bssl::UniquePtr<BIO> bio = newSocketBio(socket.fd);
     TEST_AND_RETURN(false, bio != nullptr);
     auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get());
@@ -540,8 +543,6 @@
     }
 };
 
-} // namespace
-
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
     return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier,
                                                                          mAuth.get());
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 0e8e187..2b3ff44 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,9 +16,15 @@
       "name": "binderDriverInterfaceTest"
     },
     {
+      "name": "binderRecordReplayTest"
+    },
+    {
       "name": "binderHostDeviceTest"
     },
     {
+      "name": "binderParcelBenchmark"
+    },
+    {
       "name": "binderTextOutputTest"
     },
     {
@@ -58,6 +64,9 @@
       "name": "libbinderthreadstateutils_test"
     },
     {
+      "name": "fuzz_service_test"
+    },
+    {
       "name": "CtsOsTestCases",
       "options": [
         {
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index d960a0b..744da0f 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -105,12 +105,6 @@
     [[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd,
                                              const sp<IBinder>& keepAliveBinder);
 
-    // Start recording transactions to the unique_fd in data.
-    // See RecordedTransaction.h for more details.
-    [[nodiscard]] status_t startRecordingTransactions(const Parcel& data);
-    // Stop the current recording.
-    [[nodiscard]] status_t stopRecordingTransactions();
-
 protected:
     virtual             ~BBinder();
 
@@ -131,6 +125,8 @@
 
     [[nodiscard]] status_t setRpcClientDebug(const Parcel& data);
     void removeRpcServerLink(const sp<RpcServerLink>& link);
+    [[nodiscard]] status_t startRecordingTransactions(const Parcel& data);
+    [[nodiscard]] status_t stopRecordingTransactions();
 
     std::atomic<Extras*> mExtras;
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index d261c21..9347ce4 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -147,7 +147,12 @@
             void                flushCommands();
             bool                flushIfNeeded();
 
-            // For main functions - dangerous for libraries to use
+            // Adds the current thread into the binder threadpool.
+            //
+            // This is in addition to any threads which are started
+            // with startThreadPool. Libraries should not call this
+            // function, as they may be loaded into processes which
+            // try to configure the threadpool differently.
             void                joinThreadPool(bool isMain = true);
             
             // Stop the local process.
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 2e22b84..bda3d19 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -93,7 +93,17 @@
       */
      void reRegister();
 
-   private:
+     /**
+      * Create a second instance of lazy service registrar.
+      *
+      * WARNING: dangerous! DO NOT USE THIS - LazyServiceRegistrar
+      * should be single-instanced, so that the service will only
+      * shut down when all services are unused. A separate instance
+      * is only used to test race conditions.
+      */
+     static LazyServiceRegistrar createExtraTestInstance();
+
+ private:
      std::shared_ptr<internal::ClientCounterCallback> mClientCC;
      LazyServiceRegistrar();
 };
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 162cd40..4e231ed 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -34,13 +34,8 @@
 #include <binder/IInterface.h>
 #include <binder/Parcelable.h>
 
-#ifdef BINDER_IPC_32BIT
-//NOLINTNEXTLINE(google-runtime-int) b/173188702
-typedef unsigned int binder_size_t;
-#else
 //NOLINTNEXTLINE(google-runtime-int) b/173188702
 typedef unsigned long long binder_size_t;
-#endif
 
 struct flat_binder_object;
 
@@ -154,6 +149,11 @@
     // This Api is used by fuzzers to skip dataAvail checks.
     void setEnforceNoDataAvail(bool enforceNoDataAvail);
 
+    // When fuzzing, we want to remove certain ABI checks that cause significant
+    // lost coverage, and we also want to avoid logs that cost too much to write.
+    void setServiceFuzzing();
+    bool isServiceFuzzing() const;
+
     void                freeData();
 
     size_t              objectsCount() const;
@@ -266,7 +266,8 @@
     status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
             { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val)
             { return writeData(val); }
     // Write an Enum vector with underlying type != int8_t.
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
@@ -276,17 +277,20 @@
     status_t            writeEnumVector(const std::optional<std::vector<T>>& val)
             { return writeData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val) __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            writeEnumVector(const std::unique_ptr<std::vector<T>>& val)
             { return writeData(val); }
 
     template<typename T>
     status_t            writeParcelableVector(const std::optional<std::vector<std::optional<T>>>& val)
             { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            writeParcelableVector(const std::unique_ptr<std::vector<std::unique_ptr<T>>>& val)
             { return writeData(val); }
     template<typename T>
-    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val) __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::unique_ptr<T>>>& val)
             { return writeData(val); }
     template<typename T>
     status_t            writeParcelableVector(const std::shared_ptr<std::vector<std::optional<T>>>& val)
@@ -422,7 +426,8 @@
     status_t            readEnumVector(std::vector<T>* val) const
             { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const
             { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            readEnumVector(std::optional<std::vector<T>>* val) const
@@ -432,7 +437,8 @@
     status_t            readEnumVector(std::vector<T>* val) const
             { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
-    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const __attribute__((deprecated("use std::optional version instead")))
+    [[deprecated("use std::optional version instead")]] //
+    status_t            readEnumVector(std::unique_ptr<std::vector<T>>* val) const
             { return readData(val); }
     template<typename T, std::enable_if_t<std::is_enum_v<T> && !std::is_same_v<typename std::underlying_type_t<T>,int8_t>, bool> = 0>
     status_t            readEnumVector(std::optional<std::vector<T>>* val) const
@@ -443,8 +449,9 @@
                             std::optional<std::vector<std::optional<T>>>* val) const
             { return readData(val); }
     template<typename T>
+    [[deprecated("use std::optional version instead")]] //
     status_t            readParcelableVector(
-                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const __attribute__((deprecated("use std::optional version instead")))
+                            std::unique_ptr<std::vector<std::unique_ptr<T>>>* val) const
             { return readData(val); }
     template<typename T>
     status_t            readParcelableVector(std::vector<T>* val) const
@@ -1335,6 +1342,7 @@
 
     // Set this to false to skip dataAvail checks.
     bool mEnforceNoDataAvail;
+    bool mServiceFuzzing;
 
     release_func        mOwner;
 
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index ce578e3..9dc370b 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -52,10 +52,29 @@
 
     sp<IBinder> getContextObject(const sp<IBinder>& caller);
 
-    // For main functions - dangerous for libraries to use
+    // This should be called before startThreadPool at the beginning
+    // of a program, and libraries should never call it because programs
+    // should configure their own threadpools. The threadpool size can
+    // never be decreased.
+    //
+    // The 'maxThreads' value refers to the total number of threads
+    // that will be started by the kernel. This is in addition to any
+    // threads started by 'startThreadPool' or 'joinRpcThreadpool'.
+    status_t setThreadPoolMaxThreadCount(size_t maxThreads);
+
+    // Libraries should not call this, as processes should configure
+    // threadpools themselves. Should be called in the main function
+    // directly before any code executes or joins the threadpool.
+    //
+    // Starts one thread, PLUS those requested in setThreadPoolMaxThreadCount,
+    // PLUS those manually requested in joinThreadPool.
+    //
+    // For instance, if setThreadPoolMaxCount(3) is called and
+    // startThreadpPool (+1 thread) and joinThreadPool (+1 thread)
+    // are all called, then up to 5 threads can be started.
     void startThreadPool();
 
-    bool becomeContextManager();
+    [[nodiscard]] bool becomeContextManager();
 
     sp<IBinder> getStrongProxyForHandle(int32_t handle);
     void expungeHandle(int32_t handle, IBinder* binder);
@@ -63,8 +82,6 @@
     // TODO: deprecate.
     void spawnPooledThread(bool isMain);
 
-    // For main functions - dangerous for libraries to use
-    status_t setThreadPoolMaxThreadCount(size_t maxThreads);
     status_t enableOnewaySpamDetection(bool enable);
 
     // Set the name of the current thread to look like a threadpool
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 1001b64..b804f7b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -137,7 +137,7 @@
      * used. However, this can be used in order to prevent newer protocol
      * versions from ever being used. This is expected to be useful for testing.
      */
-    void setProtocolVersion(uint32_t version);
+    [[nodiscard]] bool setProtocolVersion(uint32_t version);
 
     /**
      * Set the supported transports for sending and receiving file descriptors.
@@ -163,14 +163,18 @@
      * Allows a root object to be created for each session.
      *
      * Takes one argument: a callable that is invoked once per new session.
-     * The callable takes two arguments: a type-erased pointer to an OS- and
-     * transport-specific address structure, e.g., sockaddr_vm for vsock, and
-     * an integer representing the size in bytes of that structure. The
-     * callable should validate the size, then cast the type-erased pointer
-     * to a pointer to the actual type of the address, e.g., const void* to
-     * const sockaddr_vm*.
+     * The callable takes three arguments:
+     * - a weak pointer to the session. If you want to hold onto this in the root object, then
+     *   you should keep a weak pointer, and promote it when needed. For instance, if you refer
+     *   to this from the root object, then you could get ahold of transport-specific information.
+     * - a type-erased pointer to an OS- and transport-specific address structure, e.g.,
+     *   sockaddr_vm for vsock
+     * - an integer representing the size in bytes of that structure. The callable should
+     *   validate the size, then cast the type-erased pointer to a pointer to the actual type of the
+     *   address, e.g., const void* to const sockaddr_vm*.
      */
-    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object);
+    void setPerSessionRootObject(
+            std::function<sp<IBinder>(wp<RpcSession> session, const void*, size_t)>&& object);
     sp<IBinder> getRootObject();
 
     /**
@@ -184,6 +188,13 @@
     void setConnectionFilter(std::function<bool(const void*, size_t)>&& filter);
 
     /**
+     * Set optional modifier of each newly created server socket.
+     *
+     * The only argument is a successfully created file descriptor, not bound to an address yet.
+     */
+    void setServerSocketModifier(std::function<void(base::borrowed_fd)>&& modifier);
+
+    /**
      * See RpcTransportCtx::getCertificate
      */
     std::vector<uint8_t> getCertificate(RpcCertificateFormat);
@@ -265,8 +276,9 @@
 
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
-    std::function<sp<IBinder>(const void*, size_t)> mRootObjectFactory;
+    std::function<sp<IBinder>(wp<RpcSession>, const void*, size_t)> mRootObjectFactory;
     std::function<bool(const void*, size_t)> mConnectionFilter;
+    std::function<void(base::borrowed_fd)> mServerSocketModifier;
     std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
     RpcConditionVariable mShutdownCv;
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index fd52a3a..6db9ad9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -39,6 +39,16 @@
 class FdTrigger;
 struct RpcTransportFd;
 
+// for 'friend'
+class RpcTransportRaw;
+class RpcTransportTls;
+class RpcTransportTipcAndroid;
+class RpcTransportTipcTrusty;
+class RpcTransportCtxRaw;
+class RpcTransportCtxTls;
+class RpcTransportCtxTipcAndroid;
+class RpcTransportCtxTipcTrusty;
+
 // Represents a socket connection.
 // No thread-safety is guaranteed for these APIs.
 class RpcTransport {
@@ -92,7 +102,21 @@
      */
     [[nodiscard]] virtual bool isWaiting() = 0;
 
-protected:
+private:
+    // limit the classes which can implement RpcTransport. Being able to change this
+    // interface is important to allow development of RPC binder. In the past, we
+    // changed this interface to use iovec for efficiency, and we added FDs to the
+    // interface. If another transport is needed, it should be added directly here.
+    // non-socket FDs likely also need changes in RpcSession in order to get
+    // connected, and similarly to how addrinfo was type-erased from RPC binder
+    // interfaces when RpcTransportTipc* was added, other changes may be needed
+    // to add more transports.
+
+    friend class ::android::RpcTransportRaw;
+    friend class ::android::RpcTransportTls;
+    friend class ::android::RpcTransportTipcAndroid;
+    friend class ::android::RpcTransportTipcTrusty;
+
     RpcTransport() = default;
 };
 
@@ -117,7 +141,13 @@
     [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
             RpcCertificateFormat format) const = 0;
 
-protected:
+private:
+    // see comment on RpcTransport
+    friend class ::android::RpcTransportCtxRaw;
+    friend class ::android::RpcTransportCtxTls;
+    friend class ::android::RpcTransportCtxTipcAndroid;
+    friend class ::android::RpcTransportCtxTipcTrusty;
+
     RpcTransportCtx() = default;
 };
 
@@ -140,7 +170,7 @@
     RpcTransportCtxFactory() = default;
 };
 
-struct RpcTransportFd {
+struct RpcTransportFd final {
 private:
     mutable bool isPolling{false};
 
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index a157792..7d0acd1 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -40,12 +40,13 @@
 [[nodiscard]] ARpcServer* ARpcServer_newVsock(AIBinder* service, unsigned int cid,
                                               unsigned int port);
 
-// Starts a Unix domain RPC server with a given init-managed Unix domain `name`
+// Starts a Unix domain RPC server with an open raw socket file descriptor
 // and a given root IBinder object.
-// The socket should be created in init.rc with the same `name`.
+// The socket should be created and bound to an address.
 // Returns an opaque handle to the running server instance, or null if the server
 // could not be started.
-[[nodiscard]] ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name);
+// The socket will be closed by the server once the server goes out of scope.
+[[nodiscard]] ARpcServer* ARpcServer_newBoundSocket(AIBinder* service, int socketFd);
 
 // Starts an RPC server that bootstraps sessions using an existing Unix domain
 // socket pair, with a given root IBinder object.
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index a167f23..f51cd9b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -105,22 +105,15 @@
     return createObjectHandle<ARpcServer>(server);
 }
 
-ARpcServer* ARpcServer_newInitUnixDomain(AIBinder* service, const char* name) {
+ARpcServer* ARpcServer_newBoundSocket(AIBinder* service, int socketFd) {
     auto server = RpcServer::make();
-    auto fd = unique_fd(android_get_control_socket(name));
+    auto fd = unique_fd(socketFd);
     if (!fd.ok()) {
-        LOG(ERROR) << "Failed to get fd for the socket:" << name;
+        LOG(ERROR) << "Invalid socket fd " << socketFd;
         return nullptr;
     }
-    // Control socket fds are inherited from init, so they don't have O_CLOEXEC set.
-    // But we don't want any child processes to inherit the socket we are running
-    // the server on, so attempt to set the flag now.
-    if (fcntl(fd, F_SETFD, FD_CLOEXEC) != 0) {
-        LOG(WARNING) << "Failed to set CLOEXEC on control socket with name " << name
-                     << " error: " << errno;
-    }
     if (status_t status = server->setupRawSocketServer(std::move(fd)); status != OK) {
-        LOG(ERROR) << "Failed to set up Unix Domain RPC server with name " << name
+        LOG(ERROR) << "Failed to set up RPC server with fd " << socketFd
                    << " error: " << statusToString(status).c_str();
         return nullptr;
     }
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index 63679c2..50f7deb 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -3,7 +3,7 @@
     ARpcServer_free;
     ARpcServer_join;
     ARpcServer_newInet;
-    ARpcServer_newInitUnixDomain;
+    ARpcServer_newBoundSocket;
     ARpcServer_newVsock;
     ARpcServer_shutdown;
     ARpcServer_start;
diff --git a/libs/binder/ndk/.clang-format b/libs/binder/ndk/.clang-format
index 9a9d936..6077414 100644
--- a/libs/binder/ndk/.clang-format
+++ b/libs/binder/ndk/.clang-format
@@ -2,9 +2,7 @@
 ColumnLimit: 100
 IndentWidth: 4
 ContinuationIndentWidth: 8
-PointerAlignment: Left
 TabWidth: 4
 AllowShortFunctionsOnASingleLine: Inline
 PointerAlignment: Left
-TabWidth: 4
 UseTab: Never
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index d0de7b9..f7dd9c9 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -137,7 +137,7 @@
     // since it's an error condition. Do the comparison after we take the lock and
     // check the pointer equality fast path. By always taking the lock, it's also
     // more flake-proof. However, the check is not dependent on the lock.
-    if (descriptor != newDescriptor) {
+    if (descriptor != newDescriptor && !(asABpBinder() && asABpBinder()->isServiceFuzzing())) {
         if (getBinder()->isBinderAlive()) {
             LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
                        << "' but descriptor is actually '" << SanitizeString(descriptor) << "'.";
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 67bb092..9d5368f 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -104,10 +104,14 @@
     ::android::sp<::android::IBinder> getBinder() override { return mRemote; }
     ABpBinder* asABpBinder() override { return this; }
 
+    bool isServiceFuzzing() const { return mServiceFuzzing; }
+    void setServiceFuzzing() { mServiceFuzzing = true; }
+
    private:
     friend android::sp<ABpBinder>;
     explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
     ::android::sp<::android::IBinder> mRemote;
+    bool mServiceFuzzing = false;
 };
 
 struct AIBinder_Class {
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index d6937c2..ed53891 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -115,17 +115,29 @@
      */
     AIBinder** getR() { return &mBinder; }
 
-    bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
-    bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
-    bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
-    bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
-    bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
-    bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
-
    private:
     AIBinder* mBinder = nullptr;
 };
 
+#define SP_AIBINDER_COMPARE(_op_)                                                    \
+    static inline bool operator _op_(const SpAIBinder& lhs, const SpAIBinder& rhs) { \
+        return lhs.get() _op_ rhs.get();                                             \
+    }                                                                                \
+    static inline bool operator _op_(const SpAIBinder& lhs, const AIBinder* rhs) {   \
+        return lhs.get() _op_ rhs;                                                   \
+    }                                                                                \
+    static inline bool operator _op_(const AIBinder* lhs, const SpAIBinder& rhs) {   \
+        return lhs _op_ rhs.get();                                                   \
+    }
+
+SP_AIBINDER_COMPARE(!=)
+SP_AIBINDER_COMPARE(<)
+SP_AIBINDER_COMPARE(<=)
+SP_AIBINDER_COMPARE(==)
+SP_AIBINDER_COMPARE(>)
+SP_AIBINDER_COMPARE(>=)
+#undef SP_AIBINDER_COMPARE
+
 namespace impl {
 
 /**
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 9949de2..6273804 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -138,6 +138,8 @@
 
     /**
      * Dumps information about the interface. By default, dumps nothing.
+     *
+     * This method is not given ownership of the FD.
      */
     virtual inline binder_status_t dump(int fd, const char** args, uint32_t numArgs);
 
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index 3fbe90d..68528e1 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -24,7 +24,14 @@
 __BEGIN_DECLS
 
 /**
- * This creates a threadpool for incoming binder transactions if it has not already been created.
+ * This creates a threadpool for incoming binder transactions if it has not already been created,
+ * spawning one thread, and allowing the kernel to lazily start threads according to the count
+ * that is specified in ABinderProcess_setThreadPoolMaxThreadCount.
+ *
+ * For instance, if ABinderProcess_setThreadPoolMaxThreadCount(3) is called,
+ * ABinderProcess_startThreadPool() is called (+1 thread) then the main thread calls
+ * ABinderProcess_joinThreadPool() (+1 thread), up to *5* total threads will be started
+ * (2 directly, and 3 more if the kernel starts them lazily).
  *
  * When using this, it is expected that ABinderProcess_setupPolling and
  * ABinderProcess_handlePolledCommands are not used.
@@ -36,7 +43,12 @@
 /**
  * This sets the maximum number of threads that can be started in the threadpool. By default, after
  * startThreadPool is called, this is 15. If it is called additional times, it will only prevent
- * the kernel from starting new threads and will not delete already existing threads.
+ * the kernel from starting new threads and will not delete already existing threads. This should
+ * be called once before startThreadPool. The number of threads can never decrease.
+ *
+ * This count refers to the number of threads that will be created lazily by the kernel, in
+ * addition to the threads created by ABinderProcess_startThreadPool or
+ * ABinderProcess_joinThreadPool.
  *
  * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
  * function should be responsible for configuring the threadpool for the entire application.
@@ -50,8 +62,9 @@
  */
 bool ABinderProcess_isThreadPoolStarted(void);
 /**
- * This adds the current thread to the threadpool. This may cause the threadpool to exceed the
- * maximum size.
+ * This adds the current thread to the threadpool. This thread will be in addition to the thread
+ * started by ABinderProcess_startThreadPool and the lazy kernel-started threads specified by
+ * ABinderProcess_setThreadPoolMaxThreadCount.
  *
  * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
  * function should be responsible for configuring the threadpool for the entire application.
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index b5a2e2f..037aa2e 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -270,6 +270,13 @@
     }
     sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
     AIBinder_incStrong(ret.get());
+
+    if (ret.get() != nullptr && parcel->get()->isServiceFuzzing()) {
+        if (auto bp = ret->asABpBinder(); bp != nullptr) {
+            bp->setServiceFuzzing();
+        }
+    }
+
     *binder = ret.get();
     return PruneStatusT(status);
 }
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index cefc42f..25b8e97 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -107,11 +107,13 @@
     }
     static bool activeServicesCallback(bool hasClients, void* context) {
         if (hasClients) {
+            LOG(INFO) << "hasClients, so not unregistering.";
             return false;
         }
 
         // Unregister all services
         if (!AServiceManager_tryUnregister()) {
+            LOG(INFO) << "Could not unregister service the first time.";
             // Prevent shutdown (test will fail)
             return false;
         }
@@ -121,6 +123,7 @@
 
         // Unregister again before shutdown
         if (!AServiceManager_tryUnregister()) {
+            LOG(INFO) << "Could not unregister service the second time.";
             // Prevent shutdown (test will fail)
             return false;
         }
@@ -128,6 +131,7 @@
         // Check if the context was passed correctly
         MyBinderNdkUnitTest* service = static_cast<MyBinderNdkUnitTest*>(context);
         if (service->contextTestValue != kContextTestValue) {
+            LOG(INFO) << "Incorrect context value.";
             // Prevent shutdown (test will fail)
             return false;
         }
@@ -279,8 +283,8 @@
 
 TEST(NdkBinder, CheckServiceThatDoesExist) {
     AIBinder* binder = AServiceManager_checkService(kExistingNonNdkService);
-    EXPECT_NE(nullptr, binder);
-    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder));
+    ASSERT_NE(nullptr, binder) << "Could not get " << kExistingNonNdkService;
+    EXPECT_EQ(STATUS_OK, AIBinder_ping(binder)) << "Could not ping " << kExistingNonNdkService;
 
     AIBinder_decStrong(binder);
 }
@@ -373,18 +377,24 @@
 }
 
 TEST(NdkBinder, GetTestServiceStressTest) {
-    // libbinder has some complicated logic to make sure only one instance of
-    // ABpBinder is associated with each binder.
-
     constexpr size_t kNumThreads = 10;
     constexpr size_t kNumCalls = 1000;
     std::vector<std::thread> threads;
 
+    // this is not a lazy service, but we must make sure that it's started before calling
+    // checkService on it, since the other process serving it might not be started yet.
+    {
+        // getService, not waitForService, to take advantage of timeout
+        auto binder = ndk::SpAIBinder(AServiceManager_getService(IFoo::kSomeInstanceName));
+        ASSERT_NE(nullptr, binder.get());
+    }
+
     for (size_t i = 0; i < kNumThreads; i++) {
         threads.push_back(std::thread([&]() {
             for (size_t j = 0; j < kNumCalls; j++) {
                 auto binder =
                         ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+                ASSERT_NE(nullptr, binder.get());
                 EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
             }
         }));
@@ -479,6 +489,8 @@
 }
 
 TEST(NdkBinder, ActiveServicesCallbackTest) {
+    LOG(INFO) << "ActiveServicesCallbackTest starting";
+
     ndk::SpAIBinder binder(AServiceManager_waitForService(kActiveServicesNdkUnitTestService));
     std::shared_ptr<aidl::IBinderNdkUnitTest> service =
             aidl::IBinderNdkUnitTest::fromBinder(binder);
@@ -489,6 +501,7 @@
     service = nullptr;
     IPCThreadState::self()->flushCommands();
 
+    LOG(INFO) << "ActiveServicesCallbackTest about to sleep";
     sleep(kShutdownWaitTime);
 
     ASSERT_FALSE(isServiceRunning(kActiveServicesNdkUnitTestService))
@@ -497,14 +510,28 @@
 
 struct DeathRecipientCookie {
     std::function<void(void)>*onDeath, *onUnlink;
+
+    // may contain additional data
+    // - if it contains AIBinder, then you must call AIBinder_unlinkToDeath manually,
+    //   because it would form a strong reference cycle
+    // - if it points to a data member of another structure, this should have a weak
+    //   promotable reference or a strong reference, in case that object is deleted
+    //   while the death recipient is firing
 };
 void LambdaOnDeath(void* cookie) {
     auto funcs = static_cast<DeathRecipientCookie*>(cookie);
+
+    // may reference other cookie members
+
     (*funcs->onDeath)();
 };
 void LambdaOnUnlink(void* cookie) {
     auto funcs = static_cast<DeathRecipientCookie*>(cookie);
     (*funcs->onUnlink)();
+
+    // may reference other cookie members
+
+    delete funcs;
 };
 TEST(NdkBinder, DeathRecipient) {
     using namespace std::chrono_literals;
@@ -536,12 +563,12 @@
         unlinkCv.notify_one();
     };
 
-    DeathRecipientCookie cookie = {&onDeath, &onUnlink};
+    DeathRecipientCookie* cookie = new DeathRecipientCookie{&onDeath, &onUnlink};
 
     AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
     AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink);
 
-    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie)));
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(cookie)));
 
     // the binder driver should return this if the service dies during the transaction
     EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
@@ -734,9 +761,9 @@
           // local
           ndk::SharedRefBase::make<MyBinderNdkUnitTest>()->asBinder()}) {
         // convert to platform binder
-        EXPECT_NE(binder.get(), nullptr);
+        EXPECT_NE(binder, nullptr);
         sp<IBinder> platformBinder = AIBinder_toPlatformBinder(binder.get());
-        EXPECT_NE(platformBinder.get(), nullptr);
+        EXPECT_NE(platformBinder, nullptr);
         auto proxy = interface_cast<IBinderNdkUnitTest>(platformBinder);
         EXPECT_NE(proxy, nullptr);
 
@@ -747,7 +774,7 @@
 
         // convert back
         ndk::SpAIBinder backBinder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(platformBinder));
-        EXPECT_EQ(backBinder.get(), binder.get());
+        EXPECT_EQ(backBinder, binder);
     }
 }
 
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d36ebac..672d6cf 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -97,34 +97,12 @@
     crate_name: "binder_ndk_bindgen",
     wrapper_src: "sys/BinderBindings.hpp",
     source_stem: "bindings",
-    bindgen_flags: [
+    bindgen_flag_files: [
         // Unfortunately the only way to specify the rust_non_exhaustive enum
         // style for a type is to make it the default
-        "--default-enum-style",
-        "rust_non_exhaustive",
         // and then specify constified enums for the enums we don't want
         // rustified
-        "--constified-enum",
-        "android::c_interface::consts::.*",
-
-        "--allowlist-type",
-        "android::c_interface::.*",
-        "--allowlist-type",
-        "AStatus",
-        "--allowlist-type",
-        "AIBinder_Class",
-        "--allowlist-type",
-        "AIBinder",
-        "--allowlist-type",
-        "AIBinder_Weak",
-        "--allowlist-type",
-        "AIBinder_DeathRecipient",
-        "--allowlist-type",
-        "AParcel",
-        "--allowlist-type",
-        "binder_status_t",
-        "--allowlist-function",
-        ".*",
+        "libbinder_ndk_bindgen_flags.txt",
     ],
     shared_libs: [
         "libbinder_ndk",
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 2d2bf7c..1dc0b24 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -103,7 +103,12 @@
             //
             // This shouldn't cause issues with blocking the thread as only one task will run in a
             // call to `block_on`, so there aren't other tasks to block.
-            let result = spawn_me();
+            //
+            // If the `block_in_place` call fails, then you are driving a current-thread runtime on
+            // the binder threadpool. Instead, it is recommended to use `TokioRuntime<Handle>` when
+            // the runtime is a current-thread runtime, as the current-thread runtime can be driven
+            // only by `Runtime::block_on` calls and not by `Handle::block_on`.
+            let result = tokio::task::block_in_place(spawn_me);
             Box::pin(after_spawn(result))
         } else {
             let handle = tokio::task::spawn_blocking(spawn_me);
diff --git a/libs/binder/rust/libbinder_ndk_bindgen_flags.txt b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt
new file mode 100644
index 0000000..551c59f
--- /dev/null
+++ b/libs/binder/rust/libbinder_ndk_bindgen_flags.txt
@@ -0,0 +1,11 @@
+--default-enum-style=rust_non_exhaustive
+--constified-enum=android::c_interface::consts::.*
+--allowlist-type=android::c_interface::.*
+--allowlist-type=AStatus
+--allowlist-type=AIBinder_Class
+--allowlist-type=AIBinder
+--allowlist-type=AIBinder_Weak
+--allowlist-type=AIBinder_DeathRecipient
+--allowlist-type=AParcel
+--allowlist-type=binder_status_t
+--allowlist-function=.*
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 0067a20..788abc4 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -75,7 +75,6 @@
     visibility: [":__subpackages__"],
     source_stem: "bindings",
     bindgen_flags: [
-        "--size_t-is-usize",
         "--blocklist-type",
         "AIBinder",
         "--raw-line",
diff --git a/libs/binder/rust/rpcbinder/src/server.rs b/libs/binder/rust/rpcbinder/src/server.rs
index c87876a..6fda878 100644
--- a/libs/binder/rust/rpcbinder/src/server.rs
+++ b/libs/binder/rust/rpcbinder/src/server.rs
@@ -33,9 +33,9 @@
     pub struct RpcServerRef;
 }
 
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
 unsafe impl Send for RpcServer {}
-/// SAFETY - The underlying C++ RpcServer class is thread-safe.
+/// SAFETY: The underlying C++ RpcServer class is thread-safe.
 unsafe impl Sync for RpcServer {}
 
 impl RpcServer {
@@ -57,26 +57,21 @@
     }
 
     /// Creates a binder RPC server, serving the supplied binder service implementation on the given
-    /// socket file name. The socket should be initialized in init.rc with the same name.
-    pub fn new_init_unix_domain(
+    /// socket file descriptor. The socket should be bound to an address before calling this
+    /// function.
+    pub fn new_bound_socket(
         mut service: SpIBinder,
-        socket_name: &str,
+        socket_fd: OwnedFd,
     ) -> Result<RpcServer, Error> {
-        let socket_name = match CString::new(socket_name) {
-            Ok(s) => s,
-            Err(e) => {
-                log::error!("Cannot convert {} to CString. Error: {:?}", socket_name, e);
-                return Err(Error::from(ErrorKind::InvalidInput));
-            }
-        };
         let service = service.as_native_mut();
 
         // SAFETY: Service ownership is transferring to the server and won't be valid afterward.
         // Plus the binder objects are threadsafe.
+        // The server takes ownership of the socket FD.
         unsafe {
-            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newInitUnixDomain(
+            Self::checked_from_ptr(binder_rpc_unstable_bindgen::ARpcServer_newBoundSocket(
                 service,
-                socket_name.as_ptr(),
+                socket_fd.into_raw_fd(),
             ))
         }
     }
@@ -129,7 +124,9 @@
         if ptr.is_null() {
             return Err(Error::new(ErrorKind::Other, "Failed to start server"));
         }
-        Ok(RpcServer::from_ptr(ptr))
+        // SAFETY: Our caller must pass us a valid or null pointer, and we've checked that it's not
+        // null.
+        Ok(unsafe { RpcServer::from_ptr(ptr) })
     }
 }
 
@@ -139,7 +136,7 @@
         &self,
         modes: &[FileDescriptorTransportMode],
     ) {
-        // SAFETY - Does not keep the pointer after returning does, nor does it
+        // SAFETY: Does not keep the pointer after returning does, nor does it
         // read past its boundary. Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcServer_setSupportedFileDescriptorTransportModes(
@@ -152,18 +149,21 @@
 
     /// Starts a new background thread and calls join(). Returns immediately.
     pub fn start(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         unsafe { binder_rpc_unstable_bindgen::ARpcServer_start(self.as_ptr()) };
     }
 
     /// Joins the RpcServer thread. The call blocks until the server terminates.
     /// This must be called from exactly one thread.
     pub fn join(&self) {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         unsafe { binder_rpc_unstable_bindgen::ARpcServer_join(self.as_ptr()) };
     }
 
     /// Shuts down the running RpcServer. Can be called multiple times and from
     /// multiple threads. Called automatically during drop().
     pub fn shutdown(&self) -> Result<(), Error> {
+        // SAFETY: RpcServerRef wraps a valid pointer to an ARpcServer.
         if unsafe { binder_rpc_unstable_bindgen::ARpcServer_shutdown(self.as_ptr()) } {
             Ok(())
         } else {
diff --git a/libs/binder/rust/rpcbinder/src/session.rs b/libs/binder/rust/rpcbinder/src/session.rs
index 28c5390..79a9510 100644
--- a/libs/binder/rust/rpcbinder/src/session.rs
+++ b/libs/binder/rust/rpcbinder/src/session.rs
@@ -36,15 +36,15 @@
     pub struct RpcSessionRef;
 }
 
-/// SAFETY - The opaque handle can be cloned freely.
+/// SAFETY: The opaque handle can be cloned freely.
 unsafe impl Send for RpcSession {}
-/// SAFETY - The underlying C++ RpcSession class is thread-safe.
+/// SAFETY: The underlying C++ RpcSession class is thread-safe.
 unsafe impl Sync for RpcSession {}
 
 impl RpcSession {
     /// Allocates a new RpcSession object.
     pub fn new() -> RpcSession {
-        // SAFETY - Takes ownership of the returned handle, which has correct refcount.
+        // SAFETY: Takes ownership of the returned handle, which has correct refcount.
         unsafe { RpcSession::from_ptr(binder_rpc_unstable_bindgen::ARpcSession_new()) }
     }
 }
@@ -58,7 +58,7 @@
 impl RpcSessionRef {
     /// Sets the file descriptor transport mode for this session.
     pub fn set_file_descriptor_transport_mode(&self, mode: FileDescriptorTransportMode) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setFileDescriptorTransportMode(
                 self.as_ptr(),
@@ -69,7 +69,7 @@
 
     /// Sets the maximum number of incoming threads.
     pub fn set_max_incoming_threads(&self, threads: usize) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setMaxIncomingThreads(self.as_ptr(), threads)
         };
@@ -77,7 +77,7 @@
 
     /// Sets the maximum number of outgoing connections.
     pub fn set_max_outgoing_connections(&self, connections: usize) {
-        // SAFETY - Only passes the 'self' pointer as an opaque handle.
+        // SAFETY: Only passes the 'self' pointer as an opaque handle.
         unsafe {
             binder_rpc_unstable_bindgen::ARpcSession_setMaxOutgoingConnections(
                 self.as_ptr(),
@@ -210,10 +210,10 @@
 type RequestFd<'a> = &'a mut dyn FnMut() -> Option<RawFd>;
 
 unsafe extern "C" fn request_fd_wrapper(param: *mut c_void) -> c_int {
+    let request_fd_ptr = param as *mut RequestFd;
     // SAFETY: This is only ever called by RpcPreconnectedClient, within the lifetime of the
     // BinderFdFactory reference, with param being a properly aligned non-null pointer to an
     // initialized instance.
-    let request_fd_ptr = param as *mut RequestFd;
-    let request_fd = request_fd_ptr.as_mut().unwrap();
+    let request_fd = unsafe { request_fd_ptr.as_mut().unwrap() };
     request_fd().unwrap_or(-1)
 }
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index d0e35de..463c210 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -97,8 +97,8 @@
 
 /// Interface stability promise
 ///
-/// An interface can promise to be a stable vendor interface ([`Vintf`]), or
-/// makes no stability guarantees ([`Local`]). [`Local`] is
+/// An interface can promise to be a stable vendor interface ([`Stability::Vintf`]),
+/// or makes no stability guarantees ([`Stability::Local`]). [`Stability::Local`] is
 /// currently the default stability.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
 pub enum Stability {
@@ -139,8 +139,8 @@
 /// via `Binder::new(object)`.
 ///
 /// This is a low-level interface that should normally be automatically
-/// generated from AIDL via the [`declare_binder_interface!`] macro. When using
-/// the AIDL backend, users need only implement the high-level AIDL-defined
+/// generated from AIDL via the [`crate::declare_binder_interface!`] macro.
+/// When using the AIDL backend, users need only implement the high-level AIDL-defined
 /// interface. The AIDL compiler then generates a container struct that wraps
 /// the user-defined service and implements `Remotable`.
 pub trait Remotable: Send + Sync {
@@ -260,7 +260,14 @@
     /// Trying to use this function on a local binder will result in an
     /// INVALID_OPERATION code being returned and nothing happening.
     ///
-    /// This link always holds a weak reference to its recipient.
+    /// This link only holds a weak reference to its recipient. If the
+    /// `DeathRecipient` is dropped then it will be unlinked.
+    ///
+    /// Note that the notifications won't work if you don't first start at least
+    /// one Binder thread by calling
+    /// [`ProcessState::start_thread_pool`](crate::ProcessState::start_thread_pool)
+    /// or
+    /// [`ProcessState::join_thread_pool`](crate::ProcessState::join_thread_pool).
     fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()>;
 
     /// Remove a previously registered death notification.
@@ -290,18 +297,17 @@
     /// Note: the returned pointer will not be constant. Calling this method
     /// multiple times for the same type will result in distinct class
     /// pointers. A static getter for this value is implemented in
-    /// [`declare_binder_interface!`].
+    /// [`crate::declare_binder_interface!`].
     pub fn new<I: InterfaceClassMethods>() -> InterfaceClass {
         let descriptor = CString::new(I::get_descriptor()).unwrap();
+        // Safety: `AIBinder_Class_define` expects a valid C string, and three
+        // valid callback functions, all non-null pointers. The C string is
+        // copied and need not be valid for longer than the call, so we can drop
+        // it after the call. We can safely assign null to the onDump and
+        // handleShellCommand callbacks as long as the class pointer was
+        // non-null. Rust None for a Option<fn> is guaranteed to be a NULL
+        // pointer. Rust retains ownership of the pointer after it is defined.
         let ptr = unsafe {
-            // Safety: `AIBinder_Class_define` expects a valid C string, and
-            // three valid callback functions, all non-null pointers. The C
-            // string is copied and need not be valid for longer than the call,
-            // so we can drop it after the call. We can safely assign null to
-            // the onDump and handleShellCommand callbacks as long as the class
-            // pointer was non-null. Rust None for a Option<fn> is guaranteed to
-            // be a NULL pointer. Rust retains ownership of the pointer after it
-            // is defined.
             let class = sys::AIBinder_Class_define(
                 descriptor.as_ptr(),
                 Some(I::on_create),
@@ -331,13 +337,12 @@
 
     /// Get the interface descriptor string of this class.
     pub fn get_descriptor(&self) -> String {
+        // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor is
+        // always a two-byte null terminated sequence of u16s. Thus, we can
+        // continue reading from the pointer until we hit a null value, and this
+        // pointer can be a valid slice if the slice length is <= the number of
+        // u16 elements before the null terminator.
         unsafe {
-            // SAFETY: The descriptor returned by AIBinder_Class_getDescriptor
-            // is always a two-byte null terminated sequence of u16s. Thus, we
-            // can continue reading from the pointer until we hit a null value,
-            // and this pointer can be a valid slice if the slice length is <=
-            // the number of u16 elements before the null terminator.
-
             let raw_descriptor: *const c_char = sys::AIBinder_Class_getDescriptor(self.0);
             CStr::from_ptr(raw_descriptor)
                 .to_str()
@@ -535,17 +540,15 @@
             static CLASS_INIT: std::sync::Once = std::sync::Once::new();
             static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
 
+            // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+            // variable, and therefore is thread-safe, as it can only occur
+            // once.
             CLASS_INIT.call_once(|| unsafe {
-                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
-                // variable, and therefore is thread-safe, as it can only occur
-                // once.
                 CLASS = Some($constructor);
             });
-            unsafe {
-                // Safety: The `CLASS` variable can only be mutated once, above,
-                // and is subsequently safe to read from any thread.
-                CLASS.unwrap()
-            }
+            // Safety: The `CLASS` variable can only be mutated once, above, and
+            // is subsequently safe to read from any thread.
+            unsafe { CLASS.unwrap() }
         }
     };
 }
@@ -657,6 +660,8 @@
     fn as_native_mut(&mut self) -> *mut T;
 }
 
+// Safety: If V is a valid Android C++ type then we can either use that or a
+// null pointer.
 unsafe impl<T, V: AsNative<T>> AsNative<T> for Option<V> {
     fn as_native(&self) -> *const T {
         self.as_ref().map_or(ptr::null(), |v| v.as_native())
@@ -917,15 +922,15 @@
                 static CLASS_INIT: std::sync::Once = std::sync::Once::new();
                 static mut CLASS: Option<$crate::binder_impl::InterfaceClass> = None;
 
+                // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
+                // variable, and therefore is thread-safe, as it can only occur
+                // once.
                 CLASS_INIT.call_once(|| unsafe {
-                    // Safety: This assignment is guarded by the `CLASS_INIT` `Once`
-                    // variable, and therefore is thread-safe, as it can only occur
-                    // once.
                     CLASS = Some($crate::binder_impl::InterfaceClass::new::<$crate::binder_impl::Binder<$native>>());
                 });
+                // Safety: The `CLASS` variable can only be mutated once, above,
+                // and is subsequently safe to read from any thread.
                 unsafe {
-                    // Safety: The `CLASS` variable can only be mutated once, above,
-                    // and is subsequently safe to read from any thread.
                     CLASS.unwrap()
                 }
             }
@@ -1018,17 +1023,7 @@
                 }
 
                 if ibinder.associate_class(<$native as $crate::binder_impl::Remotable>::get_class()) {
-                    let service: std::result::Result<$crate::binder_impl::Binder<$native>, $crate::StatusCode> =
-                        std::convert::TryFrom::try_from(ibinder.clone());
-                    if let Ok(service) = service {
-                        // We were able to associate with our expected class and
-                        // the service is local.
-                        todo!()
-                        //return Ok($crate::Strong::new(Box::new(service)));
-                    } else {
-                        // Service is remote
-                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
-                    }
+                    return Ok($crate::Strong::new(Box::new(<$proxy as $crate::binder_impl::Proxy>::from_binder(ibinder)?)));
                 }
 
                 Err($crate::StatusCode::BAD_TYPE.into())
@@ -1122,6 +1117,10 @@
         }
 
         impl $crate::binder_impl::Deserialize for $enum {
+            type UninitType = Self;
+            fn uninit() -> Self::UninitType { Self::UninitType::default() }
+            fn from_init(value: Self) -> Self::UninitType { value }
+
             fn deserialize(parcel: &$crate::binder_impl::BorrowedParcel<'_>) -> std::result::Result<Self, $crate::StatusCode> {
                 parcel.read().map(Self)
             }
diff --git a/libs/binder/rust/src/error.rs b/libs/binder/rust/src/error.rs
index f6b09ed..eb04cc3 100644
--- a/libs/binder/rust/src/error.rs
+++ b/libs/binder/rust/src/error.rs
@@ -20,6 +20,7 @@
 use std::error;
 use std::ffi::{CStr, CString};
 use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
+use std::ptr;
 use std::result;
 
 pub use sys::binder_status_t as status_t;
@@ -92,7 +93,7 @@
 /// track of and chain binder errors along with service specific errors.
 ///
 /// Used in AIDL transactions to represent failed transactions.
-pub struct Status(*mut sys::AStatus);
+pub struct Status(ptr::NonNull<sys::AStatus>);
 
 // Safety: The `AStatus` that the `Status` points to must have an entirely thread-safe API for the
 // duration of the `Status` object's lifetime. We ensure this by not allowing mutation of a `Status`
@@ -111,43 +112,37 @@
 impl Status {
     /// Create a status object representing a successful transaction.
     pub fn ok() -> Self {
-        let ptr = unsafe {
-            // Safety: `AStatus_newOk` always returns a new, heap allocated
-            // pointer to an `ASTatus` object, so we know this pointer will be
-            // valid.
-            //
-            // Rust takes ownership of the returned pointer.
-            sys::AStatus_newOk()
-        };
-        Self(ptr)
+        // Safety: `AStatus_newOk` always returns a new, heap allocated
+        // pointer to an `ASTatus` object, so we know this pointer will be
+        // valid.
+        //
+        // Rust takes ownership of the returned pointer.
+        let ptr = unsafe { sys::AStatus_newOk() };
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 
     /// Create a status object from a service specific error
     pub fn new_service_specific_error(err: i32, message: Option<&CStr>) -> Status {
         let ptr = if let Some(message) = message {
-            unsafe {
-                // Safety: Any i32 is a valid service specific error for the
-                // error code parameter. We construct a valid, null-terminated
-                // `CString` from the message, which must be a valid C-style
-                // string to pass as the message. This function always returns a
-                // new, heap allocated pointer to an `AStatus` object, so we
-                // know the returned pointer will be valid.
-                //
-                // Rust takes ownership of the returned pointer.
-                sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr())
-            }
+            // Safety: Any i32 is a valid service specific error for the
+            // error code parameter. We construct a valid, null-terminated
+            // `CString` from the message, which must be a valid C-style
+            // string to pass as the message. This function always returns a
+            // new, heap allocated pointer to an `AStatus` object, so we
+            // know the returned pointer will be valid.
+            //
+            // Rust takes ownership of the returned pointer.
+            unsafe { sys::AStatus_fromServiceSpecificErrorWithMessage(err, message.as_ptr()) }
         } else {
-            unsafe {
-                // Safety: Any i32 is a valid service specific error for the
-                // error code parameter. This function always returns a new,
-                // heap allocated pointer to an `AStatus` object, so we know the
-                // returned pointer will be valid.
-                //
-                // Rust takes ownership of the returned pointer.
-                sys::AStatus_fromServiceSpecificError(err)
-            }
+            // Safety: Any i32 is a valid service specific error for the
+            // error code parameter. This function always returns a new,
+            // heap allocated pointer to an `AStatus` object, so we know the
+            // returned pointer will be valid.
+            //
+            // Rust takes ownership of the returned pointer.
+            unsafe { sys::AStatus_fromServiceSpecificError(err) }
         };
-        Self(ptr)
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 
     /// Creates a status object from a service specific error.
@@ -158,10 +153,12 @@
     /// Create a status object from an exception code
     pub fn new_exception(exception: ExceptionCode, message: Option<&CStr>) -> Status {
         if let Some(message) = message {
+            // Safety: the C string pointer is valid and not retained by the
+            // function.
             let ptr = unsafe {
                 sys::AStatus_fromExceptionCodeWithMessage(exception as i32, message.as_ptr())
             };
-            Self(ptr)
+            Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
         } else {
             exception.into()
         }
@@ -181,42 +178,36 @@
     ///
     /// This constructor is safe iff `ptr` is a valid pointer to an `AStatus`.
     pub(crate) unsafe fn from_ptr(ptr: *mut sys::AStatus) -> Self {
-        Self(ptr)
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 
     /// Returns `true` if this status represents a successful transaction.
     pub fn is_ok(&self) -> bool {
-        unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_isOk` here.
-            sys::AStatus_isOk(self.as_native())
-        }
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_isOk` here.
+        unsafe { sys::AStatus_isOk(self.as_native()) }
     }
 
     /// Returns a description of the status.
     pub fn get_description(&self) -> String {
-        let description_ptr = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getDescription`
-            // here.
-            //
-            // `AStatus_getDescription` always returns a valid pointer to a null
-            // terminated C string. Rust is responsible for freeing this pointer
-            // via `AStatus_deleteDescription`.
-            sys::AStatus_getDescription(self.as_native())
-        };
-        let description = unsafe {
-            // Safety: `AStatus_getDescription` always returns a valid C string,
-            // which can be safely converted to a `CStr`.
-            CStr::from_ptr(description_ptr)
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getDescription`
+        // here.
+        //
+        // `AStatus_getDescription` always returns a valid pointer to a null
+        // terminated C string. Rust is responsible for freeing this pointer
+        // via `AStatus_deleteDescription`.
+        let description_ptr = unsafe { sys::AStatus_getDescription(self.as_native()) };
+        // Safety: `AStatus_getDescription` always returns a valid C string,
+        // which can be safely converted to a `CStr`.
+        let description = unsafe { CStr::from_ptr(description_ptr) };
         let description = description.to_string_lossy().to_string();
+        // Safety: `description_ptr` was returned from
+        // `AStatus_getDescription` above, and must be freed via
+        // `AStatus_deleteDescription`. We must not access the pointer after
+        // this call, so we copy it into an owned string above and return
+        // that string.
         unsafe {
-            // Safety: `description_ptr` was returned from
-            // `AStatus_getDescription` above, and must be freed via
-            // `AStatus_deleteDescription`. We must not access the pointer after
-            // this call, so we copy it into an owned string above and return
-            // that string.
             sys::AStatus_deleteDescription(description_ptr);
         }
         description
@@ -224,12 +215,10 @@
 
     /// Returns the exception code of the status.
     pub fn exception_code(&self) -> ExceptionCode {
-        let code = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getExceptionCode`
-            // here.
-            sys::AStatus_getExceptionCode(self.as_native())
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getExceptionCode`
+        // here.
+        let code = unsafe { sys::AStatus_getExceptionCode(self.as_native()) };
         parse_exception_code(code)
     }
 
@@ -240,11 +229,9 @@
     /// exception or a service specific error. To find out if this transaction
     /// as a whole is okay, use [`is_ok`](Self::is_ok) instead.
     pub fn transaction_error(&self) -> StatusCode {
-        let code = unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to `AStatus_getStatus` here.
-            sys::AStatus_getStatus(self.as_native())
-        };
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to `AStatus_getStatus` here.
+        let code = unsafe { sys::AStatus_getStatus(self.as_native()) };
         parse_status_code(code)
     }
 
@@ -257,12 +244,10 @@
     /// find out if this transaction as a whole is okay, use
     /// [`is_ok`](Self::is_ok) instead.
     pub fn service_specific_error(&self) -> i32 {
-        unsafe {
-            // Safety: `Status` always contains a valid `AStatus` pointer, so we
-            // are always passing a valid pointer to
-            // `AStatus_getServiceSpecificError` here.
-            sys::AStatus_getServiceSpecificError(self.as_native())
-        }
+        // Safety: `Status` always contains a valid `AStatus` pointer, so we
+        // are always passing a valid pointer to
+        // `AStatus_getServiceSpecificError` here.
+        unsafe { sys::AStatus_getServiceSpecificError(self.as_native()) }
     }
 
     /// Calls `op` if the status was ok, otherwise returns an `Err` value of
@@ -320,25 +305,21 @@
 
 impl From<status_t> for Status {
     fn from(status: status_t) -> Status {
-        let ptr = unsafe {
-            // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
-            // this is a safe FFI call. Unknown values will be coerced into
-            // UNKNOWN_ERROR.
-            sys::AStatus_fromStatus(status)
-        };
-        Self(ptr)
+        // Safety: `AStatus_fromStatus` expects any `status_t` integer, so
+        // this is a safe FFI call. Unknown values will be coerced into
+        // UNKNOWN_ERROR.
+        let ptr = unsafe { sys::AStatus_fromStatus(status) };
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 }
 
 impl From<ExceptionCode> for Status {
     fn from(code: ExceptionCode) -> Status {
-        let ptr = unsafe {
-            // Safety: `AStatus_fromExceptionCode` expects any
-            // `binder_exception_t` (i32) integer, so this is a safe FFI call.
-            // Unknown values will be coerced into EX_TRANSACTION_FAILED.
-            sys::AStatus_fromExceptionCode(code as i32)
-        };
-        Self(ptr)
+        // Safety: `AStatus_fromExceptionCode` expects any
+        // `binder_exception_t` (i32) integer, so this is a safe FFI call.
+        // Unknown values will be coerced into EX_TRANSACTION_FAILED.
+        let ptr = unsafe { sys::AStatus_fromExceptionCode(code as i32) };
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null AStatus pointer"))
     }
 }
 
@@ -362,30 +343,118 @@
 
 impl Drop for Status {
     fn drop(&mut self) {
+        // Safety: `Status` manages the lifetime of its inner `AStatus`
+        // pointee, so we need to delete it here. We know that the pointer
+        // will be valid here since `Status` always contains a valid pointer
+        // while it is alive.
         unsafe {
-            // Safety: `Status` manages the lifetime of its inner `AStatus`
-            // pointee, so we need to delete it here. We know that the pointer
-            // will be valid here since `Status` always contains a valid pointer
-            // while it is alive.
-            sys::AStatus_delete(self.0);
+            sys::AStatus_delete(self.0.as_mut());
         }
     }
 }
 
-/// # Safety
-///
-/// `Status` always contains a valid pointer to an `AStatus` object, so we can
-/// trivially convert it to a correctly-typed raw pointer.
+/// Safety: `Status` always contains a valid pointer to an `AStatus` object, so
+/// we can trivially convert it to a correctly-typed raw pointer.
 ///
 /// Care must be taken that the returned pointer is only dereferenced while the
 /// `Status` object is still alive.
 unsafe impl AsNative<sys::AStatus> for Status {
     fn as_native(&self) -> *const sys::AStatus {
-        self.0
+        self.0.as_ptr()
     }
 
     fn as_native_mut(&mut self) -> *mut sys::AStatus {
-        self.0
+        // Safety: The pointer will be valid here since `Status` always contains
+        // a valid and initialized pointer while it is alive.
+        unsafe { self.0.as_mut() }
+    }
+}
+
+/// A conversion from `std::result::Result<T, E>` to `binder::Result<T>`. If this type is `Ok(T)`,
+/// it's returned as is. If this type is `Err(E)`, `E` is converted into `Status` which can be
+/// either a general binder exception, or a service-specific exception.
+///
+/// # Examples
+///
+/// ```
+/// // std::io::Error is formatted as the exception's message
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+///     std::fs::metadata(name)
+///         .or_service_specific_exception(NOT_FOUND)?
+/// }
+///
+/// // A custom function is used to create the exception's message
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+///     std::fs::metadata(name)
+///         .or_service_specific_exception_with(NOT_FOUND,
+///             |e| format!("file {} not found: {:?}", name, e))?
+/// }
+///
+/// // anyhow::Error is formatted as the exception's message
+/// use anyhow::{Context, Result};
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+///     std::fs::metadata(name)
+///         .context("file {} not found")
+///         .or_service_specific_exception(NOT_FOUND)?
+/// }
+///
+/// // General binder exceptions can be created similarly
+/// fn file_exists(name: &str) -> binder::Result<bool> {
+///     std::fs::metadata(name)
+///         .or_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT)?
+/// }
+/// ```
+pub trait IntoBinderResult<T, E> {
+    /// Converts the embedded error into a general binder exception of code `exception`. The
+    /// message of the exception is set by formatting the error for debugging.
+    fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status>;
+
+    /// Converts the embedded error into a general binder exception of code `exception`. The
+    /// message of the exception is set by lazily evaluating the `op` function.
+    fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+        self,
+        exception: ExceptionCode,
+        op: O,
+    ) -> result::Result<T, Status>;
+
+    /// Converts the embedded error into a service-specific binder exception. `error_code` is used
+    /// to distinguish different service-specific binder exceptions. The message of the exception
+    /// is set by formatting the error for debugging.
+    fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status>;
+
+    /// Converts the embedded error into a service-specific binder exception. `error_code` is used
+    /// to distinguish different service-specific binder exceptions. The message of the exception
+    /// is set by lazily evaluating the `op` function.
+    fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+        self,
+        error_code: i32,
+        op: O,
+    ) -> result::Result<T, Status>;
+}
+
+impl<T, E: std::fmt::Debug> IntoBinderResult<T, E> for result::Result<T, E> {
+    fn or_binder_exception(self, exception: ExceptionCode) -> result::Result<T, Status> {
+        self.or_binder_exception_with(exception, |e| format!("{:?}", e))
+    }
+
+    fn or_binder_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+        self,
+        exception: ExceptionCode,
+        op: O,
+    ) -> result::Result<T, Status> {
+        self.map_err(|e| Status::new_exception_str(exception, Some(op(e))))
+    }
+
+    fn or_service_specific_exception(self, error_code: i32) -> result::Result<T, Status> {
+        self.or_service_specific_exception_with(error_code, |e| format!("{:?}", e))
+    }
+
+    fn or_service_specific_exception_with<M: AsRef<str>, O: FnOnce(E) -> M>(
+        self,
+        error_code: i32,
+        op: O,
+    ) -> result::Result<T, Status> {
+        self.map_err(|e| Status::new_service_specific_error_str(error_code, Some(op(e))))
     }
 }
 
@@ -425,4 +494,66 @@
         assert_eq!(status.service_specific_error(), 0);
         assert_eq!(status.get_description(), "Status(-5, EX_ILLEGAL_STATE): ''".to_string());
     }
+
+    #[test]
+    fn convert_to_service_specific_exception() {
+        let res: std::result::Result<(), Status> =
+            Err("message").or_service_specific_exception(-42);
+
+        assert!(res.is_err());
+        let status = res.unwrap_err();
+        assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+        assert_eq!(status.service_specific_error(), -42);
+        assert_eq!(
+            status.get_description(),
+            "Status(-8, EX_SERVICE_SPECIFIC): '-42: \"message\"'".to_string()
+        );
+    }
+
+    #[test]
+    fn convert_to_service_specific_exception_with() {
+        let res: std::result::Result<(), Status> = Err("message")
+            .or_service_specific_exception_with(-42, |e| format!("outer message: {:?}", e));
+
+        assert!(res.is_err());
+        let status = res.unwrap_err();
+        assert_eq!(status.exception_code(), ExceptionCode::SERVICE_SPECIFIC);
+        assert_eq!(status.service_specific_error(), -42);
+        assert_eq!(
+            status.get_description(),
+            "Status(-8, EX_SERVICE_SPECIFIC): '-42: outer message: \"message\"'".to_string()
+        );
+    }
+
+    #[test]
+    fn convert_to_binder_exception() {
+        let res: std::result::Result<(), Status> =
+            Err("message").or_binder_exception(ExceptionCode::ILLEGAL_STATE);
+
+        assert!(res.is_err());
+        let status = res.unwrap_err();
+        assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+        assert_eq!(status.service_specific_error(), 0);
+        assert_eq!(
+            status.get_description(),
+            "Status(-5, EX_ILLEGAL_STATE): '\"message\"'".to_string()
+        );
+    }
+
+    #[test]
+    fn convert_to_binder_exception_with() {
+        let res: std::result::Result<(), Status> = Err("message")
+            .or_binder_exception_with(ExceptionCode::ILLEGAL_STATE, |e| {
+                format!("outer message: {:?}", e)
+            });
+
+        assert!(res.is_err());
+        let status = res.unwrap_err();
+        assert_eq!(status.exception_code(), ExceptionCode::ILLEGAL_STATE);
+        assert_eq!(status.service_specific_error(), 0);
+        assert_eq!(
+            status.get_description(),
+            "Status(-5, EX_ILLEGAL_STATE): 'outer message: \"message\"'".to_string()
+        );
+    }
 }
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 0c8b48f..8841fe6 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,7 +106,7 @@
 
 pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
 pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
-pub use error::{ExceptionCode, Status, StatusCode};
+pub use error::{ExceptionCode, IntoBinderResult, Status, StatusCode};
 pub use native::{
     add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
     LazyServiceGuard,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 5557168..b248f5e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -42,7 +42,7 @@
     rust_object: *mut T,
 }
 
-/// # Safety
+/// Safety:
 ///
 /// A `Binder<T>` is a pair of unique owning pointers to two values:
 ///   * a C++ ABBinder which the C++ API guarantees can be passed between threads
@@ -54,7 +54,7 @@
 /// to how `Box<T>` is `Send` if `T` is `Send`.
 unsafe impl<T: Remotable> Send for Binder<T> {}
 
-/// # Safety
+/// Safety:
 ///
 /// A `Binder<T>` is a pair of unique owning pointers to two values:
 ///   * a C++ ABBinder which is thread-safe, i.e. `Send + Sync`
@@ -89,15 +89,13 @@
     pub fn new_with_stability(rust_object: T, stability: Stability) -> Binder<T> {
         let class = T::get_class();
         let rust_object = Box::into_raw(Box::new(rust_object));
-        let ibinder = unsafe {
-            // Safety: `AIBinder_new` expects a valid class pointer (which we
-            // initialize via `get_class`), and an arbitrary pointer
-            // argument. The caller owns the returned `AIBinder` pointer, which
-            // is a strong reference to a `BBinder`. This reference should be
-            // decremented via `AIBinder_decStrong` when the reference lifetime
-            // ends.
-            sys::AIBinder_new(class.into(), rust_object as *mut c_void)
-        };
+        // Safety: `AIBinder_new` expects a valid class pointer (which we
+        // initialize via `get_class`), and an arbitrary pointer
+        // argument. The caller owns the returned `AIBinder` pointer, which
+        // is a strong reference to a `BBinder`. This reference should be
+        // decremented via `AIBinder_decStrong` when the reference lifetime
+        // ends.
+        let ibinder = unsafe { sys::AIBinder_new(class.into(), rust_object as *mut c_void) };
         let mut binder = Binder { ibinder, rust_object };
         binder.mark_stability(stability);
         binder
@@ -176,15 +174,14 @@
     ///        }
     ///        # }
     pub fn set_extension(&mut self, extension: &mut SpIBinder) -> Result<()> {
-        let status = unsafe {
-            // Safety: `AIBinder_setExtension` expects two valid, mutable
-            // `AIBinder` pointers. We are guaranteed that both `self` and
-            // `extension` contain valid `AIBinder` pointers, because they
-            // cannot be initialized without a valid
-            // pointer. `AIBinder_setExtension` does not take ownership of
-            // either parameter.
-            sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut())
-        };
+        let status =
+        // Safety: `AIBinder_setExtension` expects two valid, mutable
+        // `AIBinder` pointers. We are guaranteed that both `self` and
+        // `extension` contain valid `AIBinder` pointers, because they
+        // cannot be initialized without a valid
+        // pointer. `AIBinder_setExtension` does not take ownership of
+        // either parameter.
+            unsafe { sys::AIBinder_setExtension(self.as_native_mut(), extension.as_native_mut()) };
         status_result(status)
     }
 
@@ -199,9 +196,9 @@
         match stability {
             Stability::Local => self.mark_local_stability(),
             Stability::Vintf => {
+                // Safety: Self always contains a valid `AIBinder` pointer, so
+                // we can always call this C API safely.
                 unsafe {
-                    // Safety: Self always contains a valid `AIBinder` pointer, so
-                    // we can always call this C API safely.
                     sys::AIBinder_markVintfStability(self.as_native_mut());
                 }
             }
@@ -212,9 +209,9 @@
     /// building for android_vendor and system otherwise.
     #[cfg(android_vendor)]
     fn mark_local_stability(&mut self) {
+        // Safety: Self always contains a valid `AIBinder` pointer, so we can
+        // always call this C API safely.
         unsafe {
-            // Safety: Self always contains a valid `AIBinder` pointer, so
-            // we can always call this C API safely.
             sys::AIBinder_markVendorStability(self.as_native_mut());
         }
     }
@@ -223,9 +220,9 @@
     /// building for android_vendor and system otherwise.
     #[cfg(not(android_vendor))]
     fn mark_local_stability(&mut self) {
+        // Safety: Self always contains a valid `AIBinder` pointer, so we can
+        // always call this C API safely.
         unsafe {
-            // Safety: Self always contains a valid `AIBinder` pointer, so
-            // we can always call this C API safely.
             sys::AIBinder_markSystemStability(self.as_native_mut());
         }
     }
@@ -239,13 +236,13 @@
     /// remotable object, which will prevent the object from being dropped while
     /// the `SpIBinder` is alive.
     fn as_binder(&self) -> SpIBinder {
+        // Safety: `self.ibinder` is guaranteed to always be a valid pointer
+        // to an `AIBinder` by the `Binder` constructor. We are creating a
+        // copy of the `self.ibinder` strong reference, but
+        // `SpIBinder::from_raw` assumes it receives an owned pointer with
+        // its own strong reference. We first increment the reference count,
+        // so that the new `SpIBinder` will be tracked as a new reference.
         unsafe {
-            // Safety: `self.ibinder` is guaranteed to always be a valid pointer
-            // to an `AIBinder` by the `Binder` constructor. We are creating a
-            // copy of the `self.ibinder` strong reference, but
-            // `SpIBinder::from_raw` assumes it receives an owned pointer with
-            // its own strong reference. We first increment the reference count,
-            // so that the new `SpIBinder` will be tracked as a new reference.
             sys::AIBinder_incStrong(self.ibinder);
             SpIBinder::from_raw(self.ibinder).unwrap()
         }
@@ -275,10 +272,20 @@
         reply: *mut sys::AParcel,
     ) -> status_t {
         let res = {
-            let mut reply = BorrowedParcel::from_raw(reply).unwrap();
-            let data = BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap();
-            let object = sys::AIBinder_getUserData(binder);
-            let binder: &T = &*(object as *const T);
+            // Safety: The caller must give us a parcel pointer which is either
+            // null or valid at least for the duration of this function call. We
+            // don't keep the resulting value beyond the function.
+            let mut reply = unsafe { BorrowedParcel::from_raw(reply).unwrap() };
+            // Safety: The caller must give us a parcel pointer which is either
+            // null or valid at least for the duration of this function call. We
+            // don't keep the resulting value beyond the function.
+            let data = unsafe { BorrowedParcel::from_raw(data as *mut sys::AParcel).unwrap() };
+            // Safety: Our caller promised that `binder` is a non-null, valid
+            // pointer to a local `AIBinder`.
+            let object = unsafe { sys::AIBinder_getUserData(binder) };
+            // Safety: Our caller promised that the binder has a `T` pointer in
+            // its user data.
+            let binder: &T = unsafe { &*(object as *const T) };
             binder.on_transact(code, &data, &mut reply)
         };
         match res {
@@ -295,7 +302,9 @@
     /// Must be called with a valid pointer to a `T` object. After this call,
     /// the pointer will be invalid and should not be dereferenced.
     unsafe extern "C" fn on_destroy(object: *mut c_void) {
-        drop(Box::from_raw(object as *mut T));
+        // Safety: Our caller promised that `object` is a valid pointer to a
+        // `T`.
+        drop(unsafe { Box::from_raw(object as *mut T) });
     }
 
     /// Called whenever a new, local `AIBinder` object is needed of a specific
@@ -320,7 +329,7 @@
     /// Must be called with a non-null, valid pointer to a local `AIBinder` that
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
-    /// poiinters with length num_args.
+    /// pointers with length num_args.
     unsafe extern "C" fn on_dump(
         binder: *mut sys::AIBinder,
         fd: i32,
@@ -330,8 +339,9 @@
         if fd < 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
         }
-        // We don't own this file, so we need to be careful not to drop it.
-        let file = ManuallyDrop::new(File::from_raw_fd(fd));
+        // Safety: Our caller promised that fd is a file descriptor. We don't
+        // own this file descriptor, so we need to be careful not to drop it.
+        let file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd)) };
 
         if args.is_null() && num_args != 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
@@ -340,14 +350,22 @@
         let args = if args.is_null() || num_args == 0 {
             vec![]
         } else {
-            slice::from_raw_parts(args, num_args as usize)
-                .iter()
-                .map(|s| CStr::from_ptr(*s))
-                .collect()
+            // Safety: Our caller promised that `args` is an array of
+            // null-terminated string pointers with length `num_args`.
+            unsafe {
+                slice::from_raw_parts(args, num_args as usize)
+                    .iter()
+                    .map(|s| CStr::from_ptr(*s))
+                    .collect()
+            }
         };
 
-        let object = sys::AIBinder_getUserData(binder);
-        let binder: &T = &*(object as *const T);
+        // Safety: Our caller promised that `binder` is a non-null, valid
+        // pointer to a local `AIBinder`.
+        let object = unsafe { sys::AIBinder_getUserData(binder) };
+        // Safety: Our caller promised that the binder has a `T` pointer in its
+        // user data.
+        let binder: &T = unsafe { &*(object as *const T) };
         let res = binder.on_dump(&file, &args);
 
         match res {
@@ -363,11 +381,11 @@
     // actually destroys the object, it calls `on_destroy` and we can drop the
     // `rust_object` then.
     fn drop(&mut self) {
+        // Safety: When `self` is dropped, we can no longer access the
+        // reference, so can decrement the reference count. `self.ibinder` is
+        // always a valid `AIBinder` pointer, so is valid to pass to
+        // `AIBinder_decStrong`.
         unsafe {
-            // Safety: When `self` is dropped, we can no longer access the
-            // reference, so can decrement the reference count. `self.ibinder`
-            // is always a valid `AIBinder` pointer, so is valid to pass to
-            // `AIBinder_decStrong`.
             sys::AIBinder_decStrong(self.ibinder);
         }
     }
@@ -377,14 +395,11 @@
     type Target = T;
 
     fn deref(&self) -> &Self::Target {
-        unsafe {
-            // Safety: While `self` is alive, the reference count of the
-            // underlying object is > 0 and therefore `on_destroy` cannot be
-            // called. Therefore while `self` is alive, we know that
-            // `rust_object` is still a valid pointer to a heap allocated object
-            // of type `T`.
-            &*self.rust_object
-        }
+        // Safety: While `self` is alive, the reference count of the underlying
+        // object is > 0 and therefore `on_destroy` cannot be called. Therefore
+        // while `self` is alive, we know that `rust_object` is still a valid
+        // pointer to a heap allocated object of type `T`.
+        unsafe { &*self.rust_object }
     }
 }
 
@@ -405,13 +420,10 @@
         if Some(class) != ibinder.get_class() {
             return Err(StatusCode::BAD_TYPE);
         }
-        let userdata = unsafe {
-            // Safety: `SpIBinder` always holds a valid pointer pointer to an
-            // `AIBinder`, which we can safely pass to
-            // `AIBinder_getUserData`. `ibinder` retains ownership of the
-            // returned pointer.
-            sys::AIBinder_getUserData(ibinder.as_native_mut())
-        };
+        // Safety: `SpIBinder` always holds a valid pointer pointer to an
+        // `AIBinder`, which we can safely pass to `AIBinder_getUserData`.
+        // `ibinder` retains ownership of the returned pointer.
+        let userdata = unsafe { sys::AIBinder_getUserData(ibinder.as_native_mut()) };
         if userdata.is_null() {
             return Err(StatusCode::UNEXPECTED_NULL);
         }
@@ -422,12 +434,10 @@
     }
 }
 
-/// # Safety
-///
-/// The constructor for `Binder` guarantees that `self.ibinder` will contain a
-/// valid, non-null pointer to an `AIBinder`, so this implementation is type
-/// safe. `self.ibinder` will remain valid for the entire lifetime of `self`
-/// because we hold a strong reference to the `AIBinder` until `self` is
+/// Safety: The constructor for `Binder` guarantees that `self.ibinder` will
+/// contain a valid, non-null pointer to an `AIBinder`, so this implementation
+/// is type safe. `self.ibinder` will remain valid for the entire lifetime of
+/// `self` because we hold a strong reference to the `AIBinder` until `self` is
 /// dropped.
 unsafe impl<B: Remotable> AsNative<sys::AIBinder> for Binder<B> {
     fn as_native(&self) -> *const sys::AIBinder {
@@ -447,14 +457,12 @@
 /// This function will panic if the identifier contains a 0 byte (NUL).
 pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
     let instance = CString::new(identifier).unwrap();
-    let status = unsafe {
-        // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
-        // string pointers. Caller retains ownership of both
-        // pointers. `AServiceManager_addService` creates a new strong reference
-        // and copies the string, so both pointers need only be valid until the
-        // call returns.
-        sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr())
-    };
+    let status =
+    // Safety: `AServiceManager_addService` expects valid `AIBinder` and C
+    // string pointers. Caller retains ownership of both pointers.
+    // `AServiceManager_addService` creates a new strong reference and copies
+    // the string, so both pointers need only be valid until the call returns.
+        unsafe { sys::AServiceManager_addService(binder.as_native_mut(), instance.as_ptr()) };
     status_result(status)
 }
 
@@ -470,13 +478,12 @@
 /// This function will panic if the identifier contains a 0 byte (NUL).
 pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
     let instance = CString::new(identifier).unwrap();
+    // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+    // string pointers. Caller retains ownership of both
+    // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+    // and copies the string, so both pointers need only be valid until the
+    // call returns.
     let status = unsafe {
-        // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
-        // string pointers. Caller retains ownership of both
-        // pointers. `AServiceManager_registerLazyService` creates a new strong reference
-        // and copies the string, so both pointers need only be valid until the
-        // call returns.
-
         sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
     };
     status_result(status)
@@ -491,10 +498,8 @@
 ///
 /// Consider using [`LazyServiceGuard`] rather than calling this directly.
 pub fn force_lazy_services_persist(persist: bool) {
-    unsafe {
-        // Safety: No borrowing or transfer of ownership occurs here.
-        sys::AServiceManager_forceLazyServicesPersist(persist)
-    }
+    // Safety: No borrowing or transfer of ownership occurs here.
+    unsafe { sys::AServiceManager_forceLazyServicesPersist(persist) }
 }
 
 /// An RAII object to ensure a process which registers lazy services is not killed. During the
@@ -576,8 +581,6 @@
 /// Determine whether the current thread is currently executing an incoming
 /// transaction.
 pub fn is_handling_transaction() -> bool {
-    unsafe {
-        // Safety: This method is always safe to call.
-        sys::AIBinder_isHandlingTransaction()
-    }
+    // Safety: This method is always safe to call.
+    unsafe { sys::AIBinder_isHandlingTransaction() }
 }
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index e4c568e..3c615ed 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -52,11 +52,8 @@
     ptr: NonNull<sys::AParcel>,
 }
 
-/// # Safety
-///
-/// This type guarantees that it owns the AParcel and that all access to
-/// the AParcel happens through the Parcel, so it is ok to send across
-/// threads.
+/// Safety: This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the Parcel, so it is ok to send across threads.
 unsafe impl Send for Parcel {}
 
 /// Container for a message (data and object references) that can be sent
@@ -73,11 +70,9 @@
 impl Parcel {
     /// Create a new empty `Parcel`.
     pub fn new() -> Parcel {
-        let ptr = unsafe {
-            // Safety: If `AParcel_create` succeeds, it always returns
-            // a valid pointer. If it fails, the process will crash.
-            sys::AParcel_create()
-        };
+        // Safety: If `AParcel_create` succeeds, it always returns
+        // a valid pointer. If it fails, the process will crash.
+        let ptr = unsafe { sys::AParcel_create() };
         Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
     }
 
@@ -171,10 +166,8 @@
     }
 }
 
-/// # Safety
-///
-/// The `Parcel` constructors guarantee that a `Parcel` object will always
-/// contain a valid pointer to an `AParcel`.
+/// Safety: The `Parcel` constructors guarantee that a `Parcel` object will
+/// always contain a valid pointer to an `AParcel`.
 unsafe impl AsNative<sys::AParcel> for Parcel {
     fn as_native(&self) -> *const sys::AParcel {
         self.ptr.as_ptr()
@@ -185,10 +178,8 @@
     }
 }
 
-/// # Safety
-///
-/// The `BorrowedParcel` constructors guarantee that a `BorrowedParcel` object
-/// will always contain a valid pointer to an `AParcel`.
+/// Safety: The `BorrowedParcel` constructors guarantee that a `BorrowedParcel`
+/// object will always contain a valid pointer to an `AParcel`.
 unsafe impl<'a> AsNative<sys::AParcel> for BorrowedParcel<'a> {
     fn as_native(&self) -> *const sys::AParcel {
         self.ptr.as_ptr()
@@ -203,10 +194,8 @@
 impl<'a> BorrowedParcel<'a> {
     /// Data written to parcelable is zero'd before being deleted or reallocated.
     pub fn mark_sensitive(&mut self) {
-        unsafe {
-            // Safety: guaranteed to have a parcel object, and this method never fails
-            sys::AParcel_markSensitive(self.as_native())
-        }
+        // Safety: guaranteed to have a parcel object, and this method never fails
+        unsafe { sys::AParcel_markSensitive(self.as_native()) }
     }
 
     /// Write a type that implements [`Serialize`] to the parcel.
@@ -265,11 +254,15 @@
             f(&mut subparcel)?;
         }
         let end = self.get_data_position();
+        // Safety: start is less than the current size of the parcel data
+        // buffer, because we just got it with `get_data_position`.
         unsafe {
             self.set_data_position(start)?;
         }
         assert!(end >= start);
         self.write(&(end - start))?;
+        // Safety: end is less than the current size of the parcel data
+        // buffer, because we just got it with `get_data_position`.
         unsafe {
             self.set_data_position(end)?;
         }
@@ -278,20 +271,16 @@
 
     /// Returns the current position in the parcel data.
     pub fn get_data_position(&self) -> i32 {
-        unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`, and this call is otherwise safe.
-            sys::AParcel_getDataPosition(self.as_native())
-        }
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        unsafe { sys::AParcel_getDataPosition(self.as_native()) }
     }
 
     /// Returns the total size of the parcel.
     pub fn get_data_size(&self) -> i32 {
-        unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`, and this call is otherwise safe.
-            sys::AParcel_getDataSize(self.as_native())
-        }
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        unsafe { sys::AParcel_getDataSize(self.as_native()) }
     }
 
     /// Move the current read/write position in the parcel.
@@ -304,7 +293,9 @@
     /// accesses are bounds checked, this call is still safe, but we can't rely
     /// on that.
     pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
-        status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and the caller guarantees that `pos` is within bounds.
+        status_result(unsafe { sys::AParcel_setDataPosition(self.as_native(), pos) })
     }
 
     /// Append a subset of another parcel.
@@ -317,10 +308,10 @@
         start: i32,
         size: i32,
     ) -> Result<()> {
+        // Safety: `Parcel::appendFrom` from C++ checks that `start`
+        // and `size` are in bounds, and returns an error otherwise.
+        // Both `self` and `other` always contain valid pointers.
         let status = unsafe {
-            // Safety: `Parcel::appendFrom` from C++ checks that `start`
-            // and `size` are in bounds, and returns an error otherwise.
-            // Both `self` and `other` always contain valid pointers.
             sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
         };
         status_result(status)
@@ -418,7 +409,9 @@
     /// accesses are bounds checked, this call is still safe, but we can't rely
     /// on that.
     pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
-        self.borrowed_ref().set_data_position(pos)
+        // Safety: We have the same safety requirements as
+        // `BorrowedParcel::set_data_position`.
+        unsafe { self.borrowed_ref().set_data_position(pos) }
     }
 
     /// Append a subset of another parcel.
@@ -461,7 +454,7 @@
     /// and call a closure with the sub-parcel as its parameter.
     /// The closure can keep reading data from the sub-parcel
     /// until it runs out of input data. The closure is responsible
-    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// for calling `ReadableSubParcel::has_more_data` to check for
     /// more data before every read, at least until Rust generators
     /// are stabilized.
     /// After the closure returns, skip to the end of the current
@@ -504,7 +497,10 @@
         f(subparcel)?;
 
         // Advance the data position to the actual end,
-        // in case the closure read less data than was available
+        // in case the closure read less data than was available.
+        //
+        // Safety: end must be less than the current size of the parcel, because
+        // we checked above against `get_data_size`.
         unsafe {
             self.set_data_position(end)?;
         }
@@ -595,7 +591,7 @@
     /// and call a closure with the sub-parcel as its parameter.
     /// The closure can keep reading data from the sub-parcel
     /// until it runs out of input data. The closure is responsible
-    /// for calling [`ReadableSubParcel::has_more_data`] to check for
+    /// for calling `ReadableSubParcel::has_more_data` to check for
     /// more data before every read, at least until Rust generators
     /// are stabilized.
     /// After the closure returns, skip to the end of the current
@@ -649,17 +645,17 @@
 // Internal APIs
 impl<'a> BorrowedParcel<'a> {
     pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
+        // null or a valid pointer to an `AIBinder`, both of which are
+        // valid, safe inputs to `AParcel_writeStrongBinder`.
+        //
+        // This call does not take ownership of the binder. However, it does
+        // require a mutable pointer, which we cannot extract from an
+        // immutable reference, so we clone the binder, incrementing the
+        // refcount before the call. The refcount will be immediately
+        // decremented when this temporary is dropped.
         unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`. `AsNative` for `Option<SpIBinder`> will either return
-            // null or a valid pointer to an `AIBinder`, both of which are
-            // valid, safe inputs to `AParcel_writeStrongBinder`.
-            //
-            // This call does not take ownership of the binder. However, it does
-            // require a mutable pointer, which we cannot extract from an
-            // immutable reference, so we clone the binder, incrementing the
-            // refcount before the call. The refcount will be immediately
-            // decremented when this temporary is dropped.
             status_result(sys::AParcel_writeStrongBinder(
                 self.as_native_mut(),
                 binder.cloned().as_native_mut(),
@@ -669,33 +665,28 @@
 
     pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
         let mut binder = ptr::null_mut();
-        let status = unsafe {
-            // Safety: `BorrowedParcel` always contains a valid pointer to an
-            // `AParcel`. We pass a valid, mutable out pointer to the `binder`
-            // parameter. After this call, `binder` will be either null or a
-            // valid pointer to an `AIBinder` owned by the caller.
-            sys::AParcel_readStrongBinder(self.as_native(), &mut binder)
-        };
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`. We pass a valid, mutable out pointer to the `binder`
+        // parameter. After this call, `binder` will be either null or a
+        // valid pointer to an `AIBinder` owned by the caller.
+        let status = unsafe { sys::AParcel_readStrongBinder(self.as_native(), &mut binder) };
 
         status_result(status)?;
 
-        Ok(unsafe {
-            // Safety: `binder` is either null or a valid, owned pointer at this
-            // point, so can be safely passed to `SpIBinder::from_raw`.
-            SpIBinder::from_raw(binder)
-        })
+        // Safety: `binder` is either null or a valid, owned pointer at this
+        // point, so can be safely passed to `SpIBinder::from_raw`.
+        Ok(unsafe { SpIBinder::from_raw(binder) })
     }
 }
 
 impl Drop for Parcel {
     fn drop(&mut self) {
         // Run the C++ Parcel complete object destructor
-        unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. Since we own the parcel, we can safely delete it
-            // here.
-            sys::AParcel_delete(self.ptr.as_ptr())
-        }
+        //
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. Since we own the parcel, we can safely delete it
+        // here.
+        unsafe { sys::AParcel_delete(self.ptr.as_ptr()) }
     }
 }
 
@@ -732,6 +723,8 @@
 
     parcel.write(&1i32).unwrap();
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         parcel.set_data_position(start).unwrap();
     }
@@ -748,6 +741,8 @@
 
     parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
     // Skip over string length
+    // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(str_start).is_ok());
     }
@@ -756,42 +751,56 @@
 
     assert!(parcel.read::<bool>().unwrap());
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<i8>().unwrap(), 72i8);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<u16>().unwrap(), 25928);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<i32>().unwrap(), 1819043144);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<u32>().unwrap(), 1819043144);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<i64>().unwrap(), 4764857262830019912);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert_eq!(parcel.read::<u64>().unwrap(), 4764857262830019912);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -799,6 +808,8 @@
     assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
     assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -806,6 +817,8 @@
     assert_eq!(parcel.read::<f64>().unwrap(), 34732488246.197815);
 
     // Skip back to before the string length
+    // SAFETY: str_start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(str_start).is_ok());
     }
@@ -819,15 +832,21 @@
     let start = parcel.get_data_position();
 
     assert!(parcel.write("Hello, Binder!").is_ok());
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
     assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
 
     assert!(parcel.write("Embedded null \0 inside a string").is_ok());
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -835,6 +854,8 @@
         parcel.read::<Option<String>>().unwrap().unwrap(),
         "Embedded null \0 inside a string",
     );
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -849,6 +870,8 @@
     let s3 = "Some more text here.";
 
     assert!(parcel.write(&[s1, s2, s3][..]).is_ok());
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -874,6 +897,8 @@
 
     assert_eq!(parcel.get_data_position(), start + expected_len);
 
+    // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+    // made it any shorter since we got the position.
     unsafe {
         parcel.set_data_position(start).unwrap();
     }
@@ -893,6 +918,8 @@
     assert_eq!(4, parcel2.get_data_size());
     assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
     assert_eq!(8, parcel2.get_data_size());
+    // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+    // empty.
     unsafe {
         parcel2.set_data_position(0).unwrap();
     }
@@ -903,6 +930,8 @@
     assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
     assert_eq!(Ok(()), parcel2.append_from(&parcel1, 2, 2));
     assert_eq!(4, parcel2.get_data_size());
+    // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+    // empty.
     unsafe {
         parcel2.set_data_position(0).unwrap();
     }
@@ -911,6 +940,8 @@
     let mut parcel2 = Parcel::new();
     assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
     assert_eq!(2, parcel2.get_data_size());
+    // SAFETY: 0 is less than the current size of the parcel data buffer, because the parcel is not
+    // empty.
     unsafe {
         parcel2.set_data_position(0).unwrap();
     }
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index de6d649..5c688fa 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -73,14 +73,12 @@
 impl Serialize for ParcelFileDescriptor {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let fd = self.0.as_raw_fd();
-        let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
-            // valid file, so we can borrow a valid file
-            // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
-            // ownership of the fd, so we need not duplicate it first.
-            sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd)
-        };
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. Likewise, `ParcelFileDescriptor` always contains a
+        // valid file, so we can borrow a valid file
+        // descriptor. `AParcel_writeParcelFileDescriptor` does NOT take
+        // ownership of the fd, so we need not duplicate it first.
+        let status = unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), fd) };
         status_result(status)
     }
 }
@@ -92,13 +90,12 @@
         if let Some(f) = this {
             f.serialize(parcel)
         } else {
-            let status = unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
-                // value `-1` as the file descriptor to signify serializing a
-                // null file descriptor.
-                sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32)
-            };
+            let status =
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. `AParcel_writeParcelFileDescriptor` accepts the
+            // value `-1` as the file descriptor to signify serializing a
+            // null file descriptor.
+                unsafe { sys::AParcel_writeParcelFileDescriptor(parcel.as_native_mut(), -1i32) };
             status_result(status)
         }
     }
@@ -107,31 +104,37 @@
 impl DeserializeOption for ParcelFileDescriptor {
     fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let mut fd = -1i32;
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. We pass a valid mutable pointer to an i32, which
+        // `AParcel_readParcelFileDescriptor` assigns the valid file
+        // descriptor into, or `-1` if deserializing a null file
+        // descriptor. The read function passes ownership of the file
+        // descriptor to its caller if it was non-null, so we must take
+        // ownership of the file and ensure that it is eventually closed.
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. We pass a valid mutable pointer to an i32, which
-            // `AParcel_readParcelFileDescriptor` assigns the valid file
-            // descriptor into, or `-1` if deserializing a null file
-            // descriptor. The read function passes ownership of the file
-            // descriptor to its caller if it was non-null, so we must take
-            // ownership of the file and ensure that it is eventually closed.
             status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
         }
         if fd < 0 {
             Ok(None)
         } else {
-            let file = unsafe {
-                // Safety: At this point, we know that the file descriptor was
-                // not -1, so must be a valid, owned file descriptor which we
-                // can safely turn into a `File`.
-                File::from_raw_fd(fd)
-            };
+            // Safety: At this point, we know that the file descriptor was
+            // not -1, so must be a valid, owned file descriptor which we
+            // can safely turn into a `File`.
+            let file = unsafe { File::from_raw_fd(fd) };
             Ok(Some(ParcelFileDescriptor::new(file)))
         }
     }
 }
 
 impl Deserialize for ParcelFileDescriptor {
+    type UninitType = Option<Self>;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        Some(value)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 4b658fc..9008a3c 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-use crate::binder::{AsNative, FromIBinder, Stability, Strong};
+use crate::binder::{AsNative, FromIBinder, Interface, Stability, Strong};
 use crate::error::{status_result, status_t, Result, Status, StatusCode};
 use crate::parcel::BorrowedParcel;
 use crate::proxy::SpIBinder;
@@ -22,7 +22,7 @@
 
 use std::convert::{TryFrom, TryInto};
 use std::ffi::c_void;
-use std::mem::{self, ManuallyDrop, MaybeUninit};
+use std::mem::{self, ManuallyDrop};
 use std::os::raw::c_char;
 use std::ptr;
 use std::slice;
@@ -50,20 +50,40 @@
     fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
 }
 
-/// A struct whose instances can be written to a [`Parcel`].
+/// A struct whose instances can be written to a [`crate::parcel::Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Serialize {
-    /// Serialize this instance into the given [`Parcel`].
+    /// Serialize this instance into the given [`crate::parcel::Parcel`].
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
 }
 
-/// A struct whose instances can be restored from a [`Parcel`].
+/// A struct whose instances can be restored from a [`crate::parcel::Parcel`].
 // Might be able to hook this up as a serde backend in the future?
 pub trait Deserialize: Sized {
-    /// Deserialize an instance from the given [`Parcel`].
+    /// Type for the uninitialized value of this type. Will be either `Self`
+    /// if the type implements `Default`, `Option<Self>` otherwise.
+    type UninitType;
+
+    /// Assert at compile-time that `Self` and `Self::UninitType` have the same
+    /// size and alignment. This will either fail to compile or evaluate to `true`.
+    /// The only two macros that work here are `panic!` and `assert!`, so we cannot
+    /// use `assert_eq!`.
+    const ASSERT_UNINIT_SIZE_AND_ALIGNMENT: bool = {
+        assert!(std::mem::size_of::<Self>() == std::mem::size_of::<Self::UninitType>());
+        assert!(std::mem::align_of::<Self>() == std::mem::align_of::<Self::UninitType>());
+        true
+    };
+
+    /// Return an uninitialized or default-initialized value for this type.
+    fn uninit() -> Self::UninitType;
+
+    /// Convert an initialized value of type `Self` into `Self::UninitType`.
+    fn from_init(value: Self) -> Self::UninitType;
+
+    /// Deserialize an instance from the given [`crate::parcel::Parcel`].
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
 
-    /// Deserialize an instance from the given [`Parcel`] onto the
+    /// Deserialize an instance from the given [`crate::parcel::Parcel`] onto the
     /// current object. This operation will overwrite the old value
     /// partially or completely, depending on how much data is available.
     fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
@@ -82,8 +102,8 @@
 pub trait SerializeArray: Serialize + Sized {
     /// Serialize an array of this type into the given parcel.
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: Safe FFI, slice will always be a safe pointer to pass.
         let res = unsafe {
-            // Safety: Safe FFI, slice will always be a safe pointer to pass.
             sys::AParcel_writeParcelableArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const c_void,
@@ -97,7 +117,9 @@
 
 /// Callback to serialize an element of a generic parcelable array.
 ///
-/// Safety: We are relying on binder_ndk to not overrun our slice. As long as it
+/// # Safety
+///
+/// We are relying on binder_ndk to not overrun our slice. As long as it
 /// doesn't provide an index larger than the length of the original slice in
 /// serialize_array, this operation is safe. The index provided is zero-based.
 unsafe extern "C" fn serialize_element<T: Serialize>(
@@ -105,9 +127,14 @@
     array: *const c_void,
     index: usize,
 ) -> status_t {
-    let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
+    // Safety: The caller guarantees that `array` is a valid pointer of the
+    // appropriate type.
+    let slice: &[T] = unsafe { slice::from_raw_parts(array.cast(), index + 1) };
 
-    let mut parcel = match BorrowedParcel::from_raw(parcel) {
+    // Safety: The caller must give us a parcel pointer which is either null or
+    // valid at least for the duration of this function call. We don't keep the
+    // resulting value beyond the function.
+    let mut parcel = match unsafe { BorrowedParcel::from_raw(parcel) } {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -121,10 +148,10 @@
 pub trait DeserializeArray: Deserialize {
     /// Deserialize an array of type from the given parcel.
     fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
-        let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
+        let mut vec: Option<Vec<Self::UninitType>> = None;
+        // Safety: Safe FFI, vec is the correct opaque type expected by
+        // allocate_vec and deserialize_element.
         let res = unsafe {
-            // Safety: Safe FFI, vec is the correct opaque type expected by
-            // allocate_vec and deserialize_element.
             sys::AParcel_readParcelableArray(
                 parcel.as_native(),
                 &mut vec as *mut _ as *mut c_void,
@@ -133,36 +160,41 @@
             )
         };
         status_result(res)?;
-        let vec: Option<Vec<Self>> = unsafe {
-            // Safety: We are assuming that the NDK correctly initialized every
-            // element of the vector by now, so we know that all the
-            // MaybeUninits are now properly initialized. We can transmute from
-            // Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T> has the same
-            // alignment and size as T, so the pointer to the vector allocation
-            // will be compatible.
-            mem::transmute(vec)
-        };
+        // Safety: We are assuming that the NDK correctly initialized every
+        // element of the vector by now, so we know that all the
+        // UninitTypes are now properly initialized. We can transmute from
+        // Vec<T::UninitType> to Vec<T> because T::UninitType has the same
+        // alignment and size as T, so the pointer to the vector allocation
+        // will be compatible.
+        let vec: Option<Vec<Self>> = unsafe { mem::transmute(vec) };
         Ok(vec)
     }
 }
 
 /// Callback to deserialize a parcelable element.
 ///
+/// # Safety
+///
 /// The opaque array data pointer must be a mutable pointer to an
-/// `Option<Vec<MaybeUninit<T>>>` with at least enough elements for `index` to be valid
+/// `Option<Vec<T::UninitType>>` with at least enough elements for `index` to be valid
 /// (zero-based).
 unsafe extern "C" fn deserialize_element<T: Deserialize>(
     parcel: *const sys::AParcel,
     array: *mut c_void,
     index: usize,
 ) -> status_t {
-    let vec = &mut *(array as *mut Option<Vec<MaybeUninit<T>>>);
+    // Safety: The caller guarantees that `array` is a valid pointer of the
+    // appropriate type.
+    let vec = unsafe { &mut *(array as *mut Option<Vec<T::UninitType>>) };
     let vec = match vec {
         Some(v) => v,
         None => return StatusCode::BAD_INDEX as status_t,
     };
 
-    let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
+    // Safety: The caller must give us a parcel pointer which is either null or
+    // valid at least for the duration of this function call. We don't keep the
+    // resulting value beyond the function.
+    let parcel = match unsafe { BorrowedParcel::from_raw(parcel as *mut _) } {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -170,7 +202,7 @@
         Ok(e) => e,
         Err(code) => return code as status_t,
     };
-    ptr::write(vec[index].as_mut_ptr(), element);
+    vec[index] = T::from_init(element);
     StatusCode::OK as status_t
 }
 
@@ -233,17 +265,22 @@
 /// # Safety
 ///
 /// The opaque data pointer passed to the array read function must be a mutable
-/// pointer to an `Option<Vec<MaybeUninit<T>>>`. `buffer` will be assigned a mutable pointer
-/// to the allocated vector data if this function returns true.
-unsafe extern "C" fn allocate_vec_with_buffer<T>(
+/// pointer to an `Option<Vec<T::UninitType>>`. `buffer` will be assigned a mutable pointer
+/// to the allocated vector data if this function returns true. `buffer` must be a valid pointer.
+unsafe extern "C" fn allocate_vec_with_buffer<T: Deserialize>(
     data: *mut c_void,
     len: i32,
     buffer: *mut *mut T,
 ) -> bool {
-    let res = allocate_vec::<T>(data, len);
-    let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
+    // Safety: We have the same safety requirements as `allocate_vec` for `data`.
+    let res = unsafe { allocate_vec::<T>(data, len) };
+    // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+    let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
     if let Some(new_vec) = vec {
-        *buffer = new_vec.as_mut_ptr() as *mut T;
+        // Safety: The caller guarantees that `buffer` is a valid pointer.
+        unsafe {
+            *buffer = new_vec.as_mut_ptr() as *mut T;
+        }
     }
     res
 }
@@ -253,22 +290,24 @@
 /// # Safety
 ///
 /// The opaque data pointer passed to the array read function must be a mutable
-/// pointer to an `Option<Vec<MaybeUninit<T>>>`.
-unsafe extern "C" fn allocate_vec<T>(data: *mut c_void, len: i32) -> bool {
-    let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
+/// pointer to an `Option<Vec<T::UninitType>>`.
+unsafe extern "C" fn allocate_vec<T: Deserialize>(data: *mut c_void, len: i32) -> bool {
+    // Safety: The caller guarantees that `data` is a valid mutable pointer to the appropriate type.
+    let vec = unsafe { &mut *(data as *mut Option<Vec<T::UninitType>>) };
     if len < 0 {
         *vec = None;
         return true;
     }
-    let mut new_vec: Vec<MaybeUninit<T>> = Vec::with_capacity(len as usize);
 
-    // Safety: We are filling the vector with uninitialized data here, but this
-    // is safe because the vector contains MaybeUninit elements which can be
-    // uninitialized. We're putting off the actual unsafe bit, transmuting the
-    // vector to a Vec<T> until the contents are initialized.
-    new_vec.set_len(len as usize);
+    // Assert at compile time that `T` and `T::UninitType` have the same size and alignment.
+    let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT;
+    let mut new_vec: Vec<T::UninitType> = Vec::with_capacity(len as usize);
+    new_vec.resize_with(len as usize, T::uninit);
 
-    ptr::write(vec, Some(new_vec));
+    // Safety: The caller guarantees that vec is a valid mutable pointer to the appropriate type.
+    unsafe {
+        ptr::write(vec, Some(new_vec));
+    }
     true
 }
 
@@ -283,22 +322,25 @@
 }
 
 /// Safety: All elements in the vector must be properly initialized.
-unsafe fn vec_assume_init<T>(vec: Vec<MaybeUninit<T>>) -> Vec<T> {
-    // We can convert from Vec<MaybeUninit<T>> to Vec<T> because MaybeUninit<T>
-    // has the same alignment and size as T, so the pointer to the vector
-    // allocation will be compatible.
+unsafe fn vec_assume_init<T: Deserialize>(vec: Vec<T::UninitType>) -> Vec<T> {
+    // Assert at compile time that `T` and `T::UninitType` have the same size and alignment.
+    let _ = T::ASSERT_UNINIT_SIZE_AND_ALIGNMENT;
+
     let mut vec = ManuallyDrop::new(vec);
-    Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
+    // Safety: We can convert from Vec<T::UninitType> to Vec<T> because
+    // T::UninitType has the same alignment and size as T, so the pointer to the
+    // vector allocation will be compatible.
+    unsafe { Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity()) }
 }
 
 macro_rules! impl_parcelable {
     {Serialize, $ty:ty, $write_fn:path} => {
         impl Serialize for $ty {
             fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`, and any `$ty` literal value is safe to pass to
+                // `$write_fn`.
                 unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`, and any `$ty` literal value is safe to pass to
-                    // `$write_fn`.
                     status_result($write_fn(parcel.as_native_mut(), *self))
                 }
             }
@@ -307,13 +349,16 @@
 
     {Deserialize, $ty:ty, $read_fn:path} => {
         impl Deserialize for $ty {
+            type UninitType = Self;
+            fn uninit() -> Self::UninitType { Self::UninitType::default() }
+            fn from_init(value: Self) -> Self::UninitType { value }
             fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 let mut val = Self::default();
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. We pass a valid, mutable pointer to `val`, a
+                // literal of type `$ty`, and `$read_fn` will write the
+                // value read into `val` if successful
                 unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. We pass a valid, mutable pointer to `val`, a
-                    // literal of type `$ty`, and `$read_fn` will write the
-                    // value read into `val` if successful
                     status_result($read_fn(parcel.as_native(), &mut val))?
                 };
                 Ok(val)
@@ -324,13 +369,13 @@
     {SerializeArray, $ty:ty, $write_array_fn:path} => {
         impl SerializeArray for $ty {
             fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
+                // will be a valid pointer to an array of elements of type
+                // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
+                // dangling, but this is safe since the pointer is not
+                // dereferenced if the length parameter is 0.
                 let status = unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
-                    // will be a valid pointer to an array of elements of type
-                    // `$ty`. If the slice length is 0, `slice.as_ptr()` may be
-                    // dangling, but this is safe since the pointer is not
-                    // dereferenced if the length parameter is 0.
                     $write_array_fn(
                         parcel.as_native_mut(),
                         slice.as_ptr(),
@@ -348,12 +393,12 @@
     {DeserializeArray, $ty:ty, $read_array_fn:path} => {
         impl DeserializeArray for $ty {
             fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
-                let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
+                let mut vec: Option<Vec<Self::UninitType>> = None;
+                // Safety: `Parcel` always contains a valid pointer to an
+                // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
+                // be of type `*mut Option<Vec<T::UninitType>>`, so `&mut vec` is
+                // correct for it.
                 let status = unsafe {
-                    // Safety: `Parcel` always contains a valid pointer to an
-                    // `AParcel`. `allocate_vec<T>` expects the opaque pointer to
-                    // be of type `*mut Option<Vec<MaybeUninit<T>>>`, so `&mut vec` is
-                    // correct for it.
                     $read_array_fn(
                         parcel.as_native(),
                         &mut vec as *mut _ as *mut c_void,
@@ -361,11 +406,11 @@
                     )
                 };
                 status_result(status)?;
+                // Safety: We are assuming that the NDK correctly
+                // initialized every element of the vector by now, so we
+                // know that all the UninitTypes are now properly
+                // initialized.
                 let vec: Option<Vec<Self>> = unsafe {
-                    // Safety: We are assuming that the NDK correctly
-                    // initialized every element of the vector by now, so we
-                    // know that all the MaybeUninits are now properly
-                    // initialized.
                     vec.map(|vec| vec_assume_init(vec))
                 };
                 Ok(vec)
@@ -440,6 +485,14 @@
 }
 
 impl Deserialize for u8 {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         i8::deserialize(parcel).map(|v| v as u8)
     }
@@ -447,13 +500,13 @@
 
 impl SerializeArray for u8 {
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+        // valid pointer to an array of elements of type `$ty`. If the slice
+        // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+        // since the pointer is not dereferenced if the length parameter is
+        // 0.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
-            // valid pointer to an array of elements of type `$ty`. If the slice
-            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
-            // since the pointer is not dereferenced if the length parameter is
-            // 0.
             sys::AParcel_writeByteArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const i8,
@@ -471,6 +524,14 @@
 }
 
 impl Deserialize for i16 {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         u16::deserialize(parcel).map(|v| v as i16)
     }
@@ -478,13 +539,13 @@
 
 impl SerializeArray for i16 {
     fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
+        // valid pointer to an array of elements of type `$ty`. If the slice
+        // length is 0, `slice.as_ptr()` may be dangling, but this is safe
+        // since the pointer is not dereferenced if the length parameter is
+        // 0.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. If the slice is > 0 length, `slice.as_ptr()` will be a
-            // valid pointer to an array of elements of type `$ty`. If the slice
-            // length is 0, `slice.as_ptr()` may be dangling, but this is safe
-            // since the pointer is not dereferenced if the length parameter is
-            // 0.
             sys::AParcel_writeCharArray(
                 parcel.as_native_mut(),
                 slice.as_ptr() as *const u16,
@@ -498,22 +559,22 @@
 impl SerializeOption for str {
     fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         match this {
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. If the string pointer is null,
+            // `AParcel_writeString` requires that the length is -1 to
+            // indicate that we want to serialize a null string.
             None => unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. If the string pointer is null,
-                // `AParcel_writeString` requires that the length is -1 to
-                // indicate that we want to serialize a null string.
                 status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
             },
+            // Safety: `Parcel` always contains a valid pointer to an
+            // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
+            // string pointer of `length` bytes, which is what str in Rust
+            // is. The docstring for `AParcel_writeString` says that the
+            // string input should be null-terminated, but it doesn't
+            // actually rely on that fact in the code. If this ever becomes
+            // necessary, we will need to null-terminate the str buffer
+            // before sending it.
             Some(s) => unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. `AParcel_writeString` assumes that we pass a utf-8
-                // string pointer of `length` bytes, which is what str in Rust
-                // is. The docstring for `AParcel_writeString` says that the
-                // string input should be null-terminated, but it doesn't
-                // actually rely on that fact in the code. If this ever becomes
-                // necessary, we will need to null-terminate the str buffer
-                // before sending it.
                 status_result(sys::AParcel_writeString(
                     parcel.as_native_mut(),
                     s.as_ptr() as *const c_char,
@@ -547,13 +608,21 @@
 }
 
 impl Deserialize for Option<String> {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
+        // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
+        // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
+        // for `allocate_vec`, so `vec` is safe to pass as the opaque data
+        // pointer on platforms where char is signed.
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
-            // `Option<Vec<u8>>` is equivalent to the expected `Option<Vec<i8>>`
-            // for `allocate_vec`, so `vec` is safe to pass as the opaque data
-            // pointer on platforms where char is signed.
             sys::AParcel_readString(
                 parcel.as_native(),
                 &mut vec as *mut _ as *mut c_void,
@@ -575,6 +644,14 @@
 impl DeserializeArray for Option<String> {}
 
 impl Deserialize for String {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
@@ -611,6 +688,14 @@
 }
 
 impl<T: DeserializeArray> Deserialize for Vec<T> {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeArray::deserialize_array(parcel)
             .transpose()
@@ -640,6 +725,14 @@
 impl<T: SerializeArray, const N: usize> SerializeArray for [T; N] {}
 
 impl<T: DeserializeArray, const N: usize> Deserialize for [T; N] {
+    type UninitType = [T::UninitType; N];
+    fn uninit() -> Self::UninitType {
+        [(); N].map(|_| T::uninit())
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value.map(T::from_init)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let vec = DeserializeArray::deserialize_array(parcel)
             .transpose()
@@ -664,6 +757,14 @@
 }
 
 impl Deserialize for Stability {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         i32::deserialize(parcel).and_then(Stability::try_from)
     }
@@ -671,34 +772,39 @@
 
 impl Serialize for Status {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        // Safety: `Parcel` always contains a valid pointer to an `AParcel`
+        // and `Status` always contains a valid pointer to an `AStatus`, so
+        // both parameters are valid and safe. This call does not take
+        // ownership of either of its parameters.
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`
-            // and `Status` always contains a valid pointer to an `AStatus`, so
-            // both parameters are valid and safe. This call does not take
-            // ownership of either of its parameters.
             status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
         }
     }
 }
 
 impl Deserialize for Status {
+    type UninitType = Option<Self>;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        Some(value)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut status_ptr = ptr::null_mut();
-        let ret_status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
-            // `AParcel`. We pass a mutable out pointer which will be
-            // assigned a valid `AStatus` pointer if the function returns
-            // status OK. This function passes ownership of the status
-            // pointer to the caller, if it was assigned.
-            sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr)
-        };
+        let ret_status =
+        // Safety: `Parcel` always contains a valid pointer to an
+        // `AParcel`. We pass a mutable out pointer which will be
+        // assigned a valid `AStatus` pointer if the function returns
+        // status OK. This function passes ownership of the status
+        // pointer to the caller, if it was assigned.
+            unsafe { sys::AParcel_readStatusHeader(parcel.as_native(), &mut status_ptr) };
         status_result(ret_status)?;
-        Ok(unsafe {
-            // Safety: At this point, the return status of the read call was ok,
-            // so we know that `status_ptr` is a valid, owned pointer to an
-            // `AStatus`, from which we can safely construct a `Status` object.
-            Status::from_ptr(status_ptr)
-        })
+        // Safety: At this point, the return status of the read call was ok,
+        // so we know that `status_ptr` is a valid, owned pointer to an
+        // `AStatus`, from which we can safely construct a `Status` object.
+        Ok(unsafe { Status::from_ptr(status_ptr) })
     }
 }
 
@@ -717,12 +823,29 @@
 impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
 
 impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
+    type UninitType = Option<Strong<T>>;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        Some(value)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let ibinder: SpIBinder = parcel.read()?;
         FromIBinder::try_from(ibinder)
     }
 }
 
+struct AssertIBinder;
+impl Interface for AssertIBinder {}
+impl FromIBinder for AssertIBinder {
+    // This is only needed so we can assert on the size of Strong<AssertIBinder>
+    fn try_from(_: SpIBinder) -> Result<Strong<Self>> {
+        unimplemented!()
+    }
+}
+
 impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
     fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let ibinder: Option<SpIBinder> = parcel.read()?;
@@ -752,6 +875,14 @@
 }
 
 impl<T: DeserializeOption> Deserialize for Option<T> {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeOption::deserialize_option(parcel)
     }
@@ -767,7 +898,6 @@
 /// `Serialize`, `SerializeArray` and `SerializeOption` for
 /// structured parcelables. The target type must implement the
 /// `Parcelable` trait.
-/// ```
 #[macro_export]
 macro_rules! impl_serialize_for_parcelable {
     ($parcelable:ident) => {
@@ -821,6 +951,9 @@
     };
     ($parcelable:ident < $( $param:ident ),* > ) => {
         impl < $($param: Default),* > $crate::binder_impl::Deserialize for $parcelable < $($param),* > {
+            type UninitType = Self;
+            fn uninit() -> Self::UninitType { Self::UninitType::default() }
+            fn from_init(value: Self) -> Self::UninitType { value }
             fn deserialize(
                 parcel: &$crate::binder_impl::BorrowedParcel<'_>,
             ) -> std::result::Result<Self, $crate::StatusCode> {
@@ -876,6 +1009,14 @@
 }
 
 impl<T: Deserialize> Deserialize for Box<T> {
+    type UninitType = Option<Self>;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        Some(value)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel).map(Box::new)
     }
@@ -900,6 +1041,7 @@
 
     #[test]
     fn test_custom_parcelable() {
+        #[derive(Default)]
         struct Custom(u32, bool, String, Vec<String>);
 
         impl Serialize for Custom {
@@ -912,6 +1054,14 @@
         }
 
         impl Deserialize for Custom {
+            type UninitType = Self;
+            fn uninit() -> Self::UninitType {
+                Self::UninitType::default()
+            }
+            fn from_init(value: Self) -> Self::UninitType {
+                value
+            }
+
             fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 Ok(Custom(
                     parcel.read()?,
@@ -937,6 +1087,8 @@
 
         assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -959,6 +1111,8 @@
 
         assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -968,6 +1122,8 @@
         assert_eq!(parcel.read::<u32>().unwrap(), 0);
         assert_eq!(parcel.read::<u32>().unwrap(), 0);
         assert_eq!(parcel.read::<u32>().unwrap(), 1);
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -983,12 +1139,17 @@
 
         assert!(parcel.write(&u8s[..]).is_ok());
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
 
         assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
         assert_eq!(parcel.read::<u32>().unwrap(), 0x752aff65); // bytes
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -998,18 +1159,25 @@
 
         let i8s = [-128i8, 127, 42, -117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
 
         assert!(parcel.write(&i8s[..]).is_ok());
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
 
         assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
         assert_eq!(parcel.read::<u32>().unwrap(), 0x8b2a7f80); // bytes
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1019,10 +1187,14 @@
 
         let u16s = [u16::max_value(), 12_345, 42, 117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1032,6 +1204,9 @@
         assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
         assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
         assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1042,10 +1217,14 @@
 
         let i16s = [i16::max_value(), i16::min_value(), 42, -117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1055,6 +1234,9 @@
         assert_eq!(parcel.read::<u32>().unwrap(), 0x8000); // i16::min_value()
         assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
         assert_eq!(parcel.read::<u32>().unwrap(), 0xff8b); // -117
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1065,10 +1247,14 @@
 
         let u32s = [u32::max_value(), 12_345, 42, 117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1078,6 +1264,9 @@
         assert_eq!(parcel.read::<u32>().unwrap(), 12345); // 12,345
         assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
         assert_eq!(parcel.read::<u32>().unwrap(), 117); // 117
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1088,10 +1277,14 @@
 
         let i32s = [i32::max_value(), i32::min_value(), 42, -117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1101,6 +1294,9 @@
         assert_eq!(parcel.read::<u32>().unwrap(), 0x80000000); // i32::min_value()
         assert_eq!(parcel.read::<u32>().unwrap(), 42); // 42
         assert_eq!(parcel.read::<u32>().unwrap(), 0xffffff8b); // -117
+
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1111,10 +1307,14 @@
 
         let u64s = [u64::max_value(), 12_345, 42, 117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1125,10 +1325,14 @@
 
         let i64s = [i64::max_value(), i64::min_value(), 42, -117];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1139,10 +1343,14 @@
 
         let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1155,10 +1363,14 @@
 
         let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
@@ -1176,10 +1388,14 @@
 
         let strs = [s1, s2, s3, s4];
 
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
         assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+        // SAFETY: start is less than the current size of the parcel data buffer, because we haven't
+        // made it any shorter since we got the position.
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
         }
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index c829d37..f906113 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -133,8 +133,8 @@
                 }
             }
             ParcelableHolderData::Parcel(ref mut parcel) => {
+                // Safety: 0 should always be a valid position.
                 unsafe {
-                    // Safety: 0 should always be a valid position.
                     parcel.set_data_position(0)?;
                 }
 
@@ -161,6 +161,15 @@
     }
 }
 
+impl Clone for ParcelableHolder {
+    fn clone(&self) -> ParcelableHolder {
+        ParcelableHolder {
+            data: Mutex::new(self.data.lock().unwrap().clone()),
+            stability: self.stability,
+        }
+    }
+}
+
 impl Serialize for ParcelableHolder {
     fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<(), StatusCode> {
         parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
@@ -169,6 +178,14 @@
 }
 
 impl Deserialize for ParcelableHolder {
+    type UninitType = Self;
+    fn uninit() -> Self::UninitType {
+        Self::new(Default::default())
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        value
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self, StatusCode> {
         let status: i32 = parcel.read()?;
         if status == NULL_PARCELABLE_FLAG {
@@ -197,15 +214,15 @@
                 parcelable.write_to_parcel(parcel)?;
 
                 let end = parcel.get_data_position();
+                // Safety: we got the position from `get_data_position`.
                 unsafe {
-                    // Safety: we got the position from `get_data_position`.
                     parcel.set_data_position(length_start)?;
                 }
 
                 assert!(end >= data_start);
                 parcel.write(&(end - data_start))?;
+                // Safety: we got the position from `get_data_position`.
                 unsafe {
-                    // Safety: we got the position from `get_data_position`.
                     parcel.set_data_position(end)?;
                 }
 
@@ -243,11 +260,11 @@
         new_parcel.append_from(parcel, data_start, data_size)?;
         *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
 
+        // Safety: `append_from` checks if `data_size` overflows
+        // `parcel` and returns `BAD_VALUE` if that happens. We also
+        // explicitly check for negative and zero `data_size` above,
+        // so `data_end` is guaranteed to be greater than `data_start`.
         unsafe {
-            // Safety: `append_from` checks if `data_size` overflows
-            // `parcel` and returns `BAD_VALUE` if that happens. We also
-            // explicitly check for negative and zero `data_size` above,
-            // so `data_end` is guaranteed to be greater than `data_start`.
             parcel.set_data_position(data_end)?;
         }
 
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 254efae..dad3379 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -49,14 +49,12 @@
     }
 }
 
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Send for SpIBinder {}
 
-/// # Safety
-///
-/// An `SpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe
+/// Safety: An `SpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Sync for SpIBinder {}
 
 impl SpIBinder {
@@ -97,11 +95,9 @@
     /// Return true if this binder object is hosted in a different process than
     /// the current one.
     pub fn is_remote(&self) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer.
-            sys::AIBinder_isRemote(self.as_native())
-        }
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer.
+        unsafe { sys::AIBinder_isRemote(self.as_native()) }
     }
 
     /// Try to convert this Binder object into a trait object for the given
@@ -116,12 +112,12 @@
     /// Return the interface class of this binder object, if associated with
     /// one.
     pub fn get_class(&mut self) -> Option<InterfaceClass> {
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer. `AIBinder_getClass` returns either a null
+        // pointer or a valid pointer to an `AIBinder_Class`. After mapping
+        // null to None, we can safely construct an `InterfaceClass` if the
+        // pointer was non-null.
         unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer. `AIBinder_getClass` returns either a null
-            // pointer or a valid pointer to an `AIBinder_Class`. After mapping
-            // null to None, we can safely construct an `InterfaceClass` if the
-            // pointer was non-null.
             let class = sys::AIBinder_getClass(self.as_native_mut());
             class.as_ref().map(|p| InterfaceClass::from_ptr(p))
         }
@@ -152,7 +148,8 @@
     ///
     /// See `SpIBinder::from_raw`.
     pub unsafe fn new_spibinder(ptr: *mut sys::AIBinder) -> Option<SpIBinder> {
-        SpIBinder::from_raw(ptr)
+        // Safety: The caller makes the same guarantees as this requires.
+        unsafe { SpIBinder::from_raw(ptr) }
     }
 }
 
@@ -171,30 +168,24 @@
 
 impl AssociateClass for SpIBinder {
     fn associate_class(&mut self, class: InterfaceClass) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that it always contains a valid
-            // `AIBinder` pointer. An `InterfaceClass` can always be converted
-            // into a valid `AIBinder_Class` pointer, so these parameters are
-            // always safe.
-            sys::AIBinder_associateClass(self.as_native_mut(), class.into())
-        }
+        // Safety: `SpIBinder` guarantees that it always contains a valid
+        // `AIBinder` pointer. An `InterfaceClass` can always be converted
+        // into a valid `AIBinder_Class` pointer, so these parameters are
+        // always safe.
+        unsafe { sys::AIBinder_associateClass(self.as_native_mut(), class.into()) }
     }
 }
 
 impl Ord for SpIBinder {
     fn cmp(&self, other: &Self) -> Ordering {
-        let less_than = unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
-            // this pointer is always safe to pass to `AIBinder_lt` (null is
-            // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr())
-        };
-        let greater_than = unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
-            // this pointer is always safe to pass to `AIBinder_lt` (null is
-            // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr())
-        };
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+        // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+        // pass to this function, but we should never do that).
+        let less_than = unsafe { sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr()) };
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so this
+        // pointer is always safe to pass to `AIBinder_lt` (null is also safe to
+        // pass to this function, but we should never do that).
+        let greater_than = unsafe { sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr()) };
         if !less_than && !greater_than {
             Ordering::Equal
         } else if less_than {
@@ -221,10 +212,10 @@
 
 impl Clone for SpIBinder {
     fn clone(&self) -> Self {
+        // Safety: Cloning a strong reference must increment the reference
+        // count. We are guaranteed by the `SpIBinder` constructor
+        // invariants that `self.0` is always a valid `AIBinder` pointer.
         unsafe {
-            // Safety: Cloning a strong reference must increment the reference
-            // count. We are guaranteed by the `SpIBinder` constructor
-            // invariants that `self.0` is always a valid `AIBinder` pointer.
             sys::AIBinder_incStrong(self.0.as_ptr());
         }
         Self(self.0)
@@ -235,9 +226,9 @@
     // We hold a strong reference to the IBinder in SpIBinder and need to give up
     // this reference on drop.
     fn drop(&mut self) {
+        // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
+        // know this pointer is safe to pass to `AIBinder_decStrong` here.
         unsafe {
-            // Safety: SpIBinder always holds a valid `AIBinder` pointer, so we
-            // know this pointer is safe to pass to `AIBinder_decStrong` here.
             sys::AIBinder_decStrong(self.as_native_mut());
         }
     }
@@ -246,26 +237,24 @@
 impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
     fn prepare_transact(&self) -> Result<Parcel> {
         let mut input = ptr::null_mut();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. It is safe to cast from an
+        // immutable pointer to a mutable pointer here, because
+        // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
+        // methods but the parameter is unfortunately not marked as const.
+        //
+        // After the call, input will be either a valid, owned `AParcel`
+        // pointer, or null.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. It is safe to cast from an
-            // immutable pointer to a mutable pointer here, because
-            // `AIBinder_prepareTransaction` only calls immutable `AIBinder`
-            // methods but the parameter is unfortunately not marked as const.
-            //
-            // After the call, input will be either a valid, owned `AParcel`
-            // pointer, or null.
             sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
         };
 
         status_result(status)?;
 
-        unsafe {
-            // Safety: At this point, `input` is either a valid, owned `AParcel`
-            // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
-            // taking ownership of the parcel.
-            Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
-        }
+        // Safety: At this point, `input` is either a valid, owned `AParcel`
+        // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
+        // taking ownership of the parcel.
+        unsafe { Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL) }
     }
 
     fn submit_transact(
@@ -275,23 +264,23 @@
         flags: TransactionFlags,
     ) -> Result<Parcel> {
         let mut reply = ptr::null_mut();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. Although `IBinder::transact` is
+        // not a const method, it is still safe to cast our immutable
+        // pointer to mutable for the call. First, `IBinder::transact` is
+        // thread-safe, so concurrency is not an issue. The only way that
+        // `transact` can affect any visible, mutable state in the current
+        // process is by calling `onTransact` for a local service. However,
+        // in order for transactions to be thread-safe, this method must
+        // dynamically lock its data before modifying it. We enforce this
+        // property in Rust by requiring `Sync` for remotable objects and
+        // only providing `on_transact` with an immutable reference to
+        // `self`.
+        //
+        // This call takes ownership of the `data` parcel pointer, and
+        // passes ownership of the `reply` out parameter to its caller. It
+        // does not affect ownership of the `binder` parameter.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. Although `IBinder::transact` is
-            // not a const method, it is still safe to cast our immutable
-            // pointer to mutable for the call. First, `IBinder::transact` is
-            // thread-safe, so concurrency is not an issue. The only way that
-            // `transact` can affect any visible, mutable state in the current
-            // process is by calling `onTransact` for a local service. However,
-            // in order for transactions to be thread-safe, this method must
-            // dynamically lock its data before modifying it. We enforce this
-            // property in Rust by requiring `Sync` for remotable objects and
-            // only providing `on_transact` with an immutable reference to
-            // `self`.
-            //
-            // This call takes ownership of the `data` parcel pointer, and
-            // passes ownership of the `reply` out parameter to its caller. It
-            // does not affect ownership of the `binder` parameter.
             sys::AIBinder_transact(
                 self.as_native() as *mut sys::AIBinder,
                 code,
@@ -302,45 +291,45 @@
         };
         status_result(status)?;
 
-        unsafe {
-            // Safety: `reply` is either a valid `AParcel` pointer or null
-            // after the call to `AIBinder_transact` above, so we can
-            // construct a `Parcel` out of it. `AIBinder_transact` passes
-            // ownership of the `reply` parcel to Rust, so we need to
-            // construct an owned variant.
-            Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
-        }
+        // Safety: `reply` is either a valid `AParcel` pointer or null
+        // after the call to `AIBinder_transact` above, so we can
+        // construct a `Parcel` out of it. `AIBinder_transact` passes
+        // ownership of the `reply` parcel to Rust, so we need to
+        // construct an owned variant.
+        unsafe { Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL) }
     }
 
     fn is_binder_alive(&self) -> bool {
-        unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`.
-            //
-            // This call does not affect ownership of its pointer parameter.
-            sys::AIBinder_isAlive(self.as_native())
-        }
+        // Safety: `SpIBinder` guarantees that `self` always contains a valid
+        // pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
+        unsafe { sys::AIBinder_isAlive(self.as_native()) }
     }
 
     #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool) {
+        // Safety: `SpIBinder` guarantees that `self` always contains a valid
+        // pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
         unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
     }
 
     fn dump<F: AsRawFd>(&mut self, fp: &F, args: &[&str]) -> Result<()> {
         let args: Vec<_> = args.iter().map(|a| CString::new(*a).unwrap()).collect();
         let mut arg_ptrs: Vec<_> = args.iter().map(|a| a.as_ptr()).collect();
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
+        // file descriptor parameter is always be a valid open file. The
+        // `args` pointer parameter is a valid pointer to an array of C
+        // strings that will outlive the call since `args` lives for the
+        // whole function scope.
+        //
+        // This call does not affect ownership of its binder pointer
+        // parameter and does not take ownership of the file or args array
+        // parameters.
         let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `AsRawFd` guarantees that the
-            // file descriptor parameter is always be a valid open file. The
-            // `args` pointer parameter is a valid pointer to an array of C
-            // strings that will outlive the call since `args` lives for the
-            // whole function scope.
-            //
-            // This call does not affect ownership of its binder pointer
-            // parameter and does not take ownership of the file or args array
-            // parameters.
             sys::AIBinder_dump(
                 self.as_native_mut(),
                 fp.as_raw_fd(),
@@ -353,22 +342,18 @@
 
     fn get_extension(&mut self) -> Result<Option<SpIBinder>> {
         let mut out = ptr::null_mut();
-        let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. After this call, the `out`
-            // parameter will be either null, or a valid pointer to an
-            // `AIBinder`.
-            //
-            // This call passes ownership of the out pointer to its caller
-            // (assuming it is set to a non-null value).
-            sys::AIBinder_getExtension(self.as_native_mut(), &mut out)
-        };
-        let ibinder = unsafe {
-            // Safety: The call above guarantees that `out` is either null or a
-            // valid, owned pointer to an `AIBinder`, both of which are safe to
-            // pass to `SpIBinder::from_raw`.
-            SpIBinder::from_raw(out)
-        };
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. After this call, the `out`
+        // parameter will be either null, or a valid pointer to an
+        // `AIBinder`.
+        //
+        // This call passes ownership of the out pointer to its caller
+        // (assuming it is set to a non-null value).
+        let status = unsafe { sys::AIBinder_getExtension(self.as_native_mut(), &mut out) };
+        // Safety: The call above guarantees that `out` is either null or a
+        // valid, owned pointer to an `AIBinder`, both of which are safe to
+        // pass to `SpIBinder::from_raw`.
+        let ibinder = unsafe { SpIBinder::from_raw(out) };
 
         status_result(status)?;
         Ok(ibinder)
@@ -377,17 +362,17 @@
 
 impl<T: AsNative<sys::AIBinder>> IBinder for T {
     fn link_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `recipient` can always be
+        // converted into a valid pointer to an
+        // `AIBinder_DeathRecipient`.
+        //
+        // The cookie is also the correct pointer, and by calling new_cookie,
+        // we have created a new ref-count to the cookie, which linkToDeath
+        // takes ownership of. Once the DeathRecipient is unlinked for any
+        // reason (including if this call fails), the onUnlinked callback
+        // will consume that ref-count.
         status_result(unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `recipient` can always be
-            // converted into a valid pointer to an
-            // `AIBinder_DeathRecipient`.
-            //
-            // The cookie is also the correct pointer, and by calling new_cookie,
-            // we have created a new ref-count to the cookie, which linkToDeath
-            // takes ownership of. Once the DeathRecipient is unlinked for any
-            // reason (including if this call fails), the onUnlinked callback
-            // will consume that ref-count.
             sys::AIBinder_linkToDeath(
                 self.as_native_mut(),
                 recipient.as_native_mut(),
@@ -397,13 +382,13 @@
     }
 
     fn unlink_to_death(&mut self, recipient: &mut DeathRecipient) -> Result<()> {
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`. `recipient` can always be
+        // converted into a valid pointer to an
+        // `AIBinder_DeathRecipient`. Any value is safe to pass as the
+        // cookie, although we depend on this value being set by
+        // `get_cookie` when the death recipient callback is called.
         status_result(unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`. `recipient` can always be
-            // converted into a valid pointer to an
-            // `AIBinder_DeathRecipient`. Any value is safe to pass as the
-            // cookie, although we depend on this value being set by
-            // `get_cookie` when the death recipient callback is called.
             sys::AIBinder_unlinkToDeath(
                 self.as_native_mut(),
                 recipient.as_native_mut(),
@@ -413,13 +398,11 @@
     }
 
     fn ping_binder(&mut self) -> Result<()> {
-        let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `self` always contains a
-            // valid pointer to an `AIBinder`.
-            //
-            // This call does not affect ownership of its pointer parameter.
-            sys::AIBinder_ping(self.as_native_mut())
-        };
+        // Safety: `SpIBinder` guarantees that `self` always contains a
+        // valid pointer to an `AIBinder`.
+        //
+        // This call does not affect ownership of its pointer parameter.
+        let status = unsafe { sys::AIBinder_ping(self.as_native_mut()) };
         status_result(status)
     }
 }
@@ -439,6 +422,14 @@
 impl SerializeArray for SpIBinder {}
 
 impl Deserialize for SpIBinder {
+    type UninitType = Option<Self>;
+    fn uninit() -> Self::UninitType {
+        Self::UninitType::default()
+    }
+    fn from_init(value: Self) -> Self::UninitType {
+        Some(value)
+    }
+
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
         parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
@@ -464,35 +455,31 @@
     }
 }
 
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Send for WpIBinder {}
 
-/// # Safety
-///
-/// A `WpIBinder` is an immutable handle to a C++ IBinder, which is thread-safe.
+/// Safety: A `WpIBinder` is an immutable handle to a C++ IBinder, which is
+/// thread-safe.
 unsafe impl Sync for WpIBinder {}
 
 impl WpIBinder {
     /// Create a new weak reference from an object that can be converted into a
     /// raw `AIBinder` pointer.
     fn new<B: AsNative<sys::AIBinder>>(binder: &mut B) -> WpIBinder {
-        let ptr = unsafe {
-            // Safety: `SpIBinder` guarantees that `binder` always contains a
-            // valid pointer to an `AIBinder`.
-            sys::AIBinder_Weak_new(binder.as_native_mut())
-        };
+        // Safety: `SpIBinder` guarantees that `binder` always contains a valid
+        // pointer to an `AIBinder`.
+        let ptr = unsafe { sys::AIBinder_Weak_new(binder.as_native_mut()) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new"))
     }
 
     /// Promote this weak reference to a strong reference to the binder object.
     pub fn promote(&self) -> Option<SpIBinder> {
+        // Safety: `WpIBinder` always contains a valid weak reference, so we can
+        // pass this pointer to `AIBinder_Weak_promote`. Returns either null or
+        // an AIBinder owned by the caller, both of which are valid to pass to
+        // `SpIBinder::from_raw`.
         unsafe {
-            // Safety: `WpIBinder` always contains a valid weak reference, so we
-            // can pass this pointer to `AIBinder_Weak_promote`. Returns either
-            // null or an AIBinder owned by the caller, both of which are valid
-            // to pass to `SpIBinder::from_raw`.
             let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr());
             SpIBinder::from_raw(ptr)
         }
@@ -501,35 +488,27 @@
 
 impl Clone for WpIBinder {
     fn clone(&self) -> Self {
-        let ptr = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_clone`
-            // (although null is also a safe value to pass to this API).
-            //
-            // We get ownership of the returned pointer, so can construct a new
-            // WpIBinder object from it.
-            sys::AIBinder_Weak_clone(self.0.as_ptr())
-        };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_clone`
+        // (although null is also a safe value to pass to this API).
+        //
+        // We get ownership of the returned pointer, so can construct a new
+        // WpIBinder object from it.
+        let ptr = unsafe { sys::AIBinder_Weak_clone(self.0.as_ptr()) };
         Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone"))
     }
 }
 
 impl Ord for WpIBinder {
     fn cmp(&self, other: &Self) -> Ordering {
-        let less_than = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
-            // (null is also safe to pass to this function, but we should never
-            // do that).
-            sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr())
-        };
-        let greater_than = unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
-            // so this pointer is always safe to pass to `AIBinder_Weak_lt`
-            // (null is also safe to pass to this function, but we should never
-            // do that).
-            sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr())
-        };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+        // also safe to pass to this function, but we should never do that).
+        let less_than = unsafe { sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr()) };
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so
+        // this pointer is always safe to pass to `AIBinder_Weak_lt` (null is
+        // also safe to pass to this function, but we should never do that).
+        let greater_than = unsafe { sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr()) };
         if !less_than && !greater_than {
             Ordering::Equal
         } else if less_than {
@@ -556,9 +535,9 @@
 
 impl Drop for WpIBinder {
     fn drop(&mut self) {
+        // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
+        // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
         unsafe {
-            // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
-            // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
             sys::AIBinder_Weak_delete(self.0.as_ptr());
         }
     }
@@ -566,7 +545,7 @@
 
 /// Rust wrapper around DeathRecipient objects.
 ///
-/// The cookie in this struct represents an Arc<F> for the owned callback.
+/// The cookie in this struct represents an `Arc<F>` for the owned callback.
 /// This struct owns a ref-count of it, and so does every binder that we
 /// have been linked with.
 ///
@@ -584,17 +563,13 @@
     cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
 }
 
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
 /// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
 unsafe impl Send for DeathRecipient {}
 
-/// # Safety
-///
-/// A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and a pointer
-/// to a `Fn` which is `Sync` and `Send` (the cookie field). As
+/// Safety: A `DeathRecipient` is a wrapper around `AIBinder_DeathRecipient` and
+/// a pointer to a `Fn` which is `Sync` and `Send` (the cookie field). As
 /// `AIBinder_DeathRecipient` is threadsafe, this structure is too.
 unsafe impl Sync for DeathRecipient {}
 
@@ -606,19 +581,17 @@
         F: Fn() + Send + Sync + 'static,
     {
         let callback: *const F = Arc::into_raw(Arc::new(callback));
-        let recipient = unsafe {
-            // Safety: The function pointer is a valid death recipient callback.
-            //
-            // This call returns an owned `AIBinder_DeathRecipient` pointer
-            // which must be destroyed via `AIBinder_DeathRecipient_delete` when
-            // no longer needed.
-            sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
-        };
+        // Safety: The function pointer is a valid death recipient callback.
+        //
+        // This call returns an owned `AIBinder_DeathRecipient` pointer which
+        // must be destroyed via `AIBinder_DeathRecipient_delete` when no longer
+        // needed.
+        let recipient = unsafe { sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>)) };
+        // Safety: The function pointer is a valid onUnlinked callback.
+        //
+        // All uses of linkToDeath in this file correctly increment the
+        // ref-count that this onUnlinked callback will decrement.
         unsafe {
-            // Safety: The function pointer is a valid onUnlinked callback.
-            //
-            // All uses of linkToDeath in this file correctly increment the
-            // ref-count that this onUnlinked callback will decrement.
             sys::AIBinder_DeathRecipient_setOnUnlinked(
                 recipient,
                 Some(Self::cookie_decr_refcount::<F>),
@@ -640,7 +613,12 @@
     ///
     /// The caller must handle the returned ref-count correctly.
     unsafe fn new_cookie(&self) -> *mut c_void {
-        (self.vtable.cookie_incr_refcount)(self.cookie);
+        // Safety: `cookie_incr_refcount` points to
+        // `Self::cookie_incr_refcount`, and `self.cookie` is the cookie for an
+        // Arc<F>.
+        unsafe {
+            (self.vtable.cookie_incr_refcount)(self.cookie);
+        }
 
         // Return a raw pointer with ownership of a ref-count
         self.cookie
@@ -659,13 +637,14 @@
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the caller must hold a ref-count to it.
     unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        let callback = (cookie as *const F).as_ref().unwrap();
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        let callback = unsafe { (cookie as *const F).as_ref().unwrap() };
         callback();
     }
 
@@ -674,34 +653,34 @@
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the owner must give up a ref-count to it.
     unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        drop(Arc::from_raw(cookie as *const F));
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        drop(unsafe { Arc::from_raw(cookie as *const F) });
     }
 
     /// Callback that increments the ref-count.
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// The `cookie` parameter must be the cookie for an `Arc<F>` and
     /// the owner must handle the created ref-count properly.
     unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void)
     where
         F: Fn() + Send + Sync + 'static,
     {
-        let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F));
+        // Safety: The caller promises that `cookie` is for an Arc<F>.
+        let arc = mem::ManuallyDrop::new(unsafe { Arc::from_raw(cookie as *const F) });
         mem::forget(Arc::clone(&arc));
     }
 }
 
-/// # Safety
-///
-/// A `DeathRecipient` is always constructed with a valid raw pointer to an
-/// `AIBinder_DeathRecipient`, so it is always type-safe to extract this
+/// Safety: A `DeathRecipient` is always constructed with a valid raw pointer to
+/// an `AIBinder_DeathRecipient`, so it is always type-safe to extract this
 /// pointer.
 unsafe impl AsNative<sys::AIBinder_DeathRecipient> for DeathRecipient {
     fn as_native(&self) -> *const sys::AIBinder_DeathRecipient {
@@ -715,18 +694,19 @@
 
 impl Drop for DeathRecipient {
     fn drop(&mut self) {
+        // Safety: `self.recipient` is always a valid, owned
+        // `AIBinder_DeathRecipient` pointer returned by
+        // `AIBinder_DeathRecipient_new` when `self` was created. This delete
+        // method can only be called once when `self` is dropped.
         unsafe {
-            // Safety: `self.recipient` is always a valid, owned
-            // `AIBinder_DeathRecipient` pointer returned by
-            // `AIBinder_DeathRecipient_new` when `self` was created. This
-            // delete method can only be called once when `self` is dropped.
             sys::AIBinder_DeathRecipient_delete(self.recipient);
+        }
 
-            // Safety: We own a ref-count to the cookie, and so does every
-            // linked binder. This call gives up our ref-count. The linked
-            // binders should already have given up their ref-count, or should
-            // do so shortly.
-            (self.vtable.cookie_decr_refcount)(self.cookie)
+        // Safety: We own a ref-count to the cookie, and so does every linked
+        // binder. This call gives up our ref-count. The linked binders should
+        // already have given up their ref-count, or should do so shortly.
+        unsafe {
+            (self.vtable.cookie_decr_refcount)(self.cookie);
         }
     }
 }
@@ -746,11 +726,9 @@
     fn from_binder(binder: SpIBinder) -> Result<Self>;
 }
 
-/// # Safety
-///
-/// This is a convenience method that wraps `AsNative` for `SpIBinder` to allow
-/// invocation of `IBinder` methods directly from `Interface` objects. It shares
-/// the same safety as the implementation for `SpIBinder`.
+/// Safety: This is a convenience method that wraps `AsNative` for `SpIBinder`
+/// to allow invocation of `IBinder` methods directly from `Interface` objects.
+/// It shares the same safety as the implementation for `SpIBinder`.
 unsafe impl<T: Proxy> AsNative<sys::AIBinder> for T {
     fn as_native(&self) -> *const sys::AIBinder {
         self.as_binder().as_native()
@@ -765,24 +743,20 @@
 /// exist.
 pub fn get_service(name: &str) -> Option<SpIBinder> {
     let name = CString::new(name).ok()?;
-    unsafe {
-        // Safety: `AServiceManager_getService` returns either a null pointer or
-        // a valid pointer to an owned `AIBinder`. Either of these values is
-        // safe to pass to `SpIBinder::from_raw`.
-        SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr()))
-    }
+    // Safety: `AServiceManager_getService` returns either a null pointer or a
+    // valid pointer to an owned `AIBinder`. Either of these values is safe to
+    // pass to `SpIBinder::from_raw`.
+    unsafe { SpIBinder::from_raw(sys::AServiceManager_getService(name.as_ptr())) }
 }
 
 /// Retrieve an existing service, or start it if it is configured as a dynamic
 /// service and isn't yet started.
 pub fn wait_for_service(name: &str) -> Option<SpIBinder> {
     let name = CString::new(name).ok()?;
-    unsafe {
-        // Safety: `AServiceManager_waitforService` returns either a null
-        // pointer or a valid pointer to an owned `AIBinder`. Either of these
-        // values is safe to pass to `SpIBinder::from_raw`.
-        SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr()))
-    }
+    // Safety: `AServiceManager_waitforService` returns either a null pointer or
+    // a valid pointer to an owned `AIBinder`. Either of these values is safe to
+    // pass to `SpIBinder::from_raw`.
+    unsafe { SpIBinder::from_raw(sys::AServiceManager_waitForService(name.as_ptr())) }
 }
 
 /// Retrieve an existing service for a particular interface, blocking for a few
@@ -801,12 +775,10 @@
 pub fn is_declared(interface: &str) -> Result<bool> {
     let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
 
-    unsafe {
-        // Safety: `interface` is a valid null-terminated C-style string and is
-        // only borrowed for the lifetime of the call. The `interface` local
-        // outlives this call as it lives for the function scope.
-        Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
-    }
+    // Safety: `interface` is a valid null-terminated C-style string and is only
+    // borrowed for the lifetime of the call. The `interface` local outlives
+    // this call as it lives for the function scope.
+    unsafe { Ok(sys::AServiceManager_isDeclared(interface.as_ptr())) }
 }
 
 /// Retrieve all declared instances for a particular interface
@@ -819,11 +791,13 @@
         // CString, and outlives this callback. The null handling here is just
         // to avoid the possibility of unwinding across C code if this crate is
         // ever compiled with panic=unwind.
-        if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+        if let Some(instances) = unsafe { opaque.cast::<Vec<CString>>().as_mut() } {
             // Safety: instance is a valid null-terminated C string with a
             // lifetime at least as long as this function, and we immediately
             // copy it into an owned CString.
-            instances.push(CStr::from_ptr(instance).to_owned());
+            unsafe {
+                instances.push(CStr::from_ptr(instance).to_owned());
+            }
         } else {
             eprintln!("Opaque pointer was null in get_declared_instances callback!");
         }
@@ -831,10 +805,10 @@
 
     let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
     let mut instances: Vec<CString> = vec![];
+    // Safety: `interface` and `instances` are borrowed for the length of this
+    // call and both outlive the call. `interface` is guaranteed to be a valid
+    // null-terminated C-style string.
     unsafe {
-        // Safety: `interface` and `instances` are borrowed for the length of
-        // this call and both outlive the call. `interface` is guaranteed to be
-        // a valid null-terminated C-style string.
         sys::AServiceManager_forEachDeclaredInstance(
             interface.as_ptr(),
             &mut instances as *mut _ as *mut c_void,
@@ -852,10 +826,8 @@
         })
 }
 
-/// # Safety
-///
-/// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
-/// `AIBinder`, so we can trivially extract this pointer here.
+/// Safety: `SpIBinder` guarantees that `binder` always contains a valid pointer
+/// to an `AIBinder`, so we can trivially extract this pointer here.
 unsafe impl AsNative<sys::AIBinder> for SpIBinder {
     fn as_native(&self) -> *const sys::AIBinder {
         self.0.as_ptr()
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index cc18741..a3a2562 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -22,30 +22,48 @@
 pub struct ProcessState;
 
 impl ProcessState {
-    /// Start the Binder IPC thread pool
+    /// Starts the Binder IPC thread pool.
+    ///
+    /// Starts 1 thread, plus allows the kernel to lazily start up to
+    /// `num_threads` additional threads as specified by
+    /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count).
+    ///
+    /// This should be done before creating any Binder client or server. If
+    /// neither this nor [`join_thread_pool`](Self::join_thread_pool) are
+    /// called, then some things (such as callbacks and
+    /// [`IBinder::link_to_death`](crate::IBinder::link_to_death)) will silently
+    /// not work: the callbacks will be queued but never called as there is no
+    /// thread to call them on.
     pub fn start_thread_pool() {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_startThreadPool();
         }
     }
 
-    /// Set the maximum number of threads that can be started in the threadpool.
+    /// Sets the maximum number of threads that can be started in the
+    /// threadpool.
     ///
-    /// By default, after startThreadPool is called, this is 15. If it is called
-    /// additional times, it will only prevent the kernel from starting new
-    /// threads and will not delete already existing threads.
+    /// By default, after [`start_thread_pool`](Self::start_thread_pool) is
+    /// called, this is 15. If it is called additional times, the thread pool
+    /// size can only be increased.
     pub fn set_thread_pool_max_thread_count(num_threads: u32) {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_setThreadPoolMaxThreadCount(num_threads);
         }
     }
 
-    /// Block on the Binder IPC thread pool
+    /// Blocks on the Binder IPC thread pool by adding the current thread to the
+    /// pool.
+    ///
+    /// Note that this adds the current thread in addition to those that are
+    /// created by
+    /// [`set_thread_pool_max_thread_count`](Self::set_thread_pool_max_thread_count)
+    /// and [`start_thread_pool`](Self::start_thread_pool).
     pub fn join_thread_pool() {
+        // Safety: Safe FFI
         unsafe {
-            // Safety: Safe FFI
             sys::ABinderProcess_joinThreadPool();
         }
     }
@@ -68,10 +86,8 @@
     /// \return calling uid or the current process's UID if this thread isn't
     /// processing a transaction.
     pub fn get_calling_uid() -> uid_t {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_getCallingUid()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_getCallingUid() }
     }
 
     /// This returns the calling PID assuming that this thread is called from a
@@ -93,10 +109,8 @@
     /// If the transaction being processed is a oneway transaction, then this
     /// method will return 0.
     pub fn get_calling_pid() -> pid_t {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_getCallingPid()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_getCallingPid() }
     }
 
     /// Determine whether the current thread is currently executing an incoming transaction.
@@ -104,10 +118,8 @@
     /// \return true if the current thread is currently executing an incoming transaction, and false
     /// otherwise.
     pub fn is_handling_transaction() -> bool {
-        unsafe {
-            // Safety: Safe FFI
-            sys::AIBinder_isHandlingTransaction()
-        }
+        // Safety: Safe FFI
+        unsafe { sys::AIBinder_isHandlingTransaction() }
     }
 
     /// This function makes the client's security context available to the
diff --git a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
index 59ca6ed..663b9bb 100644
--- a/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
+++ b/libs/binder/rust/tests/binderRustNdkInteropTest.cpp
@@ -54,14 +54,12 @@
     EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
 
     auto interface = aidl::IBinderRustNdkInteropTest::fromBinder(binder);
-    // TODO(b/167723746): this test requires that fromBinder allow association
-    // with an already associated local binder by treating it as remote.
-    EXPECT_EQ(interface, nullptr);
+    EXPECT_NE(interface, nullptr);
 
-    // std::string in("testing");
-    // std::string out;
-    // EXPECT_TRUE(interface->echo(in, &out).isOk());
-    // EXPECT_EQ(in, out);
+    std::string in("testing");
+    std::string out;
+    EXPECT_TRUE(interface->echo(in, &out).isOk());
+    EXPECT_EQ(in, out);
 }
 
 int main(int argc, char** argv) {
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index ca2cedc..c049b80 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -545,6 +545,11 @@
     }
 
     fn get_expected_selinux_context() -> &'static str {
+        // SAFETY: The pointer we pass to `getcon` is valid because it comes from a reference, and
+        // `getcon` doesn't retain it after it returns. If `getcon` succeeds then `out_ptr` will
+        // point to a valid C string, otherwise it will remain null. We check for null, so the
+        // pointer we pass to `CStr::from_ptr` must be a valid pointer to a C string. There is a
+        // memory leak as we don't call `freecon`, but that's fine because this is just a test.
         unsafe {
             let mut out_ptr = ptr::null_mut();
             assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 415ede1..37f182e 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -28,10 +28,11 @@
 ///
 /// # Safety
 ///
-/// service_name must be a valid, non-null C-style string (null-terminated).
+/// service_name must be a valid, non-null C-style string (nul-terminated).
 #[no_mangle]
 pub unsafe extern "C" fn rust_call_ndk(service_name: *const c_char) -> c_int {
-    let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+    // SAFETY: Our caller promises that service_name is a valid C string.
+    let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
 
     // The Rust class descriptor pointer will not match the NDK one, but the
     // descriptor strings match so this needs to still associate.
@@ -85,10 +86,11 @@
 ///
 /// # Safety
 ///
-/// service_name must be a valid, non-null C-style string (null-terminated).
+/// service_name must be a valid, non-null C-style string (nul-terminated).
 #[no_mangle]
 pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
-    let service_name = CStr::from_ptr(service_name).to_str().unwrap();
+    // SAFETY: Our caller promises that service_name is a valid C string.
+    let service_name = unsafe { CStr::from_ptr(service_name) }.to_str().unwrap();
     let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
     match binder::add_service(service_name, service.as_binder()) {
         Ok(_) => StatusCode::OK as c_int,
diff --git a/libs/binder/rust/tests/parcel_fuzzer/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
index df8a2af..ac96823 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/rust/tests/parcel_fuzzer/Android.bp
@@ -21,6 +21,7 @@
             "waghpawan@google.com",
             "smoreland@google.com",
         ],
+        triage_assignee: "waghpawan@google.com",
         // hotlist "AIDL fuzzers bugs" on buganizer
         hotlists: ["4637097"],
     },
diff --git a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
index 29bf92c..ce0f742 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
+++ b/libs/binder/rust/tests/parcel_fuzzer/parcel_fuzzer.rs
@@ -105,9 +105,9 @@
     for operation in read_operations {
         match operation {
             ReadOperation::SetDataPosition { pos } => {
+                // Safety: Safe if pos is less than current size of the parcel.
+                // It relies on C++ code for bound checks
                 unsafe {
-                    // Safety: Safe if pos is less than current size of the parcel.
-                    // It relies on C++ code for bound checks
                     match parcel.set_data_position(pos) {
                         Ok(result) => result,
                         Err(e) => println!("error occurred while setting data position: {:?}", e),
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
index 43a3094..5cac647 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp
@@ -11,7 +11,6 @@
     source_stem: "bindings",
     visibility: [":__subpackages__"],
     bindgen_flags: [
-        "--size_t-is-usize",
         "--allowlist-function",
         "createRandomParcel",
         "--allowlist-function",
diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
index 5cb406a..2537ce0 100644
--- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
+++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/fuzz_service_test/Android.bp
@@ -29,6 +29,7 @@
             "waghpawan@google.com",
             "smoreland@google.com",
         ],
+        triage_assignee: "waghpawan@google.com",
         // hotlist "AIDL fuzzers bugs" on buganizer
         hotlists: ["4637097"],
     },
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 6220db4..2b6c282 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -26,7 +26,7 @@
 use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
 
 use std::ffi::{c_void, CStr, CString};
-use std::sync::Once;
+use std::sync::OnceLock;
 
 #[allow(
     non_camel_case_types,
@@ -70,20 +70,18 @@
     };
 }
 
-static SERVICE_ONCE: Once = Once::new();
-static mut SERVICE: Option<SpIBinder> = None;
+static SERVICE: OnceLock<SpIBinder> = OnceLock::new();
 
 /// Start binder service and return a raw AIBinder pointer to it.
 ///
 /// Safe to call multiple times, only creates the service once.
 #[no_mangle]
 pub extern "C" fn rust_service() -> *mut c_void {
-    unsafe {
-        SERVICE_ONCE.call_once(|| {
-            SERVICE = Some(BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
-        });
-        SERVICE.as_ref().unwrap().as_raw().cast()
-    }
+    let service = SERVICE
+        .get_or_init(|| BnReadParcelTest::new_binder((), BinderFeatures::default()).as_binder());
+    // SAFETY: The SpIBinder will remain alive as long as the program is running because it is in
+    // the static SERVICE, so the pointer is valid forever.
+    unsafe { service.as_raw().cast() }
 }
 
 /// Empty interface just to use the declare_binder_interface macro
@@ -113,11 +111,13 @@
         bindings::Transaction_TEST_BOOL => {
             assert!(parcel.read::<bool>()?);
             assert!(!parcel.read::<bool>()?);
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
             assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
 
             reply.write(&true)?;
             reply.write(&false)?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_BOOL }[..])?;
             reply.write(&(None as Option<Vec<bool>>))?;
         }
@@ -125,14 +125,18 @@
             assert_eq!(parcel.read::<i8>()?, 0);
             assert_eq!(parcel.read::<i8>()?, 1);
             assert_eq!(parcel.read::<i8>()?, i8::max_value());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<i8>>()?, unsafe { bindings::TESTDATA_I8 });
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<u8>>()?, unsafe { bindings::TESTDATA_U8 });
             assert_eq!(parcel.read::<Option<Vec<i8>>>()?, None);
 
             reply.write(&0i8)?;
             reply.write(&1i8)?;
             reply.write(&i8::max_value())?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_I8 }[..])?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_U8 }[..])?;
             reply.write(&(None as Option<Vec<i8>>))?;
         }
@@ -140,12 +144,14 @@
             assert_eq!(parcel.read::<u16>()?, 0);
             assert_eq!(parcel.read::<u16>()?, 1);
             assert_eq!(parcel.read::<u16>()?, u16::max_value());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
             assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
 
             reply.write(&0u16)?;
             reply.write(&1u16)?;
             reply.write(&u16::max_value())?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_CHARS }[..])?;
             reply.write(&(None as Option<Vec<u16>>))?;
         }
@@ -153,12 +159,14 @@
             assert_eq!(parcel.read::<i32>()?, 0);
             assert_eq!(parcel.read::<i32>()?, 1);
             assert_eq!(parcel.read::<i32>()?, i32::max_value());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
             assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
 
             reply.write(&0i32)?;
             reply.write(&1i32)?;
             reply.write(&i32::max_value())?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_I32 }[..])?;
             reply.write(&(None as Option<Vec<i32>>))?;
         }
@@ -166,12 +174,14 @@
             assert_eq!(parcel.read::<i64>()?, 0);
             assert_eq!(parcel.read::<i64>()?, 1);
             assert_eq!(parcel.read::<i64>()?, i64::max_value());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
             assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
 
             reply.write(&0i64)?;
             reply.write(&1i64)?;
             reply.write(&i64::max_value())?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_I64 }[..])?;
             reply.write(&(None as Option<Vec<i64>>))?;
         }
@@ -179,12 +189,14 @@
             assert_eq!(parcel.read::<u64>()?, 0);
             assert_eq!(parcel.read::<u64>()?, 1);
             assert_eq!(parcel.read::<u64>()?, u64::max_value());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
             assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
 
             reply.write(&0u64)?;
             reply.write(&1u64)?;
             reply.write(&u64::max_value())?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_U64 }[..])?;
             reply.write(&(None as Option<Vec<u64>>))?;
         }
@@ -192,10 +204,12 @@
             assert_eq!(parcel.read::<f32>()?, 0f32);
             let floats = parcel.read::<Vec<f32>>()?;
             assert!(floats[0].is_nan());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(floats[1..], unsafe { bindings::TESTDATA_FLOAT }[1..]);
             assert_eq!(parcel.read::<Option<Vec<f32>>>()?, None);
 
             reply.write(&0f32)?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_FLOAT }[..])?;
             reply.write(&(None as Option<Vec<f32>>))?;
         }
@@ -203,10 +217,12 @@
             assert_eq!(parcel.read::<f64>()?, 0f64);
             let doubles = parcel.read::<Vec<f64>>()?;
             assert!(doubles[0].is_nan());
+            // SAFETY: Just reading an extern constant.
             assert_eq!(doubles[1..], unsafe { bindings::TESTDATA_DOUBLE }[1..]);
             assert_eq!(parcel.read::<Option<Vec<f64>>>()?, None);
 
             reply.write(&0f64)?;
+            // SAFETY: Just reading an extern constant.
             reply.write(&unsafe { bindings::TESTDATA_DOUBLE }[..])?;
             reply.write(&(None as Option<Vec<f64>>))?;
         }
@@ -216,14 +232,17 @@
             let s: Option<String> = parcel.read()?;
             assert_eq!(s, None);
             let s: Option<Vec<Option<String>>> = parcel.read()?;
+            // SAFETY: Just reading an extern constant.
             for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
                 let expected =
+            // SAFETY: Just reading an extern constant.
                     unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
                 assert_eq!(s.as_deref(), expected);
             }
             let s: Option<Vec<Option<String>>> = parcel.read()?;
             assert_eq!(s, None);
 
+            // SAFETY: Just reading an extern constant.
             let strings: Vec<Option<String>> = unsafe {
                 bindings::TESTDATA_STRS
                     .iter()
@@ -258,8 +277,7 @@
             assert!(ibinders[1].is_none());
             assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
 
-            let service =
-                unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
+            let service = SERVICE.get().expect("Global binder service not initialized").clone();
             reply.write(&service)?;
             reply.write(&(None as Option<&SpIBinder>))?;
             reply.write(&[Some(&service), None][..])?;
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 873e955..cd3e7c0 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -32,28 +32,8 @@
 }
 
 cc_test {
-    name: "binderDriverInterfaceTest_IPC_32",
-    defaults: ["binder_test_defaults"],
-    srcs: ["binderDriverInterfaceTest.cpp"],
-    header_libs: ["libbinder_headers"],
-    compile_multilib: "32",
-    multilib: {
-        lib32: {
-            suffix: "",
-        },
-    },
-    cflags: ["-DBINDER_IPC_32BIT=1"],
-    test_suites: ["vts"],
-}
-
-cc_test {
     name: "binderDriverInterfaceTest",
     defaults: ["binder_test_defaults"],
-    product_variables: {
-        binder32bit: {
-            cflags: ["-DBINDER_IPC_32BIT=1"],
-        },
-    },
     header_libs: ["libbinder_headers"],
     srcs: ["binderDriverInterfaceTest.cpp"],
     test_suites: [
@@ -62,30 +42,6 @@
     ],
 }
 
-cc_test {
-    name: "binderLibTest_IPC_32",
-    defaults: ["binder_test_defaults"],
-    srcs: ["binderLibTest.cpp"],
-    shared_libs: [
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libutils",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-    compile_multilib: "32",
-    multilib: {
-        lib32: {
-            suffix: "",
-        },
-    },
-    cflags: ["-DBINDER_IPC_32BIT=1"],
-    test_suites: ["vts"],
-    require_root: true,
-}
-
 // unit test only, which can run on host and doesn't use /dev/binder
 cc_test {
     name: "binderUnitTest",
@@ -111,13 +67,41 @@
 }
 
 cc_test {
-    name: "binderLibTest",
-    defaults: ["binder_test_defaults"],
-    product_variables: {
-        binder32bit: {
-            cflags: ["-DBINDER_IPC_32BIT=1"],
+    name: "binderRecordReplayTest",
+    srcs: ["binderRecordReplayTest.cpp"],
+    shared_libs: [
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+    static_libs: [
+        "binderRecordReplayTestIface-cpp",
+        "binderReadParcelIface-cpp",
+        "libbinder_random_parcel_seeds",
+        "libbinder_random_parcel",
+    ],
+    test_suites: ["general-tests"],
+    require_root: true,
+}
+
+aidl_interface {
+    name: "binderRecordReplayTestIface",
+    unstable: true,
+    srcs: [
+        "IBinderRecordReplayTest.aidl",
+    ],
+    imports: ["binderReadParcelIface"],
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
         },
     },
+}
+
+cc_test {
+    name: "binderLibTest",
+    defaults: ["binder_test_defaults"],
 
     srcs: ["binderLibTest.cpp"],
     shared_libs: [
@@ -716,6 +700,7 @@
         "liblog",
         "libutils",
     ],
+    test_suites: ["general-tests"],
 }
 
 cc_test_host {
@@ -818,3 +803,15 @@
         hotlists: ["4637097"],
     },
 }
+
+cc_defaults {
+    name: "fuzzer_disable_leaks",
+    fuzz_config: {
+        asan_options: [
+            "detect_leaks=0",
+        ],
+        hwasan_options: [
+            "detect_leaks=0",
+        ],
+    },
+}
diff --git a/libs/binder/tests/IBinderRecordReplayTest.aidl b/libs/binder/tests/IBinderRecordReplayTest.aidl
new file mode 100644
index 0000000..bd6b03c
--- /dev/null
+++ b/libs/binder/tests/IBinderRecordReplayTest.aidl
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+import parcelables.SingleDataParcelable;
+
+interface IBinderRecordReplayTest {
+    void setByte(byte input);
+    byte getByte();
+
+    void setChar(char input);
+    char getChar();
+
+    void setBoolean(boolean input);
+    boolean getBoolean();
+
+    void setInt(int input);
+    int getInt();
+
+    void setFloat(float input);
+    float getFloat();
+
+    void setLong(long input);
+    long getLong();
+
+    void setDouble(double input);
+    double getDouble();
+
+    void setString(String input);
+    String getString();
+
+    void setSingleDataParcelable(in SingleDataParcelable p);
+    SingleDataParcelable getSingleDataParcelable();
+
+    void setByteArray(in byte[] input);
+    byte[] getByteArray();
+
+    void setCharArray(in char[] input);
+    char[] getCharArray();
+
+    void setBooleanArray(in boolean[] input);
+    boolean[] getBooleanArray();
+
+    void setIntArray(in int[] input);
+    int[] getIntArray();
+
+    void setFloatArray(in float[] input);
+    float[] getFloatArray();
+
+    void setLongArray(in long[] input);
+    long[] getLongArray();
+
+    void setDoubleArray(in double[] input);
+    double[] getDoubleArray();
+
+    void setStringArray(in String[] input);
+    String[] getStringArray();
+
+    void setSingleDataParcelableArray(in SingleDataParcelable[] input);
+    SingleDataParcelable[] getSingleDataParcelableArray();
+}
diff --git a/libs/binder/tests/binderAbiHelper.h b/libs/binder/tests/binderAbiHelper.h
deleted file mode 100644
index 369b55d..0000000
--- a/libs/binder/tests/binderAbiHelper.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2020 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 <stdlib.h>
-#include <iostream>
-
-#ifdef BINDER_IPC_32BIT
-static constexpr bool kBuild32Abi = true;
-#else
-static constexpr bool kBuild32Abi = false;
-#endif
-
-// TODO: remove when CONFIG_ANDROID_BINDER_IPC_32BIT is no longer supported
-static inline bool ReadKernelConfigIs32BitAbi() {
-    // failure case implies we run with standard ABI
-    return 0 == system("zcat /proc/config.gz | grep -E \"^CONFIG_ANDROID_BINDER_IPC_32BIT=y$\"");
-}
-
-static inline void ExitIfWrongAbi() {
-    bool runtime32Abi = ReadKernelConfigIs32BitAbi();
-
-    if (kBuild32Abi != runtime32Abi) {
-        std::cout << "[==========] Running 1 test from 1 test suite." << std::endl;
-        std::cout << "[----------] Global test environment set-up." << std::endl;
-        std::cout << "[----------] 1 tests from BinderLibTest" << std::endl;
-        std::cout << "[ RUN      ] BinderTest.AbortForWrongAbi" << std::endl;
-        std::cout << "[ INFO     ] test build abi 32: " << kBuild32Abi << " runtime abi 32: " << runtime32Abi << " so, skipping tests " << std::endl;
-        std::cout << "[       OK ] BinderTest.AbortForWrongAbi (0 ms) " << std::endl;
-        std::cout << "[----------] 1 tests from BinderTest (0 ms total)" << std::endl;
-        std::cout << "" << std::endl;
-        std::cout << "[----------] Global test environment tear-down" << std::endl;
-        std::cout << "[==========] 1 test from 1 test suite ran. (0 ms total)" << std::endl;
-        std::cout << "[  PASSED  ] 1 tests." << std::endl;
-        exit(0);
-    }
-}
-
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index bc40864..6712c9c 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -216,16 +216,16 @@
     auto server = RpcServer::make();
     server->setRootObject(sp<BBinder>::make());
 
-    CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+    ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
 
     std::thread([server]() { server->join(); }).detach();
 
-    status_t status;
     auto session = RpcSession::make();
-    status = session->setupUnixDomainClient(addr.c_str());
-    CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+    status_t status = session->setupUnixDomainClient(addr.c_str());
+    ASSERT_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
 
     auto remoteBinder = session->getRootObject();
+    ASSERT_NE(remoteBinder, nullptr);
 
     size_t mallocs = 0, totalBytes = 0;
     {
@@ -233,7 +233,7 @@
             mallocs++;
             totalBytes += bytes;
         });
-        CHECK_EQ(OK, remoteBinder->pingBinder());
+        ASSERT_EQ(OK, remoteBinder->pingBinder());
     }
     EXPECT_EQ(mallocs, 1);
     EXPECT_EQ(totalBytes, 40);
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index 8cc3054..cf23a46 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -25,8 +25,6 @@
 #include <sys/mman.h>
 #include <poll.h>
 
-#include "binderAbiHelper.h"
-
 #define BINDER_DEV_NAME "/dev/binder"
 
 testing::Environment* binder_env;
@@ -362,8 +360,7 @@
     binderTestReadEmpty();
 }
 
-int main(int argc, char **argv) {
-    ExitIfWrongAbi();
+int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
     binder_env = AddGlobalTestEnvironment(new BinderDriverInterfaceTestEnv());
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 8974ad7..e021af0 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -48,7 +48,6 @@
 #include <sys/un.h>
 
 #include "../binder_module.h"
-#include "binderAbiHelper.h"
 
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
 
@@ -83,7 +82,7 @@
 static constexpr int kSchedPolicy = SCHED_RR;
 static constexpr int kSchedPriority = 7;
 static constexpr int kSchedPriorityMore = 8;
-static constexpr int kKernelThreads = 15;
+static constexpr int kKernelThreads = 17; // anything different than the default
 
 static String16 binderLibTestServiceName = String16("test.binderLib");
 
@@ -1358,17 +1357,20 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
                 StatusEq(NO_ERROR));
     int32_t replyi = reply.readInt32();
-    // Expect 16 threads: kKernelThreads = 15 + Pool thread == 16
-    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+    // see getThreadPoolMaxTotalThreadCount for why there is a race
+    EXPECT_TRUE(replyi == kKernelThreads + 1 || replyi == kKernelThreads + 2) << replyi;
+
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_LOCK, data, &reply), NO_ERROR);
 
     /*
-     * This will use all threads in the pool expect the main pool thread.
-     * The service should run fine without locking, and the thread count should
-     * not exceed 16 (15 Max + pool thread).
+     * This will use all threads in the pool but one. There are actually kKernelThreads+2
+     * available in the other process (startThreadPool, joinThreadPool, + the kernel-
+     * started threads from setThreadPoolMaxThreadCount
+     *
+     * Adding one more will cause it to deadlock.
      */
     std::vector<std::thread> ts;
-    for (size_t i = 0; i < kKernelThreads; i++) {
+    for (size_t i = 0; i < kKernelThreads + 1; i++) {
         ts.push_back(std::thread([&] {
             Parcel local_reply;
             EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
@@ -1376,8 +1378,13 @@
         }));
     }
 
-    data.writeInt32(500);
-    // Give a chance for all threads to be used
+    // make sure all of the above calls will be queued in parallel. Otherwise, most of
+    // the time, the below call will pre-empt them (presumably because we have the
+    // scheduler timeslice already + scheduler hint).
+    sleep(1);
+
+    data.writeInt32(1000);
+    // Give a chance for all threads to be used (kKernelThreads + 1 thread in use)
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR);
 
     for (auto &t : ts) {
@@ -1387,7 +1394,7 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
                 StatusEq(NO_ERROR));
     replyi = reply.readInt32();
-    EXPECT_EQ(replyi, kKernelThreads + 1);
+    EXPECT_EQ(replyi, kKernelThreads + 2);
 }
 
 TEST_F(BinderLibTest, ThreadPoolStarted) {
@@ -2022,9 +2029,7 @@
     return 1; /* joinThreadPool should not return */
 }
 
-int main(int argc, char **argv) {
-    ExitIfWrongAbi();
-
+int main(int argc, char** argv) {
     if (argc == 4 && !strcmp(argv[1], "--servername")) {
         binderservername = argv[2];
     } else {
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 359c783..0a0dae0 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -29,6 +29,7 @@
 using android::status_t;
 using android::String16;
 using android::String8;
+using android::base::unique_fd;
 using android::binder::Status;
 
 TEST(Parcel, NonNullTerminatedString8) {
@@ -112,6 +113,166 @@
     EXPECT_EQ(ret[1], STDIN_FILENO);
 }
 
+TEST(Parcel, AppendFromEmpty) {
+    Parcel p1;
+    Parcel p2;
+    p2.writeInt32(2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(2, p1.readInt32());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendPlainData) {
+    Parcel p1;
+    p1.writeInt32(1);
+    Parcel p2;
+    p2.writeInt32(2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(2, p1.readInt32());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendPlainDataPartial) {
+    Parcel p1;
+    p1.writeInt32(1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeInt32(3);
+    p2.writeInt32(4);
+
+    // only copy 8 bytes (two int32's worth)
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(3, p1.readInt32());
+    ASSERT_EQ(0, p1.readInt32()); // not 4, end of Parcel
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+}
+
+TEST(Parcel, AppendWithBinder) {
+    sp<IBinder> b1 = sp<BBinder>::make();
+    sp<IBinder> b2 = sp<BBinder>::make();
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeStrongBinder(b1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeStrongBinder(b2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(b1, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(b2, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_EQ(b2, p2.readStrongBinder());
+}
+
+TEST(Parcel, AppendWithBinderPartial) {
+    sp<IBinder> b1 = sp<BBinder>::make();
+    sp<IBinder> b2 = sp<BBinder>::make();
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeStrongBinder(b1);
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeStrongBinder(b2);
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into strong binder
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_EQ(b1, p1.readStrongBinder());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(1935813253, p1.readInt32()); // whatever garbage that is there (ABI)
+    ASSERT_EQ(1, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_EQ(b2, p2.readStrongBinder());
+}
+
+TEST(Parcel, AppendWithFd) {
+    unique_fd fd1 = unique_fd(dup(0));
+    unique_fd fd2 = unique_fd(dup(0));
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeDupFileDescriptor(0);      // with ownership
+    p1.writeFileDescriptor(fd1.get()); // without ownership
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeDupFileDescriptor(0);      // with ownership
+    p2.writeFileDescriptor(fd2.get()); // without ownership
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, p2.dataSize()));
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(4, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+}
+
+TEST(Parcel, AppendWithFdPartial) {
+    unique_fd fd1 = unique_fd(dup(0));
+    unique_fd fd2 = unique_fd(dup(0));
+
+    Parcel p1;
+    p1.writeInt32(1);
+    p1.writeDupFileDescriptor(0);      // with ownership
+    p1.writeFileDescriptor(fd1.get()); // without ownership
+    Parcel p2;
+    p2.writeInt32(2);
+    p2.writeDupFileDescriptor(0);      // with ownership
+    p2.writeFileDescriptor(fd2.get()); // without ownership
+
+    ASSERT_EQ(OK, p1.appendFrom(&p2, 0, 8)); // BAD: 4 bytes into binder
+
+    p1.setDataPosition(0);
+    ASSERT_EQ(1, p1.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_EQ(2, p1.readInt32());
+    ASSERT_EQ(1717840517, p1.readInt32()); // whatever garbage that is there (ABI)
+    ASSERT_EQ(2, p1.objectsCount());
+
+    p2.setDataPosition(0);
+    ASSERT_EQ(2, p2.readInt32());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+    ASSERT_NE(-1, p1.readFileDescriptor());
+}
+
 // Tests a second operation results in a parcel at the same location as it
 // started.
 void parcelOpSameLength(const std::function<void(Parcel*)>& a, const std::function<void(Parcel*)>& b) {
diff --git a/libs/binder/tests/binderRecordReplayTest.cpp b/libs/binder/tests/binderRecordReplayTest.cpp
new file mode 100644
index 0000000..6773c95
--- /dev/null
+++ b/libs/binder/tests/binderRecordReplayTest.cpp
@@ -0,0 +1,334 @@
+/*
+ * 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 <BnBinderRecordReplayTest.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <fuzzseeds/random_parcel_seeds.h>
+
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "parcelables/SingleDataParcelable.h"
+
+using namespace android;
+using android::generateSeedsFromRecording;
+using android::binder::Status;
+using android::binder::debug::RecordedTransaction;
+using parcelables::SingleDataParcelable;
+
+const String16 kServerName = String16("binderRecordReplay");
+
+#define GENERATE_GETTER_SETTER_PRIMITIVE(name, T) \
+    Status set##name(T input) {                   \
+        m##name = input;                          \
+        return Status::ok();                      \
+    }                                             \
+                                                  \
+    Status get##name(T* output) {                 \
+        *output = m##name;                        \
+        return Status::ok();                      \
+    }                                             \
+    T m##name
+
+#define GENERATE_GETTER_SETTER(name, T) \
+    Status set##name(const T& input) {  \
+        m##name = input;                \
+        return Status::ok();            \
+    }                                   \
+                                        \
+    Status get##name(T* output) {       \
+        *output = m##name;              \
+        return Status::ok();            \
+    }                                   \
+    T m##name
+
+class MyRecordReplay : public BnBinderRecordReplayTest {
+public:
+    GENERATE_GETTER_SETTER_PRIMITIVE(Boolean, bool);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Byte, int8_t);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Int, int);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Char, char16_t);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Long, int64_t);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Float, float);
+    GENERATE_GETTER_SETTER_PRIMITIVE(Double, double);
+
+    GENERATE_GETTER_SETTER(String, String16);
+    GENERATE_GETTER_SETTER(SingleDataParcelable, SingleDataParcelable);
+
+    GENERATE_GETTER_SETTER(BooleanArray, std::vector<bool>);
+    GENERATE_GETTER_SETTER(ByteArray, std::vector<uint8_t>);
+    GENERATE_GETTER_SETTER(IntArray, std::vector<int>);
+    GENERATE_GETTER_SETTER(CharArray, std::vector<char16_t>);
+    GENERATE_GETTER_SETTER(LongArray, std::vector<int64_t>);
+    GENERATE_GETTER_SETTER(FloatArray, std::vector<float>);
+    GENERATE_GETTER_SETTER(DoubleArray, std::vector<double>);
+    GENERATE_GETTER_SETTER(StringArray, std::vector<::android::String16>);
+    GENERATE_GETTER_SETTER(SingleDataParcelableArray, std::vector<SingleDataParcelable>);
+};
+
+std::vector<uint8_t> retrieveData(base::borrowed_fd fd) {
+    struct stat fdStat;
+    EXPECT_TRUE(fstat(fd.get(), &fdStat) != -1);
+    EXPECT_TRUE(fdStat.st_size != 0);
+
+    std::vector<uint8_t> buffer(fdStat.st_size);
+    auto readResult = android::base::ReadFully(fd, buffer.data(), fdStat.st_size);
+    EXPECT_TRUE(readResult != 0);
+    return std::move(buffer);
+}
+
+void replayFuzzService(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+    base::unique_fd seedFd(open("/data/local/tmp/replayFuzzService",
+                                O_RDWR | O_CREAT | O_CLOEXEC | O_TRUNC, 0666));
+    ASSERT_TRUE(seedFd.ok());
+
+    // generate corpus from this transaction.
+    generateSeedsFromRecording(seedFd, transaction);
+
+    // Read the data which has been written to seed corpus
+    ASSERT_EQ(0, lseek(seedFd.get(), 0, SEEK_SET));
+    std::vector<uint8_t> seedData = retrieveData(seedFd);
+
+    // use fuzzService to replay the corpus
+    FuzzedDataProvider provider(seedData.data(), seedData.size());
+    fuzzService(binder, std::move(provider));
+}
+
+void replayBinder(const sp<BpBinder>& binder, const RecordedTransaction& transaction) {
+    // TODO: move logic to replay RecordedTransaction into RecordedTransaction
+    Parcel data;
+    data.setData(transaction.getDataParcel().data(), transaction.getDataParcel().dataSize());
+    auto result = binder->transact(transaction.getCode(), data, nullptr, transaction.getFlags());
+
+    // make sure recording does the thing we expect it to do
+    EXPECT_EQ(OK, result);
+}
+
+class BinderRecordReplayTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        // get the remote service
+        auto binder = defaultServiceManager()->getService(kServerName);
+        ASSERT_NE(nullptr, binder);
+        mInterface = interface_cast<IBinderRecordReplayTest>(binder);
+        mBpBinder = binder->remoteBinder();
+        ASSERT_NE(nullptr, mBpBinder);
+    }
+
+    template <typename T, typename U>
+    void recordReplay(Status (IBinderRecordReplayTest::*set)(T), U recordedValue,
+                      Status (IBinderRecordReplayTest::*get)(U*), U changedValue) {
+        auto replayFunctions = {&replayBinder, &replayFuzzService};
+        for (auto replayFunc : replayFunctions) {
+            base::unique_fd fd(open("/data/local/tmp/binderRecordReplayTest.rec",
+                                    O_RDWR | O_CREAT | O_CLOEXEC, 0666));
+            ASSERT_TRUE(fd.ok());
+
+            // record a transaction
+            mBpBinder->startRecordingBinder(fd);
+            auto status = (*mInterface.*set)(recordedValue);
+            EXPECT_TRUE(status.isOk());
+            mBpBinder->stopRecordingBinder();
+
+            // test transaction does the thing we expect it to do
+            U output;
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
+            EXPECT_EQ(output, recordedValue);
+
+            // write over the existing state
+            status = (*mInterface.*set)(changedValue);
+            EXPECT_TRUE(status.isOk());
+
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
+
+            EXPECT_EQ(output, changedValue);
+
+            // replay transaction
+            ASSERT_EQ(0, lseek(fd.get(), 0, SEEK_SET));
+            std::optional<RecordedTransaction> transaction = RecordedTransaction::fromFile(fd);
+            ASSERT_NE(transaction, std::nullopt);
+
+            const RecordedTransaction& recordedTransaction = *transaction;
+            // call replay function with recorded transaction
+            (*replayFunc)(mBpBinder, recordedTransaction);
+
+            status = (*mInterface.*get)(&output);
+            EXPECT_TRUE(status.isOk());
+            EXPECT_EQ(output, recordedValue);
+        }
+    }
+
+private:
+    sp<BpBinder> mBpBinder;
+    sp<IBinderRecordReplayTest> mInterface;
+};
+
+TEST_F(BinderRecordReplayTest, ReplayByte) {
+    recordReplay(&IBinderRecordReplayTest::setByte, int8_t{122}, &IBinderRecordReplayTest::getByte,
+                 int8_t{90});
+}
+
+TEST_F(BinderRecordReplayTest, ReplayBoolean) {
+    recordReplay(&IBinderRecordReplayTest::setBoolean, true, &IBinderRecordReplayTest::getBoolean,
+                 false);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayChar) {
+    recordReplay(&IBinderRecordReplayTest::setChar, char16_t{'G'},
+                 &IBinderRecordReplayTest::getChar, char16_t{'K'});
+}
+
+TEST_F(BinderRecordReplayTest, ReplayInt) {
+    recordReplay(&IBinderRecordReplayTest::setInt, 3, &IBinderRecordReplayTest::getInt, 5);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayFloat) {
+    recordReplay(&IBinderRecordReplayTest::setFloat, 1.1f, &IBinderRecordReplayTest::getFloat,
+                 22.0f);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayLong) {
+    recordReplay(&IBinderRecordReplayTest::setLong, int64_t{1LL << 55},
+                 &IBinderRecordReplayTest::getLong, int64_t{1LL << 12});
+}
+
+TEST_F(BinderRecordReplayTest, ReplayDouble) {
+    recordReplay(&IBinderRecordReplayTest::setDouble, 0.00, &IBinderRecordReplayTest::getDouble,
+                 1.11);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayString) {
+    const ::android::String16& input1 = String16("This is saved string");
+    const ::android::String16& input2 = String16("This is changed string");
+    recordReplay(&IBinderRecordReplayTest::setString, input1, &IBinderRecordReplayTest::getString,
+                 input2);
+}
+
+TEST_F(BinderRecordReplayTest, ReplaySingleDataParcelable) {
+    SingleDataParcelable saved, changed;
+    saved.data = 3;
+    changed.data = 5;
+    recordReplay(&IBinderRecordReplayTest::setSingleDataParcelable, saved,
+                 &IBinderRecordReplayTest::getSingleDataParcelable, changed);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayByteArray) {
+    std::vector<uint8_t> savedArray = {uint8_t{255}, uint8_t{0}, uint8_t{127}};
+    std::vector<uint8_t> changedArray = {uint8_t{2}, uint8_t{7}, uint8_t{117}};
+    recordReplay(&IBinderRecordReplayTest::setByteArray, savedArray,
+                 &IBinderRecordReplayTest::getByteArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayBooleanArray) {
+    std::vector<bool> savedArray = {true, false, true};
+    std::vector<bool> changedArray = {false, true, false};
+    recordReplay(&IBinderRecordReplayTest::setBooleanArray, savedArray,
+                 &IBinderRecordReplayTest::getBooleanArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayCharArray) {
+    std::vector<char16_t> savedArray = {char16_t{'G'}, char16_t{'L'}, char16_t{'K'}, char16_t{'T'}};
+    std::vector<char16_t> changedArray = {char16_t{'X'}, char16_t{'Y'}, char16_t{'Z'}};
+    recordReplay(&IBinderRecordReplayTest::setCharArray, savedArray,
+                 &IBinderRecordReplayTest::getCharArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayIntArray) {
+    std::vector<int> savedArray = {12, 45, 178};
+    std::vector<int> changedArray = {32, 14, 78, 1899};
+    recordReplay(&IBinderRecordReplayTest::setIntArray, savedArray,
+                 &IBinderRecordReplayTest::getIntArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayFloatArray) {
+    std::vector<float> savedArray = {12.14f, 45.56f, 123.178f};
+    std::vector<float> changedArray = {0.00f, 14.0f, 718.1f, 1899.122f, 3268.123f};
+    recordReplay(&IBinderRecordReplayTest::setFloatArray, savedArray,
+                 &IBinderRecordReplayTest::getFloatArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayLongArray) {
+    std::vector<int64_t> savedArray = {int64_t{1LL << 11}, int64_t{1LL << 55}, int64_t{1LL << 45}};
+    std::vector<int64_t> changedArray = {int64_t{1LL << 1}, int64_t{1LL << 21}, int64_t{1LL << 33},
+                                         int64_t{1LL << 62}};
+    recordReplay(&IBinderRecordReplayTest::setLongArray, savedArray,
+                 &IBinderRecordReplayTest::getLongArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayDoubleArray) {
+    std::vector<double> savedArray = {12.1412313, 45.561232, 123.1781111};
+    std::vector<double> changedArray = {0.00111, 14.32130, 712312318.19, 1899212.122,
+                                        322168.122123};
+    recordReplay(&IBinderRecordReplayTest::setDoubleArray, savedArray,
+                 &IBinderRecordReplayTest::getDoubleArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplayStringArray) {
+    std::vector<String16> savedArray = {String16("This is saved value"), String16(),
+                                        String16("\0\0", 2), String16("\xF3\x01\xAC\xAD\x21\xAF")};
+
+    std::vector<String16> changedArray = {String16("This is changed value"),
+                                          String16("\xF0\x90\x90\xB7\xE2\x82\xAC")};
+    recordReplay(&IBinderRecordReplayTest::setStringArray, savedArray,
+                 &IBinderRecordReplayTest::getStringArray, changedArray);
+}
+
+TEST_F(BinderRecordReplayTest, ReplaySingleDataParcelableArray) {
+    SingleDataParcelable s1, s2, s3, s4, s5;
+    s1.data = 5213;
+    s2.data = 1512;
+    s3.data = 4233;
+    s4.data = 123124;
+    s5.data = 0;
+    std::vector<SingleDataParcelable> saved = {s1, s2, s3};
+    std::vector<SingleDataParcelable> changed = {s4, s5};
+
+    recordReplay(&IBinderRecordReplayTest::setSingleDataParcelableArray, saved,
+                 &IBinderRecordReplayTest::getSingleDataParcelableArray, changed);
+}
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    if (fork() == 0) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+        auto server = sp<MyRecordReplay>::make();
+        android::defaultServiceManager()->addService(kServerName, server.get());
+
+        IPCThreadState::self()->joinThreadPool(true);
+        exit(1); // should not reach
+    }
+
+    // not racey, but getService sleeps for 1s
+    usleep(100000);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 5939273..9c96c41 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -129,12 +129,33 @@
     }
 }
 
+static void SetLabel(benchmark::State& state) {
+    Transport transport = static_cast<Transport>(state.range(0));
+    switch (transport) {
+#ifdef __BIONIC__
+        case KERNEL:
+            state.SetLabel("kernel");
+            break;
+#endif
+        case RPC:
+            state.SetLabel("rpc");
+            break;
+        case RPC_TLS:
+            state.SetLabel("rpc_tls");
+            break;
+        default:
+            LOG(FATAL) << "Unknown transport value: " << transport;
+    }
+}
+
 void BM_pingTransaction(benchmark::State& state) {
     sp<IBinder> binder = getBinderForOptions(state);
 
     while (state.KeepRunning()) {
         CHECK_EQ(OK, binder->pingBinder());
     }
+
+    SetLabel(state);
 }
 BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
 
@@ -164,6 +185,8 @@
         Status ret = iface->repeatString(str, &out);
         CHECK(ret.isOk()) << ret;
     }
+
+    SetLabel(state);
 }
 BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
 
@@ -182,6 +205,8 @@
         Status ret = iface->repeatBytes(bytes, &out);
         CHECK(ret.isOk()) << ret;
     }
+
+    SetLabel(state);
 }
 BENCHMARK(BM_throughputForTransportAndBytes)
         ->ArgsProduct({kTransportList,
@@ -201,6 +226,8 @@
         Status ret = iface->repeatBinder(binder, &out);
         CHECK(ret.isOk()) << ret;
     }
+
+    SetLabel(state);
 }
 BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
 
@@ -228,11 +255,6 @@
     ::benchmark::Initialize(&argc, argv);
     if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
 
-    std::cerr << "Tests suffixes:" << std::endl;
-    std::cerr << "\t.../" << Transport::KERNEL << " is KERNEL" << std::endl;
-    std::cerr << "\t.../" << Transport::RPC << " is RPC" << std::endl;
-    std::cerr << "\t.../" << Transport::RPC_TLS << " is RPC with TLS" << std::endl;
-
 #ifdef __BIONIC__
     if (0 == fork()) {
         prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8d13007..4c3c68e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -249,12 +249,12 @@
         CHECK_EQ(options.numIncomingConnectionsBySession.size(), options.numSessions);
     }
 
-    SocketType socketType = std::get<0>(GetParam());
-    RpcSecurity rpcSecurity = std::get<1>(GetParam());
-    uint32_t clientVersion = std::get<2>(GetParam());
-    uint32_t serverVersion = std::get<3>(GetParam());
-    bool singleThreaded = std::get<4>(GetParam());
-    bool noKernel = std::get<5>(GetParam());
+    SocketType socketType = GetParam().type;
+    RpcSecurity rpcSecurity = GetParam().security;
+    uint32_t clientVersion = GetParam().clientVersion;
+    uint32_t serverVersion = GetParam().serverVersion;
+    bool singleThreaded = GetParam().singleThreaded;
+    bool noKernel = GetParam().noKernel;
 
     std::string path = android::base::GetExecutableDirectory();
     auto servicePath = android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
@@ -461,8 +461,11 @@
 
     EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
 
-    // Potential flake, but make sure calls are handled in parallel.
-    EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
+    // Potential flake, but make sure calls are handled in parallel. Due
+    // to past flakes, this only checks that the amount of time taken has
+    // some parallelism. Other tests such as ThreadPoolGreaterThanEqualRequested
+    // check this more exactly.
+    EXPECT_LE(epochMsAfter, epochMsBefore + (numCalls - 1) * sleepMs);
 }
 
 TEST_P(BinderRpc, ThreadPoolOverSaturated) {
@@ -671,7 +674,7 @@
     // session 0 - will check for leaks in destrutor of proc
     // session 1 - we want to make sure it gets deleted when we drop all references to it
     auto proc = createRpcTestSocketServerProcess(
-            {.numThreads = 1, .numIncomingConnectionsBySession = {0, 1}, .numSessions = 2});
+            {.numThreads = 1, .numSessions = 2, .numIncomingConnectionsBySession = {0, 1}});
 
     wp<RpcSession> session = proc.proc->sessions.at(1).session;
 
@@ -687,6 +690,12 @@
     }
 
     EXPECT_EQ(nullptr, session.promote());
+
+    // now that it has died, wait for the remote session to shutdown
+    std::vector<int32_t> remoteCounts;
+    do {
+        EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+    } while (remoteCounts.size() > 1);
 }
 
 TEST_P(BinderRpc, SingleDeathRecipient) {
@@ -1112,15 +1121,30 @@
 }
 
 #ifdef BINDER_RPC_TO_TRUSTY_TEST
-INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
-                        ::testing::Combine(::testing::Values(SocketType::TIPC),
-                                           ::testing::Values(RpcSecurity::RAW),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::Values(true), ::testing::Values(true)),
+
+static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
+    std::vector<BinderRpc::ParamType> ret;
+
+    for (const auto& clientVersion : testVersions()) {
+        for (const auto& serverVersion : testVersions()) {
+            ret.push_back(BinderRpc::ParamType{
+                    .type = SocketType::TIPC,
+                    .security = RpcSecurity::RAW,
+                    .clientVersion = clientVersion,
+                    .serverVersion = serverVersion,
+                    .singleThreaded = true,
+                    .noKernel = true,
+            });
+        }
+    }
+
+    return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()),
                         BinderRpc::PrintParamInfo);
 #else // BINDER_RPC_TO_TRUSTY_TEST
-static bool testSupportVsockLoopback() {
+bool testSupportVsockLoopback() {
     // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
 
@@ -1220,7 +1244,15 @@
 
     if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
 
+#ifdef __BIONIC__
+    // Devices may not have vsock support. AVF tests will verify whether they do, but
+    // we can't require it due to old kernels for the time being.
     static bool hasVsockLoopback = testSupportVsockLoopback();
+#else
+    // On host machines, we always assume we have vsock loopback. If we don't, the
+    // subsequent failures will be more clear than showing one now.
+    static bool hasVsockLoopback = true;
+#endif
 
     if (hasVsockLoopback) {
         ret.push_back(SocketType::VSOCK);
@@ -1229,13 +1261,47 @@
     return ret;
 }
 
-INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
-                        ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
-                                           ::testing::ValuesIn(RpcSecurityValues()),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::Values(false, true),
-                                           ::testing::Values(false, true)),
+static std::vector<BinderRpc::ParamType> getBinderRpcParams() {
+    std::vector<BinderRpc::ParamType> ret;
+
+    constexpr bool full = false;
+
+    for (const auto& type : testSocketTypes()) {
+        if (full || type == SocketType::UNIX) {
+            for (const auto& security : RpcSecurityValues()) {
+                for (const auto& clientVersion : testVersions()) {
+                    for (const auto& serverVersion : testVersions()) {
+                        for (bool singleThreaded : {false, true}) {
+                            for (bool noKernel : {false, true}) {
+                                ret.push_back(BinderRpc::ParamType{
+                                        .type = type,
+                                        .security = security,
+                                        .clientVersion = clientVersion,
+                                        .serverVersion = serverVersion,
+                                        .singleThreaded = singleThreaded,
+                                        .noKernel = noKernel,
+                                });
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            ret.push_back(BinderRpc::ParamType{
+                    .type = type,
+                    .security = RpcSecurity::RAW,
+                    .clientVersion = RPC_WIRE_PROTOCOL_VERSION,
+                    .serverVersion = RPC_WIRE_PROTOCOL_VERSION,
+                    .singleThreaded = false,
+                    .noKernel = false,
+            });
+        }
+    }
+
+    return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(getBinderRpcParams()),
                         BinderRpc::PrintParamInfo);
 
 class BinderRpcServerRootObject
@@ -1353,7 +1419,7 @@
     base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     int sinkFd = sink.get();
     auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam())));
-    server->setProtocolVersion(std::get<1>(GetParam()));
+    ASSERT_TRUE(server->setProtocolVersion(std::get<1>(GetParam())));
     ASSERT_FALSE(server->hasServer());
     ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
     ASSERT_TRUE(server->hasServer());
@@ -1369,7 +1435,7 @@
 
     auto addr = allocateSocketAddress();
     auto server = RpcServer::make(newTlsFactory(std::get<0>(GetParam())));
-    server->setProtocolVersion(std::get<1>(GetParam()));
+    ASSERT_TRUE(server->setProtocolVersion(std::get<1>(GetParam())));
     ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
     auto joinEnds = std::make_shared<OneOffSignal>();
 
@@ -1418,7 +1484,9 @@
                 std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
             auto [socketType, rpcSecurity, certificateFormat, serverVersion] = param;
             auto rpcServer = RpcServer::make(newTlsFactory(rpcSecurity));
-            rpcServer->setProtocolVersion(serverVersion);
+            if (!rpcServer->setProtocolVersion(serverVersion)) {
+                return AssertionFailure() << "Invalid protocol version: " << serverVersion;
+            }
             switch (socketType) {
                 case SocketType::PRECONNECTED: {
                     return AssertionFailure() << "Not supported by this test";
diff --git a/libs/binder/tests/binderRpcTestFixture.h b/libs/binder/tests/binderRpcTestFixture.h
index 6cde9f7..2c9646b 100644
--- a/libs/binder/tests/binderRpcTestFixture.h
+++ b/libs/binder/tests/binderRpcTestFixture.h
@@ -79,6 +79,7 @@
         expectAlreadyShutdown = true;
     }
 
+    BinderRpcTestProcessSession(std::unique_ptr<ProcessSession> proc) : proc(std::move(proc)){};
     BinderRpcTestProcessSession(BinderRpcTestProcessSession&&) = default;
     ~BinderRpcTestProcessSession() {
         if (!expectAlreadyShutdown) {
@@ -105,15 +106,23 @@
     }
 };
 
-class BinderRpc : public ::testing::TestWithParam<
-                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
+struct BinderRpcParam {
+    SocketType type;
+    RpcSecurity security;
+    uint32_t clientVersion;
+    uint32_t serverVersion;
+    bool singleThreaded;
+    bool noKernel;
+};
+class BinderRpc : public ::testing::TestWithParam<BinderRpcParam> {
 public:
-    SocketType socketType() const { return std::get<0>(GetParam()); }
-    RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
-    uint32_t clientVersion() const { return std::get<2>(GetParam()); }
-    uint32_t serverVersion() const { return std::get<3>(GetParam()); }
-    bool serverSingleThreaded() const { return std::get<4>(GetParam()); }
-    bool noKernel() const { return std::get<5>(GetParam()); }
+    // TODO: avoid unnecessary layer of indirection
+    SocketType socketType() const { return GetParam().type; }
+    RpcSecurity rpcSecurity() const { return GetParam().security; }
+    uint32_t clientVersion() const { return GetParam().clientVersion; }
+    uint32_t serverVersion() const { return GetParam().serverVersion; }
+    bool serverSingleThreaded() const { return GetParam().singleThreaded; }
+    bool noKernel() const { return GetParam().noKernel; }
 
     bool clientOrServerSingleThreaded() const {
         return !kEnableRpcThreads || serverSingleThreaded();
@@ -138,9 +147,7 @@
     }
 
     BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
-        BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcessEtc(options),
-        };
+        BinderRpcTestProcessSession ret(createRpcTestSocketServerProcessEtc(options));
 
         ret.rootBinder = ret.proc->sessions.empty() ? nullptr : ret.proc->sessions.at(0).root;
         ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
@@ -149,15 +156,16 @@
     }
 
     static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
-        auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
-                std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
-        if (singleThreaded) {
+        auto ret = PrintToString(info.param.type) + "_" +
+                newFactory(info.param.security)->toCString() + "_clientV" +
+                std::to_string(info.param.clientVersion) + "_serverV" +
+                std::to_string(info.param.serverVersion);
+        if (info.param.singleThreaded) {
             ret += "_single_threaded";
         } else {
             ret += "_multi_threaded";
         }
-        if (noKernel) {
+        if (info.param.noKernel) {
             ret += "_no_kernel";
         } else {
             ret += "_with_kernel";
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
index a9736d5..7435f30 100644
--- a/libs/binder/tests/binderRpcTestService.cpp
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -118,7 +118,7 @@
     auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
     sp<RpcServer> server = RpcServer::make(newTlsFactory(rpcSecurity, certVerifier));
 
-    server->setProtocolVersion(serverConfig.serverVersion);
+    CHECK(server->setProtocolVersion(serverConfig.serverVersion));
     server->setMaxThreads(serverConfig.numThreads);
     server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
 
@@ -139,7 +139,8 @@
             CHECK_EQ(OK, server->setupRawSocketServer(std::move(socketFd)));
             break;
         case SocketType::VSOCK:
-            CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort));
+            CHECK_EQ(OK, server->setupVsockServer(VMADDR_CID_LOCAL, serverConfig.vsockPort))
+                    << "Need `sudo modprobe vsock_loopback`?";
             break;
         case SocketType::INET: {
             CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
@@ -164,7 +165,12 @@
         }
     }
 
-    server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+    server->setPerSessionRootObject([&](wp<RpcSession> session, const void* addrPtr, size_t len) {
+        {
+            sp<RpcSession> spSession = session.promote();
+            CHECK_NE(nullptr, spSession.get());
+        }
+
         // UNIX sockets with abstract addresses return
         // sizeof(sa_family_t)==2 in addrlen
         CHECK_GE(len, sizeof(sa_family_t));
diff --git a/libs/binder/tests/binderRpcTestServiceTrusty.cpp b/libs/binder/tests/binderRpcTestServiceTrusty.cpp
index 8557389..cb632e9 100644
--- a/libs/binder/tests/binderRpcTestServiceTrusty.cpp
+++ b/libs/binder/tests/binderRpcTestServiceTrusty.cpp
@@ -90,15 +90,18 @@
 
         auto server = std::move(*serverOrErr);
         serverInfo.server = server;
-        serverInfo.server->setProtocolVersion(serverVersion);
-        serverInfo.server->setPerSessionRootObject([=](const void* /*addrPtr*/, size_t /*len*/) {
-            auto service = sp<MyBinderRpcTestTrusty>::make();
-            // Assign a unique connection identifier to service->port so
-            // getClientPort returns a unique value per connection
-            service->port = ++gConnectionCounter;
-            service->server = server;
-            return service;
-        });
+        if (!serverInfo.server->setProtocolVersion(serverVersion)) {
+            return EXIT_FAILURE;
+        }
+        serverInfo.server->setPerSessionRootObject(
+                [=](wp<RpcSession> /*session*/, const void* /*addrPtr*/, size_t /*len*/) {
+                    auto service = sp<MyBinderRpcTestTrusty>::make();
+                    // Assign a unique connection identifier to service->port so
+                    // getClientPort returns a unique value per connection
+                    service->port = ++gConnectionCounter;
+                    service->server = server;
+                    return service;
+                });
 
         servers.push_back(std::move(serverInfo));
     }
diff --git a/libs/binder/tests/binderRpcTestTrusty.cpp b/libs/binder/tests/binderRpcTestTrusty.cpp
index 28be10d..fcb83bd 100644
--- a/libs/binder/tests/binderRpcTestTrusty.cpp
+++ b/libs/binder/tests/binderRpcTestTrusty.cpp
@@ -57,9 +57,9 @@
                                     [](size_t n) { return n != 0; }),
                         "Non-zero incoming connections on Trusty");
 
-    RpcSecurity rpcSecurity = std::get<1>(GetParam());
-    uint32_t clientVersion = std::get<2>(GetParam());
-    uint32_t serverVersion = std::get<3>(GetParam());
+    RpcSecurity rpcSecurity = GetParam().security;
+    uint32_t clientVersion = GetParam().clientVersion;
+    uint32_t serverVersion = GetParam().serverVersion;
 
     auto ret = std::make_unique<TrustyProcessSession>();
 
@@ -89,12 +89,27 @@
     return ret;
 }
 
-INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc,
-                        ::testing::Combine(::testing::Values(SocketType::TIPC),
-                                           ::testing::Values(RpcSecurity::RAW),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::ValuesIn(testVersions()),
-                                           ::testing::Values(false), ::testing::Values(true)),
+static std::vector<BinderRpc::ParamType> getTrustyBinderRpcParams() {
+    std::vector<BinderRpc::ParamType> ret;
+
+    for (const auto& clientVersion : testVersions()) {
+        for (const auto& serverVersion : testVersions()) {
+            ret.push_back(BinderRpc::ParamType{
+                    .type = SocketType::TIPC,
+                    .security = RpcSecurity::RAW,
+                    .clientVersion = clientVersion,
+                    .serverVersion = serverVersion,
+                    // TODO: should we test both versions here?
+                    .singleThreaded = false,
+                    .noKernel = true,
+            });
+        }
+    }
+
+    return ret;
+}
+
+INSTANTIATE_TEST_CASE_P(Trusty, BinderRpc, ::testing::ValuesIn(getTrustyBinderRpcParams()),
                         BinderRpc::PrintParamInfo);
 
 } // namespace android
diff --git a/libs/binder/tests/binderRpcUniversalTests.cpp b/libs/binder/tests/binderRpcUniversalTests.cpp
index 1f46010..e43508e 100644
--- a/libs/binder/tests/binderRpcUniversalTests.cpp
+++ b/libs/binder/tests/binderRpcUniversalTests.cpp
@@ -84,7 +84,7 @@
         GTEST_SKIP() << "This test requires a multi-threaded service";
     }
 
-    SocketType type = std::get<0>(GetParam());
+    SocketType type = GetParam().type;
     if (type == SocketType::PRECONNECTED || type == SocketType::UNIX ||
         type == SocketType::UNIX_BOOTSTRAP || type == SocketType::UNIX_RAW) {
         // we can't get port numbers for unix sockets
diff --git a/libs/binder/tests/binderSafeInterfaceTest.cpp b/libs/binder/tests/binderSafeInterfaceTest.cpp
index c857d62..5e8a32a 100644
--- a/libs/binder/tests/binderSafeInterfaceTest.cpp
+++ b/libs/binder/tests/binderSafeInterfaceTest.cpp
@@ -35,6 +35,7 @@
 
 #include <optional>
 
+#include <inttypes.h>
 #include <sys/eventfd.h>
 #include <sys/prctl.h>
 
@@ -686,10 +687,12 @@
     // Determine the maximum number of fds this process can have open
     struct rlimit limit {};
     ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &limit));
-    uint32_t maxFds = static_cast<uint32_t>(limit.rlim_cur);
+    uint64_t maxFds = limit.rlim_cur;
+
+    ALOG(LOG_INFO, "SafeInterfaceTest", "%s max FDs: %" PRIu64, __PRETTY_FUNCTION__, maxFds);
 
     // Perform this test enough times to rule out fd leaks
-    for (uint32_t iter = 0; iter < (2 * maxFds); ++iter) {
+    for (uint32_t iter = 0; iter < (maxFds + 100); ++iter) {
         native_handle* handle = native_handle_create(1 /*numFds*/, 1 /*numInts*/);
         ASSERT_NE(nullptr, handle);
         handle->data[0] = dup(eventFd.get());
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 35866ad..383795e 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -104,3 +104,43 @@
     local_include_dirs: ["include_random_parcel"],
     export_include_dirs: ["include_random_parcel"],
 }
+
+cc_library {
+    name: "libbinder_random_parcel_seeds",
+    host_supported: true,
+    vendor_available: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    srcs: [
+        "random_parcel_seeds.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbinder_ndk",
+        "libcutils",
+        "libutils",
+    ],
+    local_include_dirs: [
+        "include_random_parcel_seeds",
+    ],
+    export_include_dirs: ["include_random_parcel_seeds"],
+}
+
+cc_binary_host {
+    name: "binder2corpus",
+    static_libs: [
+        "libbinder_random_parcel_seeds",
+    ],
+    srcs: [
+        "binder2corpus/binder2corpus.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
new file mode 100644
index 0000000..59bf9f3
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/README.md
@@ -0,0 +1,31 @@
+# binder2corpus
+
+This tool converts recordings generated by record_binder tool to fuzzer seeds for fuzzService.
+
+# Steps to add corpus:
+
+## Start recording the service binder
+ex. record_binder start manager
+
+## Run test on device or keep device idle
+ex. atest servicemanager_test
+
+## Stop the recording
+record_binder stop manager
+
+## Pull the recording on host
+Recordings are present on device at /data/local/recordings/<service_name>. Use adb pull.
+Use inspect command of record_binder to check if there are some transactions captured.
+ex. record_binder inspect manager
+
+## run corpus generator tool
+binder2corpus <recording_path> <dir_to_write_corpus>
+
+## Build fuzzer and sync data directory
+ex. m servicemanager_fuzzer && adb sync data
+
+## Push corpus on device
+ex. adb push servicemanager_fuzzer_corpus/ /data/fuzz/x86_64/servicemanager_fuzzer/
+
+## Run fuzzer with corpus directory as argument
+ex. adb shell /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer /data/fuzz/x86_64/servicemanager_fuzzer/servicemanager_fuzzer_corpus
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
new file mode 100644
index 0000000..c0fdaea
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/binder2corpus/binder2corpus.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+#include <sys/prctl.h>
+
+using android::generateSeedsFromRecording;
+using android::status_t;
+using android::base::unique_fd;
+using android::binder::debug::RecordedTransaction;
+
+status_t generateCorpus(const char* recordingPath, const char* corpusDir) {
+    unique_fd fd(open(recordingPath, O_RDONLY));
+    if (!fd.ok()) {
+        std::cerr << "Failed to open recording file at path " << recordingPath
+                  << " with error: " << strerror(errno) << '\n';
+        return android::BAD_VALUE;
+    }
+
+    if (auto res = mkdir(corpusDir, 0766); res != 0) {
+        std::cerr
+                << "Failed to create corpus directory at path. Delete directory if already exists: "
+                << corpusDir << std::endl;
+        return android::BAD_VALUE;
+    }
+
+    int transactionNumber = 0;
+    while (auto transaction = RecordedTransaction::fromFile(fd)) {
+        ++transactionNumber;
+        std::string filePath = std::string(corpusDir) + std::string("transaction_") +
+                std::to_string(transactionNumber);
+        constexpr int openFlags = O_WRONLY | O_CREAT | O_BINARY | O_CLOEXEC;
+        android::base::unique_fd corpusFd(open(filePath.c_str(), openFlags, 0666));
+        if (!corpusFd.ok()) {
+            std::cerr << "Failed to open fd. Path " << filePath
+                      << " with error: " << strerror(errno) << std::endl;
+            return android::UNKNOWN_ERROR;
+        }
+        generateSeedsFromRecording(corpusFd, transaction.value());
+    }
+
+    if (transactionNumber == 0) {
+        std::cerr << "No valid transaction has been found in recording file:  " << recordingPath
+                  << std::endl;
+        return android::BAD_VALUE;
+    }
+
+    return android::NO_ERROR;
+}
+
+void printHelp(const char* toolName) {
+    std::cout << "Usage: \n\n"
+              << toolName
+              << " <recording_path> <destination_directory> \n\n*Use "
+                 "record_binder tool for recording binder transactions."
+              << std::endl;
+}
+
+int main(int argc, char** argv) {
+    if (argc != 3) {
+        printHelp(argv[0]);
+        return 1;
+    }
+    const char* sourcePath = argv[1];
+    const char* corpusDir = argv[2];
+    if (android::NO_ERROR != generateCorpus(sourcePath, corpusDir)) {
+        std::cerr << "Failed to generate fuzzer corpus." << std::endl;
+        return 1;
+    }
+    return 0;
+}
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
index a9a6197..cb37cfa 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_driver.h
@@ -19,7 +19,17 @@
 #include <binder/IBinder.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <vector>
+
 namespace android {
+
+/**
+ * See fuzzService, but fuzzes multiple services at the same time.
+ *
+ * Consumes providers.
+ */
+void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& provider);
+
 /**
  * Based on the random data in provider, construct an arbitrary number of
  * Parcel objects and send them to the service in serial.
@@ -34,4 +44,5 @@
  *   }
  */
 void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider);
+
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
index f2b7823..d8bf87a 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/libbinder_ndk_driver.h
@@ -16,10 +16,21 @@
 
 #pragma once
 
+#include <android/binder_auto_utils.h>
 #include <android/binder_parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <vector>
+
 namespace android {
+
+/**
+ * See fuzzService, but fuzzes multiple services at the same time.
+ *
+ * Consumes providers.
+ */
+void fuzzService(const std::vector<ndk::SpAIBinder>& binders, FuzzedDataProvider&& provider);
+
 /**
  * Based on the random data in provider, construct an arbitrary number of
  * Parcel objects and send them to the service in serial.
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
new file mode 100644
index 0000000..5755239
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel_seeds/fuzzseeds/random_parcel_seeds.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/hex.h>
+#include <android-base/logging.h>
+
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+#include <binder/RecordedTransaction.h>
+
+#include <private/android_filesystem_config.h>
+
+#include <vector>
+
+using android::Parcel;
+using android::base::HexString;
+using std::vector;
+
+namespace android {
+namespace impl {
+// computes the bytes so that if they are passed to FuzzedDataProvider and
+// provider.ConsumeIntegralInRange<T>(min, max) is called, it will return val
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T min, T max, T val);
+
+// Calls writeInBuffer method with min and max numeric limits of type T. This method
+// is reversal of ConsumeIntegral<T>() in FuzzedDataProvider
+template <typename T>
+void writeReversedBuffer(std::vector<std::byte>& integralBuffer, T val);
+} // namespace impl
+void generateSeedsFromRecording(base::borrowed_fd fd,
+                                const binder::debug::RecordedTransaction& transaction);
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 8bef33f..47d2a0a 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -21,19 +21,41 @@
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 
+#include <private/android_filesystem_config.h>
+
 namespace android {
 
 void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
-    sp<IBinder> target;
+    fuzzService(std::vector<sp<IBinder>>{binder}, std::move(provider));
+}
 
+void fuzzService(const std::vector<sp<IBinder>>& binders, FuzzedDataProvider&& provider) {
     RandomParcelOptions options{
-            .extraBinders = {binder},
+            .extraBinders = binders,
             .extraFds = {},
     };
 
+    // Reserved bytes so that we don't have to change fuzzers and seed corpus if
+    // we introduce anything new in fuzzService.
+    std::vector<uint8_t> reservedBytes = provider.ConsumeBytes<uint8_t>(8);
+    (void)reservedBytes;
+
+    // always refresh the calling identity, because we sometimes set it below, but also,
+    // the code we're fuzzing might reset it
+    IPCThreadState::self()->clearCallingIdentity();
+
+    // Always take so that a perturbation of just the one ConsumeBool byte will always
+    // take the same path, but with a different UID. Without this, the fuzzer needs to
+    // guess both the change in value and the shift at the same time.
+    int64_t maybeSetUid = provider.PickValueInArray<int64_t>(
+            {static_cast<int64_t>(AID_ROOT) << 32, static_cast<int64_t>(AID_SYSTEM) << 32,
+             provider.ConsumeIntegralInRange<int64_t>(static_cast<int64_t>(AID_ROOT) << 32,
+                                                      static_cast<int64_t>(AID_USER) << 32),
+             provider.ConsumeIntegral<int64_t>()});
+
     if (provider.ConsumeBool()) {
         // set calling uid
-        IPCThreadState::self()->restoreCallingIdentity(provider.ConsumeIntegral<int64_t>());
+        IPCThreadState::self()->restoreCallingIdentity(maybeSetUid);
     }
 
     while (provider.remaining_bytes() > 0) {
@@ -43,7 +65,8 @@
         uint32_t flags = provider.ConsumeIntegral<uint32_t>();
         Parcel data;
         // for increased fuzz coverage
-        data.setEnforceNoDataAvail(provider.ConsumeBool());
+        data.setEnforceNoDataAvail(false);
+        data.setServiceFuzzing();
 
         sp<IBinder> target = options.extraBinders.at(
                 provider.ConsumeIntegralInRange<size_t>(0, options.extraBinders.size() - 1));
@@ -61,7 +84,8 @@
 
         Parcel reply;
         // for increased fuzz coverage
-        reply.setEnforceNoDataAvail(provider.ConsumeBool());
+        reply.setEnforceNoDataAvail(false);
+        reply.setServiceFuzzing();
         (void)target->transact(code, data, &reply, flags);
 
         // feed back in binders and fds that are returned from the service, so that
@@ -77,7 +101,6 @@
     }
 
     // invariants
-
     auto ps = ProcessState::selfOrNull();
     if (ps) {
         CHECK_EQ(0, ps->getThreadPoolMaxTotalThreadCount())
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
index a1fb701..0b0ca34 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp
@@ -24,6 +24,15 @@
 
 namespace android {
 
+void fuzzService(const std::vector<ndk::SpAIBinder>& binders, FuzzedDataProvider&& provider) {
+    std::vector<sp<IBinder>> cppBinders;
+    for (const auto& binder : binders) {
+        cppBinders.push_back(binder.get()->getBinder());
+    }
+
+    fuzzService(cppBinders, std::move(provider));
+}
+
 void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) {
     fuzzService(binder->getBinder(), std::move(provider));
 }
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
new file mode 100644
index 0000000..9e3e2ab
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp
@@ -0,0 +1,146 @@
+/*
+ * 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 <android-base/file.h>
+#include <android-base/logging.h>
+
+#include <binder/RecordedTransaction.h>
+
+#include <fuzzseeds/random_parcel_seeds.h>
+
+using android::base::WriteFully;
+
+namespace android {
+namespace impl {
+template <typename T>
+std::vector<uint8_t> reverseBytes(T min, T max, T val) {
+    uint64_t range = static_cast<uint64_t>(max) - min;
+    uint64_t result = val - min;
+    size_t offset = 0;
+
+    std::vector<uint8_t> reverseData;
+    uint8_t reversed = 0;
+    reversed |= result;
+
+    while (offset < sizeof(T) * CHAR_BIT && (range >> offset) > 0) {
+        reverseData.push_back(reversed);
+        reversed = 0;
+        reversed |= (result >> CHAR_BIT);
+        result = result >> CHAR_BIT;
+        offset += CHAR_BIT;
+    }
+
+    return std::move(reverseData);
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T min, T max, T val) {
+    std::vector<uint8_t> reversedData = reverseBytes(min, max, val);
+    // ConsumeIntegral Calls read buffer from the end. Keep inserting at the front of the buffer
+    // so that we can align fuzzService operations with seed generation for readability.
+    integralBuffer.insert(integralBuffer.begin(), reversedData.begin(), reversedData.end());
+}
+
+template <typename T>
+void writeReversedBuffer(std::vector<uint8_t>& integralBuffer, T val) {
+    // For ConsumeIntegral<T>() calls, FuzzedDataProvider uses numeric limits min and max
+    // as range
+    writeReversedBuffer(integralBuffer, std::numeric_limits<T>::min(),
+                        std::numeric_limits<T>::max(), val);
+}
+
+} // namespace impl
+
+void generateSeedsFromRecording(base::borrowed_fd fd,
+                                const binder::debug::RecordedTransaction& transaction) {
+    // Write Reserved bytes for future use
+    std::vector<uint8_t> reservedBytes(8);
+    CHECK(WriteFully(fd, reservedBytes.data(), reservedBytes.size())) << fd.get();
+
+    std::vector<uint8_t> integralBuffer;
+
+    // Write UID array : Array elements are initialized in the order that they are declared
+    // UID array index 2 element
+    // int64_t aidRoot = 0;
+    impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32,
+                              static_cast<int64_t>(AID_USER) << 32,
+                              static_cast<int64_t>(AID_ROOT) << 32);
+
+    // UID array index 3 element
+    impl::writeReversedBuffer(integralBuffer, static_cast<int64_t>(AID_ROOT) << 32);
+
+    // always pick AID_ROOT -> index 0
+    size_t uidIndex = 0;
+    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(3),
+                              uidIndex);
+
+    // Never set uid in seed corpus
+    uint8_t writeUid = 0;
+    impl::writeReversedBuffer(integralBuffer, writeUid);
+
+    // Read random code. this will be from recorded transaction
+    uint8_t selectCode = 1;
+    impl::writeReversedBuffer(integralBuffer, selectCode);
+
+    // Get from recorded transaction
+    uint32_t code = transaction.getCode();
+    impl::writeReversedBuffer(integralBuffer, code);
+
+    // Get from recorded transaction
+    uint32_t flags = transaction.getFlags();
+    impl::writeReversedBuffer(integralBuffer, flags);
+
+    // always fuzz primary binder
+    size_t extraBindersIndex = 0;
+    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), static_cast<size_t>(0),
+                              extraBindersIndex);
+
+    const Parcel& dataParcel = transaction.getDataParcel();
+
+    // This buffer holds the bytes which will be used for fillRandomParcel API
+    std::vector<uint8_t> fillParcelBuffer;
+
+    // Don't take rpc path
+    uint8_t rpcBranch = 0;
+    impl::writeReversedBuffer(fillParcelBuffer, rpcBranch);
+
+    // Implicit branch on this path -> options->writeHeader(p, provider)
+    uint8_t writeHeaderInternal = 0;
+    impl::writeReversedBuffer(fillParcelBuffer, writeHeaderInternal);
+
+    // Choose to write data in parcel
+    size_t fillFuncIndex = 0;
+    impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), static_cast<size_t>(2),
+                              fillFuncIndex);
+
+    // Write parcel data size from recorded transaction
+    size_t toWrite = transaction.getDataParcel().dataBufferSize();
+    impl::writeReversedBuffer(fillParcelBuffer, static_cast<size_t>(0), toWrite, toWrite);
+
+    // Write parcel data with size towrite from recorded transaction
+    CHECK(WriteFully(fd, dataParcel.data(), toWrite)) << fd.get();
+
+    // Write Fill Parcel buffer size in integralBuffer so that fuzzService knows size of data
+    size_t subDataSize = toWrite + fillParcelBuffer.size();
+    impl::writeReversedBuffer(integralBuffer, static_cast<size_t>(0), subDataSize, subDataSize);
+
+    // Write fill parcel buffer
+    CHECK(WriteFully(fd, fillParcelBuffer.data(), fillParcelBuffer.size())) << fd.get();
+
+    // Write the integralBuffer to data
+    CHECK(WriteFully(fd, integralBuffer.data(), integralBuffer.size())) << fd.get();
+}
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
new file mode 100644
index 0000000..96092b1
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/Android.bp
@@ -0,0 +1,64 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+aidl_interface {
+    name: "testServiceIface",
+    host_supported: true,
+    unstable: true,
+    srcs: [
+        "ITestService.aidl",
+    ],
+    backend: {
+        java: {
+            enabled: true,
+            platform_apis: true,
+        },
+        rust: {
+            enabled: true,
+        },
+    },
+}
+
+// Adding this fuzzer to test the fuzzService functionality
+cc_fuzz {
+    name: "test_service_fuzzer_should_crash",
+    defaults: [
+        "service_fuzzer_defaults",
+    ],
+    static_libs: [
+        "liblog",
+        "testServiceIface-cpp",
+    ],
+    host_supported: true,
+    srcs: ["TestServiceFuzzer.cpp"],
+    fuzz_config: {
+        triage_assignee: "waghpawan@google.com",
+
+        // This fuzzer should be used only test fuzzService locally
+        fuzz_on_haiku_host: true,
+        fuzz_on_haiku_device: true,
+    },
+}
+
+sh_test_host {
+    name: "fuzz_service_test",
+    src: "run_fuzz_service_test.sh",
+    filename: "run_fuzz_service_test.sh",
+    test_config: "fuzz_service_test_config.xml",
+    data_bins: [
+        "test_service_fuzzer_should_crash",
+    ],
+    required: [
+        "test_service_fuzzer_should_crash",
+    ],
+    target: {
+        linux_bionic: {
+            enabled: false,
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+    test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl
new file mode 100644
index 0000000..5089ae5
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/ITestService.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+interface ITestService {
+
+    void setIntData(int input);
+
+    void setCharData(char input);
+
+    void setBooleanData(boolean input);
+
+    void setService(ITestService service);
+}
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
new file mode 100644
index 0000000..46205d7
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 <BnTestService.h>
+#include <fuzzbinder/libbinder_driver.h>
+
+#include <binder/IPCThreadState.h>
+#include <log/log.h>
+
+#include <private/android_filesystem_config.h>
+
+using android::binder::Status;
+
+namespace android {
+
+enum class CrashType {
+    NONE,
+    ON_PLAIN,
+    ON_BINDER,
+    ON_KNOWN_UID,
+    ON_SYSTEM_AID,
+    ON_ROOT_AID,
+};
+
+// This service is to verify that fuzzService is functioning properly
+class TestService : public BnTestService {
+public:
+    TestService(CrashType crash) : mCrash(crash) {}
+
+    void onData() {
+        switch (mCrash) {
+            case CrashType::ON_PLAIN: {
+                LOG_ALWAYS_FATAL("Expected crash, PLAIN.");
+                break;
+            }
+            case CrashType::ON_KNOWN_UID: {
+                if (IPCThreadState::self()->getCallingUid() == getuid()) {
+                    LOG_ALWAYS_FATAL("Expected crash, KNOWN_UID.");
+                }
+                break;
+            }
+            case CrashType::ON_SYSTEM_AID: {
+                if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) {
+                    LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM.");
+                }
+                break;
+            }
+            case CrashType::ON_ROOT_AID: {
+                if (IPCThreadState::self()->getCallingUid() == AID_ROOT) {
+                    LOG_ALWAYS_FATAL("Expected crash, AID_ROOT.");
+                }
+                break;
+            }
+            default:
+                break;
+        }
+    }
+
+    Status setIntData(int /*input*/) override {
+        onData();
+        return Status::ok();
+    }
+
+    Status setCharData(char16_t /*input*/) override {
+        onData();
+        return Status::ok();
+    }
+
+    Status setBooleanData(bool /*input*/) override {
+        onData();
+        return Status::ok();
+    }
+
+    Status setService(const sp<ITestService>& service) override {
+        onData();
+        if (mCrash == CrashType::ON_BINDER && service != nullptr) {
+            LOG_ALWAYS_FATAL("Expected crash, BINDER.");
+        }
+        return Status::ok();
+    }
+
+private:
+    CrashType mCrash;
+};
+
+CrashType gCrashType = CrashType::NONE;
+
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
+    if (*argc < 2) {
+        printf("You must specify at least one argument\n");
+        exit(0); // success because this is a crash test
+    }
+
+    std::string arg = std::string((*argv)[1]);
+
+    // ignore first argument, because we consume it
+    (*argv)[1] = (*argv[0]);
+    (*argc)--;
+    (*argv)++;
+
+    if (arg == "PLAIN") {
+        gCrashType = CrashType::ON_PLAIN;
+    } else if (arg == "KNOWN_UID") {
+        gCrashType = CrashType::ON_KNOWN_UID;
+    } else if (arg == "AID_SYSTEM") {
+        gCrashType = CrashType::ON_SYSTEM_AID;
+    } else if (arg == "AID_ROOT") {
+        gCrashType = CrashType::ON_ROOT_AID;
+    } else if (arg == "BINDER") {
+        gCrashType = CrashType::ON_BINDER;
+    } else {
+        printf("INVALID ARG\n");
+        exit(0); // success because this is a crash test
+    }
+
+    return 0;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    auto service = sp<TestService>::make(gCrashType);
+    fuzzService(service, FuzzedDataProvider(data, size));
+    return 0;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml
new file mode 100644
index 0000000..19eb33a
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/fuzz_service_test_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs fuzzService test">
+    <option name="null-device" value="true" />
+    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest" >
+        <option name="binary" value="run_fuzz_service_test.sh"/>
+        <option name="relative-path-execution" value="true" />
+    </test>
+</configuration>
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
new file mode 100755
index 0000000..25906d8
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# 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.
+
+color_success=$'\E'"[0;32m"
+color_failed=$'\E'"[0;31m"
+color_reset=$'\E'"[00m"
+
+FUZZER_NAME=test_service_fuzzer_should_crash
+FUZZER_OUT=fuzzer-output
+
+if [ ! -f "$FUZZER_NAME" ]
+then
+    echo -e "${color_failed}Binary $FUZZER_NAME does not exist"
+    echo "${color_reset}"
+    exit 1
+fi
+
+for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER; do
+    echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE"
+
+    ./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT"
+
+    echo "INFO: Searching fuzzer output for expected crashes"
+    if grep -q "Expected crash, $CRASH_TYPE." "$FUZZER_OUT"
+    then
+        echo -e "${color_success}Success: Found expected crash. fuzzService test successful!"
+    else
+        echo -e "${color_failed}Failed: Unable to find successful fuzzing output from test_service_fuzzer_should_crash"
+        echo "${color_reset}"
+        exit 1
+    fi
+done
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index b8ae84d..dcc8b8e 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -135,7 +135,7 @@
 
     // b/260736889 - limit arbitrarily, due to thread resource exhaustion, which currently
     // aborts. Servers should consider RpcServer::setConnectionFilter instead.
-    constexpr size_t kMaxConnections = 1000;
+    constexpr size_t kMaxConnections = 10;
 
     while (provider.remaining_bytes() > 0) {
         if (connections.empty() ||
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index 910c9dc..a6fd487 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -51,8 +51,10 @@
     sp<RpcSession> session = RpcSession::make();
     session->setMaxIncomingThreads(1);
     status_t status;
-    for (size_t tries = 0; tries < 5; tries++) {
-        usleep(10000);
+
+    // b/274084938 - ASAN may be slow, wait a while
+    for (size_t tries = 0; tries < 50; tries++) {
+        usleep(100000);
         status = session->setupUnixDomainClient(addr.c_str());
         if (status == OK) break;
     }
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
index 68b0008..8f64323 100644
--- a/libs/binder/trusty/RpcServerTrusty.cpp
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -67,7 +67,7 @@
 
     // TODO(b/266741352): follow-up to prevent needing this in the future
     // Trusty needs to be set to the latest stable version that is in prebuilts there.
-    mRpcServer->setProtocolVersion(0);
+    LOG_ALWAYS_FATAL_IF(!mRpcServer->setProtocolVersion(0));
 
     if (mPortAcl) {
         // Initialize the array of pointers to uuids.
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
index d249b2e..692f82d 100644
--- a/libs/binder/trusty/RpcTransportTipcTrusty.cpp
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -29,8 +29,6 @@
 
 namespace android {
 
-namespace {
-
 // RpcTransport for Trusty.
 class RpcTransportTipcTrusty : public RpcTransport {
 public:
@@ -282,8 +280,6 @@
     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
 };
 
-} // namespace
-
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
     return std::make_unique<RpcTransportCtxTipcTrusty>();
 }
diff --git a/libs/binder/trusty/binderRpcTest/manifest.json b/libs/binder/trusty/binderRpcTest/manifest.json
index d8b080f..1cefac5 100644
--- a/libs/binder/trusty/binderRpcTest/manifest.json
+++ b/libs/binder/trusty/binderRpcTest/manifest.json
@@ -1,6 +1,6 @@
 {
     "uuid": "9dbe9fb8-60fd-4bdd-af86-03e95d7ad78b",
     "app_name": "binderRpcTest",
-    "min_heap": 163840,
+    "min_heap": 262144,
     "min_stack": 16384
 }
diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp
new file mode 100644
index 0000000..2f1f54b
--- /dev/null
+++ b/libs/binder/trusty/fuzzer/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_fuzz {
+    name: "trusty_binder_fuzzer",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: [":trusty_tipc_fuzzer"],
+    cflags: [
+        "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"",
+        "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"",
+        "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"",
+    ],
+}
+
+cc_fuzz {
+    name: "trusty_binder_rpc_fuzzer",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: [":trusty_tipc_fuzzer"],
+    cflags: [
+        "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"",
+        "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"",
+        "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"",
+    ],
+}
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
index 6678eb8..8924b36 100644
--- a/libs/binder/trusty/include/binder/RpcServerTrusty.h
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -59,14 +59,17 @@
             size_t msgMaxSize,
             std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
 
-    void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+    [[nodiscard]] bool setProtocolVersion(uint32_t version) {
+        return mRpcServer->setProtocolVersion(version);
+    }
     void setSupportedFileDescriptorTransportModes(
             const std::vector<RpcSession::FileDescriptorTransportMode>& modes) {
         mRpcServer->setSupportedFileDescriptorTransportModes(modes);
     }
     void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
     void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
-    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {
+    void setPerSessionRootObject(
+            std::function<sp<IBinder>(wp<RpcSession> session, const void*, size_t)>&& object) {
         mRpcServer->setPerSessionRootObject(std::move(object));
     }
     sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); }
diff --git a/libs/fakeservicemanager/FakeServiceManager.cpp b/libs/fakeservicemanager/FakeServiceManager.cpp
index 3272bbc..80661c1 100644
--- a/libs/fakeservicemanager/FakeServiceManager.cpp
+++ b/libs/fakeservicemanager/FakeServiceManager.cpp
@@ -26,6 +26,8 @@
 }
 
 sp<IBinder> FakeServiceManager::checkService( const String16& name) const {
+    std::lock_guard<std::mutex> l(mMutex);
+
     auto it = mNameToService.find(name);
     if (it == mNameToService.end()) {
         return nullptr;
@@ -36,6 +38,8 @@
 status_t FakeServiceManager::addService(const String16& name, const sp<IBinder>& service,
                                 bool /*allowIsolated*/,
                                 int /*dumpsysFlags*/) {
+    std::lock_guard<std::mutex> l(mMutex);
+
     if (service == nullptr) {
         return UNEXPECTED_NULL;
     }
@@ -44,6 +48,8 @@
 }
 
 Vector<String16> FakeServiceManager::listServices(int /*dumpsysFlags*/) {
+    std::lock_guard<std::mutex> l(mMutex);
+
     Vector<String16> services;
     for (auto const& [name, service] : mNameToService) {
         (void) service;
@@ -61,10 +67,14 @@
 }
 
 bool FakeServiceManager::isDeclared(const String16& name) {
+    std::lock_guard<std::mutex> l(mMutex);
+
     return mNameToService.find(name) != mNameToService.end();
 }
 
 Vector<String16> FakeServiceManager::getDeclaredInstances(const String16& name) {
+    std::lock_guard<std::mutex> l(mMutex);
+
     Vector<String16> out;
     const String16 prefix = name + String16("/");
     for (const auto& [registeredName, service] : mNameToService) {
@@ -108,6 +118,8 @@
 }
 
 void FakeServiceManager::clear() {
+    std::lock_guard<std::mutex> l(mMutex);
+
     mNameToService.clear();
 }
 }  // namespace android
diff --git a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
index 97add24..f62241d 100644
--- a/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
+++ b/libs/fakeservicemanager/include/fakeservicemanager/FakeServiceManager.h
@@ -19,6 +19,7 @@
 #include <binder/IServiceManager.h>
 
 #include <map>
+#include <mutex>
 #include <optional>
 #include <vector>
 
@@ -68,6 +69,7 @@
     void clear();
 
 private:
+    mutable std::mutex mMutex;
     std::map<String16, sp<IBinder>> mNameToService;
 };
 
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 3c8df2b..d7e7eb8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -131,13 +131,25 @@
     },
 }
 
-filegroup {
+aidl_library {
+    name: "libgui_aidl_hdrs",
+    hdrs: [
+        "android/gui/DisplayInfo.aidl",
+        "android/gui/FocusRequest.aidl",
+        "android/gui/InputApplicationInfo.aidl",
+        "android/gui/IWindowInfosListener.aidl",
+        "android/gui/IWindowInfosPublisher.aidl",
+        "android/gui/IWindowInfosReportedListener.aidl",
+        "android/gui/WindowInfo.aidl",
+        "android/gui/WindowInfosUpdate.aidl",
+    ],
+}
+
+aidl_library {
     name: "libgui_aidl",
     srcs: ["aidl/**/*.aidl"],
-    path: "aidl/",
-    aidl: {
-        deps: [":android_gui_aidl"],
-    },
+    strip_import_prefix: "aidl",
+    deps: ["libgui_aidl_hdrs"],
 }
 
 filegroup {
@@ -149,9 +161,6 @@
 cc_library_static {
     name: "libgui_aidl_static",
     vendor_available: true,
-    srcs: [
-        ":libgui_aidl",
-    ],
 
     shared_libs: [
         "libbinder",
@@ -177,9 +186,7 @@
 
     aidl: {
         export_aidl_headers: true,
-        include_dirs: [
-            "frameworks/native/libs/gui",
-        ],
+        libs: ["libgui_aidl"],
     },
 }
 
@@ -249,6 +256,7 @@
 
     shared_libs: [
         "libbinder",
+        "libGLESv2",
     ],
 
     export_shared_lib_headers: [
@@ -374,7 +382,6 @@
         "libbase",
         "libcutils",
         "libEGL",
-        "libGLESv2",
         "libhidlbase",
         "liblog",
         "libnativewindow",
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 43ff54f..b872541 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -636,7 +636,8 @@
     BQ_LOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x",
             *outSlot,
             mSlots[*outSlot].mFrameNumber,
-            mSlots[*outSlot].mGraphicBuffer->handle, returnFlags);
+            mSlots[*outSlot].mGraphicBuffer != nullptr ?
+            mSlots[*outSlot].mGraphicBuffer->handle : nullptr, returnFlags);
 
     if (outBufferAge) {
         *outBufferAge = mCore->mBufferAge;
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 05b5533..070f6bf 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,12 +1,9 @@
-adyabr@google.com
-alecmouri@google.com
-chaviw@google.com
+# Bug component: 1075131
+
 chrisforbes@google.com
 jreck@google.com
-lpy@google.com
-pdwilliams@google.com
-racarr@google.com
-vishnun@google.com
+
+file:/services/surfaceflinger/OWNERS
 
 per-file EndToEndNativeInputTest.cpp = svv@google.com
 
diff --git a/libs/gui/tests/OWNERS b/libs/gui/tests/OWNERS
new file mode 100644
index 0000000..48cd30d
--- /dev/null
+++ b/libs/gui/tests/OWNERS
@@ -0,0 +1,6 @@
+# Android > Android OS & Apps > Framework (Java + Native) > Window Manager > Surfaces
+# Bug component: 316245 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
+# Buganizer template url: https://b.corp.google.com/issues/new?component=316245&template=1018194 = per-file BLASTBufferQueue_test.cpp, DisplayInfo_test.cpp, EndToEndNativeInputTest.cpp, WindowInfos_test.cpp
+
+# Android > Android OS & Apps > graphics > Core Graphics Stack (CoGS)
+# Bug component: 1075130
diff --git a/libs/input/OWNERS b/libs/input/OWNERS
new file mode 100644
index 0000000..c88bfe9
--- /dev/null
+++ b/libs/input/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/INPUT_OWNERS
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 5d23a5e..66e1aa1 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,3 +1,5 @@
+# Bug component: 1075131
+
 adyabr@google.com
 alecmouri@google.com
 djsollen@google.com
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 073da89..8675f14 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -304,6 +304,12 @@
             return std::string("BGRA_8888");
         case android::PIXEL_FORMAT_R_8:
             return std::string("R_8");
+        case android::PIXEL_FORMAT_R_16_UINT:
+            return std::string("R_16_UINT");
+        case android::PIXEL_FORMAT_RG_1616_UINT:
+            return std::string("RG_1616_UINT");
+        case android::PIXEL_FORMAT_RGBA_10101010:
+            return std::string("RGBA_10101010");
         default:
             return StringPrintf("Unknown %#08x", format);
     }
diff --git a/libs/ui/include/ui/FatVector.h b/libs/ui/include/ui/FatVector.h
index cb61e6a..494272b 100644
--- a/libs/ui/include/ui/FatVector.h
+++ b/libs/ui/include/ui/FatVector.h
@@ -65,6 +65,17 @@
             free(p);
         }
     }
+
+    // The STL checks that this member type is present so that
+    // std::allocator_traits<InlineStdAllocator<T, SIZE>>::rebind_alloc<Other>
+    // works. std::vector won't be able to construct an
+    // InlineStdAllocator<Other, SIZE>, because InlineStdAllocator has no
+    // default constructor, but vector presumably doesn't rebind the allocator
+    // because it doesn't allocate internal node types.
+    template <class Other>
+    struct rebind {
+        typedef InlineStdAllocator<Other, SIZE> other;
+    };
     Allocation& mAllocation;
 };
 
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index f1122fd..9a6bb7a 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -152,6 +152,7 @@
 
     if (!angleGetDisplayPlatform) {
         ALOGE("dlsym lookup of ANGLEGetDisplayPlatform in libEGL_angle failed!");
+        dlclose(so);
         return false;
     }
 
@@ -162,6 +163,7 @@
     if (!((angleGetDisplayPlatform)(dpy, g_PlatformMethodNames, g_NumPlatformMethods, nullptr,
                                     &platformMethods))) {
         ALOGE("ANGLEGetDisplayPlatform call failed!");
+        dlclose(so);
         return false;
     }
     if (platformMethods) {
diff --git a/services/gpuservice/OWNERS b/services/gpuservice/OWNERS
index 0ff65bf..07c681f 100644
--- a/services/gpuservice/OWNERS
+++ b/services/gpuservice/OWNERS
@@ -4,3 +4,4 @@
 lfy@google.com
 paulthomson@google.com
 pbaiget@google.com
+kocdemir@google.com
diff --git a/services/gpuservice/tests/fuzzers/Android.bp b/services/gpuservice/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..6bcc5e8
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/Android.bp
@@ -0,0 +1,26 @@
+package {
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+    name: "gpu_service_fuzzer",
+    defaults: [
+        "service_fuzzer_defaults",
+        "fuzzer_disable_leaks",
+    ],
+    static_libs: [
+        "liblog",
+    ],
+    fuzz_config: {
+        cc: [
+            "paulthomson@google.com",
+            "pbaiget@google.com",
+        ],
+        triage_assignee: "waghpawan@google.com",
+    },
+    include_dirs: ["frameworks/native/services/gpuservice/"],
+    srcs: ["GpuServiceFuzzer.cpp"],
+    shared_libs: [
+        "libgpuservice",
+    ],
+}
diff --git a/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp
new file mode 100644
index 0000000..241b864
--- /dev/null
+++ b/services/gpuservice/tests/fuzzers/GpuServiceFuzzer.cpp
@@ -0,0 +1,29 @@
+/*
+ * 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 <fuzzbinder/libbinder_driver.h>
+
+#include "gpuservice/GpuService.h"
+
+using ::android::fuzzService;
+using ::android::GpuService;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    sp<GpuService> gpuService = new GpuService();
+    fuzzService(gpuService, FuzzedDataProvider(data, size));
+    return 0;
+}
diff --git a/services/inputflinger/OWNERS b/services/inputflinger/OWNERS
index c88bfe9..21d208f 100644
--- a/services/inputflinger/OWNERS
+++ b/services/inputflinger/OWNERS
@@ -1 +1,2 @@
+# Bug component: 136048
 include platform/frameworks/base:/INPUT_OWNERS
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c906c3e..862e128 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -6264,9 +6264,9 @@
             StringPrintf("%s does not have a focused window", application->getName().c_str());
     updateLastAnrStateLocked(*application, reason);
 
-    auto command = [this, application = std::move(application)]() REQUIRES(mLock) {
+    auto command = [this, app = std::move(application)]() REQUIRES(mLock) {
         scoped_unlock unlock(mLock);
-        mPolicy.notifyNoFocusedWindowAnr(application);
+        mPolicy.notifyNoFocusedWindowAnr(app);
     };
     postCommandLocked(std::move(command));
 }
@@ -6326,9 +6326,9 @@
 void InputDispatcher::sendWindowUnresponsiveCommandLocked(const sp<IBinder>& token,
                                                           std::optional<gui::Pid> pid,
                                                           std::string reason) {
-    auto command = [this, token, pid, reason = std::move(reason)]() REQUIRES(mLock) {
+    auto command = [this, token, pid, r = std::move(reason)]() REQUIRES(mLock) {
         scoped_unlock unlock(mLock);
-        mPolicy.notifyWindowUnresponsive(token, pid, reason);
+        mPolicy.notifyWindowUnresponsive(token, pid, r);
     };
     postCommandLocked(std::move(command));
 }
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index d50f74d..729d01f 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -26,11 +26,10 @@
 
 namespace android {
 
-
 /*
  * Input dispatcher policy interface.
  *
- * The input reader policy is used by the input reader to interact with the Window Manager
+ * The input dispatcher policy is used by the input dispatcher to interact with the Window Manager
  * and other system components.
  *
  * The actual implementation is partially supported by callbacks into the DVM
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index e27b52b..5c00260 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -19,6 +19,7 @@
 #include "SensorService.h"
 
 #include <android/util/ProtoOutputStream.h>
+#include <cutils/properties.h>
 #include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 
 namespace android {
@@ -60,10 +61,12 @@
             mGyro = uncalibratedGyro;
         }
 
-        // 200 Hz for gyro events is a good compromise between precision
-        // and power/cpu usage.
-        mEstimatedGyroRate = 200;
-        mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
+        // Wearable devices will want to tune this parameter
+        // to 100 (Hz) in device.mk to save some power.
+        int32_t value = property_get_int32(
+            "sensors.aosp_low_power_sensor_fusion.maximum_rate", 200);
+        mEstimatedGyroRate = static_cast<float>(value);
+        mTargetDelayNs = 1000000000LL / mEstimatedGyroRate;
 
         for (int i = 0; i<NUM_FUSION_MODE; ++i) {
             mFusions[i].init(i);
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index 5301fe9..ed4829a 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -11,6 +11,7 @@
     name: "libsensorserviceaidl_fuzzer",
     defaults: [
         "service_fuzzer_defaults",
+        "fuzzer_disable_leaks",
     ],
     host_supported: true,
     static_libs: [
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index b00d1a7..e939d51 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -141,7 +141,7 @@
                 printf("ALOOPER_POLL_TIMEOUT\n");
                 break;
             case ALOOPER_POLL_ERROR:
-                printf("ALOOPER_POLL_TIMEOUT\n");
+                printf("ALOOPER_POLL_ERROR\n");
                 break;
             default:
                 printf("ugh? poll returned %d\n", ret);
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 4e7da82..3270e4c 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,6 +1,9 @@
+# Bug component: 1075131
+
 adyabr@google.com
 alecmouri@google.com
 chaviw@google.com
+domlaskowski@google.com
 lpy@google.com
 pdwilliams@google.com
 racarr@google.com
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
index d073e2b..031b333 100644
--- a/services/vibratorservice/OWNERS
+++ b/services/vibratorservice/OWNERS
@@ -1 +1,3 @@
+# Bug component: 345036
+
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index a14fed2..d059f8f 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -23,6 +23,7 @@
 #include <dlfcn.h>
 #include <string.h>
 #include <sys/prctl.h>
+#include <unistd.h>
 
 #include <mutex>
 #include <string>
@@ -362,6 +363,7 @@
 void ForEachFileInZip(const std::string& zipname,
                       const std::string& dir_in_zip,
                       Functor functor) {
+    static const size_t kPageSize = getpagesize();
     int32_t err;
     ZipArchiveHandle zip = nullptr;
     if ((err = OpenArchive(zipname.c_str(), &zip)) != 0) {
@@ -389,7 +391,7 @@
         // the APK. Loading still may fail for other reasons, but this at least
         // lets us avoid failed-to-load log messages in the typical case of
         // compressed and/or unaligned libraries.
-        if (entry.method != kCompressStored || entry.offset % PAGE_SIZE != 0)
+        if (entry.method != kCompressStored || entry.offset % kPageSize != 0)
             continue;
         functor(filename);
     }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index c28390f..dd5b598 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,6 +16,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
 #include <android/hardware/graphics/common/1.0/types.h>
 #include <grallocusage/GrallocUsageConversion.h>
 #include <graphicsenv/GraphicsEnv.h>
@@ -25,8 +26,6 @@
 #include <sync/sync.h>
 #include <system/window.h>
 #include <ui/BufferQueueDefs.h>
-#include <ui/DebugUtils.h>
-#include <ui/PixelFormat.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
@@ -37,6 +36,7 @@
 
 #include "driver.h"
 
+using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
 using android::hardware::graphics::common::V1_0::BufferUsage;
 
 namespace vulkan {
@@ -503,27 +503,27 @@
     *count = num_copied;
 }
 
-android::PixelFormat GetNativePixelFormat(VkFormat format) {
-    android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888;
+PixelFormat GetNativePixelFormat(VkFormat format) {
+    PixelFormat native_format = PixelFormat::RGBA_8888;
     switch (format) {
         case VK_FORMAT_R8G8B8A8_UNORM:
         case VK_FORMAT_R8G8B8A8_SRGB:
-            native_format = android::PIXEL_FORMAT_RGBA_8888;
+            native_format = PixelFormat::RGBA_8888;
             break;
         case VK_FORMAT_R5G6B5_UNORM_PACK16:
-            native_format = android::PIXEL_FORMAT_RGB_565;
+            native_format = PixelFormat::RGB_565;
             break;
         case VK_FORMAT_R16G16B16A16_SFLOAT:
-            native_format = android::PIXEL_FORMAT_RGBA_FP16;
+            native_format = PixelFormat::RGBA_FP16;
             break;
         case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
-            native_format = android::PIXEL_FORMAT_RGBA_1010102;
+            native_format = PixelFormat::RGBA_1010102;
             break;
         case VK_FORMAT_R8_UNORM:
-            native_format = android::PIXEL_FORMAT_R_8;
+            native_format = PixelFormat::R_8;
             break;
         case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
-            native_format = android::PIXEL_FORMAT_RGBA_10101010;
+            native_format = PixelFormat::RGBA_10101010;
             break;
         default:
             ALOGV("unsupported swapchain format %d", format);
@@ -1361,7 +1361,7 @@
     if (!allocator)
         allocator = &GetData(device).allocator;
 
-    android::PixelFormat native_pixel_format =
+    PixelFormat native_pixel_format =
         GetNativePixelFormat(create_info->imageFormat);
     android_dataspace native_dataspace =
         GetNativeDataspace(create_info->imageColorSpace);
@@ -1462,10 +1462,11 @@
 
     const auto& dispatch = GetData(device).driver;
 
-    err = native_window_set_buffers_format(window, native_pixel_format);
+    err = native_window_set_buffers_format(
+        window, static_cast<int>(native_pixel_format));
     if (err != android::OK) {
         ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)",
-              decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
+              toString(native_pixel_format).c_str(), strerror(-err), err);
         return VK_ERROR_SURFACE_LOST_KHR;
     }