Merge "servicemanager: make recovery_available."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 8bcb1e5..eb9a51d 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,4 +1,5 @@
 [Builtin Hooks]
+bpfmt = true
 clang_format = true
 
 [Builtin Hooks Options]
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index e3c4ede..34ccb21 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -265,6 +265,37 @@
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu14/trace
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu16/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu16/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu17/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu17/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu18/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu18/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu19/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu19/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu20/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu20/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu21/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu21/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu22/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu22/trace
+    chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu23/trace
+    chmod 0666 /sys/kernel/tracing/per_cpu/cpu23/trace
+
+# Setup synthetic events
+    chmod 0666 /sys/kernel/tracing/synthetic_events
+    chmod 0666 /sys/kernel/debug/tracing/synthetic_events
+
+    # rss_stat_throttled
+    write /sys/kernel/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+    write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size"
+
+# Set up histogram triggers
+    # rss_stat_throttled (bucket size == 512KB)
+    chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger
+    chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger
+    write /sys/kernel/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
+    write /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger "hist:keys=mm_id,member:bucket=size/0x80000:onchange($$bucket).rss_stat_throttled(mm_id,curr,member,size)"
 
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
@@ -337,6 +368,22 @@
     chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu14/trace
     chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu15/trace
     chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu15/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu16/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu16/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu17/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu17/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu18/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu18/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu19/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu19/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu20/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu20/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu21/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu21/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu22/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu22/trace
+    chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu23/trace
+    chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu23/trace
 
 on property:persist.debug.atrace.boottrace=1
     start boottrace
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 83e6787..3722383 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -38,11 +38,6 @@
 #include "DumpPool.h"
 #include "TaskQueue.h"
 
-// Workaround for const char *args[MAX_ARGS_ARRAY_SIZE] variables until they're converted to
-// std::vector<std::string>
-// TODO: remove once not used
-#define MAX_ARGS_ARRAY_SIZE 1000
-
 // TODO: move everything under this namespace
 // TODO: and then remove explicitly android::os::dumpstate:: prefixes
 namespace android {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 5082eb0..39ef0b5 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -25,6 +25,7 @@
 #include <functional>
 #include <inttypes.h>
 #include <regex>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
@@ -281,36 +282,31 @@
 }
 
 status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) {
-    auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd));
     const binder::Status dump_permission = checkPermission(kDump);
     if (!dump_permission.isOk()) {
-        out << dump_permission.toString8() << endl;
+        dprintf(fd, "%s\n", dump_permission.toString8().c_str());
         return PERMISSION_DENIED;
     }
-    std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    out << "installd is happy!" << endl;
+    std::lock_guard<std::recursive_mutex> lock(mLock);
 
     {
         std::lock_guard<std::recursive_mutex> lock(mMountsLock);
-        out << endl << "Storage mounts:" << endl;
+        dprintf(fd, "Storage mounts:\n");
         for (const auto& n : mStorageMounts) {
-            out << "    " << n.first << " = " << n.second << endl;
+            dprintf(fd, "    %s = %s\n", n.first.c_str(), n.second.c_str());
         }
     }
 
     {
         std::lock_guard<std::recursive_mutex> lock(mQuotasLock);
-        out << endl << "Per-UID cache quotas:" << endl;
+        dprintf(fd, "Per-UID cache quotas:\n");
         for (const auto& n : mCacheQuotas) {
-            out << "    " << n.first << " = " << n.second << endl;
+            dprintf(fd, "    %d = %" PRId64 "\n", n.first, n.second);
         }
     }
 
-    out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl;
-
-    out << endl;
-    out.flush();
+    dprintf(fd, "is_dexopt_blocked:%d\n", android::installd::is_dexopt_blocked());
 
     return NO_ERROR;
 }
@@ -426,9 +422,131 @@
     return true;
 }
 
+static bool chown_app_dir(const std::string& path, uid_t uid, uid_t previousUid, gid_t cacheGid) {
+    FTS* fts;
+    char *argv[] = { (char*) path.c_str(), nullptr };
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
+        return false;
+    }
+    for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+        if (p->fts_info == FTS_D && p->fts_level == 1
+            && (strcmp(p->fts_name, "cache") == 0
+                || strcmp(p->fts_name, "code_cache") == 0)) {
+            // Mark cache dirs
+            p->fts_number = 1;
+        } else {
+            // Inherit parent's number
+            p->fts_number = p->fts_parent->fts_number;
+        }
+
+        switch (p->fts_info) {
+        case FTS_D:
+        case FTS_F:
+        case FTS_SL:
+        case FTS_SLNONE:
+            if (p->fts_statp->st_uid == previousUid) {
+                if (lchown(p->fts_path, uid, p->fts_number ? cacheGid : uid) != 0) {
+                    PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+                }
+            } else {
+                LOG(WARNING) << "Ignoring " << p->fts_path << " with unexpected UID "
+                        << p->fts_statp->st_uid << " instead of " << previousUid;
+            }
+            break;
+        }
+    }
+    fts_close(fts);
+    return true;
+}
+
+static void chown_app_profile_dir(const std::string &packageName, int32_t appId, int32_t userId) {
+    uid_t uid = multiuser_get_uid(userId, appId);
+    gid_t sharedGid = multiuser_get_shared_gid(userId, appId);
+
+    const std::string profile_dir =
+            create_primary_current_profile_package_dir_path(userId, packageName);
+    char *argv[] = { (char*) profile_dir.c_str(), nullptr };
+    if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+        for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+            switch (p->fts_info) {
+            case FTS_D:
+            case FTS_F:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (lchown(p->fts_path, uid, uid) != 0) {
+                    PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+                }
+                break;
+            }
+        }
+        fts_close(fts);
+    }
+
+    const std::string ref_profile_path =
+            create_primary_reference_profile_package_dir_path(packageName);
+    argv[0] = (char *) ref_profile_path.c_str();
+    if (FTS* fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr)) {
+        for (FTSENT* p; (p = fts_read(fts)) != nullptr;) {
+            if (p->fts_info == FTS_D && p->fts_level == 0) {
+                if (chown(p->fts_path, AID_SYSTEM, sharedGid) != 0) {
+                    PLOG(WARNING) << "Failed to chown " << p->fts_path;
+                }
+                continue;
+            }
+            switch (p->fts_info) {
+            case FTS_D:
+            case FTS_F:
+            case FTS_SL:
+            case FTS_SLNONE:
+                if (lchown(p->fts_path, sharedGid, sharedGid) != 0) {
+                    PLOG(WARNING) << "Failed to lchown " << p->fts_path;
+                }
+                break;
+            }
+        }
+        fts_close(fts);
+    }
+}
+
+static binder::Status createAppDataDirs(const std::string& path,
+        int32_t uid, int32_t* previousUid, int32_t cacheGid,
+        const std::string& seInfo, mode_t targetMode) {
+    struct stat st{};
+    bool existing = (stat(path.c_str(), &st) == 0);
+    if (existing) {
+        if (*previousUid < 0) {
+            // If previousAppId is -1 in CreateAppDataArgs, we will assume the current owner
+            // of the directory as previousUid. This is required because it is not always possible
+            // to chown app data during app upgrade (e.g. secondary users' CE storage not unlocked)
+            *previousUid = st.st_uid;
+        }
+        if (*previousUid != uid) {
+            if (!chown_app_dir(path, uid, *previousUid, cacheGid)) {
+                return error("Failed to chown " + path);
+            }
+        }
+    }
+
+    if (prepare_app_dir(path, targetMode, uid) ||
+            prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
+            prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
+        return error("Failed to prepare " + path);
+    }
+
+    // Consider restorecon over contents if label changed
+    if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
+            restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
+            restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
+        return error("Failed to restorecon " + path);
+    }
+
+    return ok();
+}
+
 binder::Status InstalldNativeService::createAppData(const std::optional<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
-        const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
+        int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
+        int64_t* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
@@ -441,6 +559,14 @@
     if (_aidl_return != nullptr) *_aidl_return = -1;
 
     int32_t uid = multiuser_get_uid(userId, appId);
+
+    // If previousAppId < 0, we will use the existing app data owner as previousAppUid
+    // If previousAppId == 0, we use uid as previousUid (no data migration will happen)
+    // if previousAppId > 0, an app is upgrading and changing its app ID
+    int32_t previousUid = previousAppId > 0
+        ? (int32_t) multiuser_get_uid(userId, previousAppId)
+        : (previousAppId == 0 ? uid : -1);
+
     int32_t cacheGid = multiuser_get_cache_gid(userId, appId);
     mode_t targetMode = targetSdkVersion >= MIN_RESTRICTED_HOME_SDK_VERSION ? 0700 : 0751;
 
@@ -451,19 +577,13 @@
 
     if (flags & FLAG_STORAGE_CE) {
         auto path = create_data_user_ce_package_path(uuid_, userId, pkgname);
-        bool existing = (access(path.c_str(), F_OK) == 0);
 
-        if (prepare_app_dir(path, targetMode, uid) ||
-                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
-                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
-            return error("Failed to prepare " + path);
+        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        if (!status.isOk()) {
+            return status;
         }
-
-        // Consider restorecon over contents if label changed
-        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
-                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
-                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
-            return error("Failed to restorecon " + path);
+        if (previousUid != uid) {
+            chown_app_profile_dir(packageName, appId, userId);
         }
 
         // Remember inode numbers of cache directories so that we can clear
@@ -485,19 +605,10 @@
     }
     if (flags & FLAG_STORAGE_DE) {
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname);
-        bool existing = (access(path.c_str(), F_OK) == 0);
 
-        if (prepare_app_dir(path, targetMode, uid) ||
-                prepare_app_cache_dir(path, "cache", 02771, uid, cacheGid) ||
-                prepare_app_cache_dir(path, "code_cache", 02771, uid, cacheGid)) {
-            return error("Failed to prepare " + path);
-        }
-
-        // Consider restorecon over contents if label changed
-        if (restorecon_app_data_lazy(path, seInfo, uid, existing) ||
-                restorecon_app_data_lazy(path, "cache", seInfo, uid, existing) ||
-                restorecon_app_data_lazy(path, "code_cache", seInfo, uid, existing)) {
-            return error("Failed to restorecon " + path);
+        auto status = createAppDataDirs(path, uid, &previousUid, cacheGid, seInfo, targetMode);
+        if (!status.isOk()) {
+            return status;
         }
 
         if (!prepare_app_profile_dir(packageName, appId, userId)) {
@@ -507,7 +618,6 @@
     return ok();
 }
 
-
 binder::Status InstalldNativeService::createAppData(
         const android::os::CreateAppDataArgs& args,
         android::os::CreateAppDataResult* _aidl_return) {
@@ -516,7 +626,7 @@
 
     int64_t ceDataInode = -1;
     auto status = createAppData(args.uuid, args.packageName, args.userId, args.flags, args.appId,
-                                args.seInfo, args.targetSdkVersion, &ceDataInode);
+            args.previousAppId, args.seInfo, args.targetSdkVersion, &ceDataInode);
     _aidl_return->ceDataInode = ceDataInode;
     _aidl_return->exceptionCode = status.exceptionCode();
     _aidl_return->exceptionMessage = status.exceptionMessage();
@@ -530,7 +640,7 @@
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
     std::vector<android::os::CreateAppDataResult> results;
-    for (auto arg : args) {
+    for (const auto &arg : args) {
         android::os::CreateAppDataResult result;
         createAppData(arg, &result);
         results.push_back(result);
@@ -628,14 +738,11 @@
         }
     }
     if (flags & FLAG_STORAGE_DE) {
-        std::string suffix = "";
-        bool only_cache = false;
+        std::string suffix;
         if (flags & FLAG_CLEAR_CACHE_ONLY) {
             suffix = CACHE_DIR_POSTFIX;
-            only_cache = true;
         } else if (flags & FLAG_CLEAR_CODE_CACHE_ONLY) {
             suffix = CODE_CACHE_DIR_POSTFIX;
-            only_cache = true;
         }
 
         auto path = create_data_user_de_package_path(uuid_, userId, pkgname) + suffix;
@@ -1230,7 +1337,7 @@
         }
 
         if (!createAppData(toUuid, packageName, user, FLAG_STORAGE_CE | FLAG_STORAGE_DE, appId,
-                seInfo, targetSdkVersion, nullptr).isOk()) {
+                /* previousAppId */ -1, seInfo, targetSdkVersion, nullptr).isOk()) {
             res = error("Failed to create package target");
             goto fail;
         }
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index ae257df..8cfda01 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -47,7 +47,8 @@
 
     binder::Status createAppData(const std::optional<std::string>& uuid,
             const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
-            const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return);
+            int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion,
+            int64_t* _aidl_return);
 
     binder::Status createAppData(
             const android::os::CreateAppDataArgs& args,
diff --git a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
index 96d7faa..d5e8ee5 100644
--- a/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
+++ b/cmds/installd/binder/android/os/CreateAppDataArgs.aidl
@@ -23,6 +23,7 @@
     int userId;
     int flags;
     int appId;
+    int previousAppId;
     @utf8InCpp String seInfo;
     int targetSdkVersion;
 }
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index ea26955..a937436 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -287,6 +287,7 @@
                 kTestUserId,
                 kAppDataFlags,
                 kTestAppUid,
+                0 /* previousAppId */,
                 se_info_,
                 kOSdkVersion,
                 &ce_data_inode_);
@@ -1257,6 +1258,7 @@
             kTestUserId,
             kAppDataFlags,
             kTestAppUid,
+            0 /* previousAppId */,
             se_info_,
             kOSdkVersion,
             &ce_data_inode_));
@@ -1320,6 +1322,7 @@
                     kTestUserId,
                     kAppDataFlags,
                     kTestAppUid,
+                    0 /* previousAppId */,
                     se_info_,
                     kOSdkVersion,
                     &ce_data_inode));
diff --git a/cmds/rss_hwm_reset/rss_hwm_reset.rc b/cmds/rss_hwm_reset/rss_hwm_reset.rc
index fbbc820..271cbf8 100644
--- a/cmds/rss_hwm_reset/rss_hwm_reset.rc
+++ b/cmds/rss_hwm_reset/rss_hwm_reset.rc
@@ -18,7 +18,7 @@
     oneshot
     user nobody
     group nobody readproc
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
     capabilities DAC_OVERRIDE
 
 on property:sys.rss_hwm_reset.on=1
diff --git a/cmds/service/Android.bp b/cmds/service/Android.bp
index 3e8e3f6..21ac11b 100644
--- a/cmds/service/Android.bp
+++ b/cmds/service/Android.bp
@@ -52,3 +52,21 @@
         "-Werror",
     ],
 }
+
+cc_binary_host {
+    name: "aservice",
+
+    srcs: ["service.cpp"],
+
+    shared_libs: [
+        "libcutils",
+        "libutils",
+        "libbinder",
+    ],
+
+    cflags: [
+        "-DXP_UNIX",
+        "-Wall",
+        "-Werror",
+    ],
+}
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 18b6b58..fe417a3 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -45,37 +45,14 @@
     }
 }
 
-// get the name of the generic interface we hold a reference to
-static String16 get_interface_name(sp<IBinder> service)
-{
-    if (service != nullptr) {
-        Parcel data, reply;
-        status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
-        if (err == NO_ERROR) {
-            return reply.readString16();
-        }
-    }
-    return String16();
-}
-
-static String8 good_old_string(const String16& src)
-{
-    String8 name8;
-    char ch8[2];
-    ch8[1] = 0;
-    for (unsigned j = 0; j < src.size(); j++) {
-        char16_t ch = src[j];
-        if (ch < 128) ch8[0] = (char)ch;
-        name8.append(ch8);
-    }
-    return name8;
-}
-
 int main(int argc, char* const argv[])
 {
     bool wantsUsage = false;
     int result = 0;
 
+    /* Strip path off the program name. */
+    char* prog_name = basename(argv[0]);
+
     while (1) {
         int ic = getopt(argc, argv, "h?");
         if (ic < 0)
@@ -87,7 +64,7 @@
             wantsUsage = true;
             break;
         default:
-            aerr << "service: Unknown option -" << ic << endl;
+            aerr << prog_name << ": Unknown option -" << ic << endl;
             wantsUsage = true;
             result = 10;
             break;
@@ -96,10 +73,13 @@
 #ifdef VENDORSERVICES
     ProcessState::initWithDriver("/dev/vndbinder");
 #endif
+#ifndef __ANDROID__
+    setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+#endif
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
     if (sm == nullptr) {
-        aerr << "service: Unable to get default service manager!" << endl;
+        aerr << prog_name << ": Unable to get default service manager!" << endl;
         return 20;
     }
 
@@ -113,7 +93,7 @@
                 aout << "Service " << argv[optind] <<
                     (service == nullptr ? ": not found" : ": found") << endl;
             } else {
-                aerr << "service: No service specified for check" << endl;
+                aerr << prog_name << ": No service specified for check" << endl;
                 wantsUsage = true;
                 result = 10;
             }
@@ -125,8 +105,8 @@
                 String16 name = services[i];
                 sp<IBinder> service = sm->checkService(name);
                 aout << i
-                     << "\t" << good_old_string(name)
-                     << ": [" << good_old_string(get_interface_name(service)) << "]"
+                     << "\t" << name
+                     << ": [" << (service ? service->getInterfaceDescriptor() : String16()) << "]"
                      << endl;
             }
         } else if (strcmp(argv[optind], "call") == 0) {
@@ -134,10 +114,11 @@
             if (optind+1 < argc) {
                 int serviceArg = optind;
                 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
-                String16 ifName = get_interface_name(service);
+                String16 ifName = (service ? service->getInterfaceDescriptor() : String16());
                 int32_t code = atoi(argv[optind++]);
                 if (service != nullptr && ifName.size() > 0) {
                     Parcel data, reply;
+                    data.markForBinder(service);
 
                     // the interface name is first
                     data.writeInterfaceToken(ifName);
@@ -147,7 +128,7 @@
                         if (strcmp(argv[optind], "i32") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no integer supplied for 'i32'" << endl;
+                                aerr << prog_name << ": no integer supplied for 'i32'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -156,7 +137,7 @@
                         } else if (strcmp(argv[optind], "i64") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no integer supplied for 'i64'" << endl;
+                                aerr << prog_name << ": no integer supplied for 'i64'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -165,7 +146,7 @@
                         } else if (strcmp(argv[optind], "s16") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no string supplied for 's16'" << endl;
+                                aerr << prog_name << ": no string supplied for 's16'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -174,7 +155,7 @@
                         } else if (strcmp(argv[optind], "f") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no number supplied for 'f'" << endl;
+                                aerr << prog_name << ": no number supplied for 'f'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -183,7 +164,7 @@
                         } else if (strcmp(argv[optind], "d") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no number supplied for 'd'" << endl;
+                                aerr << prog_name << ": no number supplied for 'd'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -195,7 +176,7 @@
                         } else if (strcmp(argv[optind], "fd") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no path supplied for 'fd'" << endl;
+                                aerr << prog_name << ": no path supplied for 'fd'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -203,7 +184,7 @@
                             const char *path = argv[optind++];
                             int fd = open(path, O_RDONLY);
                             if (fd < 0) {
-                                aerr << "service: could not open '" << path << "'" << endl;
+                                aerr << prog_name << ": could not open '" << path << "'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -212,7 +193,7 @@
                         } else if (strcmp(argv[optind], "afd") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no path supplied for 'afd'" << endl;
+                                aerr << prog_name << ": no path supplied for 'afd'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -221,7 +202,8 @@
                             int fd = open(path, O_RDONLY);
                             struct stat statbuf;
                             if (fd < 0 || fstat(fd, &statbuf) != 0) {
-                                aerr << "service: could not open or stat '" << path << "'" << endl;
+                                aerr << prog_name << ": could not open or stat"
+                                    << " '" << path << "'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -229,13 +211,14 @@
                             int afd = ashmem_create_region("test", statbuf.st_size);
                             void* ptr = mmap(NULL, statbuf.st_size,
                                    PROT_READ | PROT_WRITE, MAP_SHARED, afd, 0);
-                            read(fd, ptr, statbuf.st_size);
+                            (void)read(fd, ptr, statbuf.st_size);
                             close(fd);
                             data.writeFileDescriptor(afd, true /* take ownership */);
                         } else if (strcmp(argv[optind], "nfd") == 0) {
                             optind++;
                             if (optind >= argc) {
-                                aerr << "service: no file descriptor supplied for 'nfd'" << endl;
+                                aerr << prog_name << ": no file descriptor supplied for"
+                                    << " 'nfd'" << endl;
                                 wantsUsage = true;
                                 result = 10;
                                 break;
@@ -322,7 +305,7 @@
                             // for now just set the extra field to be null.
                             data.writeInt32(-1);
                         } else {
-                            aerr << "service: unknown option " << argv[optind] << endl;
+                            aerr << prog_name << ": unknown option " << argv[optind] << endl;
                             wantsUsage = true;
                             result = 10;
                             break;
@@ -332,44 +315,44 @@
                     service->transact(code, data, &reply);
                     aout << "Result: " << reply << endl;
                 } else {
-                    aerr << "service: Service " << argv[serviceArg]
+                    aerr << prog_name << ": Service " << argv[serviceArg]
                         << " does not exist" << endl;
                     result = 10;
                 }
             } else {
                 if (optind < argc) {
-                    aerr << "service: No service specified for call" << endl;
+                    aerr << prog_name << ": No service specified for call" << endl;
                 } else {
-                    aerr << "service: No code specified for call" << endl;
+                    aerr << prog_name << ": No code specified for call" << endl;
                 }
                 wantsUsage = true;
                 result = 10;
             }
         } else {
-            aerr << "service: Unknown command " << argv[optind] << endl;
+            aerr << prog_name << ": Unknown command " << argv[optind] << endl;
             wantsUsage = true;
             result = 10;
         }
     }
 
     if (wantsUsage) {
-        aout << "Usage: service [-h|-?]\n"
-                "       service list\n"
-                "       service check SERVICE\n"
-                "       service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR | null"
-                " | fd f | nfd n | afd f ] ...\n"
+        aout << "Usage: " << prog_name << " [-h|-?]\n"
+                "       " << prog_name << " list\n"
+                "       " << prog_name << " check SERVICE\n"
+                "       " << prog_name << " call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR"
+                " | null | fd f | nfd n | afd f ] ...\n"
                 "Options:\n"
                 "   i32: Write the 32-bit integer N into the send parcel.\n"
                 "   i64: Write the 64-bit integer N into the send parcel.\n"
-                "   f:   Write the 32-bit single-precision number N into the send parcel.\n"
-                "   d:   Write the 64-bit double-precision number N into the send parcel.\n"
+                "     f: Write the 32-bit single-precision number N into the send parcel.\n"
+                "     d: Write the 64-bit double-precision number N into the send parcel.\n"
                 "   s16: Write the UTF-16 string STR into the send parcel.\n"
                 "  null: Write a null binder into the send parcel.\n"
-                "    fd: Write a file descriptor for the file f to the send parcel.\n"
-                "   nfd: Write file descriptor n to the send parcel.\n"
-                "   afd: Write an ashmem file descriptor for a region containing the data from"
-                " file f to the send parcel.\n";
-//                "   intent: Write and Intent int the send parcel. ARGS can be\n"
+                "    fd: Write a file descriptor for the file f into the send parcel.\n"
+                "   nfd: Write the file descriptor n into the send parcel.\n"
+                "   afd: Write an ashmem file descriptor for a region containing the data from\n"
+                "          file f into the send parcel.\n";
+//                "   intent: Write an Intent into the send parcel. ARGS can be\n"
 //                "       action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
         return result;
     }
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index 6d5070f..0dd29e0 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -9,5 +9,5 @@
     onrestart class_restart main
     onrestart class_restart hal
     onrestart class_restart early_hal
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
     shutdown critical
diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc
index 756f6c3..c9305a1 100644
--- a/cmds/servicemanager/vndservicemanager.rc
+++ b/cmds/servicemanager/vndservicemanager.rc
@@ -2,7 +2,7 @@
     class core
     user system
     group system readproc
-    writepid /dev/cpuset/system-background/tasks
+    task_profiles ServiceCapacityLow
     onrestart class_restart main
     onrestart class_restart hal
     onrestart class_restart early_hal
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 5fe4ea1..931c5e3 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -89,6 +89,12 @@
 }
 
 prebuilt_etc {
+    name: "android.hardware.fingerprint.prebuilt.xml",
+    src: "android.hardware.fingerprint.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "android.hardware.location.gps.prebuilt.xml",
     src: "android.hardware.location.gps.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/include/binder/Enum.h b/include/binder/Enum.h
deleted file mode 100644
index 4c25654..0000000
--- a/include/binder/Enum.h
+++ /dev/null
@@ -1,22 +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
-
-#error Do not rely on global include files. All Android cc_* programs are given access to \
-    include_dirs for frameworks/native/include via global configuration, but this is legacy \
-    configuration. Instead, you should have a direct dependency on libbinder OR one of your \
-    dependencies should re-export libbinder headers with export_shared_lib_headers.
diff --git a/libs/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index b74923c..ac3e5b8 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -42,12 +42,13 @@
 cc_library {
     name: "libandroid_runtime_lazy",
     vendor_available: true,
+    recovery_available: true,
     double_loadable: true,
     host_supported: true,
     target: {
         darwin: {
             enabled: false,
-        }
+        },
     },
 
     cflags: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index bb1b513..8270ae5 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -25,6 +25,7 @@
     name: "libbinder_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
@@ -75,6 +76,7 @@
     vndk: {
         enabled: true,
     },
+    recovery_available: true,
     double_loadable: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
@@ -147,16 +149,17 @@
                 "UtilsHost.cpp",
             ],
         },
+        recovery: {
+            exclude_header_libs: [
+                "libandroid_runtime_vm_headers",
+            ],
+        },
     },
 
     aidl: {
         export_aidl_headers: true,
     },
 
-    // TODO(b/142684679): for com.android.media which is compiled
-    // as vendor and used as system code.
-    use_apex_name_macro: true,
-
     cflags: [
         "-Wall",
         "-Wextra",
@@ -335,6 +338,7 @@
         "libbase",
         "libbinder",
         "libbinder_ndk",
+        "liblog",
         "libutils",
     ],
     export_include_dirs: ["include_rpc_unstable"],
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index d3eef4e..ec9d554 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -547,7 +547,6 @@
     AutoMutex _l(e->mLock);
     auto rpcServer = RpcServer::make();
     LOG_ALWAYS_FATAL_IF(rpcServer == nullptr, "RpcServer::make returns null");
-    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     auto link = sp<RpcServerLink>::make(rpcServer, keepAliveBinder, weakThis);
     if (auto status = keepAliveBinder->linkToDeath(link, nullptr, 0); status != OK) {
         ALOGE("%s: keepAliveBinder->linkToDeath returns %s", __PRETTY_FUNCTION__,
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index aff9e0d..81e61da 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -448,21 +448,27 @@
 // on-device service manager.
 class ServiceManagerHostShim : public ServiceManagerShim {
 public:
-    using ServiceManagerShim::ServiceManagerShim;
+    ServiceManagerHostShim(const sp<AidlServiceManager>& impl,
+                           const RpcDelegateServiceManagerOptions& options)
+          : ServiceManagerShim(impl), mOptions(options) {}
     // ServiceManagerShim::getService is based on checkService, so no need to override it.
     sp<IBinder> checkService(const String16& name) const override {
-        return getDeviceService({String8(name).c_str()});
+        return getDeviceService({String8(name).c_str()}, mOptions);
     }
 
 protected:
     // Override realGetService for ServiceManagerShim::waitForService.
     Status realGetService(const std::string& name, sp<IBinder>* _aidl_return) {
-        *_aidl_return = getDeviceService({"-g", name});
+        *_aidl_return = getDeviceService({"-g", name}, mOptions);
         return Status::ok();
     }
+
+private:
+    RpcDelegateServiceManagerOptions mOptions;
 };
-sp<IServiceManager> createRpcDelegateServiceManager() {
-    auto binder = getDeviceService({"manager"});
+sp<IServiceManager> createRpcDelegateServiceManager(
+        const RpcDelegateServiceManagerOptions& options) {
+    auto binder = getDeviceService({"manager"}, options);
     if (binder == nullptr) {
         ALOGE("getDeviceService(\"manager\") returns null");
         return nullptr;
@@ -472,7 +478,7 @@
         ALOGE("getDeviceService(\"manager\") returns non service manager");
         return nullptr;
     }
-    return sp<ServiceManagerHostShim>::make(interface);
+    return sp<ServiceManagerHostShim>::make(interface, options);
 }
 #endif
 
diff --git a/libs/binder/OWNERS b/libs/binder/OWNERS
index 350994a..f954e74 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,6 @@
-arve@google.com
+# Bug component: 32456
 ctate@google.com
 hackbod@google.com
 maco@google.com
 smoreland@google.com
+tkjos@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 07555f6..8f4f0f0 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -98,9 +98,8 @@
     BLOB_ASHMEM_MUTABLE = 2,
 };
 
-static void acquire_object(const sp<ProcessState>& proc,
-    const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+                           const void* who) {
     switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
@@ -117,13 +116,6 @@
             return;
         }
         case BINDER_TYPE_FD: {
-            if ((obj.cookie != 0) && (outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
-                // If we own an ashmem fd, keep track of how much memory it refers to.
-                int size = ashmem_get_size_region(obj.handle);
-                if (size > 0) {
-                    *outAshmemSize += size;
-                }
-            }
             return;
         }
     }
@@ -131,9 +123,8 @@
     ALOGD("Invalid object type 0x%08x", obj.hdr.type);
 }
 
-static void release_object(const sp<ProcessState>& proc,
-    const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
-{
+static void release_object(const sp<ProcessState>& proc, const flat_binder_object& obj,
+                           const void* who) {
     switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
@@ -151,16 +142,6 @@
         }
         case BINDER_TYPE_FD: {
             if (obj.cookie != 0) { // owned
-                if ((outAshmemSize != nullptr) && ashmem_valid(obj.handle)) {
-                    int size = ashmem_get_size_region(obj.handle);
-                    if (size > 0) {
-                        // ashmem size might have changed since last time it was accounted for, e.g.
-                        // in acquire_object(). Value of *outAshmemSize is not critical since we are
-                        // releasing the object anyway. Check for integer overflow condition.
-                        *outAshmemSize -= std::min(*outAshmemSize, static_cast<size_t>(size));
-                    }
-                }
-
                 close(obj.handle);
             }
             return;
@@ -430,8 +411,9 @@
 
 status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
 {
-    if (parcel->isForRpc() != isForRpc()) {
-        ALOGE("Cannot append Parcel of one format to another.");
+    if (mSession != parcel->mSession) {
+        ALOGE("Cannot append Parcel from one context to another. They may be different formats, "
+              "and objects are specific to a context.");
         return BAD_TYPE;
     }
 
@@ -512,7 +494,7 @@
 
             flat_binder_object* flat
                 = reinterpret_cast<flat_binder_object*>(mData + off);
-            acquire_object(proc, *flat, this, &mOpenAshmemSize);
+            acquire_object(proc, *flat, this);
 
             if (flat->hdr.type == BINDER_TYPE_FD) {
                 // If this is a file descriptor, we need to dup it so the
@@ -539,6 +521,25 @@
     return memcmp(data(), other.data(), size);
 }
 
+status_t Parcel::compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+                                    size_t len, int* result) const {
+    if (len > INT32_MAX || thisOffset > INT32_MAX || otherOffset > INT32_MAX) {
+        // Don't accept size_t values which may have come from an inadvertent conversion from a
+        // negative int.
+        return BAD_VALUE;
+    }
+    size_t thisLimit;
+    if (__builtin_add_overflow(thisOffset, len, &thisLimit) || thisLimit > mDataSize) {
+        return BAD_VALUE;
+    }
+    size_t otherLimit;
+    if (__builtin_add_overflow(otherOffset, len, &otherLimit) || otherLimit > other.mDataSize) {
+        return BAD_VALUE;
+    }
+    *result = memcmp(data() + thisOffset, other.data() + otherOffset, len);
+    return NO_ERROR;
+}
+
 bool Parcel::allowFds() const
 {
     return mAllowFds;
@@ -566,6 +567,33 @@
     return mHasFds;
 }
 
+status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool* result) const {
+    if (len > INT32_MAX || offset > INT32_MAX) {
+        // Don't accept size_t values which may have come from an inadvertent conversion from a
+        // negative int.
+        return BAD_VALUE;
+    }
+    size_t limit;
+    if (__builtin_add_overflow(offset, len, &limit) || limit > mDataSize) {
+        return BAD_VALUE;
+    }
+    *result = false;
+    for (size_t i = 0; i < mObjectsSize; i++) {
+        size_t pos = mObjects[i];
+        if (pos < offset) continue;
+        if (pos + sizeof(flat_binder_object) > offset + len) {
+          if (mObjectsSorted) break;
+          else continue;
+        }
+        const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
+        if (flat->hdr.type == BINDER_TYPE_FD) {
+            *result = true;
+            break;
+        }
+    }
+    return NO_ERROR;
+}
+
 void Parcel::markSensitive() const
 {
     mDeallocZero = true;
@@ -602,6 +630,8 @@
 
 #if defined(__ANDROID_VNDK__)
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#elif defined(__ANDROID_RECOVERY__)
+constexpr int32_t kHeader = B_PACK_CHARS('R', 'E', 'C', 'O');
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
 #endif
@@ -1335,7 +1365,7 @@
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
             mObjects[mObjectsSize] = mDataPos;
-            acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
+            acquire_object(ProcessState::self(), val, this);
             mObjectsSize++;
         }
 
@@ -2225,7 +2255,7 @@
         i--;
         const flat_binder_object* flat
             = reinterpret_cast<flat_binder_object*>(data+objects[i]);
-        release_object(proc, *flat, this, &mOpenAshmemSize);
+        release_object(proc, *flat, this);
     }
 }
 
@@ -2242,7 +2272,7 @@
         i--;
         const flat_binder_object* flat
             = reinterpret_cast<flat_binder_object*>(data+objects[i]);
-        acquire_object(proc, *flat, this, &mOpenAshmemSize);
+        acquire_object(proc, *flat, this);
     }
 }
 
@@ -2447,7 +2477,7 @@
                     // will need to rescan because we may have lopped off the only FDs
                     mFdsKnown = false;
                 }
-                release_object(proc, *flat, this, &mOpenAshmemSize);
+                release_object(proc, *flat, this);
             }
 
             if (objectsSize == 0) {
@@ -2540,7 +2570,6 @@
     mAllowFds = true;
     mDeallocZero = false;
     mOwner = nullptr;
-    mOpenAshmemSize = 0;
     mWorkSourceRequestHeaderPosition = 0;
     mRequestHeaderPresent = false;
 
@@ -2557,18 +2586,9 @@
     }
 }
 
-void Parcel::scanForFds() const
-{
-    bool hasFds = false;
-    for (size_t i=0; i<mObjectsSize; i++) {
-        const flat_binder_object* flat
-            = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
-        if (flat->hdr.type == BINDER_TYPE_FD) {
-            hasFds = true;
-            break;
-        }
-    }
-    mHasFds = hasFds;
+void Parcel::scanForFds() const {
+    status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+    ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
     mFdsKnown = true;
 }
 
@@ -2576,13 +2596,28 @@
 {
     // This used to return the size of all blobs that were written to ashmem, now we're returning
     // the ashmem currently referenced by this Parcel, which should be equivalent.
-    // TODO: Remove method once ABI can be changed.
-    return mOpenAshmemSize;
+    // TODO(b/202029388): Remove method once ABI can be changed.
+    return getOpenAshmemSize();
 }
 
 size_t Parcel::getOpenAshmemSize() const
 {
-    return mOpenAshmemSize;
+    size_t openAshmemSize = 0;
+    for (size_t i = 0; i < mObjectsSize; i++) {
+        const flat_binder_object* flat =
+                reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);
+
+        // cookie is compared against zero for historical reasons
+        // > obj.cookie = takeOwnership ? 1 : 0;
+        if (flat->hdr.type == BINDER_TYPE_FD && flat->cookie != 0 && ashmem_valid(flat->handle)) {
+            int size = ashmem_get_size_region(flat->handle);
+            if (__builtin_add_overflow(openAshmemSize, size, &openAshmemSize)) {
+                ALOGE("Overflow when computing ashmem size.");
+                return SIZE_MAX;
+            }
+        }
+    }
+    return openAshmemSize;
 }
 
 // --- Parcel::Blob ---
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 94b2806..4f21cda 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -89,13 +89,21 @@
     return init(nullptr, false /*requireDefault*/);
 }
 
+[[clang::no_destroy]] static sp<ProcessState> gProcess;
+[[clang::no_destroy]] static std::mutex gProcessMutex;
+
+static void verifyNotForked(bool forked) {
+    LOG_ALWAYS_FATAL_IF(forked, "libbinder ProcessState can not be used after fork");
+}
+
 sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
 {
-    [[clang::no_destroy]] static sp<ProcessState> gProcess;
-    [[clang::no_destroy]] static std::mutex gProcessMutex;
 
     if (driver == nullptr) {
         std::lock_guard<std::mutex> l(gProcessMutex);
+        if (gProcess) {
+            verifyNotForked(gProcess->mForked);
+        }
         return gProcess;
     }
 
@@ -106,6 +114,14 @@
             driver = "/dev/binder";
         }
 
+        // we must install these before instantiating the gProcess object,
+        // otherwise this would race with creating it, and there could be the
+        // possibility of an invalid gProcess object forked by another thread
+        // before these are installed
+        int ret = pthread_atfork(ProcessState::onFork, ProcessState::parentPostFork,
+                                 ProcessState::childPostFork);
+        LOG_ALWAYS_FATAL_IF(ret != 0, "pthread_atfork error %s", strerror(ret));
+
         std::lock_guard<std::mutex> l(gProcessMutex);
         gProcess = sp<ProcessState>::make(driver);
     });
@@ -119,6 +135,7 @@
                             gProcess->getDriverName().c_str(), driver);
     }
 
+    verifyNotForked(gProcess->mForked);
     return gProcess;
 }
 
@@ -137,6 +154,24 @@
     return context;
 }
 
+void ProcessState::onFork() {
+    // make sure another thread isn't currently retrieving ProcessState
+    gProcessMutex.lock();
+}
+
+void ProcessState::parentPostFork() {
+    gProcessMutex.unlock();
+}
+
+void ProcessState::childPostFork() {
+    // another thread might call fork before gProcess is instantiated, but after
+    // the thread handler is installed
+    if (gProcess) {
+        gProcess->mForked = true;
+    }
+    gProcessMutex.unlock();
+}
+
 void ProcessState::startThreadPool()
 {
     AutoMutex _l(mLock);
@@ -426,6 +461,7 @@
         mWaitingForThreads(0),
         mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
         mStarvationStartTimeMs(0),
+        mForked(false),
         mThreadPoolStarted(false),
         mThreadPoolSeq(1),
         mCallRestriction(CallRestriction::NONE) {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 967b8e3..93ed50e 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -58,10 +58,6 @@
     return sp<RpcServer>::make(std::move(ctx));
 }
 
-void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
-    mAgreedExperimental = true;
-}
-
 status_t RpcServer::setupUnixDomainServer(const char* path) {
     return setupSocketServer(UnixSocketAddress(path));
 }
@@ -127,14 +123,23 @@
 
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
     std::lock_guard<std::mutex> _l(mLock);
+    mRootObjectFactory = nullptr;
     mRootObjectWeak = mRootObject = binder;
 }
 
 void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
     std::lock_guard<std::mutex> _l(mLock);
     mRootObject.clear();
+    mRootObjectFactory = nullptr;
     mRootObjectWeak = binder;
 }
+void RpcServer::setPerSessionRootObject(
+        std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& makeObject) {
+    std::lock_guard<std::mutex> _l(mLock);
+    mRootObject.clear();
+    mRootObjectWeak.clear();
+    mRootObjectFactory = std::move(makeObject);
+}
 
 sp<IBinder> RpcServer::getRootObject() {
     std::lock_guard<std::mutex> _l(mLock);
@@ -154,14 +159,12 @@
 }
 
 void RpcServer::start() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
     std::lock_guard<std::mutex> _l(mLock);
     LOG_ALWAYS_FATAL_IF(mJoinThread.get(), "Already started!");
     mJoinThread = std::make_unique<std::thread>(&joinRpcServer, sp<RpcServer>::fromExisting(this));
 }
 
 void RpcServer::join() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
 
     {
         std::lock_guard<std::mutex> _l(mLock);
@@ -174,8 +177,14 @@
 
     status_t status;
     while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
-        unique_fd clientFd(TEMP_FAILURE_RETRY(
-                accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+        sockaddr_storage addr;
+        socklen_t addrLen = sizeof(addr);
+
+        unique_fd clientFd(
+                TEMP_FAILURE_RETRY(accept4(mServer.get(), reinterpret_cast<sockaddr*>(&addr),
+                                           &addrLen, SOCK_CLOEXEC | SOCK_NONBLOCK)));
+
+        LOG_ALWAYS_FATAL_IF(addrLen > static_cast<socklen_t>(sizeof(addr)), "Truncated address");
 
         if (clientFd < 0) {
             ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -187,7 +196,7 @@
             std::lock_guard<std::mutex> _l(mLock);
             std::thread thread =
                     std::thread(&RpcServer::establishConnection, sp<RpcServer>::fromExisting(this),
-                                std::move(clientFd));
+                                std::move(clientFd), addr, addrLen);
             mConnectingThreads[thread.get_id()] = std::move(thread);
         }
     }
@@ -257,10 +266,8 @@
     return mConnectingThreads.size();
 }
 
-void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
-    // TODO(b/183988761): cannot trust this simple ID
-    LOG_ALWAYS_FATAL_IF(!server->mAgreedExperimental, "no!");
-
+void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+                                    const sockaddr_storage addr, socklen_t addrLen) {
     // mShutdownTrigger can only be cleared once connection threads have joined.
     // It must be set before this thread is started
     LOG_ALWAYS_FATAL_IF(server->mShutdownTrigger == nullptr);
@@ -383,11 +390,23 @@
             session = RpcSession::make();
             session->setMaxIncomingThreads(server->mMaxThreads);
             if (!session->setProtocolVersion(protocolVersion)) return;
+
+            // if null, falls back to server root
+            sp<IBinder> sessionSpecificRoot;
+            if (server->mRootObjectFactory != nullptr) {
+                sessionSpecificRoot =
+                        server->mRootObjectFactory(reinterpret_cast<const sockaddr*>(&addr),
+                                                   addrLen);
+                if (sessionSpecificRoot == nullptr) {
+                    ALOGE("Warning: server returned null from root object factory");
+                }
+            }
+
             if (!session->setForServer(server,
                                        sp<RpcServer::EventListener>::fromExisting(
                                                static_cast<RpcServer::EventListener*>(
                                                        server.get())),
-                                       sessionId)) {
+                                       sessionId, sessionSpecificRoot)) {
                 ALOGE("Failed to attach server to session");
                 return;
             }
@@ -478,19 +497,16 @@
 }
 
 bool RpcServer::hasServer() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
     std::lock_guard<std::mutex> _l(mLock);
     return mServer.ok();
 }
 
 unique_fd RpcServer::releaseServer() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
     std::lock_guard<std::mutex> _l(mLock);
     return std::move(mServer);
 }
 
 status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
     std::lock_guard<std::mutex> _l(mLock);
     if (mServer.ok()) {
         ALOGE("Each RpcServer can only have one server.");
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 486b67b..a5a2bb1 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -29,13 +29,11 @@
 #include <android-base/hex.h>
 #include <android-base/macros.h>
 #include <android-base/scopeguard.h>
-#include <android_runtime/vm.h>
 #include <binder/BpBinder.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
-#include <jni.h>
 #include <utils/String8.h>
 
 #include "FdTrigger.h"
@@ -48,6 +46,11 @@
 extern "C" pid_t gettid();
 #endif
 
+#ifndef __ANDROID_RECOVERY__
+#include <android_runtime/vm.h>
+#include <jni.h>
+#endif
+
 namespace android {
 
 using base::unique_fd;
@@ -90,6 +93,20 @@
     return mMaxIncomingThreads;
 }
 
+void RpcSession::setMaxOutgoingThreads(size_t threads) {
+    std::lock_guard<std::mutex> _l(mMutex);
+    LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
+                        "Must set max outgoing threads before setting up connections, but has %zu "
+                        "client(s) and %zu server(s)",
+                        mConnections.mOutgoing.size(), mConnections.mIncoming.size());
+    mMaxOutgoingThreads = threads;
+}
+
+size_t RpcSession::getMaxOutgoingThreads() {
+    std::lock_guard<std::mutex> _l(mMutex);
+    return mMaxOutgoingThreads;
+}
+
 bool RpcSession::setProtocolVersion(uint32_t version) {
     if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
         version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
@@ -301,6 +318,9 @@
 }
 
 namespace {
+#ifdef __ANDROID_RECOVERY__
+class JavaThreadAttacher {};
+#else
 // RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
 // Android Runtime doesn't exist, no-op.
 class JavaThreadAttacher {
@@ -353,6 +373,7 @@
         return fn();
     }
 };
+#endif
 } // namespace
 
 void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
@@ -360,7 +381,7 @@
 
     if (setupResult.status == OK) {
         LOG_ALWAYS_FATAL_IF(!connection, "must have connection if setup succeeded");
-        JavaThreadAttacher javaThreadAttacher;
+        [[maybe_unused]] JavaThreadAttacher javaThreadAttacher;
         while (true) {
             status_t status = session->state()->getAndExecuteCommand(connection, session,
                                                                      RpcState::CommandType::ANY);
@@ -473,6 +494,12 @@
         return status;
     }
 
+    size_t outgoingThreads = std::min(numThreadsAvailable, mMaxOutgoingThreads);
+    ALOGI_IF(outgoingThreads != numThreadsAvailable,
+             "Server hints client to start %zu outgoing threads, but client will only start %zu "
+             "because it is preconfigured to start at most %zu outgoing threads.",
+             numThreadsAvailable, outgoingThreads, mMaxOutgoingThreads);
+
     // TODO(b/189955605): we should add additional sessions dynamically
     // instead of all at once - the other side should be responsible for setting
     // up additional connections. We need to create at least one (unless 0 are
@@ -480,7 +507,10 @@
     // any requests at all.
 
     // we've already setup one client
-    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+    LOG_RPC_DETAIL("RpcSession::setupClient() instantiating %zu outgoing (server max: %zu) and %zu "
+                   "incoming threads",
+                   outgoingThreads, numThreadsAvailable, mMaxIncomingThreads);
+    for (size_t i = 0; i + 1 < outgoingThreads; i++) {
         if (status_t status = connectAndInit(mId, false /*incoming*/); status != OK) return status;
     }
 
@@ -665,7 +695,8 @@
 
     status_t status = OK;
     if (init) {
-        mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+        status =
+                mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
     {
@@ -677,7 +708,8 @@
 }
 
 bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
-                              const std::vector<uint8_t>& sessionId) {
+                              const std::vector<uint8_t>& sessionId,
+                              const sp<IBinder>& sessionSpecificRoot) {
     LOG_ALWAYS_FATAL_IF(mForServer != nullptr);
     LOG_ALWAYS_FATAL_IF(server == nullptr);
     LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
@@ -690,6 +722,7 @@
     mId = sessionId;
     mForServer = server;
     mEventListener = eventListener;
+    mSessionSpecificRootObject = sessionSpecificRoot;
     return true;
 }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 9ba64f3..09b3d68 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -870,7 +870,9 @@
                     if (server) {
                         switch (transaction->code) {
                             case RPC_SPECIAL_TRANSACT_GET_ROOT: {
-                                replyStatus = reply.writeStrongBinder(server->getRootObject());
+                                sp<IBinder> root = session->mSessionSpecificRootObject
+                                        ?: server->getRootObject();
+                                replyStatus = reply.writeStrongBinder(root);
                                 break;
                             }
                             default: {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 50de22b..dba0a43 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -60,20 +60,21 @@
     RpcState();
     ~RpcState();
 
-    status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
-                                    const sp<RpcSession>& session, uint32_t* version);
-    status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
-                                const sp<RpcSession>& session);
-    status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
-                                const sp<RpcSession>& session);
+    [[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,
+                                              const sp<RpcSession>& session);
+    [[nodiscard]] status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
+                                              const sp<RpcSession>& session);
 
     // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
     sp<IBinder> getRootObject(const sp<RpcSession::RpcConnection>& connection,
                               const sp<RpcSession>& session);
-    status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
-                           const sp<RpcSession>& session, size_t* maxThreadsOut);
-    status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
-                          const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut);
+    [[nodiscard]] status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
+                                         const sp<RpcSession>& session, size_t* maxThreadsOut);
+    [[nodiscard]] status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
+                                        const sp<RpcSession>& session,
+                                        std::vector<uint8_t>* sessionIdOut);
 
     [[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
                                     const sp<IBinder>& address, uint32_t code, const Parcel& data,
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 27cc563..194254a 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -124,7 +124,8 @@
 
 } // namespace
 
-sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs) {
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+                             const RpcDelegateServiceManagerOptions& options) {
     std::vector<std::string> prefix{"adb", "shell", "servicedispatcher"};
     serviceDispatcherArgs.insert(serviceDispatcherArgs.begin(), prefix.begin(), prefix.end());
 
@@ -158,6 +159,10 @@
     LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
 
     auto rpcSession = RpcSession::make();
+    if (options.maxOutgoingThreads.has_value()) {
+        rpcSession->setMaxOutgoingThreads(*options.maxOutgoingThreads);
+    }
+
     if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
         status != OK) {
         ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
diff --git a/libs/binder/ServiceManagerHost.h b/libs/binder/ServiceManagerHost.h
index e59724c..c5310da 100644
--- a/libs/binder/ServiceManagerHost.h
+++ b/libs/binder/ServiceManagerHost.h
@@ -21,11 +21,14 @@
 
 namespace android {
 
+struct RpcDelegateServiceManagerOptions;
+
 // Get a service on device by running servicedispatcher with the given args, e.g.
 //     getDeviceService({"foo"});
 // Return nullptr on any error.
 // When the returned binder object is destroyed, remove adb forwarding and kills
 // the long-running servicedispatcher process.
-sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs);
+sp<IBinder> getDeviceService(std::vector<std::string>&& serviceDispatcherArgs,
+                             const RpcDelegateServiceManagerOptions& options);
 
 } // namespace android
diff --git a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
index ece7989..bffab5e 100644
--- a/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -27,4 +27,7 @@
   @utf8InCpp String diskImagePath;
   long versionCode;
   @utf8InCpp String versionName;
+  boolean hasBootClassPathJars;
+  boolean hasDex2OatBootClassPathJars;
+  boolean hasSystemServerClassPathJars;
 }
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index ff90b30..7d14315 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -129,48 +129,50 @@
 
 #endif
 
-#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)\
-    const ::android::StaticString16                                     \
-        I##INTERFACE##_descriptor_static_str16(__IINTF_CONCAT(u, NAME));\
-    const ::android::String16 I##INTERFACE::descriptor(                 \
-        I##INTERFACE##_descriptor_static_str16);                        \
-    const ::android::String16&                                          \
-            I##INTERFACE::getInterfaceDescriptor() const {              \
-        return I##INTERFACE::descriptor;                                \
-    }                                                                   \
-    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
-            const ::android::sp<::android::IBinder>& obj)               \
-    {                                                                   \
-        ::android::sp<I##INTERFACE> intr;                               \
-        if (obj != nullptr) {                                           \
-            intr = ::android::sp<I##INTERFACE>::cast(                   \
-                obj->queryLocalInterface(I##INTERFACE::descriptor));    \
-            if (intr == nullptr) {                                      \
-                intr = ::android::sp<Bp##INTERFACE>::make(obj);         \
-            }                                                           \
-        }                                                               \
-        return intr;                                                    \
-    }                                                                   \
-    std::unique_ptr<I##INTERFACE> I##INTERFACE::default_impl;           \
-    bool I##INTERFACE::setDefaultImpl(std::unique_ptr<I##INTERFACE> impl)\
-    {                                                                   \
-        /* Only one user of this interface can use this function     */ \
-        /* at a time. This is a heuristic to detect if two different */ \
-        /* users in the same process use this function.              */ \
-        assert(!I##INTERFACE::default_impl);                            \
-        if (impl) {                                                     \
-            I##INTERFACE::default_impl = std::move(impl);               \
-            return true;                                                \
-        }                                                               \
-        return false;                                                   \
-    }                                                                   \
-    const std::unique_ptr<I##INTERFACE>& I##INTERFACE::getDefaultImpl() \
-    {                                                                   \
-        return I##INTERFACE::default_impl;                              \
-    }                                                                   \
-    I##INTERFACE::I##INTERFACE() { }                                    \
-    I##INTERFACE::~I##INTERFACE() { }                                   \
+// Macro to be used by both IMPLEMENT_META_INTERFACE and IMPLEMENT_META_NESTED_INTERFACE
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE)                     \
+    const ::android::String16& ITYPE::getInterfaceDescriptor() const { return ITYPE::descriptor; } \
+    ::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) {        \
+        ::android::sp<ITYPE> intr;                                                                 \
+        if (obj != nullptr) {                                                                      \
+            intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor));        \
+            if (intr == nullptr) {                                                                 \
+                intr = ::android::sp<BPTYPE>::make(obj);                                           \
+            }                                                                                      \
+        }                                                                                          \
+        return intr;                                                                               \
+    }                                                                                              \
+    std::unique_ptr<ITYPE> ITYPE::default_impl;                                                    \
+    bool ITYPE::setDefaultImpl(std::unique_ptr<ITYPE> impl) {                                      \
+        /* Only one user of this interface can use this function     */                            \
+        /* at a time. This is a heuristic to detect if two different */                            \
+        /* users in the same process use this function.              */                            \
+        assert(!ITYPE::default_impl);                                                              \
+        if (impl) {                                                                                \
+            ITYPE::default_impl = std::move(impl);                                                 \
+            return true;                                                                           \
+        }                                                                                          \
+        return false;                                                                              \
+    }                                                                                              \
+    const std::unique_ptr<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; }          \
+    ITYPE::INAME() {}                                                                              \
+    ITYPE::~INAME() {}
 
+// Macro for an interface type.
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                        \
+    const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16(                     \
+            __IINTF_CONCAT(u, NAME));                                                           \
+    const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \
+    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)
+
+// Macro for "nested" interface type.
+// For example,
+//   class Parent .. { class INested .. { }; };
+// DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(Parent, Nested, "Parent.INested")
+#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(PARENT, INTERFACE, NAME)  \
+    const ::android::String16 PARENT::I##INTERFACE::descriptor(NAME);                    \
+    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(PARENT::I##INTERFACE, I##INTERFACE, \
+                                                     PARENT::Bp##INTERFACE)
 
 #define CHECK_INTERFACE(interface, data, reply)                         \
     do {                                                                \
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a48075d..240e3c2 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -188,7 +188,16 @@
 //        // ...
 //    }
 // Resources are cleaned up when the object is destroyed.
-sp<IServiceManager> createRpcDelegateServiceManager();
+//
+// For each returned binder object, at most |maxOutgoingThreads| outgoing threads are instantiated.
+// Hence, only |maxOutgoingThreads| calls can be made simultaneously. Additional calls are blocked
+// if there are |maxOutgoingThreads| ongoing calls. See RpcSession::setMaxOutgoingThreads.
+// If |maxOutgoingThreads| is not set, default is |RpcSession::kDefaultMaxOutgoingThreads|.
+struct RpcDelegateServiceManagerOptions {
+    std::optional<size_t> maxOutgoingThreads;
+};
+sp<IServiceManager> createRpcDelegateServiceManager(
+        const RpcDelegateServiceManagerOptions& options);
 #endif
 
 } // namespace android
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index fd8ac62..9670d7b 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -81,12 +81,15 @@
                                    size_t start, size_t len);
 
     int                 compareData(const Parcel& other);
+    status_t compareDataInRange(size_t thisOffset, const Parcel& other, size_t otherOffset,
+                                size_t length, int* result) const;
 
     bool                allowFds() const;
     bool                pushAllowFds(bool allowFds);
     void                restoreAllowFds(bool lastValue);
 
     bool                hasFileDescriptors() const;
+    status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool* result) const;
 
     // Zeros data when reallocating. Other mitigations may be added
     // in the future.
@@ -204,6 +207,23 @@
     status_t            writeStrongBinderVector(const std::unique_ptr<std::vector<sp<IBinder>>>& val) __attribute__((deprecated("use std::optional version instead")));
     status_t            writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
 
+    // Write an IInterface or a vector of IInterface's
+    template <typename T,
+              std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+    status_t writeStrongBinder(const sp<T>& val) {
+        return writeStrongBinder(T::asBinder(val));
+    }
+    template <typename T,
+              std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+    status_t writeStrongBinderVector(const std::vector<sp<T>>& val) {
+        return writeData(val);
+    }
+    template <typename T,
+              std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+    status_t writeStrongBinderVector(const std::optional<std::vector<sp<T>>>& val) {
+        return writeData(val);
+    }
+
     // Write an Enum vector with underlying type int8_t.
     // Does not use padding; each byte is contiguous.
     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>
@@ -418,6 +438,16 @@
     status_t            readStrongBinderVector(std::optional<std::vector<sp<IBinder>>>* val) const;
     status_t            readStrongBinderVector(std::unique_ptr<std::vector<sp<IBinder>>>* val) const __attribute__((deprecated("use std::optional version instead")));
     status_t            readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
+    template <typename T,
+              std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+    status_t readStrongBinderVector(std::vector<sp<T>>* val) const {
+        return readData(val);
+    }
+    template <typename T,
+              std::enable_if_t<std::is_base_of_v<::android::IInterface, T>, bool> = true>
+    status_t readStrongBinderVector(std::optional<std::vector<sp<T>>>* val) const {
+        return readData(val);
+    }
 
     status_t            readByteVector(std::optional<std::vector<int8_t>>* val) const;
     status_t            readByteVector(std::unique_ptr<std::vector<int8_t>>* val) const __attribute__((deprecated("use std::optional version instead")));
@@ -1141,6 +1171,7 @@
     release_func        mOwner;
 
     sp<RpcSession> mSession;
+    size_t mReserved;
 
     class Blob {
     public:
@@ -1225,13 +1256,19 @@
         inline void* data() { return mData; }
     };
 
-private:
-    size_t mOpenAshmemSize;
-
-public:
-    // TODO: Remove once ABI can be changed.
-    size_t getBlobAshmemSize() const;
+    /**
+     * Returns the total amount of ashmem memory owned by this object.
+     *
+     * Note: for historical reasons, this does not include ashmem memory which
+     * is referenced by this Parcel, but which this parcel doesn't own (e.g.
+     * writeFileDescriptor is called without 'takeOwnership' true).
+     */
     size_t getOpenAshmemSize() const;
+
+private:
+    // TODO(b/202029388): Remove 'getBlobAshmemSize' once no prebuilts reference
+    // this
+    size_t getBlobAshmemSize() const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 72c2ab7..cf8d8e4 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -94,6 +94,10 @@
 private:
     static sp<ProcessState> init(const char* defaultDriver, bool requireDefault);
 
+    static void onFork();
+    static void parentPostFork();
+    static void childPostFork();
+
     friend class IPCThreadState;
     friend class sp<ProcessState>;
 
@@ -132,6 +136,7 @@
 
     Vector<handle_entry> mHandleToObject;
 
+    bool mForked;
     bool mThreadPoolStarted;
     volatile int32_t mThreadPoolSeq;
 
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index fb2cf23..aaa812b 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -25,10 +25,6 @@
 #include <mutex>
 #include <thread>
 
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
 namespace android {
 
 class FdTrigger;
@@ -99,8 +95,6 @@
      */
     [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
 
-    void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
     /**
      * This must be called before adding a client session.
      *
@@ -130,6 +124,10 @@
      * Holds a weak reference to the root object.
      */
     void setRootObjectWeak(const wp<IBinder>& binder);
+    /**
+     * Allows a root object to be created for each session
+     */
+    void setPerSessionRootObject(std::function<sp<IBinder>(const sockaddr*, socklen_t)>&& object);
     sp<IBinder> getRootObject();
 
     /**
@@ -179,11 +177,11 @@
     void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
 
-    static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
-    status_t setupSocketServer(const RpcSocketAddress& address);
+    static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
+                                    const sockaddr_storage addr, socklen_t addrLen);
+    [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
-    bool mAgreedExperimental = false;
     size_t mMaxThreads = 1;
     std::optional<uint32_t> mProtocolVersion;
     base::unique_fd mServer; // socket we are accepting sessions on
@@ -194,6 +192,7 @@
     std::map<std::thread::id, std::thread> mConnectingThreads;
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
+    std::function<sp<IBinder>(const sockaddr*, socklen_t)> mRootObjectFactory;
     std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
     std::condition_variable mShutdownCv;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index e64572b..1bc8464 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -26,10 +26,6 @@
 #include <thread>
 #include <vector>
 
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
 namespace android {
 
 class Parcel;
@@ -50,6 +46,8 @@
  */
 class RpcSession final : public virtual RefBase {
 public:
+    static constexpr size_t kDefaultMaxOutgoingThreads = 10;
+
     // Create an RpcSession with default configuration (raw sockets).
     static sp<RpcSession> make();
 
@@ -72,6 +70,18 @@
     size_t getMaxIncomingThreads();
 
     /**
+     * Set the maximum number of outgoing threads allowed to be made.
+     * By default, this is |kDefaultMaxOutgoingThreads|. This must be called before setting up this
+     * connection as a client.
+     *
+     * This limits the number of outgoing threads on top of the remote peer setting. This RpcSession
+     * will only instantiate |min(maxOutgoingThreads, remoteMaxThreads)| outgoing threads, where
+     * |remoteMaxThreads| can be retrieved from the remote peer via |getRemoteMaxThreads()|.
+     */
+    void setMaxOutgoingThreads(size_t threads);
+    size_t getMaxOutgoingThreads();
+
+    /**
      * By default, the minimum of the supported versions of the client and the
      * server will be used. Usually, this API should only be used for debugging.
      */
@@ -126,7 +136,7 @@
      * Query the other side of the session for the maximum number of threads
      * it supports (maximum number of concurrent non-nested synchronous transactions)
      */
-    status_t getRemoteMaxThreads(size_t* maxThreads);
+    [[nodiscard]] status_t getRemoteMaxThreads(size_t* maxThreads);
 
     /**
      * See RpcTransportCtx::getCertificate
@@ -206,7 +216,7 @@
         bool allowNested = false;
     };
 
-    status_t readId();
+    [[nodiscard]] status_t readId();
 
     // A thread joining a server must always call these functions in order, and
     // cleanup is only programmed once into join. These are in separate
@@ -242,12 +252,13 @@
                                                  bool init);
     [[nodiscard]] bool setForServer(const wp<RpcServer>& server,
                                     const wp<RpcSession::EventListener>& eventListener,
-                                    const std::vector<uint8_t>& sessionId);
+                                    const std::vector<uint8_t>& sessionId,
+                                    const sp<IBinder>& sessionSpecificRoot);
     sp<RpcConnection> assignIncomingConnectionToThisThread(
             std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
 
-    status_t initShutdownTrigger();
+    [[nodiscard]] status_t initShutdownTrigger();
 
     enum class ConnectionUse {
         CLIENT,
@@ -258,8 +269,8 @@
     // Object representing exclusive access to a connection.
     class ExclusiveConnection {
     public:
-        static status_t find(const sp<RpcSession>& session, ConnectionUse use,
-                             ExclusiveConnection* connection);
+        [[nodiscard]] static status_t find(const sp<RpcSession>& session, ConnectionUse use,
+                                           ExclusiveConnection* connection);
 
         ~ExclusiveConnection();
         const sp<RpcConnection>& get() { return mConnection; }
@@ -299,6 +310,10 @@
     sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
     wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
 
+    // session-specific root object (if a different root is used for each
+    // session)
+    sp<IBinder> mSessionSpecificRootObject;
+
     std::vector<uint8_t> mId;
 
     std::unique_ptr<FdTrigger> mShutdownTrigger;
@@ -308,6 +323,7 @@
     std::mutex mMutex; // for all below
 
     size_t mMaxIncomingThreads = 0;
+    size_t mMaxOutgoingThreads = kDefaultMaxOutgoingThreads;
     std::optional<uint32_t> mProtocolVersion;
 
     std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
index 08f5eed..5baa4d7 100644
--- a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include <sys/socket.h>
+
 extern "C" {
 
 struct AIBinder;
@@ -30,6 +32,14 @@
 bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
                           void* param);
 
+// Starts an RPC server on a given port and a given root IBinder factory.
+// RunRpcServerWithFactory acts like RunRpcServerCallback, but instead of
+// assigning single root IBinder object to all connections, factory is called
+// whenever a client connects, making it possible to assign unique IBinder
+// object to each client.
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+                          void* factoryContext, unsigned int port);
+
 AIBinder* RpcClient(unsigned int cid, unsigned int port);
 
 // Connect to an RPC server with preconnected file descriptors.
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
index 4c2f296..ab64828 100644
--- a/libs/binder/include_tls/binder/RpcAuth.h
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -40,7 +40,7 @@
     // - SSL_CTX_use_certificate
     // - SSL_CTX_set*_chain
     // - SSL_CTX_add0_chain_cert
-    virtual status_t configure(SSL_CTX* ctx) = 0;
+    [[nodiscard]] virtual status_t configure(SSL_CTX* ctx) = 0;
 };
 
 } // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index cad55fb..bf2b25b 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,6 +19,7 @@
 #include <android/binder_libbinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <linux/vm_sockets.h>
 
 using android::OK;
 using android::RpcServer;
@@ -29,10 +30,31 @@
 
 extern "C" {
 
+bool RunRpcServerWithFactory(AIBinder* (*factory)(unsigned int cid, void* context),
+                             void* factoryContext, unsigned int port) {
+    auto server = RpcServer::make();
+    if (status_t status = server->setupVsockServer(port); status != OK) {
+        LOG(ERROR) << "Failed to set up vsock server with port " << port
+                   << " error: " << statusToString(status).c_str();
+        return false;
+    }
+    server->setPerSessionRootObject([=](const sockaddr* addr, socklen_t addrlen) {
+        LOG_ALWAYS_FATAL_IF(addr->sa_family != AF_VSOCK, "address is not a vsock");
+        LOG_ALWAYS_FATAL_IF(addrlen < sizeof(sockaddr_vm), "sockaddr is truncated");
+        const sockaddr_vm* vaddr = reinterpret_cast<const sockaddr_vm*>(addr);
+        return AIBinder_toPlatformBinder(factory(vaddr->svm_cid, factoryContext));
+    });
+
+    server->join();
+
+    // Shutdown any open sessions since server failed.
+    (void)server->shutdown();
+    return true;
+}
+
 bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
                           void* param) {
     auto server = RpcServer::make();
-    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     if (status_t status = server->setupVsockServer(port); status != OK) {
         LOG(ERROR) << "Failed to set up vsock server with port " << port
                    << " error: " << statusToString(status).c_str();
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 9c04e58..ee46fcb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -54,6 +54,7 @@
 
     defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
+    recovery_available: true,
 
     llndk: {
         symbol_file: "libbinder_ndk.map.txt",
@@ -155,6 +156,7 @@
     name: "libbinder_headers_platform_shared",
     export_include_dirs: ["include_cpp"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..6949c2c 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -104,6 +104,17 @@
     return {};
 }
 
+// b/175635923 libcxx causes "implicit-conversion" with a string with invalid char
+static std::string SanitizeString(const String16& str) {
+    std::string sanitized{String8(str)};
+    for (auto& c : sanitized) {
+        if (!isprint(c)) {
+            c = '?';
+        }
+    }
+    return sanitized;
+}
+
 bool AIBinder::associateClass(const AIBinder_Class* clazz) {
     if (clazz == nullptr) return false;
 
@@ -118,7 +129,7 @@
     if (descriptor != newDescriptor) {
         if (getBinder()->isBinderAlive()) {
             LOG(ERROR) << __func__ << ": Expecting binder to have class '" << newDescriptor
-                       << "' but descriptor is actually '" << descriptor << "'.";
+                       << "' but descriptor is actually '" << SanitizeString(descriptor) << "'.";
         } else {
             // b/155793159
             LOG(ERROR) << __func__ << ": Cannot associate class '" << newDescriptor
@@ -555,6 +566,10 @@
     return ::android::IPCThreadState::self()->getCallingPid();
 }
 
+bool AIBinder_isHandlingTransaction() {
+    return ::android::IPCThreadState::self()->getServingStackPointer() != nullptr;
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         return;
@@ -780,3 +795,7 @@
     AIBinder_incStrong(ndkBinder.get());
     return ndkBinder.get();
 }
+
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) {
+    binder->asABBinder()->setMinSchedulerPolicy(policy, priority);
+}
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 5de64f8..09411e7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -190,9 +190,9 @@
     BnCInterface() {}
     virtual ~BnCInterface() {}
 
-    SpAIBinder asBinder() override;
+    SpAIBinder asBinder() override final;
 
-    bool isRemote() override { return false; }
+    bool isRemote() override final { return false; }
 
    protected:
     /**
@@ -215,9 +215,9 @@
     explicit BpCInterface(const SpAIBinder& binder) : mBinder(binder) {}
     virtual ~BpCInterface() {}
 
-    SpAIBinder asBinder() override;
+    SpAIBinder asBinder() override final;
 
-    bool isRemote() override { return AIBinder_isRemote(mBinder.get()); }
+    bool isRemote() override final { return AIBinder_isRemote(mBinder.get()); }
 
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override {
         return AIBinder_dump(asBinder().get(), fd, args, numArgs);
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 563d011..67623a6 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -27,15 +27,67 @@
 #pragma once
 
 #include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
 #include <android/binder_internal_logging.h>
 #include <android/binder_parcel.h>
 
 #include <optional>
 #include <string>
+#include <type_traits>
 #include <vector>
 
 namespace ndk {
 
+namespace {
+template <typename Test, template <typename...> class Ref>
+struct is_specialization : std::false_type {};
+
+template <template <typename...> class Ref, typename... Args>
+struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
+
+template <typename Test, template <typename...> class Ref>
+static inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
+
+// Get the first template type from a container, the T from MyClass<T, ...>.
+template <typename T>
+struct first_template_type {
+    using type = void;
+};
+
+template <template <typename...> class V, typename T, typename... Args>
+struct first_template_type<V<T, Args...>> {
+    using type = T;
+};
+
+template <typename T>
+using first_template_type_t = typename first_template_type<T>::type;
+
+// Tells if T represents NDK interface (shared_ptr<ICInterface-derived>)
+template <typename T>
+static inline constexpr bool is_interface_v = is_specialization_v<T, std::shared_ptr>&&
+        std::is_base_of_v<::ndk::ICInterface, first_template_type_t<T>>;
+
+// Tells if T represents NDK parcelable with readFromParcel/writeToParcel methods defined
+template <typename T, typename = void>
+struct is_parcelable : std::false_type {};
+
+template <typename T>
+struct is_parcelable<
+        T, std::void_t<decltype(std::declval<T>().readFromParcel(std::declval<const AParcel*>())),
+                       decltype(std::declval<T>().writeToParcel(std::declval<AParcel*>()))>>
+    : std::true_type {};
+
+template <typename T>
+static inline constexpr bool is_parcelable_v = is_parcelable<T>::value;
+
+// Tells if T represents nullable NDK parcelable (optional<parcelable> or unique_ptr<parcelable>)
+template <typename T>
+static inline constexpr bool is_nullable_parcelable_v = is_parcelable_v<first_template_type_t<T>> &&
+                                                        (is_specialization_v<T, std::optional> ||
+                                                         is_specialization_v<T, std::unique_ptr>);
+
+}  // namespace
+
 /**
  * This retrieves and allocates a vector to size 'length' and returns the underlying buffer.
  */
@@ -429,11 +481,19 @@
  */
 template <typename P>
 static inline binder_status_t AParcel_writeParcelable(AParcel* parcel, const P& p) {
-    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
-    if (status != STATUS_OK) {
-        return status;
+    if constexpr (is_interface_v<P>) {
+        if (!p) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+        return first_template_type_t<P>::writeToParcel(parcel, p);
+    } else {
+        static_assert(is_parcelable_v<P>);
+        binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+        if (status != STATUS_OK) {
+            return status;
+        }
+        return p.writeToParcel(parcel);
     }
-    return p.writeToParcel(parcel);
 }
 
 /**
@@ -441,85 +501,81 @@
  */
 template <typename P>
 static inline binder_status_t AParcel_readParcelable(const AParcel* parcel, P* p) {
-    int32_t null;
-    binder_status_t status = AParcel_readInt32(parcel, &null);
-    if (status != STATUS_OK) {
+    if constexpr (is_interface_v<P>) {
+        binder_status_t status = first_template_type_t<P>::readFromParcel(parcel, p);
+        if (status == STATUS_OK) {
+            if (!*p) {
+                return STATUS_UNEXPECTED_NULL;
+            }
+        }
         return status;
+    } else {
+        static_assert(is_parcelable_v<P>);
+        int32_t null;
+        binder_status_t status = AParcel_readInt32(parcel, &null);
+        if (status != STATUS_OK) {
+            return status;
+        }
+        if (null == 0) {
+            return STATUS_UNEXPECTED_NULL;
+        }
+        return p->readFromParcel(parcel);
     }
-    if (null == 0) {
-        return STATUS_UNEXPECTED_NULL;
-    }
-    return p->readFromParcel(parcel);
 }
 
 /**
  * Convenience API for writing a nullable parcelable.
  */
 template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
-                                                              const std::optional<P>& p) {
-    if (p == std::nullopt) {
-        return AParcel_writeInt32(parcel, 0);  // null
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel, const P& p) {
+    if constexpr (is_interface_v<P>) {
+        return first_template_type_t<P>::writeToParcel(parcel, p);
+    } else {
+        static_assert(is_nullable_parcelable_v<P>);
+        if (!p) {
+            return AParcel_writeInt32(parcel, 0);  // null
+        }
+        binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+        if (status != STATUS_OK) {
+            return status;
+        }
+        return p->writeToParcel(parcel);
     }
-    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
-    if (status != STATUS_OK) {
-        return status;
-    }
-    return p->writeToParcel(parcel);
-}
-
-/**
- * Convenience API for writing a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
-                                                              const std::unique_ptr<P>& p) {
-    if (!p) {
-        return AParcel_writeInt32(parcel, 0);  // null
-    }
-    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
-    if (status != STATUS_OK) {
-        return status;
-    }
-    return p->writeToParcel(parcel);
 }
 
 /**
  * Convenience API for reading a nullable parcelable.
  */
 template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
-                                                             std::optional<P>* p) {
-    int32_t null;
-    binder_status_t status = AParcel_readInt32(parcel, &null);
-    if (status != STATUS_OK) {
-        return status;
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel, P* p) {
+    if constexpr (is_interface_v<P>) {
+        return first_template_type_t<P>::readFromParcel(parcel, p);
+    } else if constexpr (is_specialization_v<P, std::optional>) {
+        int32_t null;
+        binder_status_t status = AParcel_readInt32(parcel, &null);
+        if (status != STATUS_OK) {
+            return status;
+        }
+        if (null == 0) {
+            *p = std::nullopt;
+            return STATUS_OK;
+        }
+        *p = std::optional<first_template_type_t<P>>(first_template_type_t<P>{});
+        return (*p)->readFromParcel(parcel);
+    } else {
+        static_assert(is_specialization_v<P, std::unique_ptr>);
+        int32_t null;
+        binder_status_t status = AParcel_readInt32(parcel, &null);
+        if (status != STATUS_OK) {
+            return status;
+        }
+        if (null == 0) {
+            p->reset();
+            return STATUS_OK;
+        }
+        *p = std::make_unique<first_template_type_t<P>>();
+        return (*p)->readFromParcel(parcel);
     }
-    if (null == 0) {
-        *p = std::nullopt;
-        return STATUS_OK;
-    }
-    *p = std::optional<P>(P{});
-    return (*p)->readFromParcel(parcel);
-}
-
-/**
- * Convenience API for reading a nullable parcelable.
- */
-template <typename P>
-static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
-                                                             std::unique_ptr<P>* p) {
-    int32_t null;
-    binder_status_t status = AParcel_readInt32(parcel, &null);
-    if (status != STATUS_OK) {
-        return status;
-    }
-    if (null == 0) {
-        p->reset();
-        return STATUS_OK;
-    }
-    *p = std::make_unique<P>();
-    return (*p)->readFromParcel(parcel);
 }
 
 /**
@@ -543,6 +599,28 @@
 }
 
 /**
+ * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_writeNullableStdVectorParcelableElement(AParcel* parcel,
+                                                                const void* vectorData,
+                                                                size_t index) {
+    const std::optional<std::vector<P>>* vector =
+            static_cast<const std::optional<std::vector<P>>*>(vectorData);
+    return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a parcelable object of type P inside a std::vector<P> at index 'index' from 'parcel'.
+ */
+template <typename P>
+binder_status_t AParcel_readNullableStdVectorParcelableElement(const AParcel* parcel,
+                                                               void* vectorData, size_t index) {
+    std::optional<std::vector<P>>* vector = static_cast<std::optional<std::vector<P>>*>(vectorData);
+    return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
+}
+
+/**
  * Writes a ScopedFileDescriptor object inside a std::vector<ScopedFileDescriptor> at index 'index'
  * to 'parcel'.
  */
@@ -551,11 +629,7 @@
         AParcel* parcel, const void* vectorData, size_t index) {
     const std::vector<ScopedFileDescriptor>* vector =
             static_cast<const std::vector<ScopedFileDescriptor>*>(vectorData);
-    int writeFd = vector->at(index).get();
-    if (writeFd < 0) {
-        return STATUS_UNEXPECTED_NULL;
-    }
-    return AParcel_writeParcelFileDescriptor(parcel, writeFd);
+    return AParcel_writeRequiredParcelFileDescriptor(parcel, vector->at(index));
 }
 
 /**
@@ -567,15 +641,79 @@
         const AParcel* parcel, void* vectorData, size_t index) {
     std::vector<ScopedFileDescriptor>* vector =
             static_cast<std::vector<ScopedFileDescriptor>*>(vectorData);
-    int readFd;
-    binder_status_t status = AParcel_readParcelFileDescriptor(parcel, &readFd);
-    if (status == STATUS_OK) {
-        if (readFd < 0) {
-            return STATUS_UNEXPECTED_NULL;
-        }
-        vector->at(index).set(readFd);
-    }
-    return status;
+    return AParcel_readRequiredParcelFileDescriptor(parcel, &vector->at(index));
+}
+
+/**
+ * Writes a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+        AParcel* parcel, const void* vectorData, size_t index) {
+    const std::optional<std::vector<ScopedFileDescriptor>>* vector =
+            static_cast<const std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+    return AParcel_writeNullableParcelFileDescriptor(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads a ScopedFileDescriptor object inside a std::optional<std::vector<ScopedFileDescriptor>> at
+ * index 'index' from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<ScopedFileDescriptor>(
+        const AParcel* parcel, void* vectorData, size_t index) {
+    std::optional<std::vector<ScopedFileDescriptor>>* vector =
+            static_cast<std::optional<std::vector<ScopedFileDescriptor>>*>(vectorData);
+    return AParcel_readNullableParcelFileDescriptor(parcel, &(*vector)->at(index));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeStdVectorParcelableElement<SpAIBinder>(AParcel* parcel,
+                                                                           const void* vectorData,
+                                                                           size_t index) {
+    const std::vector<SpAIBinder>* vector = static_cast<const std::vector<SpAIBinder>*>(vectorData);
+    return AParcel_writeRequiredStrongBinder(parcel, vector->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::vector<SpAIBinder> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readStdVectorParcelableElement<SpAIBinder>(const AParcel* parcel,
+                                                                          void* vectorData,
+                                                                          size_t index) {
+    std::vector<SpAIBinder>* vector = static_cast<std::vector<SpAIBinder>*>(vectorData);
+    return AParcel_readRequiredStrongBinder(parcel, &vector->at(index));
+}
+
+/**
+ * Writes an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * to 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_writeNullableStdVectorParcelableElement<SpAIBinder>(
+        AParcel* parcel, const void* vectorData, size_t index) {
+    const std::optional<std::vector<SpAIBinder>>* vector =
+            static_cast<const std::optional<std::vector<SpAIBinder>>*>(vectorData);
+    return AParcel_writeNullableStrongBinder(parcel, (*vector)->at(index));
+}
+
+/**
+ * Reads an SpAIBinder object inside a std::optional<std::vector<SpAIBinder>> at index 'index'
+ * from 'parcel'.
+ */
+template <>
+inline binder_status_t AParcel_readNullableStdVectorParcelableElement<SpAIBinder>(
+        const AParcel* parcel, void* vectorData, size_t index) {
+    std::optional<std::vector<SpAIBinder>>* vector =
+            static_cast<std::optional<std::vector<SpAIBinder>>*>(vectorData);
+    return AParcel_readNullableStrongBinder(parcel, &(*vector)->at(index));
 }
 
 /**
@@ -598,6 +736,30 @@
                                        AParcel_readStdVectorParcelableElement<P>);
 }
 
+/**
+ * Convenience API for writing a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeVector(AParcel* parcel,
+                                                  const std::optional<std::vector<P>>& vec) {
+    if (!vec) return AParcel_writeInt32(parcel, -1);
+    const void* vectorData = static_cast<const void*>(&vec);
+    return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec->size()),
+                                        AParcel_writeNullableStdVectorParcelableElement<P>);
+}
+
+/**
+ * Convenience API for reading a std::optional<std::vector<P>>
+ */
+template <typename P>
+static inline binder_status_t AParcel_readVector(const AParcel* parcel,
+                                                 std::optional<std::vector<P>>* vec) {
+    void* vectorData = static_cast<void*>(vec);
+    return AParcel_readParcelableArray(parcel, vectorData,
+                                       AParcel_nullableStdVectorExternalAllocator<P>,
+                                       AParcel_readNullableStdVectorParcelableElement<P>);
+}
+
 // @START
 /**
  * Writes a vector of int32_t to the next location in a non-null parcel.
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 43533c5..565542b 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -393,6 +393,14 @@
 pid_t AIBinder_getCallingPid() __INTRODUCED_IN(29);
 
 /**
+ * Determine whether the current thread is currently executing an incoming transaction.
+ *
+ * \return true if the current thread is currently executing an incoming transaction, and false
+ * otherwise.
+ */
+bool AIBinder_isHandlingTransaction() __INTRODUCED_IN(33);
+
+/**
  * This can only be called if a strong reference to this object already exists in process.
  *
  * Available since API level 29.
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index e315c79..b0217c4 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -55,4 +55,17 @@
  */
 __attribute__((weak, warn_unused_result)) const char* AIBinder_getCallingSid() __INTRODUCED_IN(31);
 
+/**
+ * Sets a minimum scheduler policy for all transactions coming into this
+ * AIBinder.
+ *
+ * This must be called before the object is sent to another process.
+ * Aborts on invalid values. Not thread safe.
+ *
+ * \param binder local server binder to set the policy for
+ * \param policy scheduler policy as defined in linux UAPI
+ * \param priority priority. [-20..19] for SCHED_NORMAL, [1..99] for RT
+ */
+void AIBinder_setMinSchedulerPolicy(AIBinder* binder, int policy, int priority) __INTRODUCED_IN(33);
+
 __END_DECLS
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 8605686..197c0a1 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -119,11 +119,11 @@
     AIBinder_setRequestingSid; # apex
     AParcel_markSensitive; # systemapi llndk
     AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_forceLazyServicesPersist; # llndk
+    AServiceManager_forceLazyServicesPersist; # apex llndk
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_isUpdatableViaApex; # apex
     AServiceManager_reRegister; # llndk
-    AServiceManager_registerLazyService; # llndk
+    AServiceManager_registerLazyService; # apex llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
     AServiceManager_waitForService; # apex llndk
@@ -145,6 +145,8 @@
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
+    AIBinder_isHandlingTransaction;
+    AIBinder_setMinSchedulerPolicy; # llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d9d7caf..4561d6e 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,6 +17,29 @@
     rustlibs: [
         "liblibc",
         "libbinder_ndk_sys",
+        "libdowncast_rs",
+    ],
+    host_supported: true,
+    vendor_available: true,
+    target: {
+        darwin: {
+            enabled: false,
+        }
+    },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.compos",
+        "com.android.virt",
+    ],
+}
+
+rust_library {
+    name: "libbinder_tokio_rs",
+    crate_name: "binder_tokio",
+    srcs: ["binder_tokio/lib.rs"],
+    rustlibs: [
+        "libbinder_rs",
+        "libtokio",
     ],
     host_supported: true,
     target: {
@@ -42,6 +65,7 @@
         "libbinder_ndk",
     ],
     host_supported: true,
+    vendor_available: true,
     target: {
         darwin: {
             enabled: false,
@@ -83,6 +107,7 @@
         "libbinder_ndk",
     ],
     host_supported: true,
+    vendor_available: true,
 
     // Currently necessary for host builds
     // TODO(b/31559095): bionic on host should define this
@@ -133,6 +158,7 @@
     rustlibs: [
         "liblibc",
         "libbinder_ndk_sys",
+        "libdowncast_rs",
     ],
 }
 
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
new file mode 100644
index 0000000..91047be
--- /dev/null
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+//! This crate lets you use the Tokio `spawn_blocking` pool with AIDL in async
+//! Rust code.
+//!
+//! This crate works by defining a type [`Tokio`], which you can use as the
+//! generic parameter in the async version of the trait generated by the AIDL
+//! compiler.
+//! ```text
+//! use binder_tokio::Tokio;
+//!
+//! binder::get_interface::<dyn SomeAsyncInterface<Tokio>>("...").
+//! ```
+//!
+//! [`Tokio`]: crate::Tokio
+
+use binder::public_api::{BinderAsyncPool, BoxFuture, Strong};
+use binder::{FromIBinder, StatusCode};
+use std::future::Future;
+
+/// Retrieve an existing service for a particular interface, sleeping for a few
+/// seconds if it doesn't yet exist.
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+    if binder::is_handling_transaction() {
+        // See comment in the BinderAsyncPool impl.
+        return binder::public_api::get_interface::<T>(name);
+    }
+
+    let name = name.to_string();
+    let res = tokio::task::spawn_blocking(move || {
+        binder::public_api::get_interface::<T>(&name)
+    }).await;
+
+    // The `is_panic` branch is not actually reachable in Android as we compile
+    // with `panic = abort`.
+    match res {
+        Ok(Ok(service)) => Ok(service),
+        Ok(Err(err)) => Err(err),
+        Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+        Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+        Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+    }
+}
+
+/// Retrieve an existing service for a particular interface, or start it if it
+/// is configured as a dynamic service and isn't yet started.
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+    if binder::is_handling_transaction() {
+        // See comment in the BinderAsyncPool impl.
+        return binder::public_api::wait_for_interface::<T>(name);
+    }
+
+    let name = name.to_string();
+    let res = tokio::task::spawn_blocking(move || {
+        binder::public_api::wait_for_interface::<T>(&name)
+    }).await;
+
+    // The `is_panic` branch is not actually reachable in Android as we compile
+    // with `panic = abort`.
+    match res {
+        Ok(Ok(service)) => Ok(service),
+        Ok(Err(err)) => Err(err),
+        Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+        Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION),
+        Err(_) => Err(StatusCode::UNKNOWN_ERROR),
+    }
+}
+
+/// Use the Tokio `spawn_blocking` pool with AIDL.
+pub enum Tokio {}
+
+impl BinderAsyncPool for Tokio {
+    fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+    where
+        F1: FnOnce() -> A,
+        F2: FnOnce(A) -> Fut,
+        Fut: Future<Output = Result<B, E>>,
+        F1: Send + 'static,
+        F2: Send + 'a,
+        Fut: Send + 'a,
+        A: Send + 'static,
+        B: Send + 'a,
+        E: From<crate::StatusCode>,
+    {
+        if binder::is_handling_transaction() {
+            // We are currently on the thread pool for a binder server, so we should execute the
+            // transaction on the current thread so that the binder kernel driver is able to apply
+            // its deadlock prevention strategy to the sub-call.
+            //
+            // 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();
+            Box::pin(after_spawn(result))
+        } else {
+            let handle = tokio::task::spawn_blocking(spawn_me);
+            Box::pin(async move {
+                // The `is_panic` branch is not actually reachable in Android as we compile
+                // with `panic = abort`.
+                match handle.await {
+                    Ok(res) => after_spawn(res).await,
+                    Err(e) if e.is_panic() => std::panic::resume_unwind(e.into_panic()),
+                    Err(e) if e.is_cancelled() => Err(StatusCode::FAILED_TRANSACTION.into()),
+                    Err(_) => Err(StatusCode::UNKNOWN_ERROR.into()),
+                }
+            })
+        }
+    }
+}
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 41ceee5..d09ac83 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,12 +17,13 @@
 //! Trait definitions for binder objects
 
 use crate::error::{status_t, Result, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::{Parcel, BorrowedParcel};
 use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
 use crate::sys;
 
 use std::borrow::Borrow;
 use std::cmp::Ordering;
+use std::convert::TryFrom;
 use std::ffi::{c_void, CStr, CString};
 use std::fmt;
 use std::fs::File;
@@ -70,6 +71,7 @@
 /// An interface can promise to be a stable vendor interface ([`Vintf`]), or
 /// makes no stability guarantees ([`Local`]). [`Local`] is
 /// currently the default stability.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
 pub enum Stability {
     /// Default stability, visible to other modules in the same compilation
     /// context (e.g. modules on system.img)
@@ -85,6 +87,28 @@
     }
 }
 
+impl From<Stability> for i32 {
+    fn from(stability: Stability) -> i32 {
+        use Stability::*;
+        match stability {
+            Local => 0,
+            Vintf => 1,
+        }
+    }
+}
+
+impl TryFrom<i32> for Stability {
+    type Error = StatusCode;
+    fn try_from(stability: i32) -> Result<Stability> {
+        use Stability::*;
+        match stability {
+            0 => Ok(Local),
+            1 => Ok(Vintf),
+            _ => Err(StatusCode::BAD_VALUE)
+        }
+    }
+}
+
 /// A local service that can be remotable via Binder.
 ///
 /// An object that implement this interface made be made into a Binder service
@@ -105,7 +129,7 @@
     /// Handle and reply to a request to invoke a transaction on this object.
     ///
     /// `reply` may be [`None`] if the sender does not expect a reply.
-    fn on_transact(&self, code: TransactionCode, data: &Parcel, reply: &mut Parcel) -> Result<()>;
+    fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
 
     /// Handle a request to invoke the dump transaction on this
     /// object.
@@ -143,6 +167,7 @@
     fn ping_binder(&mut self) -> Result<()>;
 
     /// Indicate that the service intends to receive caller security contexts.
+    #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool);
 
     /// Dump this object to the given file handle
@@ -182,14 +207,14 @@
     /// * `flags` - Transaction flags, e.g. marking the transaction as
     ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
     /// * `input_callback` A callback for building the `Parcel`.
-    fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
+    fn transact<F: FnOnce(BorrowedParcel<'_>) -> Result<()>>(
         &self,
         code: TransactionCode,
         flags: TransactionFlags,
         input_callback: F,
     ) -> Result<Parcel> {
         let mut parcel = self.prepare_transact()?;
-        input_callback(&mut parcel)?;
+        input_callback(parcel.borrowed())?;
         self.submit_transact(code, parcel, flags)
     }
 }
@@ -451,8 +476,8 @@
 ///     fn on_transact(
 ///         &self,
 ///         code: TransactionCode,
-///         data: &Parcel,
-///         reply: &mut Parcel,
+///         data: &BorrowedParcel,
+///         reply: &mut BorrowedParcel,
 ///     ) -> Result<()> {
 ///         // ...
 ///     }
@@ -611,6 +636,7 @@
 pub struct BinderFeatures {
     /// Indicates that the service intends to receive caller security contexts. This must be true
     /// for `ThreadState::with_calling_sid` to work.
+    #[cfg(not(android_vndk))]
     pub set_requesting_sid: bool,
     // Ensure that clients include a ..BinderFeatures::default() to preserve backwards compatibility
     // when new fields are added. #[non_exhaustive] doesn't work because it prevents struct
@@ -631,13 +657,13 @@
 /// have the following type:
 ///
 /// ```
-/// # use binder::{Interface, TransactionCode, Parcel};
+/// # use binder::{Interface, TransactionCode, BorrowedParcel};
 /// # trait Placeholder {
 /// fn on_transact(
 ///     service: &dyn Interface,
 ///     code: TransactionCode,
-///     data: &Parcel,
-///     reply: &mut Parcel,
+///     data: &BorrowedParcel,
+///     reply: &mut BorrowedParcel,
 /// ) -> binder::Result<()>;
 /// # }
 /// ```
@@ -652,7 +678,7 @@
 /// using the provided function, `on_transact`.
 ///
 /// ```
-/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, Parcel};
+/// use binder::{declare_binder_interface, Binder, Interface, TransactionCode, BorrowedParcel};
 ///
 /// pub trait IServiceManager: Interface {
 ///     // remote methods...
@@ -668,8 +694,8 @@
 /// fn on_transact(
 ///     service: &dyn IServiceManager,
 ///     code: TransactionCode,
-///     data: &Parcel,
-///     reply: &mut Parcel,
+///     data: &BorrowedParcel,
+///     reply: &mut BorrowedParcel,
 /// ) -> binder::Result<()> {
 ///     // ...
 ///     Ok(())
@@ -689,12 +715,14 @@
         $interface:path[$descriptor:expr] {
             native: $native:ident($on_transact:path),
             proxy: $proxy:ident,
+            $(async: $async_interface:ident,)?
         }
     } => {
         $crate::declare_binder_interface! {
             $interface[$descriptor] {
                 native: $native($on_transact),
                 proxy: $proxy {},
+                $(async: $async_interface,)?
                 stability: $crate::Stability::default(),
             }
         }
@@ -704,6 +732,7 @@
         $interface:path[$descriptor:expr] {
             native: $native:ident($on_transact:path),
             proxy: $proxy:ident,
+            $(async: $async_interface:ident,)?
             stability: $stability:expr,
         }
     } => {
@@ -711,6 +740,7 @@
             $interface[$descriptor] {
                 native: $native($on_transact),
                 proxy: $proxy {},
+                $(async: $async_interface,)?
                 stability: $stability,
             }
         }
@@ -722,6 +752,7 @@
             proxy: $proxy:ident {
                 $($fname:ident: $fty:ty = $finit:expr),*
             },
+            $(async: $async_interface:ident,)?
         }
     } => {
         $crate::declare_binder_interface! {
@@ -730,6 +761,7 @@
                 proxy: $proxy {
                     $($fname: $fty = $finit),*
                 },
+                $(async: $async_interface,)?
                 stability: $crate::Stability::default(),
             }
         }
@@ -741,6 +773,7 @@
             proxy: $proxy:ident {
                 $($fname:ident: $fty:ty = $finit:expr),*
             },
+            $(async: $async_interface:ident,)?
             stability: $stability:expr,
         }
     } => {
@@ -752,6 +785,7 @@
                 proxy: $proxy {
                     $($fname: $fty = $finit),*
                 },
+                $(async: $async_interface,)?
                 stability: $stability,
             }
         }
@@ -767,6 +801,8 @@
                 $($fname:ident: $fty:ty = $finit:expr),*
             },
 
+            $( async: $async_interface:ident, )?
+
             stability: $stability:expr,
         }
     } => {
@@ -803,6 +839,7 @@
             /// Create a new binder service.
             pub fn new_binder<T: $interface + Sync + Send + 'static>(inner: T, features: $crate::BinderFeatures) -> $crate::Strong<dyn $interface> {
                 let mut binder = $crate::Binder::new_with_stability($native(Box::new(inner)), $stability);
+                #[cfg(not(android_vndk))]
                 $crate::IBinderInternal::set_requesting_sid(&mut binder, features.set_requesting_sid);
                 $crate::Strong::new(Box::new(binder))
             }
@@ -813,7 +850,7 @@
                 $descriptor
             }
 
-            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::Parcel, reply: &mut $crate::Parcel) -> $crate::Result<()> {
+            fn on_transact(&self, code: $crate::TransactionCode, data: &$crate::BorrowedParcel<'_>, reply: &mut $crate::BorrowedParcel<'_>) -> $crate::Result<()> {
                 match $on_transact(&*self.0, code, data, reply) {
                     // The C++ backend converts UNEXPECTED_NULL into an exception
                     Err($crate::StatusCode::UNEXPECTED_NULL) => {
@@ -888,19 +925,19 @@
         where
             dyn $interface: $crate::Interface
         {
-            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 let binder = $crate::Interface::as_binder(self);
                 parcel.write(&binder)
             }
         }
 
         impl $crate::parcel::SerializeOption for dyn $interface + '_ {
-            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 parcel.write(&this.map($crate::Interface::as_binder))
             }
         }
 
-        impl std::fmt::Debug for dyn $interface {
+        impl std::fmt::Debug for dyn $interface + '_ {
             fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
                 f.pad(stringify!($interface))
             }
@@ -914,6 +951,73 @@
                     .expect(concat!("Error cloning interface ", stringify!($interface)))
             }
         }
+
+        $(
+        // Async interface trait implementations.
+        impl<P: $crate::BinderAsyncPool> $crate::FromIBinder for dyn $async_interface<P> {
+            fn try_from(mut ibinder: $crate::SpIBinder) -> $crate::Result<$crate::Strong<dyn $async_interface<P>>> {
+                use $crate::AssociateClass;
+
+                let existing_class = ibinder.get_class();
+                if let Some(class) = existing_class {
+                    if class != <$native as $crate::Remotable>::get_class() &&
+                        class.get_descriptor() == <$native as $crate::Remotable>::get_descriptor()
+                    {
+                        // The binder object's descriptor string matches what we
+                        // expect. We still need to treat this local or already
+                        // associated object as remote, because we can't cast it
+                        // into a Rust service object without a matching class
+                        // pointer.
+                        return Ok($crate::Strong::new(Box::new(<$proxy as $crate::Proxy>::from_binder(ibinder)?)));
+                    }
+                }
+
+                if ibinder.associate_class(<$native as $crate::Remotable>::get_class()) {
+                    let service: $crate::Result<$crate::Binder<$native>> =
+                        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::Proxy>::from_binder(ibinder)?)));
+                    }
+                }
+
+                Err($crate::StatusCode::BAD_TYPE.into())
+            }
+        }
+
+        impl<P: $crate::BinderAsyncPool> $crate::parcel::Serialize for dyn $async_interface<P> + '_ {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
+                let binder = $crate::Interface::as_binder(self);
+                parcel.write(&binder)
+            }
+        }
+
+        impl<P: $crate::BinderAsyncPool> $crate::parcel::SerializeOption for dyn $async_interface<P> + '_ {
+            fn serialize_option(this: Option<&Self>, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
+                parcel.write(&this.map($crate::Interface::as_binder))
+            }
+        }
+
+        impl<P: $crate::BinderAsyncPool> std::fmt::Debug for dyn $async_interface<P> + '_ {
+            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                f.pad(stringify!($async_interface))
+            }
+        }
+
+        /// Convert a &dyn $async_interface to Strong<dyn $async_interface>
+        impl<P: $crate::BinderAsyncPool> std::borrow::ToOwned for dyn $async_interface<P> {
+            type Owned = $crate::Strong<dyn $async_interface<P>>;
+            fn to_owned(&self) -> Self::Owned {
+                self.as_binder().into_interface()
+                    .expect(concat!("Error cloning interface ", stringify!($async_interface)))
+            }
+        }
+        )?
     };
 }
 
@@ -939,26 +1043,26 @@
         }
 
         impl $crate::parcel::Serialize for $enum {
-            fn serialize(&self, parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize(&self, parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 parcel.write(&self.0)
             }
         }
 
         impl $crate::parcel::SerializeArray for $enum {
-            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::Parcel) -> $crate::Result<()> {
+            fn serialize_array(slice: &[Self], parcel: &mut $crate::parcel::BorrowedParcel<'_>) -> $crate::Result<()> {
                 let v: Vec<$backing> = slice.iter().map(|x| x.0).collect();
                 <$backing as binder::parcel::SerializeArray>::serialize_array(&v[..], parcel)
             }
         }
 
         impl $crate::parcel::Deserialize for $enum {
-            fn deserialize(parcel: &$crate::parcel::Parcel) -> $crate::Result<Self> {
+            fn deserialize(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Self> {
                 parcel.read().map(Self)
             }
         }
 
         impl $crate::parcel::DeserializeArray for $enum {
-            fn deserialize_array(parcel: &$crate::parcel::Parcel) -> $crate::Result<Option<Vec<Self>>> {
+            fn deserialize_array(parcel: &$crate::parcel::BorrowedParcel<'_>) -> $crate::Result<Option<Vec<Self>>> {
                 let v: Option<Vec<$backing>> =
                     <$backing as binder::parcel::DeserializeArray>::deserialize_array(parcel)?;
                 Ok(v.map(|v| v.into_iter().map(Self).collect()))
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
new file mode 100644
index 0000000..214c0b5
--- /dev/null
+++ b/libs/binder/rust/src/binder_async.rs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+use std::future::Future;
+use std::pin::Pin;
+
+/// A type alias for a pinned, boxed future that lets you write shorter code without littering it
+/// with Pin and Send bounds.
+pub type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
+
+/// A thread pool for running binder transactions.
+pub trait BinderAsyncPool {
+    /// This function should conceptually behave like this:
+    ///
+    /// ```text
+    /// let result = spawn_thread(|| spawn_me()).await;
+    /// return after_spawn(result).await;
+    /// ```
+    ///
+    /// If the spawning fails for some reason, the method may also skip the `after_spawn` closure
+    /// and immediately return an error.
+    ///
+    /// The only difference between different implementations should be which
+    /// `spawn_thread` method is used. For Tokio, it would be `tokio::task::spawn_blocking`.
+    ///
+    /// This method has the design it has because the only way to define a trait that
+    /// allows the return type of the spawn to be chosen by the caller is to return a
+    /// boxed `Future` trait object, and including `after_spawn` in the trait function
+    /// allows the caller to avoid double-boxing if they want to do anything to the value
+    /// returned from the spawned thread.
+    fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+    where
+        F1: FnOnce() -> A,
+        F2: FnOnce(A) -> Fut,
+        Fut: Future<Output = Result<B, E>>,
+        F1: Send + 'static,
+        F2: Send + 'a,
+        Fut: Send + 'a,
+        A: Send + 'static,
+        B: Send + 'a,
+        E: From<crate::StatusCode>;
+}
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 7e8e3a5..b94dfa1 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -50,8 +50,8 @@
 //! fn on_transact(
 //!     service: &dyn ITest,
 //!     code: TransactionCode,
-//!     _data: &Parcel,
-//!     reply: &mut Parcel,
+//!     _data: &BorrowedParcel,
+//!     reply: &mut BorrowedParcel,
 //! ) -> binder::Result<()> {
 //!     match code {
 //!         SpIBinder::FIRST_CALL_TRANSACTION => {
@@ -98,6 +98,7 @@
 
 #[macro_use]
 mod binder;
+mod binder_async;
 mod error;
 mod native;
 mod state;
@@ -111,9 +112,10 @@
     Stability, Strong, TransactionCode, TransactionFlags, Weak, FIRST_CALL_TRANSACTION,
     FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
 };
+pub use crate::binder_async::{BoxFuture, BinderAsyncPool};
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
-pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
-pub use parcel::Parcel;
+pub use native::{add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service, Binder};
+pub use parcel::{BorrowedParcel, Parcel};
 pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
 pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
 pub use state::{ProcessState, ThreadState};
@@ -127,14 +129,15 @@
 
 /// The public API usable outside AIDL-generated interface crates.
 pub mod public_api {
-    pub use super::parcel::ParcelFileDescriptor;
+    pub use super::parcel::{ParcelFileDescriptor, ParcelableHolder};
     pub use super::{
         add_service, force_lazy_services_persist, get_interface, register_lazy_service,
         wait_for_interface,
     };
     pub use super::{
-        BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
-        Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
+        BinderAsyncPool, BinderFeatures, BoxFuture, DeathRecipient, ExceptionCode, IBinder,
+        Interface, ProcessState, SpIBinder, Status, StatusCode, Strong, ThreadState, Weak,
+        WpIBinder,
     };
 
     /// Binder result containing a [`Status`] on error.
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index a91092e..b7c7ae4 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -18,7 +18,7 @@
     AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
 };
 use crate::error::{status_result, status_t, Result, StatusCode};
-use crate::parcel::{Parcel, Serialize};
+use crate::parcel::{BorrowedParcel, Serialize};
 use crate::proxy::SpIBinder;
 use crate::sys;
 
@@ -161,8 +161,8 @@
     ///        # fn on_transact(
     ///        #     service: &dyn IBar,
     ///        #     code: TransactionCode,
-    ///        #     data: &Parcel,
-    ///        #     reply: &mut Parcel,
+    ///        #     data: &BorrowedParcel,
+    ///        #     reply: &mut BorrowedParcel,
     ///        # ) -> binder::Result<()> {
     ///        #     Ok(())
     ///        # }
@@ -212,7 +212,7 @@
 
     /// Mark this binder object with local stability, which is vendor if we are
     /// building for the VNDK and system otherwise.
-    #[cfg(vendor_ndk)]
+    #[cfg(any(vendor_ndk, android_vndk))]
     fn mark_local_stability(&mut self) {
         unsafe {
             // Safety: Self always contains a valid `AIBinder` pointer, so
@@ -223,7 +223,7 @@
 
     /// Mark this binder object with local stability, which is vendor if we are
     /// building for the VNDK and system otherwise.
-    #[cfg(not(vendor_ndk))]
+    #[cfg(not(any(vendor_ndk, android_vndk)))]
     fn mark_local_stability(&mut self) {
         unsafe {
             // Safety: Self always contains a valid `AIBinder` pointer, so
@@ -277,8 +277,8 @@
         reply: *mut sys::AParcel,
     ) -> status_t {
         let res = {
-            let mut reply = Parcel::borrowed(reply).unwrap();
-            let data = Parcel::borrowed(data as *mut sys::AParcel).unwrap();
+            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);
             binder.on_transact(code, &data, &mut reply)
@@ -384,7 +384,7 @@
 }
 
 impl<B: Remotable> Serialize for Binder<B> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(Some(&self.as_binder()))
     }
 }
@@ -503,8 +503,8 @@
     fn on_transact(
         &self,
         _code: TransactionCode,
-        _data: &Parcel,
-        _reply: &mut Parcel,
+        _data: &BorrowedParcel<'_>,
+        _reply: &mut BorrowedParcel<'_>,
     ) -> Result<()> {
         Ok(())
     }
@@ -517,3 +517,12 @@
 }
 
 impl Interface for () {}
+
+/// 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()
+    }
+}
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index dad89ec..206b90c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -21,19 +21,22 @@
 use crate::proxy::SpIBinder;
 use crate::sys;
 
-use std::cell::RefCell;
 use std::convert::TryInto;
+use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
-use std::ptr;
+use std::ptr::{self, NonNull};
 use std::fmt;
 
 mod file_descriptor;
 mod parcelable;
+mod parcelable_holder;
 
 pub use self::file_descriptor::ParcelFileDescriptor;
 pub use self::parcelable::{
     Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+    Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
 };
+pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
 
 /// Container for a message (data and object references) that can be sent
 /// through Binder.
@@ -42,40 +45,42 @@
 /// other side of the IPC, and references to live Binder objects that will
 /// result in the other side receiving a proxy Binder connected with the
 /// original Binder in the Parcel.
-pub enum Parcel {
-    /// Owned parcel pointer
-    Owned(*mut sys::AParcel),
-    /// Borrowed parcel pointer (will not be destroyed on drop)
-    Borrowed(*mut sys::AParcel),
+///
+/// This type represents a parcel that is owned by Rust code.
+#[repr(transparent)]
+pub struct Parcel {
+    ptr: NonNull<sys::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 {
-        match *self {
-            Self::Owned(x) | Self::Borrowed(x) => x,
-        }
-    }
+/// 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 {}
 
-    fn as_native_mut(&mut self) -> *mut sys::AParcel {
-        match *self {
-            Self::Owned(x) | Self::Borrowed(x) => x,
-        }
-    }
+/// Container for a message (data and object references) that can be sent
+/// through Binder.
+///
+/// This object is a borrowed variant of [`Parcel`]. It is a separate type from
+/// `&mut Parcel` because it is not valid to `mem::swap` two parcels.
+#[repr(transparent)]
+pub struct BorrowedParcel<'a> {
+    ptr: NonNull<sys::AParcel>,
+    _lifetime: PhantomData<&'a mut Parcel>,
 }
 
 impl Parcel {
-    /// Create a borrowed reference to a parcel object from a raw pointer.
-    ///
-    /// # Safety
-    ///
-    /// This constructor is safe if the raw pointer parameter is either null
-    /// (resulting in `None`), or a valid pointer to an `AParcel` object.
-    pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
-        ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
+    /// 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()
+        };
+        Self {
+            ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
+        }
     }
 
     /// Create an owned reference to a parcel object from a raw pointer.
@@ -86,28 +91,129 @@
     /// (resulting in `None`), or a valid pointer to an `AParcel` object. The
     /// parcel object must be owned by the caller prior to this call, as this
     /// constructor takes ownership of the parcel and will destroy it on drop.
-    pub(crate) unsafe fn owned(ptr: *mut sys::AParcel) -> Option<Parcel> {
-        ptr.as_mut().map(|ptr| Self::Owned(ptr))
+    ///
+    /// Additionally, the caller must guarantee that it is valid to take
+    /// ownership of the AParcel object. All future access to the AParcel
+    /// must happen through this `Parcel`.
+    ///
+    /// Because `Parcel` implements `Send`, the pointer must never point to any
+    /// thread-local data, e.g., a variable on the stack, either directly or
+    /// indirectly.
+    pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<Parcel> {
+        NonNull::new(ptr).map(|ptr| Self { ptr })
     }
 
-    /// Consume the parcel, transferring ownership to the caller if the parcel
-    /// was owned.
-    pub(crate) fn into_raw(mut self) -> *mut sys::AParcel {
-        let ptr = self.as_native_mut();
+    /// Consume the parcel, transferring ownership to the caller.
+    pub(crate) fn into_raw(self) -> *mut sys::AParcel {
+        let ptr = self.ptr.as_ptr();
         let _ = ManuallyDrop::new(self);
         ptr
     }
 
-    pub(crate) fn is_owned(&self) -> bool {
-        match *self {
-            Self::Owned(_) => true,
-            Self::Borrowed(_) => false,
+    /// Get a borrowed view into the contents of this `Parcel`.
+    pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+        // Safety: The raw pointer is a valid pointer to an AParcel, and the
+        // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+        // borrow checker will ensure that the `AParcel` can only be accessed
+        // via the `BorrowParcel` until it goes out of scope.
+        BorrowedParcel {
+            ptr: self.ptr,
+            _lifetime: PhantomData,
+        }
+    }
+
+    /// Get an immutable borrowed view into the contents of this `Parcel`.
+    pub fn borrowed_ref(&self) -> &BorrowedParcel<'_> {
+        // Safety: Parcel and BorrowedParcel are both represented in the same
+        // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
+        // so casting references as done here is valid.
+        unsafe {
+            &*(self as *const Parcel as *const BorrowedParcel<'_>)
         }
     }
 }
 
+impl Default for Parcel {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Clone for Parcel {
+    fn clone(&self) -> Self {
+        let mut new_parcel = Self::new();
+        new_parcel
+            .borrowed()
+            .append_all_from(self.borrowed_ref())
+            .expect("Failed to append from Parcel");
+        new_parcel
+    }
+}
+
+impl<'a> BorrowedParcel<'a> {
+    /// Create a borrowed reference to a parcel object from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// This constructor is safe if the raw pointer parameter is either null
+    /// (resulting in `None`), or a valid pointer to an `AParcel` object.
+    ///
+    /// Since the raw pointer is not restricted by any lifetime, the lifetime on
+    /// the returned `BorrowedParcel` object can be chosen arbitrarily by the
+    /// caller. The caller must ensure it is valid to mutably borrow the AParcel
+    /// for the duration of the lifetime that the caller chooses. Note that
+    /// since this is a mutable borrow, it must have exclusive access to the
+    /// AParcel for the duration of the borrow.
+    pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
+        Some(Self {
+            ptr: NonNull::new(ptr)?,
+            _lifetime: PhantomData,
+        })
+    }
+
+    /// Get a sub-reference to this reference to the parcel.
+    pub fn reborrow(&mut self) -> BorrowedParcel<'_> {
+        // Safety: The raw pointer is a valid pointer to an AParcel, and the
+        // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
+        // borrow checker will ensure that the `AParcel` can only be accessed
+        // via the `BorrowParcel` until it goes out of scope.
+        BorrowedParcel {
+            ptr: self.ptr,
+            _lifetime: PhantomData,
+        }
+    }
+}
+
+/// # 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()
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AParcel {
+        self.ptr.as_ptr()
+    }
+}
+
+/// # 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()
+    }
+
+    fn as_native_mut(&mut self) -> *mut sys::AParcel {
+        self.ptr.as_ptr()
+    }
+}
+
 // Data serialization methods
-impl Parcel {
+impl<'a> BorrowedParcel<'a> {
     /// Data written to parcelable is zero'd before being deleted or reallocated.
     pub fn mark_sensitive(&mut self) {
         unsafe {
@@ -116,12 +222,12 @@
         }
     }
 
-    /// Write a type that implements [`Serialize`] to the `Parcel`.
+    /// Write a type that implements [`Serialize`] to the parcel.
     pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
         parcelable.serialize(self)
     }
 
-    /// Writes the length of a slice to the `Parcel`.
+    /// Writes the length of a slice to the parcel.
     ///
     /// This is used in AIDL-generated client side code to indicate the
     /// allocated space for an output array parameter.
@@ -134,7 +240,7 @@
         }
     }
 
-    /// Perform a series of writes to the `Parcel`, prepended with the length
+    /// Perform a series of writes to the parcel, prepended with the length
     /// (in bytes) of the written data.
     ///
     /// The length `0i32` will be written to the parcel first, followed by the
@@ -148,7 +254,7 @@
     ///
     /// ```
     /// # use binder::{Binder, Interface, Parcel};
-    /// # let mut parcel = Parcel::Owned(std::ptr::null_mut());
+    /// # let mut parcel = Parcel::new();
     /// parcel.sized_write(|subparcel| {
     ///     subparcel.write(&1u32)?;
     ///     subparcel.write(&2u32)?;
@@ -162,14 +268,14 @@
     /// [16i32, 1u32, 2u32, 3u32]
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
-    where for<'a>
-        F: Fn(&'a WritableSubParcel<'a>) -> Result<()>
+    where
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
     {
         let start = self.get_data_position();
         self.write(&0i32)?;
         {
-            let subparcel = WritableSubParcel(RefCell::new(self));
-            f(&subparcel)?;
+            let mut subparcel = WritableSubParcel(self.reborrow());
+            f(&mut subparcel)?;
         }
         let end = self.get_data_position();
         unsafe {
@@ -186,8 +292,8 @@
     /// Returns the current position in the parcel data.
     pub fn get_data_position(&self) -> i32 {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
-            // and this call is otherwise safe.
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
+            // `AParcel`, and this call is otherwise safe.
             sys::AParcel_getDataPosition(self.as_native())
         }
     }
@@ -195,8 +301,8 @@
     /// Returns the total size of the parcel.
     pub fn get_data_size(&self) -> i32 {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an `AParcel`,
-            // and this call is otherwise safe.
+            // Safety: `BorrowedParcel` always contains a valid pointer to an
+            // `AParcel`, and this call is otherwise safe.
             sys::AParcel_getDataSize(self.as_native())
         }
     }
@@ -213,29 +319,145 @@
     pub unsafe fn set_data_position(&self, pos: i32) -> Result<()> {
         status_result(sys::AParcel_setDataPosition(self.as_native(), pos))
     }
+
+    /// Append a subset of another parcel.
+    ///
+    /// This appends `size` bytes of data from `other` starting at offset
+    /// `start` to the current parcel, or returns an error if not possible.
+    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+        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)
+    }
+
+    /// Append the contents of another parcel.
+    pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+        // Safety: `BorrowedParcel` always contains a valid pointer to an
+        // `AParcel`, and this call is otherwise safe.
+        let size = unsafe { sys::AParcel_getDataSize(other.as_native()) };
+        self.append_from(other, 0, size)
+    }
 }
 
-/// A segment of a writable parcel, used for [`Parcel::sized_write`].
-pub struct WritableSubParcel<'a>(RefCell<&'a mut Parcel>);
+/// A segment of a writable parcel, used for [`BorrowedParcel::sized_write`].
+pub struct WritableSubParcel<'a>(BorrowedParcel<'a>);
 
 impl<'a> WritableSubParcel<'a> {
     /// Write a type that implements [`Serialize`] to the sub-parcel.
-    pub fn write<S: Serialize + ?Sized>(&self, parcelable: &S) -> Result<()> {
-        parcelable.serialize(&mut *self.0.borrow_mut())
+    pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+        parcelable.serialize(&mut self.0)
+    }
+}
+
+impl Parcel {
+    /// Data written to parcelable is zero'd before being deleted or reallocated.
+    pub fn mark_sensitive(&mut self) {
+        self.borrowed().mark_sensitive()
+    }
+
+    /// Write a type that implements [`Serialize`] to the parcel.
+    pub fn write<S: Serialize + ?Sized>(&mut self, parcelable: &S) -> Result<()> {
+        self.borrowed().write(parcelable)
+    }
+
+    /// Writes the length of a slice to the parcel.
+    ///
+    /// This is used in AIDL-generated client side code to indicate the
+    /// allocated space for an output array parameter.
+    pub fn write_slice_size<T>(&mut self, slice: Option<&[T]>) -> Result<()> {
+        self.borrowed().write_slice_size(slice)
+    }
+
+    /// Perform a series of writes to the parcel, prepended with the length
+    /// (in bytes) of the written data.
+    ///
+    /// The length `0i32` will be written to the parcel first, followed by the
+    /// writes performed by the callback. The initial length will then be
+    /// updated to the length of all data written by the callback, plus the
+    /// size of the length elemement itself (4 bytes).
+    ///
+    /// # Examples
+    ///
+    /// After the following call:
+    ///
+    /// ```
+    /// # use binder::{Binder, Interface, Parcel};
+    /// # let mut parcel = Parcel::new();
+    /// parcel.sized_write(|subparcel| {
+    ///     subparcel.write(&1u32)?;
+    ///     subparcel.write(&2u32)?;
+    ///     subparcel.write(&3u32)
+    /// });
+    /// ```
+    ///
+    /// `parcel` will contain the following:
+    ///
+    /// ```ignore
+    /// [16i32, 1u32, 2u32, 3u32]
+    /// ```
+    pub fn sized_write<F>(&mut self, f: F) -> Result<()>
+    where
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+    {
+        self.borrowed().sized_write(f)
+    }
+
+    /// Returns the current position in the parcel data.
+    pub fn get_data_position(&self) -> i32 {
+        self.borrowed_ref().get_data_position()
+    }
+
+    /// Returns the total size of the parcel.
+    pub fn get_data_size(&self) -> i32 {
+        self.borrowed_ref().get_data_size()
+    }
+
+    /// Move the current read/write position in the parcel.
+    ///
+    /// # Safety
+    ///
+    /// This method is safe if `pos` is less than the current size of the parcel
+    /// data buffer. Otherwise, we are relying on correct bounds checking in the
+    /// Parcel C++ code on every subsequent read or write to this parcel. If all
+    /// 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)
+    }
+
+    /// Append a subset of another parcel.
+    ///
+    /// This appends `size` bytes of data from `other` starting at offset
+    /// `start` to the current parcel, or returns an error if not possible.
+    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+        self.borrowed().append_from(other, start, size)
+    }
+
+    /// Append the contents of another parcel.
+    pub fn append_all_from(&mut self, other: &impl AsNative<sys::AParcel>) -> Result<()> {
+        self.borrowed().append_all_from(other)
     }
 }
 
 // Data deserialization methods
-impl Parcel {
-    /// Attempt to read a type that implements [`Deserialize`] from this
-    /// `Parcel`.
+impl<'a> BorrowedParcel<'a> {
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel.
     pub fn read<D: Deserialize>(&self) -> Result<D> {
         D::deserialize(self)
     }
 
-    /// Attempt to read a type that implements [`Deserialize`] from this
-    /// `Parcel` onto an existing value. This operation will overwrite the old
-    /// value partially or completely, depending on how much data is available.
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel
+    /// onto an existing value. This operation will overwrite the old value
+    /// partially or completely, depending on how much data is available.
     pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
         x.deserialize_from(self)
     }
@@ -268,9 +490,9 @@
     /// });
     /// ```
     ///
-    pub fn sized_read<F>(&self, mut f: F) -> Result<()>
+    pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'a> F: FnMut(ReadableSubParcel<'a>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
     {
         let start = self.get_data_position();
         let parcelable_size: i32 = self.read()?;
@@ -285,7 +507,10 @@
         }
 
         let subparcel = ReadableSubParcel {
-            parcel: self,
+            parcel: BorrowedParcel {
+                ptr: self.ptr,
+                _lifetime: PhantomData,
+            },
             end_position: end,
         };
         f(subparcel)?;
@@ -299,8 +524,8 @@
         Ok(())
     }
 
-    /// Read a vector size from the `Parcel` and resize the given output vector
-    /// to be correctly sized for that amount of data.
+    /// Read a vector size from the parcel and resize the given output vector to
+    /// be correctly sized for that amount of data.
     ///
     /// This method is used in AIDL-generated server side code for methods that
     /// take a mutable slice reference parameter.
@@ -318,7 +543,7 @@
         Ok(())
     }
 
-    /// Read a vector size from the `Parcel` and either create a correctly sized
+    /// Read a vector size from the parcel and either create a correctly sized
     /// vector for that amount of data or set the output parameter to None if
     /// the vector should be null.
     ///
@@ -346,7 +571,7 @@
 
 /// A segment of a readable parcel, used for [`Parcel::sized_read`].
 pub struct ReadableSubParcel<'a> {
-    parcel: &'a Parcel,
+    parcel: BorrowedParcel<'a>,
     end_position: i32,
 }
 
@@ -356,7 +581,7 @@
         // The caller should have checked this,
         // but it can't hurt to double-check
         assert!(self.has_more_data());
-        D::deserialize(self.parcel)
+        D::deserialize(&self.parcel)
     }
 
     /// Check if the sub-parcel has more data to read
@@ -365,11 +590,82 @@
     }
 }
 
-// Internal APIs
 impl Parcel {
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel.
+    pub fn read<D: Deserialize>(&self) -> Result<D> {
+        self.borrowed_ref().read()
+    }
+
+    /// Attempt to read a type that implements [`Deserialize`] from this parcel
+    /// onto an existing value. This operation will overwrite the old value
+    /// partially or completely, depending on how much data is available.
+    pub fn read_onto<D: Deserialize>(&self, x: &mut D) -> Result<()> {
+        self.borrowed_ref().read_onto(x)
+    }
+
+    /// Safely read a sized parcelable.
+    ///
+    /// Read the size of a parcelable, compute the end position
+    /// of that parcelable, then build a sized readable sub-parcel
+    /// 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
+    /// more data before every read, at least until Rust generators
+    /// are stabilized.
+    /// After the closure returns, skip to the end of the current
+    /// parcelable regardless of how much the closure has read.
+    ///
+    /// # Examples
+    ///
+    /// ```no_run
+    /// let mut parcelable = Default::default();
+    /// parcel.sized_read(|subparcel| {
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.a = subparcel.read()?;
+    ///     }
+    ///     if subparcel.has_more_data() {
+    ///         parcelable.b = subparcel.read()?;
+    ///     }
+    ///     Ok(())
+    /// });
+    /// ```
+    ///
+    pub fn sized_read<F>(&self, f: F) -> Result<()>
+    where
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+    {
+        self.borrowed_ref().sized_read(f)
+    }
+
+    /// Read a vector size from the parcel and resize the given output vector to
+    /// be correctly sized for that amount of data.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_out_vec<D: Default + Deserialize>(&self, out_vec: &mut Vec<D>) -> Result<()> {
+        self.borrowed_ref().resize_out_vec(out_vec)
+    }
+
+    /// Read a vector size from the parcel and either create a correctly sized
+    /// vector for that amount of data or set the output parameter to None if
+    /// the vector should be null.
+    ///
+    /// This method is used in AIDL-generated server side code for methods that
+    /// take a mutable slice reference parameter.
+    pub fn resize_nullable_out_vec<D: Default + Deserialize>(
+        &self,
+        out_vec: &mut Option<Vec<D>>,
+    ) -> Result<()> {
+        self.borrowed_ref().resize_nullable_out_vec(out_vec)
+    }
+}
+
+// Internal APIs
+impl<'a> BorrowedParcel<'a> {
     pub(crate) fn write_binder(&mut self, binder: Option<&SpIBinder>) -> Result<()> {
         unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
+            // 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`.
@@ -389,7 +685,7 @@
     pub(crate) fn read_binder(&self) -> Result<Option<SpIBinder>> {
         let mut binder = ptr::null_mut();
         let status = unsafe {
-            // Safety: `Parcel` always contains a valid pointer to an
+            // 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.
@@ -409,13 +705,11 @@
 impl Drop for Parcel {
     fn drop(&mut self) {
         // Run the C++ Parcel complete object destructor
-        if let Self::Owned(ptr) = *self {
-            unsafe {
-                // Safety: `Parcel` always contains a valid pointer to an
-                // `AParcel`. If we own the parcel, we can safely delete it
-                // here.
-                sys::AParcel_delete(ptr)
-            }
+        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())
         }
     }
 }
@@ -427,43 +721,16 @@
     }
 }
 
-#[cfg(test)]
-impl Parcel {
-    /// Create a new parcel tied to a bogus binder. TESTING ONLY!
-    ///
-    /// This can only be used for testing! All real parcel operations must be
-    /// done in the callback to [`IBinder::transact`] or in
-    /// [`Remotable::on_transact`] using the parcels provided to these methods.
-    pub(crate) fn new_for_test(binder: &mut SpIBinder) -> Result<Self> {
-        let mut input = ptr::null_mut();
-        let status = unsafe {
-            // Safety: `SpIBinder` guarantees that `binder` always contains a
-            // valid pointer to an `AIBinder`. We pass a valid, mutable out
-            // pointer to receive a newly constructed parcel. When successful
-            // this function assigns a new pointer to an `AParcel` to `input`
-            // and transfers ownership of this pointer to the caller. Thus,
-            // after this call, `input` will either be null or point to a valid,
-            // owned `AParcel`.
-            sys::AIBinder_prepareTransaction(binder.as_native_mut(), &mut input)
-        };
-        status_result(status)?;
-        unsafe {
-            // Safety: `input` is either null or a valid, owned pointer to an
-            // `AParcel`, so is valid to safe to
-            // `Parcel::owned`. `Parcel::owned` takes ownership of the parcel
-            // pointer.
-            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
-        }
+impl<'a> fmt::Debug for BorrowedParcel<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("BorrowedParcel")
+            .finish()
     }
 }
 
 #[test]
 fn test_read_write() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-
-    let mut service = Binder::new(()).as_binder();
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     assert_eq!(parcel.read::<bool>(), Err(StatusCode::NOT_ENOUGH_DATA));
@@ -478,7 +745,7 @@
     assert_eq!(parcel.read::<Option<String>>(), Ok(None));
     assert_eq!(parcel.read::<String>(), Err(StatusCode::UNEXPECTED_NULL));
 
-    assert_eq!(parcel.read_binder().err(), Some(StatusCode::BAD_TYPE));
+    assert_eq!(parcel.borrowed_ref().read_binder().err(), Some(StatusCode::BAD_TYPE));
 
     parcel.write(&1i32).unwrap();
 
@@ -493,11 +760,7 @@
 #[test]
 #[allow(clippy::float_cmp)]
 fn test_read_data() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-
-    let mut service = Binder::new(()).as_binder();
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let str_start = parcel.get_data_position();
 
     parcel.write(&b"Hello, Binder!\0"[..]).unwrap();
@@ -572,11 +835,7 @@
 
 #[test]
 fn test_utf8_utf16_conversions() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-
-    let mut service = Binder::new(()).as_binder();
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     assert!(parcel.write("Hello, Binder!").is_ok());
@@ -636,11 +895,7 @@
 
 #[test]
 fn test_sized_write() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-
-    let mut service = Binder::new(()).as_binder();
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     let arr = [1i32, 2i32, 3i32];
@@ -668,3 +923,43 @@
         &arr,
     );
 }
+
+#[test]
+fn test_append_from() {
+    let mut parcel1 = Parcel::new();
+    parcel1.write(&42i32).expect("Could not perform write");
+
+    let mut parcel2 = Parcel::new();
+    assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+    assert_eq!(4, parcel2.get_data_size());
+    assert_eq!(Ok(()), parcel2.append_all_from(&parcel1));
+    assert_eq!(8, parcel2.get_data_size());
+    unsafe {
+        parcel2.set_data_position(0).unwrap();
+    }
+    assert_eq!(Ok(42), parcel2.read::<i32>());
+    assert_eq!(Ok(42), parcel2.read::<i32>());
+
+    let mut parcel2 = Parcel::new();
+    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());
+    unsafe {
+        parcel2.set_data_position(0).unwrap();
+    }
+    assert_eq!(Ok(42), parcel2.read::<i32>());
+
+    let mut parcel2 = Parcel::new();
+    assert_eq!(Ok(()), parcel2.append_from(&parcel1, 0, 2));
+    assert_eq!(2, parcel2.get_data_size());
+    unsafe {
+        parcel2.set_data_position(0).unwrap();
+    }
+    assert_eq!(Err(StatusCode::NOT_ENOUGH_DATA), parcel2.read::<i32>());
+
+    let mut parcel2 = Parcel::new();
+    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 4, 2));
+    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, 4));
+    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, -1, 4));
+    assert_eq!(Err(StatusCode::BAD_VALUE), parcel2.append_from(&parcel1, 2, -1));
+}
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index f71a686..b0dea94 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
  */
 
 use super::{
-    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+    Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
     SerializeOption,
 };
 use crate::binder::AsNative;
@@ -61,7 +61,7 @@
 }
 
 impl Serialize for ParcelFileDescriptor {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    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
@@ -78,7 +78,7 @@
 impl SerializeArray for ParcelFileDescriptor {}
 
 impl SerializeOption for ParcelFileDescriptor {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(f) = this {
             f.serialize(parcel)
         } else {
@@ -94,10 +94,8 @@
     }
 }
 
-impl SerializeArray for Option<ParcelFileDescriptor> {}
-
 impl DeserializeOption for ParcelFileDescriptor {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let mut fd = -1i32;
         unsafe {
             // Safety: `Parcel` always contains a valid pointer to an
@@ -126,10 +124,8 @@
     }
 }
 
-impl DeserializeArray for Option<ParcelFileDescriptor> {}
-
 impl Deserialize for ParcelFileDescriptor {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    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 56c6165..9007cba 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,36 +14,59 @@
  * limitations under the License.
  */
 
-use crate::binder::{AsNative, FromIBinder, Strong};
+use crate::binder::{AsNative, FromIBinder, Stability, Strong};
 use crate::error::{status_result, status_t, Result, Status, StatusCode};
-use crate::parcel::Parcel;
+use crate::parcel::BorrowedParcel;
 use crate::proxy::SpIBinder;
 use crate::sys;
 
-use std::convert::TryInto;
+use std::convert::{TryFrom, TryInto};
 use std::ffi::c_void;
 use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit};
+use std::mem::{self, MaybeUninit, ManuallyDrop};
 use std::ptr;
 use std::slice;
 
+/// Super-trait for Binder parcelables.
+///
+/// This trait is equivalent `android::Parcelable` in C++,
+/// and defines a common interface that all parcelables need
+/// to implement.
+pub trait Parcelable {
+    /// Internal serialization function for parcelables.
+    ///
+    /// This method is mainly for internal use.
+    /// `Serialize::serialize` and its variants are generally
+    /// preferred over this function, since the former also
+    /// prepend a header.
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
+
+    /// Internal deserialization function for parcelables.
+    ///
+    /// This method is mainly for internal use.
+    /// `Deserialize::deserialize` and its variants are generally
+    /// preferred over this function, since the former also
+    /// parse the additional header.
+    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()>;
+}
+
 /// A struct whose instances can be written to a [`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`].
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()>;
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()>;
 }
 
 /// A struct whose instances can be restored from a [`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`].
-    fn deserialize(parcel: &Parcel) -> Result<Self>;
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self>;
 
     /// Deserialize an instance from the given [`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: &Parcel) -> Result<()> {
+    fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
         *self = Self::deserialize(parcel)?;
         Ok(())
     }
@@ -57,8 +80,8 @@
 // We want the default implementation for most types, but an override for
 // a few special ones like `readByteArray` for `u8`.
 pub trait SerializeArray: Serialize + Sized {
-    /// Serialize an array of this type into the given [`Parcel`].
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    /// Serialize an array of this type into the given parcel.
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         let res = unsafe {
             // Safety: Safe FFI, slice will always be a safe pointer to pass.
             sys::AParcel_writeParcelableArray(
@@ -88,7 +111,7 @@
 
     let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
 
-    let mut parcel = match Parcel::borrowed(parcel) {
+    let mut parcel = match BorrowedParcel::from_raw(parcel) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -103,8 +126,8 @@
 /// Defaults to calling Deserialize::deserialize() manually for every element,
 /// but can be overridden for custom implementations like `readByteArray`.
 pub trait DeserializeArray: Deserialize {
-    /// Deserialize an array of type from the given [`Parcel`].
-    fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+    /// 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 res = unsafe {
             // Safety: Safe FFI, vec is the correct opaque type expected by
@@ -150,7 +173,7 @@
         None => return StatusCode::BAD_INDEX as status_t,
     };
 
-    let parcel = match Parcel::borrowed(parcel as *mut _) {
+    let parcel = match BorrowedParcel::from_raw(parcel as *mut _) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
@@ -162,6 +185,18 @@
     StatusCode::OK as status_t
 }
 
+/// Flag that specifies that the following parcelable is present.
+///
+/// This is the Rust equivalent of `Parcel::kNonNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NON_NULL_PARCELABLE_FLAG: i32 = 1;
+
+/// Flag that specifies that the following parcelable is absent.
+///
+/// This is the Rust equivalent of `Parcel::kNullParcelableFlag`
+/// from `include/binder/Parcel.h` in C++.
+pub const NULL_PARCELABLE_FLAG: i32 = 0;
+
 /// Helper trait for types that can be nullable when serialized.
 // We really need this trait instead of implementing `Serialize for Option<T>`
 // because of the Rust orphan rule which prevents us from doing
@@ -170,33 +205,33 @@
 // We also use it to provide a default implementation for AIDL-generated
 // parcelables.
 pub trait SerializeOption: Serialize {
-    /// Serialize an Option of this type into the given [`Parcel`].
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    /// Serialize an Option of this type into the given parcel.
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(inner) = this {
-            parcel.write(&1i32)?;
+            parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
             parcel.write(inner)
         } else {
-            parcel.write(&0i32)
+            parcel.write(&NULL_PARCELABLE_FLAG)
         }
     }
 }
 
 /// Helper trait for types that can be nullable when deserialized.
 pub trait DeserializeOption: Deserialize {
-    /// Deserialize an Option of this type from the given [`Parcel`].
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    /// Deserialize an Option of this type from the given parcel.
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let null: i32 = parcel.read()?;
-        if null == 0 {
+        if null == NULL_PARCELABLE_FLAG {
             Ok(None)
         } else {
             parcel.read().map(Some)
         }
     }
 
-    /// Deserialize an Option of this type from the given [`Parcel`] onto the
+    /// Deserialize an Option of this type from the given parcel onto the
     /// current object. This operation will overwrite the current value
     /// partially or completely, depending on how much data is available.
-    fn deserialize_option_from(this: &mut Option<Self>, parcel: &Parcel) -> Result<()> {
+    fn deserialize_option_from(this: &mut Option<Self>, parcel: &BorrowedParcel<'_>) -> Result<()> {
         *this = Self::deserialize_option(parcel)?;
         Ok(())
     }
@@ -262,10 +297,23 @@
     };
 }
 
+/// 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.
+    let mut vec = ManuallyDrop::new(vec);
+    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 Parcel) -> Result<()> {
+            fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
                 unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
                     // `AParcel`, and any `$ty` literal value is safe to pass to
@@ -278,7 +326,7 @@
 
     {Deserialize, $ty:ty, $read_fn:path} => {
         impl Deserialize for $ty {
-            fn deserialize(parcel: &Parcel) -> Result<Self> {
+            fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 let mut val = Self::default();
                 unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
@@ -294,7 +342,7 @@
 
     {SerializeArray, $ty:ty, $write_array_fn:path} => {
         impl SerializeArray for $ty {
-            fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+            fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
                 let status = unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
                     // `AParcel`. If the slice is > 0 length, `slice.as_ptr()`
@@ -318,7 +366,7 @@
 
     {DeserializeArray, $ty:ty, $read_array_fn:path} => {
         impl DeserializeArray for $ty {
-            fn deserialize_array(parcel: &Parcel) -> Result<Option<Vec<Self>>> {
+            fn deserialize_array(parcel: &BorrowedParcel<'_>) -> Result<Option<Vec<Self>>> {
                 let mut vec: Option<Vec<MaybeUninit<Self>>> = None;
                 let status = unsafe {
                     // Safety: `Parcel` always contains a valid pointer to an
@@ -336,11 +384,8 @@
                     // 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)
+                    // initialized.
+                    vec.map(|vec| vec_assume_init(vec))
                 };
                 Ok(vec)
             }
@@ -348,6 +393,9 @@
     };
 }
 
+impl<T: DeserializeOption> DeserializeArray for Option<T> {}
+impl<T: SerializeOption> SerializeArray for Option<T> {}
+
 parcelable_primitives! {
     impl Serialize for bool = sys::AParcel_writeBool;
     impl Deserialize for bool = sys::AParcel_readBool;
@@ -405,19 +453,19 @@
 impl DeserializeArray for bool {}
 
 impl Serialize for u8 {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         (*self as i8).serialize(parcel)
     }
 }
 
 impl Deserialize for u8 {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         i8::deserialize(parcel).map(|v| v as u8)
     }
 }
 
 impl SerializeArray for u8 {
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         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
@@ -436,19 +484,19 @@
 }
 
 impl Serialize for i16 {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         (*self as u16).serialize(parcel)
     }
 }
 
 impl Deserialize for i16 {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         u16::deserialize(parcel).map(|v| v as i16)
     }
 }
 
 impl SerializeArray for i16 {
-    fn serialize_array(slice: &[Self], parcel: &mut Parcel) -> Result<()> {
+    fn serialize_array(slice: &[Self], parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         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
@@ -467,7 +515,7 @@
 }
 
 impl SerializeOption for str {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         match this {
             None => unsafe {
                 // Safety: `Parcel` always contains a valid pointer to an
@@ -502,10 +550,8 @@
     }
 }
 
-impl SerializeArray for Option<&str> {}
-
 impl Serialize for str {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Some(self).serialize(parcel)
     }
 }
@@ -513,7 +559,7 @@
 impl SerializeArray for &str {}
 
 impl Serialize for String {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Some(self.as_str()).serialize(parcel)
     }
 }
@@ -521,15 +567,13 @@
 impl SerializeArray for String {}
 
 impl SerializeOption for String {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(String::as_str), parcel)
     }
 }
 
-impl SerializeArray for Option<String> {}
-
 impl Deserialize for Option<String> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
         let status = unsafe {
             // Safety: `Parcel` always contains a valid pointer to an `AParcel`.
@@ -557,7 +601,7 @@
 impl DeserializeArray for Option<String> {}
 
 impl Deserialize for String {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel)
             .transpose()
             .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -567,19 +611,19 @@
 impl DeserializeArray for String {}
 
 impl<T: SerializeArray> Serialize for [T] {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeArray::serialize_array(self, parcel)
     }
 }
 
 impl<T: SerializeArray> Serialize for Vec<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeArray::serialize_array(&self[..], parcel)
     }
 }
 
 impl<T: SerializeArray> SerializeOption for [T] {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         if let Some(v) = this {
             SerializeArray::serialize_array(v, parcel)
         } else {
@@ -589,13 +633,13 @@
 }
 
 impl<T: SerializeArray> SerializeOption for Vec<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(Vec::as_slice), parcel)
     }
 }
 
 impl<T: DeserializeArray> Deserialize for Vec<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeArray::deserialize_array(parcel)
             .transpose()
             .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
@@ -603,13 +647,25 @@
 }
 
 impl<T: DeserializeArray> DeserializeOption for Vec<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         DeserializeArray::deserialize_array(parcel)
     }
 }
 
+impl Serialize for Stability {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        i32::from(*self).serialize(parcel)
+    }
+}
+
+impl Deserialize for Stability {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+        i32::deserialize(parcel).and_then(Stability::try_from)
+    }
+}
+
 impl Serialize for Status {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         unsafe {
             // Safety: `Parcel` always contains a valid pointer to an `AParcel`
             // and `Status` always contains a valid pointer to an `AStatus`, so
@@ -624,7 +680,7 @@
 }
 
 impl Deserialize for Status {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    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
@@ -645,80 +701,117 @@
 }
 
 impl<T: Serialize + FromIBinder + ?Sized> Serialize for Strong<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(&**self, parcel)
     }
 }
 
 impl<T: SerializeOption + FromIBinder + ?Sized> SerializeOption for Strong<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(|b| &**b), parcel)
     }
 }
 
+impl<T: Serialize + FromIBinder + ?Sized> SerializeArray for Strong<T> {}
+
 impl<T: FromIBinder + ?Sized> Deserialize for Strong<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         let ibinder: SpIBinder = parcel.read()?;
         FromIBinder::try_from(ibinder)
     }
 }
 
 impl<T: FromIBinder + ?Sized> DeserializeOption for Strong<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         let ibinder: Option<SpIBinder> = parcel.read()?;
         ibinder.map(FromIBinder::try_from).transpose()
     }
 }
 
+impl<T: FromIBinder + ?Sized> DeserializeArray for Strong<T> {}
+
 // We need these to support Option<&T> for all T
 impl<T: Serialize + ?Sized> Serialize for &T {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(*self, parcel)
     }
 }
 
 impl<T: SerializeOption + ?Sized> SerializeOption for &T {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.copied(), parcel)
     }
 }
 
 impl<T: SerializeOption> Serialize for Option<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(self.as_ref(), parcel)
     }
 }
 
 impl<T: DeserializeOption> Deserialize for Option<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         DeserializeOption::deserialize_option(parcel)
     }
 
-    fn deserialize_from(&mut self, parcel: &Parcel) -> Result<()> {
+    fn deserialize_from(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
         DeserializeOption::deserialize_option_from(self, parcel)
     }
 }
 
+/// Implement `Serialize` trait and friends for a parcelable
+///
+/// This is an internal macro used by the AIDL compiler to implement
+/// `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) => {
+        impl $crate::parcel::Serialize for $parcelable {
+            fn serialize(
+                &self,
+                parcel: &mut $crate::parcel::BorrowedParcel<'_>,
+            ) -> $crate::Result<()> {
+                <Self as $crate::parcel::SerializeOption>::serialize_option(
+                    Some(self),
+                    parcel,
+                )
+            }
+        }
+
+        impl $crate::parcel::SerializeArray for $parcelable {}
+
+        impl $crate::parcel::SerializeOption for $parcelable {
+            fn serialize_option(
+                this: Option<&Self>,
+                parcel: &mut $crate::parcel::BorrowedParcel<'_>,
+            ) -> $crate::Result<()> {
+                if let Some(this) = this {
+                    use $crate::parcel::Parcelable;
+                    parcel.write(&$crate::parcel::NON_NULL_PARCELABLE_FLAG)?;
+                    this.write_to_parcel(parcel)
+                } else {
+                    parcel.write(&$crate::parcel::NULL_PARCELABLE_FLAG)
+                }
+            }
+        }
+    }
+}
+
 /// Implement `Deserialize` trait and friends for a parcelable
 ///
 /// This is an internal macro used by the AIDL compiler to implement
 /// `Deserialize`, `DeserializeArray` and `DeserializeOption` for
-/// structured parcelables. The target type must implement a
-/// `deserialize_parcelable` method with the following signature:
-/// ```no_run
-/// fn deserialize_parcelable(
-///     &mut self,
-///     parcel: &binder::parcel::Parcelable,
-/// ) -> binder::Result<()> {
-///     // ...
-/// }
-/// ```
+/// structured parcelables. The target type must implement the
+/// `Parcelable` trait.
 #[macro_export]
 macro_rules! impl_deserialize_for_parcelable {
     ($parcelable:ident) => {
         impl $crate::parcel::Deserialize for $parcelable {
             fn deserialize(
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<Self> {
                 $crate::parcel::DeserializeOption::deserialize_option(parcel)
                     .transpose()
@@ -726,13 +819,14 @@
             }
             fn deserialize_from(
                 &mut self,
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 let status: i32 = parcel.read()?;
-                if status == 0 {
+                if status == $crate::parcel::NULL_PARCELABLE_FLAG {
                     Err($crate::StatusCode::UNEXPECTED_NULL)
                 } else {
-                    self.deserialize_parcelable(parcel)
+                    use $crate::parcel::Parcelable;
+                    self.read_from_parcel(parcel)
                 }
             }
         }
@@ -741,7 +835,7 @@
 
         impl $crate::parcel::DeserializeOption for $parcelable {
             fn deserialize_option(
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<Option<Self>> {
                 let mut result = None;
                 Self::deserialize_option_from(&mut result, parcel)?;
@@ -749,15 +843,16 @@
             }
             fn deserialize_option_from(
                 this: &mut Option<Self>,
-                parcel: &$crate::parcel::Parcel,
+                parcel: &$crate::parcel::BorrowedParcel<'_>,
             ) -> $crate::Result<()> {
                 let status: i32 = parcel.read()?;
-                if status == 0 {
+                if status == $crate::parcel::NULL_PARCELABLE_FLAG {
                     *this = None;
                     Ok(())
                 } else {
+                    use $crate::parcel::Parcelable;
                     this.get_or_insert_with(Self::default)
-                        .deserialize_parcelable(parcel)
+                        .read_from_parcel(parcel)
                 }
             }
         }
@@ -765,334 +860,332 @@
 }
 
 impl<T: Serialize> Serialize for Box<T> {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         Serialize::serialize(&**self, parcel)
     }
 }
 
 impl<T: Deserialize> Deserialize for Box<T> {
-    fn deserialize(parcel: &Parcel) -> Result<Self> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
         Deserialize::deserialize(parcel).map(Box::new)
     }
 }
 
 impl<T: SerializeOption> SerializeOption for Box<T> {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
     }
 }
 
 impl<T: DeserializeOption> DeserializeOption for Box<T> {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<Self>> {
         DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
     }
 }
 
-#[test]
-fn test_custom_parcelable() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-    let mut service = Binder::new(()).as_binder();
+#[cfg(test)]
+mod tests {
+    use crate::Parcel;
+    use super::*;
 
-    struct Custom(u32, bool, String, Vec<String>);
+    #[test]
+    fn test_custom_parcelable() {
+        struct Custom(u32, bool, String, Vec<String>);
 
-    impl Serialize for Custom {
-        fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
-            self.0.serialize(parcel)?;
-            self.1.serialize(parcel)?;
-            self.2.serialize(parcel)?;
-            self.3.serialize(parcel)
+        impl Serialize for Custom {
+            fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+                self.0.serialize(parcel)?;
+                self.1.serialize(parcel)?;
+                self.2.serialize(parcel)?;
+                self.3.serialize(parcel)
+            }
         }
-    }
 
-    impl Deserialize for Custom {
-        fn deserialize(parcel: &Parcel) -> Result<Self> {
-            Ok(Custom(
-                parcel.read()?,
-                parcel.read()?,
-                parcel.read()?,
-                parcel.read::<Option<Vec<String>>>()?.unwrap(),
-            ))
+        impl Deserialize for Custom {
+            fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
+                Ok(Custom(
+                        parcel.read()?,
+                        parcel.read()?,
+                        parcel.read()?,
+                        parcel.read::<Option<Vec<String>>>()?.unwrap(),
+                        ))
+            }
         }
+
+        let string8 = "Custom Parcelable".to_string();
+
+        let s1 = "str1".to_string();
+        let s2 = "str2".to_string();
+        let s3 = "str3".to_string();
+
+        let strs = vec![s1, s2, s3];
+
+        let custom = Custom(123_456_789, true, string8, strs);
+
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
+
+        assert!(custom.serialize(&mut parcel.borrowed()).is_ok());
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let custom2 = Custom::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(custom2.0, 123_456_789);
+        assert!(custom2.1);
+        assert_eq!(custom2.2, custom.2);
+        assert_eq!(custom2.3, custom.3);
     }
 
-    let string8 = "Custom Parcelable".to_string();
+    #[test]
+    #[allow(clippy::excessive_precision)]
+    fn test_slice_parcelables() {
+        let bools = [true, false, false, true];
 
-    let s1 = "str1".to_string();
-    let s2 = "str2".to_string();
-    let s3 = "str3".to_string();
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
 
-    let strs = vec![s1, s2, s3];
+        assert!(bools.serialize(&mut parcel.borrowed()).is_ok());
 
-    let custom = Custom(123_456_789, true, string8, strs);
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
 
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
-    let start = parcel.get_data_position();
+        assert_eq!(parcel.read::<u32>().unwrap(), 4);
+        assert_eq!(parcel.read::<u32>().unwrap(), 1);
+        assert_eq!(parcel.read::<u32>().unwrap(), 0);
+        assert_eq!(parcel.read::<u32>().unwrap(), 0);
+        assert_eq!(parcel.read::<u32>().unwrap(), 1);
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
 
-    assert!(custom.serialize(&mut parcel).is_ok());
+        let vec = Vec::<bool>::deserialize(parcel.borrowed_ref()).unwrap();
 
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
+        assert_eq!(vec, [true, false, false, true]);
+
+        let u8s = [101u8, 255, 42, 117];
+
+        let mut parcel = Parcel::new();
+        let start = parcel.get_data_position();
+
+        assert!(parcel.write(&u8s[..]).is_ok());
+
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+        assert_eq!(vec, [101, 255, 42, 117]);
+
+        let i8s = [-128i8, 127, 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert!(parcel.write(&i8s[..]).is_ok());
+
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u8>::deserialize(parcel.borrowed_ref()).unwrap();
+        assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
+
+        let u16s = [u16::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u16s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
+
+        let i16s = [i16::max_value(), i16::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i16s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i16>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
+
+        let u32s = [u32::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
+
+        let i32s = [i32::max_value(), i32::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
+        assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
+        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
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
+
+        let u64s = [u64::max_value(), 12_345, 42, 117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(u64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<u64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
+
+        let i64s = [i64::max_value(), i64::min_value(), 42, -117];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(i64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<i64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
+
+        let f32s = [
+            std::f32::NAN,
+            std::f32::INFINITY,
+            1.23456789,
+            std::f32::EPSILON,
+        ];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(f32s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<f32>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        // NAN != NAN so we can't use it in the assert_eq:
+        assert!(vec[0].is_nan());
+        assert_eq!(vec[1..], f32s[1..]);
+
+        let f64s = [
+            std::f64::NAN,
+            std::f64::INFINITY,
+            1.234567890123456789,
+            std::f64::EPSILON,
+        ];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(f64s.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<f64>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        // NAN != NAN so we can't use it in the assert_eq:
+        assert!(vec[0].is_nan());
+        assert_eq!(vec[1..], f64s[1..]);
+
+        let s1 = "Hello, Binder!";
+        let s2 = "This is a utf8 string.";
+        let s3 = "Some more text here.";
+        let s4 = "Embedded nulls \0 \0";
+
+        let strs = [s1, s2, s3, s4];
+
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+        assert!(strs.serialize(&mut parcel.borrowed()).is_ok());
+        unsafe {
+            assert!(parcel.set_data_position(start).is_ok());
+        }
+
+        let vec = Vec::<String>::deserialize(parcel.borrowed_ref()).unwrap();
+
+        assert_eq!(vec, strs);
     }
-
-    let custom2 = Custom::deserialize(&parcel).unwrap();
-
-    assert_eq!(custom2.0, 123_456_789);
-    assert!(custom2.1);
-    assert_eq!(custom2.2, custom.2);
-    assert_eq!(custom2.3, custom.3);
-}
-
-#[test]
-#[allow(clippy::excessive_precision)]
-fn test_slice_parcelables() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-    let mut service = Binder::new(()).as_binder();
-
-    let bools = [true, false, false, true];
-
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
-    let start = parcel.get_data_position();
-
-    assert!(bools.serialize(&mut parcel).is_ok());
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4);
-    assert_eq!(parcel.read::<u32>().unwrap(), 1);
-    assert_eq!(parcel.read::<u32>().unwrap(), 0);
-    assert_eq!(parcel.read::<u32>().unwrap(), 0);
-    assert_eq!(parcel.read::<u32>().unwrap(), 1);
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<bool>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [true, false, false, true]);
-
-    let u8s = [101u8, 255, 42, 117];
-
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
-    let start = parcel.get_data_position();
-
-    assert!(parcel.write(&u8s[..]).is_ok());
-
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
-    assert_eq!(vec, [101, 255, 42, 117]);
-
-    let i8s = [-128i8, 127, 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert!(parcel.write(&i8s[..]).is_ok());
-
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u8>::deserialize(&parcel).unwrap();
-    assert_eq!(vec, [-128i8 as u8, 127, 42, -117i8 as u8]);
-
-    let u16s = [u16::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u16s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xffff); // u16::max_value()
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u16>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u16::max_value(), 12_345, 42, 117]);
-
-    let i16s = [i16::max_value(), i16::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i16s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fff); // i16::max_value()
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i16>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i16::max_value(), i16::min_value(), 42, -117]);
-
-    let u32s = [u32::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0xffffffff); // u32::max_value()
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u32>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u32::max_value(), 12_345, 42, 117]);
-
-    let i32s = [i32::max_value(), i32::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    assert_eq!(parcel.read::<u32>().unwrap(), 4); // 4 items
-    assert_eq!(parcel.read::<u32>().unwrap(), 0x7fffffff); // i32::max_value()
-    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
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i32>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i32::max_value(), i32::min_value(), 42, -117]);
-
-    let u64s = [u64::max_value(), 12_345, 42, 117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(u64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<u64>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [u64::max_value(), 12_345, 42, 117]);
-
-    let i64s = [i64::max_value(), i64::min_value(), 42, -117];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(i64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<i64>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
-
-    let f32s = [
-        std::f32::NAN,
-        std::f32::INFINITY,
-        1.23456789,
-        std::f32::EPSILON,
-    ];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(f32s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<f32>::deserialize(&parcel).unwrap();
-
-    // NAN != NAN so we can't use it in the assert_eq:
-    assert!(vec[0].is_nan());
-    assert_eq!(vec[1..], f32s[1..]);
-
-    let f64s = [
-        std::f64::NAN,
-        std::f64::INFINITY,
-        1.234567890123456789,
-        std::f64::EPSILON,
-    ];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(f64s.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<f64>::deserialize(&parcel).unwrap();
-
-    // NAN != NAN so we can't use it in the assert_eq:
-    assert!(vec[0].is_nan());
-    assert_eq!(vec[1..], f64s[1..]);
-
-    let s1 = "Hello, Binder!";
-    let s2 = "This is a utf8 string.";
-    let s3 = "Some more text here.";
-    let s4 = "Embedded nulls \0 \0";
-
-    let strs = [s1, s2, s3, s4];
-
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-    assert!(strs.serialize(&mut parcel).is_ok());
-    unsafe {
-        assert!(parcel.set_data_position(start).is_ok());
-    }
-
-    let vec = Vec::<String>::deserialize(&parcel).unwrap();
-
-    assert_eq!(vec, strs);
 }
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
new file mode 100644
index 0000000..b4282b2
--- /dev/null
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+use crate::binder::Stability;
+use crate::error::{Result, StatusCode};
+use crate::parcel::{Parcel, BorrowedParcel, Parcelable};
+use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
+
+use downcast_rs::{impl_downcast, DowncastSync};
+use std::any::Any;
+use std::sync::{Arc, Mutex};
+
+/// Metadata that `ParcelableHolder` needs for all parcelables.
+///
+/// The compiler auto-generates implementations of this trait
+/// for AIDL parcelables.
+pub trait ParcelableMetadata {
+    /// The Binder parcelable descriptor string.
+    ///
+    /// This string is a unique identifier for a Binder parcelable.
+    fn get_descriptor() -> &'static str;
+
+    /// The Binder parcelable stability.
+    fn get_stability(&self) -> Stability {
+        Stability::Local
+    }
+}
+
+trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
+impl_downcast!(sync AnyParcelable);
+impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
+
+#[derive(Debug, Clone)]
+enum ParcelableHolderData {
+    Empty,
+    Parcelable {
+        parcelable: Arc<dyn AnyParcelable>,
+        name: String,
+    },
+    Parcel(Parcel),
+}
+
+impl Default for ParcelableHolderData {
+    fn default() -> Self {
+        ParcelableHolderData::Empty
+    }
+}
+
+/// A container that can hold any arbitrary `Parcelable`.
+///
+/// This type is currently used for AIDL parcelable fields.
+///
+/// `ParcelableHolder` is currently not thread-safe (neither
+/// `Send` nor `Sync`), mainly because it internally contains
+/// a `Parcel` which in turn is not thread-safe.
+#[derive(Debug, Default)]
+pub struct ParcelableHolder {
+    // This is a `Mutex` because of `get_parcelable`
+    // which takes `&self` for consistency with C++.
+    // We could make `get_parcelable` take a `&mut self`
+    // and get rid of the `Mutex` here for a performance
+    // improvement, but then callers would require a mutable
+    // `ParcelableHolder` even for that getter method.
+    data: Mutex<ParcelableHolderData>,
+    stability: Stability,
+}
+
+impl ParcelableHolder {
+    /// Construct a new `ParcelableHolder` with the given stability.
+    pub fn new(stability: Stability) -> Self {
+        Self {
+            data: Mutex::new(ParcelableHolderData::Empty),
+            stability,
+        }
+    }
+
+    /// Reset the contents of this `ParcelableHolder`.
+    ///
+    /// Note that this method does not reset the stability,
+    /// only the contents.
+    pub fn reset(&mut self) {
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
+        // We could also clear stability here, but C++ doesn't
+    }
+
+    /// Set the parcelable contained in this `ParcelableHolder`.
+    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
+    where
+        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
+    {
+        if self.stability > p.get_stability() {
+            return Err(StatusCode::BAD_VALUE);
+        }
+
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
+            parcelable: p,
+            name: T::get_descriptor().into(),
+        };
+
+        Ok(())
+    }
+
+    /// Retrieve the parcelable stored in this `ParcelableHolder`.
+    ///
+    /// This method attempts to retrieve the parcelable inside
+    /// the current object as a parcelable of type `T`.
+    /// The object is validated against `T` by checking that
+    /// its parcelable descriptor matches the one returned
+    /// by `T::get_descriptor()`.
+    ///
+    /// Returns one of the following:
+    /// * `Err(_)` in case of error
+    /// * `Ok(None)` if the holder is empty or the descriptor does not match
+    /// * `Ok(Some(_))` if the object holds a parcelable of type `T`
+    ///   with the correct descriptor
+    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
+    where
+        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
+    {
+        let parcelable_desc = T::get_descriptor();
+        let mut data = self.data.lock().unwrap();
+        match *data {
+            ParcelableHolderData::Empty => Ok(None),
+            ParcelableHolderData::Parcelable {
+                ref parcelable,
+                ref name,
+            } => {
+                if name != parcelable_desc {
+                    return Err(StatusCode::BAD_VALUE);
+                }
+
+                match Arc::clone(parcelable).downcast_arc::<T>() {
+                    Err(_) => Err(StatusCode::BAD_VALUE),
+                    Ok(x) => Ok(Some(x)),
+                }
+            }
+            ParcelableHolderData::Parcel(ref mut parcel) => {
+                unsafe {
+                    // Safety: 0 should always be a valid position.
+                    parcel.set_data_position(0)?;
+                }
+
+                let name: String = parcel.read()?;
+                if name != parcelable_desc {
+                    return Ok(None);
+                }
+
+                let mut parcelable = T::default();
+                parcelable.read_from_parcel(parcel.borrowed_ref())?;
+
+                let parcelable = Arc::new(parcelable);
+                let result = Arc::clone(&parcelable);
+                *data = ParcelableHolderData::Parcelable { parcelable, name };
+
+                Ok(Some(result))
+            }
+        }
+    }
+
+    /// Return the stability value of this object.
+    pub fn get_stability(&self) -> Stability {
+        self.stability
+    }
+}
+
+impl_serialize_for_parcelable!(ParcelableHolder);
+impl_deserialize_for_parcelable!(ParcelableHolder);
+
+impl Parcelable for ParcelableHolder {
+    fn write_to_parcel(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
+        parcel.write(&self.stability)?;
+
+        let mut data = self.data.lock().unwrap();
+        match *data {
+            ParcelableHolderData::Empty => parcel.write(&0i32),
+            ParcelableHolderData::Parcelable {
+                ref parcelable,
+                ref name,
+            } => {
+                let length_start = parcel.get_data_position();
+                parcel.write(&0i32)?;
+
+                let data_start = parcel.get_data_position();
+                parcel.write(name)?;
+                parcelable.write_to_parcel(parcel)?;
+
+                let end = parcel.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))?;
+                unsafe {
+                    // Safety: we got the position from `get_data_position`.
+                    parcel.set_data_position(end)?;
+                }
+
+                Ok(())
+            }
+            ParcelableHolderData::Parcel(ref mut p) => {
+                parcel.write(&p.get_data_size())?;
+                parcel.append_all_from(&*p)
+            }
+        }
+    }
+
+    fn read_from_parcel(&mut self, parcel: &BorrowedParcel<'_>) -> Result<()> {
+        self.stability = parcel.read()?;
+
+        let data_size: i32 = parcel.read()?;
+        if data_size < 0 {
+            // C++ returns BAD_VALUE here,
+            // while Java returns ILLEGAL_ARGUMENT
+            return Err(StatusCode::BAD_VALUE);
+        }
+        if data_size == 0 {
+            *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
+            return Ok(());
+        }
+
+        // TODO: C++ ParcelableHolder accepts sizes up to SIZE_MAX here, but we
+        // only go up to i32::MAX because that's what our API uses everywhere
+        let data_start = parcel.get_data_position();
+        let data_end = data_start
+            .checked_add(data_size)
+            .ok_or(StatusCode::BAD_VALUE)?;
+
+        let mut new_parcel = Parcel::new();
+        new_parcel.append_from(parcel, data_start, data_size)?;
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcel(new_parcel);
+
+        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)?;
+        }
+
+        Ok(())
+    }
+}
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 68fa34b..760d862 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,8 +22,7 @@
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
-    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
-    SerializeOption,
+    Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
 };
 use crate::sys;
 
@@ -253,9 +252,9 @@
 
         unsafe {
             // Safety: At this point, `input` is either a valid, owned `AParcel`
-            // pointer, or null. `Parcel::owned` safely handles both cases,
+            // pointer, or null. `OwnedParcel::from_raw` safely handles both cases,
             // taking ownership of the parcel.
-            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
+            Parcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
@@ -266,7 +265,6 @@
         flags: TransactionFlags,
     ) -> Result<Parcel> {
         let mut reply = ptr::null_mut();
-        assert!(data.is_owned());
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
             // valid pointer to an `AIBinder`. Although `IBinder::transact` is
@@ -299,9 +297,8 @@
             // 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::owned` takes ownership
-            // of the parcel pointer.
-            Parcel::owned(reply).ok_or(StatusCode::UNEXPECTED_NULL)
+            // construct an owned variant.
+            Parcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
@@ -326,6 +323,7 @@
         status_result(status)
     }
 
+    #[cfg(not(android_vndk))]
     fn set_requesting_sid(&mut self, enable: bool) {
         unsafe { sys::AIBinder_setRequestingSid(self.as_native_mut(), enable) };
     }
@@ -417,22 +415,21 @@
 }
 
 impl Serialize for SpIBinder {
-    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+    fn serialize(&self, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(Some(self))
     }
 }
 
 impl SerializeOption for SpIBinder {
-    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut BorrowedParcel<'_>) -> Result<()> {
         parcel.write_binder(this)
     }
 }
 
 impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
 
 impl Deserialize for SpIBinder {
-    fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
+    fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
         parcel
             .read_binder()
             .transpose()
@@ -441,13 +438,12 @@
 }
 
 impl DeserializeOption for SpIBinder {
-    fn deserialize_option(parcel: &Parcel) -> Result<Option<SpIBinder>> {
+    fn deserialize_option(parcel: &BorrowedParcel<'_>) -> Result<Option<SpIBinder>> {
         parcel.read_binder()
     }
 }
 
 impl DeserializeArray for SpIBinder {}
-impl DeserializeArray for Option<SpIBinder> {}
 
 /// A weak reference to a Binder remote object.
 ///
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0e05f10..0aef744 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -99,6 +99,17 @@
         }
     }
 
+    /// Determine whether the current thread is currently executing an incoming transaction.
+    ///
+    /// \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()
+        }
+    }
+
     /// This function makes the client's security context available to the
     /// service calling this function. This can be used for access control.
     /// It does not suffer from the TOCTOU issues of get_calling_pid.
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index ecc61f4..2d1175b 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -13,6 +13,8 @@
     rustlibs: [
         "libbinder_rs",
         "libselinux_bindgen",
+        "libbinder_tokio_rs",
+        "libtokio",
     ],
     shared_libs: [
         "libselinux",
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 335e8d8..1fd2ead 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -17,7 +17,7 @@
 //! Rust Binder crate integration tests
 
 use binder::declare_binder_interface;
-use binder::parcel::Parcel;
+use binder::parcel::BorrowedParcel;
 use binder::{
     Binder, BinderFeatures, IBinderInternal, Interface, StatusCode, ThreadState, TransactionCode,
     FIRST_CALL_TRANSACTION,
@@ -154,20 +154,33 @@
     fn get_selinux_context(&self) -> binder::Result<String>;
 }
 
+/// Async trivial testing binder interface
+pub trait IATest<P>: Interface {
+    /// Returns a test string
+    fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>>;
+
+    /// Return the arguments sent via dump
+    fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>>;
+
+    /// Returns the caller's SELinux context
+    fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>>;
+}
+
 declare_binder_interface! {
     ITest["android.os.ITest"] {
         native: BnTest(on_transact),
         proxy: BpTest {
             x: i32 = 100
         },
+        async: IATest,
     }
 }
 
 fn on_transact(
     service: &dyn ITest,
     code: TransactionCode,
-    _data: &Parcel,
-    reply: &mut Parcel,
+    _data: &BorrowedParcel<'_>,
+    reply: &mut BorrowedParcel<'_>,
 ) -> binder::Result<()> {
     match code.try_into()? {
         TestTransactionCode::Test => reply.write(&service.test()?),
@@ -201,6 +214,32 @@
     }
 }
 
+impl<P: binder::BinderAsyncPool> IATest<P> for BpTest {
+    fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+        let binder = self.binder.clone();
+        P::spawn(
+            move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
+        )
+    }
+
+    fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
+        let binder = self.binder.clone();
+        P::spawn(
+            move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
+        )
+    }
+
+    fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+        let binder = self.binder.clone();
+        P::spawn(
+            move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
+            |reply| async move { reply?.read() }
+        )
+    }
+}
+
 impl ITest for Binder<BnTest> {
     fn test(&self) -> binder::Result<String> {
         self.0.test()
@@ -215,6 +254,23 @@
     }
 }
 
+impl<P: binder::BinderAsyncPool> IATest<P> for Binder<BnTest> {
+    fn test(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+        let res = self.0.test();
+        Box::pin(async move { res })
+    }
+
+    fn get_dump_args(&self) -> binder::BoxFuture<'static, binder::Result<Vec<String>>> {
+        let res = self.0.get_dump_args();
+        Box::pin(async move { res })
+    }
+
+    fn get_selinux_context(&self) -> binder::BoxFuture<'static, binder::Result<String>> {
+        let res = self.0.get_selinux_context();
+        Box::pin(async move { res })
+    }
+}
+
 /// Trivial testing binder interface
 pub trait ITestSameDescriptor: Interface {}
 
@@ -228,8 +284,8 @@
 fn on_transact_same_descriptor(
     _service: &dyn ITestSameDescriptor,
     _code: TransactionCode,
-    _data: &Parcel,
-    _reply: &mut Parcel,
+    _data: &BorrowedParcel<'_>,
+    _reply: &mut BorrowedParcel<'_>,
 ) -> binder::Result<()> {
     Ok(())
 }
@@ -255,7 +311,9 @@
         SpIBinder, StatusCode, Strong,
     };
 
-    use super::{BnTest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+    use binder_tokio::Tokio;
+
+    use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
 
     pub struct ScopedServiceProcess(Child);
 
@@ -303,12 +361,47 @@
             binder::get_interface::<dyn ITest>("this_service_does_not_exist").err(),
             Some(StatusCode::NAME_NOT_FOUND)
         );
+        assert_eq!(
+            binder::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
 
         // The service manager service isn't an ITest, so this must fail.
         assert_eq!(
             binder::get_interface::<dyn ITest>("manager").err(),
             Some(StatusCode::BAD_TYPE)
         );
+        assert_eq!(
+            binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+    }
+
+    #[tokio::test]
+    async fn check_services_async() {
+        let mut sm = binder::get_service("manager").expect("Did not get manager binder service");
+        assert!(sm.is_binder_alive());
+        assert!(sm.ping_binder().is_ok());
+
+        assert!(binder::get_service("this_service_does_not_exist").is_none());
+        assert_eq!(
+            binder_tokio::get_interface::<dyn ITest>("this_service_does_not_exist").await.err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+        assert_eq!(
+            binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+            Some(StatusCode::NAME_NOT_FOUND)
+        );
+
+        // The service manager service isn't an ITest, so this must fail.
+        assert_eq!(
+            binder_tokio::get_interface::<dyn ITest>("manager").await.err(),
+            Some(StatusCode::BAD_TYPE)
+        );
+        assert_eq!(
+            binder_tokio::get_interface::<dyn IATest<Tokio>>("manager").await.err(),
+            Some(StatusCode::BAD_TYPE)
+        );
     }
 
     #[test]
@@ -323,6 +416,10 @@
             binder::wait_for_interface::<dyn ITest>("manager").err(),
             Some(StatusCode::BAD_TYPE)
         );
+        assert_eq!(
+            binder::wait_for_interface::<dyn IATest<Tokio>>("manager").err(),
+            Some(StatusCode::BAD_TYPE)
+        );
     }
 
     #[test]
@@ -334,6 +431,15 @@
         assert_eq!(test_client.test().unwrap(), "trivial_client_test");
     }
 
+    #[tokio::test]
+    async fn trivial_client_async() {
+        let service_name = "trivial_client_test";
+        let _process = ScopedServiceProcess::new(service_name);
+        let test_client: Strong<dyn IATest<Tokio>> =
+            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
+    }
+
     #[test]
     fn wait_for_trivial_client() {
         let service_name = "wait_for_trivial_client_test";
@@ -343,23 +449,47 @@
         assert_eq!(test_client.test().unwrap(), "wait_for_trivial_client_test");
     }
 
+    #[tokio::test]
+    async fn wait_for_trivial_client_async() {
+        let service_name = "wait_for_trivial_client_test";
+        let _process = ScopedServiceProcess::new(service_name);
+        let test_client: Strong<dyn IATest<Tokio>> =
+            binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+        assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
+    }
+
+    fn get_expected_selinux_context() -> &'static str {
+        unsafe {
+            let mut out_ptr = ptr::null_mut();
+            assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
+            assert!(!out_ptr.is_null());
+            CStr::from_ptr(out_ptr)
+                .to_str()
+                .expect("context was invalid UTF-8")
+        }
+    }
+
     #[test]
     fn get_selinux_context() {
         let service_name = "get_selinux_context";
         let _process = ScopedServiceProcess::new(service_name);
         let test_client: Strong<dyn ITest> =
             binder::get_interface(service_name).expect("Did not get manager binder service");
-        let expected_context = unsafe {
-            let mut out_ptr = ptr::null_mut();
-            assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
-            assert!(!out_ptr.is_null());
-            CStr::from_ptr(out_ptr)
-        };
         assert_eq!(
             test_client.get_selinux_context().unwrap(),
-            expected_context
-                .to_str()
-                .expect("context was invalid UTF-8"),
+            get_expected_selinux_context()
+        );
+    }
+
+    #[tokio::test]
+    async fn get_selinux_context_async() {
+        let service_name = "get_selinux_context";
+        let _process = ScopedServiceProcess::new(service_name);
+        let test_client: Strong<dyn IATest<Tokio>> =
+            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        assert_eq!(
+            test_client.get_selinux_context().await.unwrap(),
+            get_expected_selinux_context()
         );
     }
 
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index 66ba846..1fc761e 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -20,7 +20,7 @@
 use binder::declare_binder_interface;
 use binder::parcel::ParcelFileDescriptor;
 use binder::{
-    Binder, BinderFeatures, ExceptionCode, Interface, Parcel, Result, SpIBinder, Status,
+    Binder, BinderFeatures, BorrowedParcel, ExceptionCode, Interface, Result, SpIBinder, Status,
     StatusCode, TransactionCode,
 };
 
@@ -111,8 +111,8 @@
 fn on_transact(
     _service: &dyn ReadParcelTest,
     code: TransactionCode,
-    parcel: &Parcel,
-    reply: &mut Parcel,
+    parcel: &BorrowedParcel<'_>,
+    reply: &mut BorrowedParcel<'_>,
 ) -> Result<()> {
     match code {
         bindings::Transaction_TEST_BOOL => {
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 23e34aa..777f3c9 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -90,7 +90,6 @@
         LOG(ERROR) << "Cannot create RpcServer";
         return EX_SOFTWARE;
     }
-    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     unsigned int port;
     if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
         LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
@@ -207,7 +206,6 @@
     service = ServiceManagerProxyToNative::asBinder(interface);
 
     auto rpcServer = RpcServer::make();
-    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     rpcServer->setRootObject(service);
     unsigned int port;
     if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index 9e10788..fdd02a4 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -18,6 +18,9 @@
     oneway void sendString(@utf8InCpp String str);
     @utf8InCpp String doubleString(@utf8InCpp String str);
 
+    // get the port that a client used to connect to this object
+    int getClientPort();
+
     // number of known RPC binders to process, RpcState::countBinders by session
     int[] countBinders();
 
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
index eec3b44..464da60 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -65,7 +65,9 @@
 
 void initHostRpcServiceManagerOnce() {
     static std::once_flag gSmOnce;
-    std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+    std::call_once(gSmOnce, [] {
+        setDefaultServiceManager(createRpcDelegateServiceManager({.maxOutgoingThreads = 1}));
+    });
 }
 
 // Test for host service manager.
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 639876f..4d316f7 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -436,6 +436,11 @@
         };
 };
 
+TEST_F(BinderLibTest, CannotUseBinderAfterFork) {
+    // EXPECT_DEATH works by forking the process
+    EXPECT_DEATH({ ProcessState::self(); }, "libbinder ProcessState can not be used after fork");
+}
+
 TEST_F(BinderLibTest, WasParceled) {
     auto binder = sp<BBinder>::make();
     EXPECT_FALSE(binder->wasParceled());
@@ -1197,7 +1202,6 @@
         auto rpcServer = RpcServer::make();
         EXPECT_NE(nullptr, rpcServer);
         if (rpcServer == nullptr) return {};
-        rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
         unsigned int port;
         if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
             ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index f8718aa..52ba9b0 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -206,7 +206,6 @@
     if (0 == fork()) {
         prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
         server->setRootObject(sp<MyBinderRpcBenchmark>::make());
-        server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
         CHECK_EQ(OK, server->setupUnixDomainServer(addr));
         server->join();
         exit(1);
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 2011801..5a96b78 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -22,6 +22,7 @@
 #include <aidl/IBinderRpcTest.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_libbinder.h>
 #include <binder/Binder.h>
@@ -109,7 +110,6 @@
     base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     int sinkFd = sink.get();
     auto server = RpcServer::make(newFactory(GetParam()));
-    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     ASSERT_FALSE(server->hasServer());
     ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
     ASSERT_TRUE(server->hasServer());
@@ -174,6 +174,7 @@
 class MyBinderRpcTest : public BnBinderRpcTest {
 public:
     wp<RpcServer> server;
+    int port = 0;
 
     Status sendString(const std::string& str) override {
         (void)str;
@@ -183,6 +184,10 @@
         *strstr = str + str;
         return Status::ok();
     }
+    Status getClientPort(int* out) override {
+        *out = port;
+        return Status::ok();
+    }
     Status countBinders(std::vector<int32_t>* out) override {
         sp<RpcServer> spServer = server.promote();
         if (spServer == nullptr) {
@@ -481,6 +486,7 @@
         size_t numThreads = 1;
         size_t numSessions = 1;
         size_t numIncomingConnections = 0;
+        size_t numOutgoingConnections = SIZE_MAX;
     };
 
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
@@ -537,7 +543,6 @@
                     auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
                     sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
 
-                    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
                     server->setMaxThreads(options.numThreads);
 
                     unsigned int outPort = 0;
@@ -614,6 +619,7 @@
 
         for (const auto& session : sessions) {
             session->setMaxIncomingThreads(options.numIncomingConnections);
+            session->setMaxOutgoingThreads(options.numOutgoingConnections);
 
             switch (socketType) {
                 case SocketType::PRECONNECTED:
@@ -641,13 +647,41 @@
 
     BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
         BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcess(options,
-                                                         [&](const sp<RpcServer>& server) {
-                                                             sp<MyBinderRpcTest> service =
-                                                                     new MyBinderRpcTest;
-                                                             server->setRootObject(service);
-                                                             service->server = server;
-                                                         }),
+                .proc = createRpcTestSocketServerProcess(
+                        options,
+                        [&](const sp<RpcServer>& server) {
+                            server->setPerSessionRootObject([&](const sockaddr* addr,
+                                                                socklen_t len) {
+                                sp<MyBinderRpcTest> service = sp<MyBinderRpcTest>::make();
+                                switch (addr->sa_family) {
+                                    case AF_UNIX:
+                                        // nothing to save
+                                        break;
+                                    case AF_VSOCK:
+                                        CHECK_EQ(len, sizeof(sockaddr_vm));
+                                        service->port = reinterpret_cast<const sockaddr_vm*>(addr)
+                                                                ->svm_port;
+                                        break;
+                                    case AF_INET:
+                                        CHECK_EQ(len, sizeof(sockaddr_in));
+                                        service->port =
+                                                ntohs(reinterpret_cast<const sockaddr_in*>(addr)
+                                                              ->sin_port);
+                                        break;
+                                    case AF_INET6:
+                                        CHECK_EQ(len, sizeof(sockaddr_in));
+                                        service->port =
+                                                ntohs(reinterpret_cast<const sockaddr_in6*>(addr)
+                                                              ->sin6_port);
+                                        break;
+                                    default:
+                                        LOG_ALWAYS_FATAL("Unrecognized address family %d",
+                                                         addr->sa_family);
+                                }
+                                service->server = server;
+                                return service;
+                            });
+                        }),
         };
 
         ret.rootBinder = ret.proc.sessions.at(0).root;
@@ -655,6 +689,9 @@
 
         return ret;
     }
+
+    void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+                                     size_t sleepMs = 500);
 };
 
 TEST_P(BinderRpc, Ping) {
@@ -677,6 +714,27 @@
     }
 }
 
+TEST_P(BinderRpc, SeparateRootObject) {
+    SocketType type = std::get<0>(GetParam());
+    if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
+        // we can't get port numbers for unix sockets
+        return;
+    }
+
+    auto proc = createRpcTestSocketServerProcess({.numSessions = 2});
+
+    int port1 = 0;
+    EXPECT_OK(proc.rootIface->getClientPort(&port1));
+
+    sp<IBinderRpcTest> rootIface2 = interface_cast<IBinderRpcTest>(proc.proc.sessions.at(1).root);
+    int port2;
+    EXPECT_OK(rootIface2->getClientPort(&port2));
+
+    // we should have a different IBinderRpcTest object created for each
+    // session, because we use setPerSessionRootObject
+    EXPECT_NE(port1, port2);
+}
+
 TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
     auto proc = createRpcTestSocketServerProcess({});
     Parcel data;
@@ -685,13 +743,21 @@
 }
 
 TEST_P(BinderRpc, AppendSeparateFormats) {
-    auto proc = createRpcTestSocketServerProcess({});
+    auto proc1 = createRpcTestSocketServerProcess({});
+    auto proc2 = createRpcTestSocketServerProcess({});
+
+    Parcel pRaw;
 
     Parcel p1;
-    p1.markForBinder(proc.rootBinder);
+    p1.markForBinder(proc1.rootBinder);
     p1.writeInt32(3);
 
+    EXPECT_EQ(BAD_TYPE, p1.appendFrom(&pRaw, 0, p1.dataSize()));
+    EXPECT_EQ(BAD_TYPE, pRaw.appendFrom(&p1, 0, p1.dataSize()));
+
     Parcel p2;
+    p2.markForBinder(proc2.rootBinder);
+    p2.writeInt32(7);
 
     EXPECT_EQ(BAD_TYPE, p1.appendFrom(&p2, 0, p2.dataSize()));
     EXPECT_EQ(BAD_TYPE, p2.appendFrom(&p1, 0, p1.dataSize()));
@@ -996,28 +1062,39 @@
     for (auto& t : ts) t.join();
 }
 
-TEST_P(BinderRpc, ThreadPoolOverSaturated) {
-    constexpr size_t kNumThreads = 10;
-    constexpr size_t kNumCalls = kNumThreads + 3;
-    constexpr size_t kSleepMs = 500;
-
-    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
-
+void BinderRpc::testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+                                            size_t sleepMs) {
     size_t epochMsBefore = epochMillis();
 
     std::vector<std::thread> ts;
-    for (size_t i = 0; i < kNumCalls; i++) {
-        ts.push_back(std::thread([&] { proc.rootIface->sleepMs(kSleepMs); }));
+    for (size_t i = 0; i < numCalls; i++) {
+        ts.push_back(std::thread([&] { iface->sleepMs(sleepMs); }));
     }
 
     for (auto& t : ts) t.join();
 
     size_t epochMsAfter = epochMillis();
 
-    EXPECT_GE(epochMsAfter, epochMsBefore + 2 * kSleepMs);
+    EXPECT_GE(epochMsAfter, epochMsBefore + 2 * sleepMs);
 
     // Potential flake, but make sure calls are handled in parallel.
-    EXPECT_LE(epochMsAfter, epochMsBefore + 3 * kSleepMs);
+    EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
+}
+
+TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+    constexpr size_t kNumThreads = 10;
+    constexpr size_t kNumCalls = kNumThreads + 3;
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
+    testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
+}
+
+TEST_P(BinderRpc, ThreadPoolLimitOutgoing) {
+    constexpr size_t kNumThreads = 20;
+    constexpr size_t kNumOutgoingConnections = 10;
+    constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = kNumThreads, .numOutgoingConnections = kNumOutgoingConnections});
+    testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
 }
 
 TEST_P(BinderRpc, ThreadingStressTest) {
@@ -1227,11 +1304,20 @@
 }
 
 TEST_P(BinderRpc, UseKernelBinderCallingId) {
+    bool okToFork = ProcessState::selfOrNull() == nullptr;
+
     auto proc = createRpcTestSocketServerProcess({});
 
-    // we can't allocate IPCThreadState so actually the first time should
-    // succeed :(
-    EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+    // If this process has used ProcessState already, then the forked process
+    // cannot use it at all. If this process hasn't used it (depending on the
+    // order tests are run), then the forked process can use it, and we'll only
+    // catch the invalid usage the second time. Such is the burden of global
+    // state!
+    if (okToFork) {
+        // we can't allocate IPCThreadState so actually the first time should
+        // succeed :(
+        EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+    }
 
     // second time! we catch the error :)
     EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
@@ -1283,11 +1369,20 @@
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
+TEST_P(BinderRpc, AidlDelegatorTest) {
+    auto proc = createRpcTestSocketServerProcess({});
+    auto myDelegator = sp<IBinderRpcTestDelegator>::make(proc.rootIface);
+    ASSERT_NE(nullptr, myDelegator);
+
+    std::string doubled;
+    EXPECT_OK(myDelegator->doubleString("cool ", &doubled));
+    EXPECT_EQ("cool cool ", doubled);
+}
+
 static bool testSupportVsockLoopback() {
     // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
     sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
-    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
         if (status == -EAFNOSUPPORT) {
             return false;
@@ -1376,7 +1471,6 @@
 TEST_P(BinderRpcSimple, Shutdown) {
     auto addr = allocateSocketAddress();
     auto server = RpcServer::make(newFactory(GetParam()));
-    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
     auto joinEnds = std::make_shared<OneOffSignal>();
 
@@ -1416,13 +1510,22 @@
     ASSERT_EQ(OK, binder->pingBinder());
 
     auto rpcServer = RpcServer::make();
-    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     unsigned int port;
     ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
     auto socket = rpcServer->releaseServer();
 
     auto keepAlive = sp<BBinder>::make();
-    ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
+    auto setRpcClientDebugStatus = binder->setRpcClientDebug(std::move(socket), keepAlive);
+
+    if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+        ASSERT_EQ(INVALID_OPERATION, setRpcClientDebugStatus)
+                << "setRpcClientDebug should return INVALID_OPERATION on non-debuggable builds, "
+                   "but get "
+                << statusToString(setRpcClientDebugStatus);
+        GTEST_SKIP();
+    }
+
+    ASSERT_EQ(OK, setRpcClientDebugStatus);
 
     auto rpcSession = RpcSession::make();
     ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
@@ -1455,7 +1558,6 @@
                 std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
             auto [socketType, rpcSecurity, certificateFormat] = param;
             auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
-            rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
             switch (socketType) {
                 case SocketType::PRECONNECTED: {
                     return AssertionFailure() << "Not supported by this test";
@@ -1917,5 +2019,6 @@
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
     android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
+
     return RUN_ALL_TESTS();
 }
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index f1fe164..32406e5 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -192,6 +192,8 @@
     // only reading one binder type for now
     PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
+    PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::os::IServiceManager>>, readStrongBinderVector),
+    PARCEL_READ_WITH_STATUS(std::optional<std::vector<android::sp<android::os::IServiceManager>>>, readStrongBinderVector),
 
     PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
     PARCEL_READ_WITH_STATUS(::std::optional<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
@@ -284,7 +286,6 @@
         FUZZ_LOG() << "readObject: " << obj;
     },
     PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
-    PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
 
     // additional parcelable objects defined in libbinder
@@ -301,6 +302,23 @@
         FUZZ_LOG() << "ParcelableHolder status: " << status;
     },
     PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
+    [] (const ::android::Parcel& p, uint8_t /* data */) {
+        FUZZ_LOG() << "about to call hasFileDescriptorsInRange() with status";
+        size_t offset = p.readUint32();
+        size_t length = p.readUint32();
+        bool result;
+        status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
+        FUZZ_LOG() << " status: " << status  << " result: " << result;
+    },
+    [] (const ::android::Parcel& p, uint8_t /* data */) {
+        FUZZ_LOG() << "about to call compareDataInRange() with status";
+        size_t thisOffset = p.readUint32();
+        size_t otherOffset = p.readUint32();
+        size_t length = p.readUint32();
+        int result;
+        status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
+        FUZZ_LOG() << " status: " << status  << " result: " << result;
+    },
 };
 // clang-format on
 #pragma clang diagnostic pop
diff --git a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
index 6b783a4..752fcbb 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -25,6 +25,7 @@
 // TODO(b/142061461): parent class
 class SomeParcelable {
 public:
+    binder_status_t writeToParcel(AParcel* /*parcel*/) { return STATUS_OK; }
     binder_status_t readFromParcel(const AParcel* parcel) {
         return AParcel_readInt32(parcel, &mValue);
     }
@@ -33,6 +34,41 @@
     int32_t mValue = 0;
 };
 
+class ISomeInterface : public ::ndk::ICInterface {
+public:
+    ISomeInterface() = default;
+    virtual ~ISomeInterface() = default;
+    static binder_status_t readFromParcel(const AParcel* parcel,
+                                          std::shared_ptr<ISomeInterface>* instance);
+};
+
+static binder_status_t onTransact(AIBinder*, transaction_code_t, const AParcel*, AParcel*) {
+    return STATUS_UNKNOWN_TRANSACTION;
+}
+
+static AIBinder_Class* g_class = ::ndk::ICInterface::defineClass("ISomeInterface", onTransact);
+
+class BpSomeInterface : public ::ndk::BpCInterface<ISomeInterface> {
+public:
+    explicit BpSomeInterface(const ::ndk::SpAIBinder& binder) : BpCInterface(binder) {}
+    virtual ~BpSomeInterface() = default;
+};
+
+binder_status_t ISomeInterface::readFromParcel(const AParcel* parcel,
+                                               std::shared_ptr<ISomeInterface>* instance) {
+    ::ndk::SpAIBinder binder;
+    binder_status_t status = AParcel_readStrongBinder(parcel, binder.getR());
+    if (status == STATUS_OK) {
+        if (AIBinder_associateClass(binder.get(), g_class)) {
+            *instance = std::static_pointer_cast<ISomeInterface>(
+                    ::ndk::ICInterface::asInterface(binder.get()));
+        } else {
+            *instance = ::ndk::SharedRefBase::make<BpSomeInterface>(binder);
+        }
+    }
+    return status;
+}
+
 #define PARCEL_READ(T, FUN)                                              \
     [](const NdkParcelAdapter& p, uint8_t /*data*/) {                    \
         FUZZ_LOG() << "about to read " #T " using " #FUN " with status"; \
@@ -95,6 +131,13 @@
         PARCEL_READ(std::vector<std::string>, ndk::AParcel_readVector),
         PARCEL_READ(std::optional<std::vector<std::optional<std::string>>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<SomeParcelable>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<std::optional<SomeParcelable>>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::vector<ndk::SpAIBinder>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<ndk::SpAIBinder>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::vector<ndk::ScopedFileDescriptor>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<ndk::ScopedFileDescriptor>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::vector<std::shared_ptr<ISomeInterface>>, ndk::AParcel_readVector),
+        PARCEL_READ(std::optional<std::vector<std::shared_ptr<ISomeInterface>>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<int32_t>, ndk::AParcel_readVector),
         PARCEL_READ(std::optional<std::vector<int32_t>>, ndk::AParcel_readVector),
         PARCEL_READ(std::vector<uint32_t>, ndk::AParcel_readVector),
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index c0f0a12..71e847f 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,6 +14,7 @@
     fuzz_config: {
         cc: ["smoreland@google.com"],
     },
+    corpus: ["corpus/*"],
     dictionary: "binder_rpc_fuzzer.dict",
 
     srcs: [
diff --git a/libs/binder/tests/rpc_fuzzer/corpus/special_transaction b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
new file mode 100644
index 0000000..37228ee
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/corpus/special_transaction
Binary files differ
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 518849a..a8713a2 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -119,7 +119,6 @@
 
     sp<RpcServer> server = RpcServer::make(makeTransportCtxFactory(&provider));
     server->setRootObject(sp<SomeBinder>::make());
-    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
 
     std::thread serverThread([=] { (void)server->join(); });
@@ -158,6 +157,8 @@
         }
     }
 
+    usleep(10000);
+
     if (hangupBeforeShutdown) {
         connections.clear();
         while (!server->listSessions().empty() || server->numUninitializedSessions()) {
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index 20c5569..e77c55c 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -44,7 +44,6 @@
     auto thread = std::thread([&]() {
         prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
         server->setRootObject(sp<BBinder>::make());
-        server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
         CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
         server->join();
     });
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 64203f7..3190038 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -146,7 +146,6 @@
     ],
 
     shared_libs: [
-        "android.frameworks.bufferhub@1.0",
         "libbinder",
         "libbufferhub",
         "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
@@ -175,7 +174,6 @@
                 "BufferHubProducer.cpp",
             ],
             exclude_shared_libs: [
-                "android.frameworks.bufferhub@1.0",
                 "libbufferhub",
                 "libbufferhubqueue",
                 "libinput",
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 8edf604..a626970 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -71,6 +71,7 @@
         case HAL_PIXEL_FORMAT_Y8:
         case HAL_PIXEL_FORMAT_Y16:
         case HAL_PIXEL_FORMAT_RAW16:
+        case HAL_PIXEL_FORMAT_RAW12:
         case HAL_PIXEL_FORMAT_RAW10:
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
         case HAL_PIXEL_FORMAT_BLOB:
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index e1b1efc..46800f2 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -33,10 +33,13 @@
 // using just a few large reads.
 static const size_t EVENT_BUFFER_SIZE = 100;
 
+static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300);
+
 DisplayEventDispatcher::DisplayEventDispatcher(
         const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
         ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
+      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false),
+        mLastVsyncCount(0), mLastScheduleVsyncTime(0) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -86,6 +89,7 @@
         }
 
         mWaitingForVsync = true;
+        mLastScheduleVsyncTime = systemTime(SYSTEM_TIME_MONOTONIC);
     }
     return OK;
 }
@@ -124,9 +128,21 @@
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
               vsyncEventData.id);
         mWaitingForVsync = false;
+        mLastVsyncCount = vsyncCount;
         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
     }
 
+    if (mWaitingForVsync) {
+        const nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
+        const nsecs_t vsyncScheduleDelay = currentTime - mLastScheduleVsyncTime;
+        if (vsyncScheduleDelay > WAITING_FOR_VSYNC_TIMEOUT) {
+            ALOGW("Vsync time out! vsyncScheduleDelay=%" PRId64 "ms", ns2ms(vsyncScheduleDelay));
+            mWaitingForVsync = false;
+            dispatchVsync(currentTime, vsyncDisplayId /* displayId is not used */,
+                          ++mLastVsyncCount, vsyncEventData /* empty data */);
+        }
+    }
+
     return 1; // keep the callback
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 30d19e3..b3647d6 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -301,7 +301,7 @@
         // continues to use it.
         sp<GraphicBuffer> buffer = new GraphicBuffer(
                 kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
-                GraphicBuffer::USAGE_SW_WRITE_RARELY,
+                DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
                 "[GLConsumer debug texture]");
         uint32_t* bits;
         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0d7795e..a82fc6f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -291,6 +291,17 @@
         return {};
     }
 
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
+        Parcel data, reply;
+        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+        SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
+                    &reply);
+        uint64_t rawId;
+        SAFE_PARCEL(reply.readUint64, &rawId);
+        *displayId = PhysicalDisplayId(rawId);
+        return NO_ERROR;
+    }
+
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1713,6 +1724,16 @@
                            [](PhysicalDisplayId id) { return id.value; });
             return reply->writeUint64Vector(rawIds);
         }
+        case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            PhysicalDisplayId id;
+            status_t result = getPrimaryPhysicalDisplayId(&id);
+            if (result != NO_ERROR) {
+                ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
+                return result;
+            }
+            return reply->writeUint64(id.value);
+        }
         case ADD_REGION_SAMPLING_LISTENER: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             Rect samplingArea;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 96da8ef..1377284 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -913,6 +913,10 @@
     return ComposerService::getComposerService()->getPhysicalDisplayIds();
 }
 
+status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
+    return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+}
+
 std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
     return ComposerService::getComposerService()->getInternalDisplayId();
 }
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4ade240..08f3597 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -56,6 +56,8 @@
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
+    uint32_t mLastVsyncCount;
+    nsecs_t mLastScheduleVsyncTime;
 
     std::vector<FrameRateOverride> mFrameRateOverrides;
 
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 2a3f6a4..ef5353f 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -140,6 +140,8 @@
      */
     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
 
+    virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
+
     // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
     std::optional<PhysicalDisplayId> getInternalDisplayId() const {
         const auto displayIds = getPhysicalDisplayIds();
@@ -624,6 +626,7 @@
         ON_PULL_ATOM,
         ADD_TUNNEL_MODE_ENABLED_LISTENER,
         REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
+        GET_PRIMARY_PHYSICAL_DISPLAY_ID,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index baa0567..4164ca3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -307,6 +307,7 @@
 
     //! Get stable IDs for connected physical displays
     static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+    static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*);
     static std::optional<PhysicalDisplayId> getInternalDisplayId();
 
     //! Get token for a physical display given its stable ID
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 59b0c04..630dd17 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -694,6 +694,7 @@
             bool /*secure*/) override { return nullptr; }
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
     status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
                                  const Vector<ComposerState>& /*state*/,
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 30c42a3..fcbc16f 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -89,8 +89,15 @@
 
     // Treblized input device config files will be located /product/usr, /system_ext/usr,
     // /odm/usr or /vendor/usr.
-    const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
-                                    getenv("ANDROID_ROOT")};
+    // These files may also be in the com.android.input.config APEX.
+    const char* rootsForPartition[]{
+            "/product",
+            "/system_ext",
+            "/odm",
+            "/vendor",
+            "/apex/com.android.input.config/etc",
+            getenv("ANDROID_ROOT"),
+    };
     for (size_t i = 0; i < size(rootsForPartition); i++) {
         if (rootsForPartition[i] == nullptr) {
             continue;
diff --git a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
index 2f31888..6882ea3 100644
--- a/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
+++ b/libs/nativedisplay/surfacetexture/EGLConsumer.cpp
@@ -191,7 +191,7 @@
         // continues to use it.
         sp<GraphicBuffer> buffer =
                 new GraphicBuffer(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
-                                  GraphicBuffer::USAGE_SW_WRITE_RARELY,
+                                  DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
                                   "[EGLConsumer debug texture]");
         uint32_t* bits;
         buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index e3d705f..abcd527 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -147,7 +147,8 @@
         OP_ACTIVITY_RECOGNITION_SOURCE = 113,
         OP_BLUETOOTH_ADVERTISE = 114,
         OP_RECORD_INCOMING_PHONE_AUDIO = 115,
-        _NUM_OP = 116
+        OP_NEARBY_WIFI_DEVICES = 116,
+        _NUM_OP = 117
     };
 
     AppOpsManager();
diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp
index 0c5a851..9e466b6 100644
--- a/libs/renderengine/RenderEngine.cpp
+++ b/libs/renderengine/RenderEngine.cpp
@@ -26,55 +26,39 @@
 namespace android {
 namespace renderengine {
 
-std::unique_ptr<RenderEngine> RenderEngine::create(const RenderEngineCreationArgs& args) {
-    RenderEngineType renderEngineType = args.renderEngineType;
-
+std::unique_ptr<RenderEngine> RenderEngine::create(RenderEngineCreationArgs args) {
     // Keep the ability to override by PROPERTIES:
     char prop[PROPERTY_VALUE_MAX];
     property_get(PROPERTY_DEBUG_RENDERENGINE_BACKEND, prop, "");
     if (strcmp(prop, "gles") == 0) {
-        renderEngineType = RenderEngineType::GLES;
+        args.renderEngineType = RenderEngineType::GLES;
     }
     if (strcmp(prop, "threaded") == 0) {
-        renderEngineType = RenderEngineType::THREADED;
+        args.renderEngineType = RenderEngineType::THREADED;
     }
     if (strcmp(prop, "skiagl") == 0) {
-        renderEngineType = RenderEngineType::SKIA_GL;
+        args.renderEngineType = RenderEngineType::SKIA_GL;
     }
     if (strcmp(prop, "skiaglthreaded") == 0) {
-        renderEngineType = RenderEngineType::SKIA_GL_THREADED;
+        args.renderEngineType = RenderEngineType::SKIA_GL_THREADED;
     }
 
-    switch (renderEngineType) {
+    switch (args.renderEngineType) {
         case RenderEngineType::THREADED:
             ALOGD("Threaded RenderEngine with GLES Backend");
             return renderengine::threaded::RenderEngineThreaded::create(
                     [args]() { return android::renderengine::gl::GLESRenderEngine::create(args); },
-                    renderEngineType);
+                    args.renderEngineType);
         case RenderEngineType::SKIA_GL:
             ALOGD("RenderEngine with SkiaGL Backend");
             return renderengine::skia::SkiaGLRenderEngine::create(args);
         case RenderEngineType::SKIA_GL_THREADED: {
-            // These need to be recreated, since they are a constant reference, and we need to
-            // let SkiaRE know that it's running as threaded, and all GL operation will happen on
-            // the same thread.
-            RenderEngineCreationArgs skiaArgs =
-                    RenderEngineCreationArgs::Builder()
-                            .setPixelFormat(args.pixelFormat)
-                            .setImageCacheSize(args.imageCacheSize)
-                            .setUseColorManagerment(args.useColorManagement)
-                            .setEnableProtectedContext(args.enableProtectedContext)
-                            .setPrecacheToneMapperShaderOnly(args.precacheToneMapperShaderOnly)
-                            .setSupportsBackgroundBlur(args.supportsBackgroundBlur)
-                            .setContextPriority(args.contextPriority)
-                            .setRenderEngineType(renderEngineType)
-                            .build();
             ALOGD("Threaded RenderEngine with SkiaGL Backend");
             return renderengine::threaded::RenderEngineThreaded::create(
-                    [skiaArgs]() {
-                        return android::renderengine::skia::SkiaGLRenderEngine::create(skiaArgs);
+                    [args]() {
+                        return android::renderengine::skia::SkiaGLRenderEngine::create(args);
                     },
-                    renderEngineType);
+                    args.renderEngineType);
         }
         case RenderEngineType::GLES:
         default:
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 5964bc3..46a7d1e 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -98,7 +98,7 @@
         SKIA_GL_THREADED = 4,
     };
 
-    static std::unique_ptr<RenderEngine> create(const RenderEngineCreationArgs& args);
+    static std::unique_ptr<RenderEngine> create(RenderEngineCreationArgs args);
 
     virtual ~RenderEngine() = 0;
 
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index ae8f238..cc627b8 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -388,7 +388,10 @@
             drawBlurLayers(renderengine, display, dstTexture);
         }
 
-        // should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+        // The majority of skia shaders needed by RenderEngine are related to sampling images.
+        // These need to be generated with various source textures.
+        // Make a list of applicable sources.
+        // GRALLOC_USAGE_HW_TEXTURE should be the same as AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE.
         const int64_t usageExternal = GRALLOC_USAGE_HW_TEXTURE;
         sp<GraphicBuffer> externalBuffer =
                 new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_8888,
@@ -396,24 +399,24 @@
         const auto externalTexture =
                 std::make_shared<ExternalTexture>(externalBuffer, *renderengine,
                                                   ExternalTexture::Usage::READABLE);
+        std::vector<const std::shared_ptr<ExternalTexture>> textures =
+            {srcTexture, externalTexture};
 
-        // Another external texture with a different pixel format triggers useIsOpaqueWorkaround
+        // Another external texture with a different pixel format triggers useIsOpaqueWorkaround.
+        // It doesn't have to be f16, but it can't be the usual 8888.
         sp<GraphicBuffer> f16ExternalBuffer =
                 new GraphicBuffer(displayRect.width(), displayRect.height(), PIXEL_FORMAT_RGBA_FP16,
                                   1, usageExternal, "primeShaderCache_external_f16");
-        const auto f16ExternalTexture =
+        // The F16 texture may not be usable on all devices, so check first that it was created.
+        status_t error = f16ExternalBuffer->initCheck();
+        if (!error) {
+            const auto f16ExternalTexture =
                 std::make_shared<ExternalTexture>(f16ExternalBuffer, *renderengine,
                                                   ExternalTexture::Usage::READABLE);
+            textures.push_back(f16ExternalTexture);
+        }
 
-        // The majority of shaders are related to sampling images.
-        // These need to be generated with various source textures
-        // The F16 texture may not be usable on all devices, so check first that it was created with
-        // the requested usage bit.
-        auto textures = {srcTexture, externalTexture};
-        auto texturesWithF16 = {srcTexture, externalTexture, f16ExternalTexture};
-        bool canUsef16 = f16ExternalBuffer->getUsage() & GRALLOC_USAGE_HW_TEXTURE;
-
-        for (auto texture : canUsef16 ? texturesWithF16 : textures) {
+        for (auto texture : textures) {
             drawImageLayers(renderengine, display, dstTexture, texture);
             // Draw layers for b/185569240.
             drawClippedLayers(renderengine, display, dstTexture, texture);
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
index 0997e9f..d073e2b 100644
--- a/libs/vibrator/OWNERS
+++ b/libs/vibrator/OWNERS
@@ -1,2 +1 @@
-lsandrade@google.com
-michaelwr@google.com
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a519786..c2a2794 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3899,6 +3899,13 @@
                                               args->downTime, args->pointerCount,
                                               args->pointerProperties, args->pointerCoords, 0, 0);
 
+        if (args->id != android::os::IInputConstants::INVALID_INPUT_EVENT_ID &&
+            IdGenerator::getSource(args->id) == IdGenerator::Source::INPUT_READER &&
+            !mInputFilterEnabled) {
+            const bool isDown = args->action == AMOTION_EVENT_ACTION_DOWN;
+            mLatencyTracker.trackListener(args->id, isDown, args->eventTime, args->readTime);
+        }
+
         needWake = enqueueInboundEventLocked(std::move(newEntry));
         mLock.unlock();
     } // release lock
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index d634dcd..52f189c 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -50,13 +50,12 @@
  * key-value pair. Equivalent to the imaginary std api std::multimap::erase(key, value).
  */
 template <typename K, typename V>
-static void eraseByKeyAndValue(std::multimap<K, V>& map, K key, V value) {
-    auto iterpair = map.equal_range(key);
-
-    for (auto it = iterpair.first; it != iterpair.second; ++it) {
+static void eraseByValue(std::multimap<K, V>& map, const V& value) {
+    for (auto it = map.begin(); it != map.end();) {
         if (it->second == value) {
-            map.erase(it);
-            break;
+            it = map.erase(it);
+        } else {
+            it++;
         }
     }
 }
@@ -76,9 +75,7 @@
         // confuse us by reporting the rest of the timeline for one of them. This should happen
         // rarely, so we won't lose much data
         mTimelines.erase(it);
-        // In case we have another input event with a different id and at the same eventTime,
-        // only erase this specific inputEventId.
-        eraseByKeyAndValue(mEventTimes, eventTime, inputEventId);
+        eraseByValue(mEventTimes, inputEventId);
         return;
     }
     mTimelines.emplace(inputEventId, InputEventTimeline(isDown, eventTime, readTime));
@@ -90,7 +87,8 @@
                                         nsecs_t finishTime) {
     const auto it = mTimelines.find(inputEventId);
     if (it == mTimelines.end()) {
-        // It's possible that an app sends a bad (or late)'Finish' signal, since it's free to do
+        // This could happen if we erased this event when duplicate events were detected. It's
+        // also possible that an app sent a bad (or late) 'Finish' signal, since it's free to do
         // anything in its process. Just drop the report and move on.
         return;
     }
@@ -120,7 +118,8 @@
         std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline) {
     const auto it = mTimelines.find(inputEventId);
     if (it == mTimelines.end()) {
-        // It's possible that an app sends a bad (or late) 'Timeline' signal, since it's free to do
+        // This could happen if we erased this event when duplicate events were detected. It's
+        // also possible that an app sent a bad (or late) 'Timeline' signal, since it's free to do
         // anything in its process. Just drop the report and move on.
         return;
     }
@@ -166,14 +165,6 @@
     }
 }
 
-void LatencyTracker::reportNow() {
-    for (const auto& [inputEventId, timeline] : mTimelines) {
-        mTimelineProcessor->processTimeline(timeline);
-    }
-    mTimelines.clear();
-    mEventTimes.clear();
-}
-
 std::string LatencyTracker::dump(const char* prefix) {
     return StringPrintf("%sLatencyTracker:\n", prefix) +
             StringPrintf("%s  mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 289b8ed..4b0c618 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -43,6 +43,12 @@
     LatencyTracker(InputEventTimelineProcessor* processor);
     /**
      * Start keeping track of an event identified by inputEventId. This must be called first.
+     * If duplicate events are encountered (events that have the same eventId), none of them will be
+     * tracked. This is because there is not enough information to correctly track them. The api's
+     * 'trackFinishedEvent' and 'trackGraphicsLatency' only contain the inputEventId, and not the
+     * eventTime. Even if eventTime was provided, there would still be a possibility of having
+     * duplicate events that happen to have the same eventTime and inputEventId. Therefore, we
+     * must drop all duplicate data.
      */
     void trackListener(int32_t inputEventId, bool isDown, nsecs_t eventTime, nsecs_t readTime);
     void trackFinishedEvent(int32_t inputEventId, const sp<IBinder>& connectionToken,
@@ -50,14 +56,6 @@
     void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
                               std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
 
-    /**
-     * Report all collected events immediately, even if some of them are currently incomplete
-     * and may receive 'trackFinishedEvent' or 'trackGraphicsLatency' calls in the future.
-     * This is useful for tests. Otherwise, tests would have to inject additional "future" events,
-     * which is not convenient.
-     */
-    void reportNow();
-
     std::string dump(const char* prefix);
 
 private:
diff --git a/services/inputflinger/tests/LatencyTracker_test.cpp b/services/inputflinger/tests/LatencyTracker_test.cpp
index e7e1937..89c0741 100644
--- a/services/inputflinger/tests/LatencyTracker_test.cpp
+++ b/services/inputflinger/tests/LatencyTracker_test.cpp
@@ -16,6 +16,7 @@
 
 #include "../dispatcher/LatencyTracker.h"
 
+#include <android-base/properties.h>
 #include <binder/Binder.h>
 #include <gtest/gtest.h>
 #include <inttypes.h>
@@ -23,11 +24,16 @@
 
 #define TAG "LatencyTracker_test"
 
+using android::base::HwTimeoutMultiplier;
 using android::inputdispatcher::InputEventTimeline;
 using android::inputdispatcher::LatencyTracker;
 
 namespace android::inputdispatcher {
 
+const std::chrono::duration ANR_TIMEOUT = std::chrono::milliseconds(
+        android::os::IInputConstants::UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
+        HwTimeoutMultiplier());
+
 InputEventTimeline getTestTimeline() {
     InputEventTimeline t(
             /*isDown*/ true,
@@ -57,6 +63,8 @@
     }
     void TearDown() override {}
 
+    void triggerEventReporting(nsecs_t lastEventTime);
+
     void assertReceivedTimeline(const InputEventTimeline& timeline);
     /**
      * Timelines can be received in any order (order is not guaranteed). So if we are expecting more
@@ -72,8 +80,17 @@
     std::deque<InputEventTimeline> mReceivedTimelines;
 };
 
+/**
+ * Send an event that would trigger the reporting of all of the events that are at least as old as
+ * the provided 'lastEventTime'.
+ */
+void LatencyTrackerTest::triggerEventReporting(nsecs_t lastEventTime) {
+    const nsecs_t triggerEventTime =
+            lastEventTime + std::chrono::nanoseconds(ANR_TIMEOUT).count() + 1;
+    mTracker->trackListener(1 /*inputEventId*/, true /*isDown*/, triggerEventTime, 3 /*readTime*/);
+}
+
 void LatencyTrackerTest::assertReceivedTimeline(const InputEventTimeline& timeline) {
-    mTracker->reportNow();
     ASSERT_FALSE(mReceivedTimelines.empty());
     const InputEventTimeline& t = mReceivedTimelines.front();
     ASSERT_EQ(timeline, t);
@@ -88,7 +105,6 @@
  * equal element in B, and for every element in B there is an equal element in A.
  */
 void LatencyTrackerTest::assertReceivedTimelines(const std::vector<InputEventTimeline>& timelines) {
-    mTracker->reportNow();
     ASSERT_EQ(timelines.size(), mReceivedTimelines.size());
     for (const InputEventTimeline& expectedTimeline : timelines) {
         bool found = false;
@@ -121,6 +137,7 @@
  */
 TEST_F(LatencyTrackerTest, TrackListener_DoesNotTriggerReporting) {
     mTracker->trackListener(1 /*inputEventId*/, false /*isDown*/, 2 /*eventTime*/, 3 /*readTime*/);
+    triggerEventReporting(2 /*eventTime*/);
     assertReceivedTimeline(InputEventTimeline{false, 2, 3});
 }
 
@@ -130,6 +147,7 @@
 TEST_F(LatencyTrackerTest, TrackFinishedEvent_DoesNotTriggerReporting) {
     mTracker->trackFinishedEvent(1 /*inputEventId*/, connection1, 2 /*deliveryTime*/,
                                  3 /*consumeTime*/, 4 /*finishTime*/);
+    triggerEventReporting(4 /*eventTime*/);
     assertReceivedTimelines({});
 }
 
@@ -141,6 +159,7 @@
     graphicsTimeline[GraphicsTimeline::GPU_COMPLETED_TIME] = 2;
     graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = 3;
     mTracker->trackGraphicsLatency(1 /*inputEventId*/, connection2, graphicsTimeline);
+    triggerEventReporting(3 /*eventTime*/);
     assertReceivedTimelines({});
 }
 
@@ -155,9 +174,30 @@
                                  expectedCT.consumeTime, expectedCT.finishTime);
     mTracker->trackGraphicsLatency(inputEventId, connectionToken, expectedCT.graphicsTimeline);
 
+    triggerEventReporting(expected.eventTime);
     assertReceivedTimeline(expected);
 }
 
+/**
+ * Send 2 events with the same inputEventId, but different eventTime's. Ensure that no crash occurs,
+ * and that the tracker drops such events completely.
+ */
+TEST_F(LatencyTrackerTest, WhenDuplicateEventsAreReported_DoesNotCrash) {
+    constexpr nsecs_t inputEventId = 1;
+    constexpr nsecs_t readTime = 3; // does not matter for this test
+    constexpr bool isDown = true;   // does not matter for this test
+
+    // In the following 2 calls to trackListener, the inputEventId's are the same, but event times
+    // are different.
+    mTracker->trackListener(inputEventId, isDown, 1 /*eventTime*/, readTime);
+    mTracker->trackListener(inputEventId, isDown, 2 /*eventTime*/, readTime);
+
+    triggerEventReporting(2 /*eventTime*/);
+    // Since we sent duplicate input events, the tracker should just delete all of them, because it
+    // does not have enough information to properly track them.
+    assertReceivedTimelines({});
+}
+
 TEST_F(LatencyTrackerTest, MultipleEvents_AreReportedConsistently) {
     constexpr int32_t inputEventId1 = 1;
     InputEventTimeline timeline1(
@@ -204,6 +244,7 @@
     mTracker->trackGraphicsLatency(inputEventId2, connection2,
                                    connectionTimeline2.graphicsTimeline);
     // Now both events should be completed
+    triggerEventReporting(timeline2.eventTime);
     assertReceivedTimelines({timeline1, timeline2});
 }
 
@@ -228,6 +269,7 @@
     mTracker->trackGraphicsLatency(1 /*inputEventId*/, token, expectedCT.graphicsTimeline);
 
     expectedTimelines[0].connectionTimelines.emplace(token, std::move(expectedCT));
+    triggerEventReporting(timeline.eventTime);
     assertReceivedTimelines(expectedTimelines);
 }
 
@@ -246,6 +288,7 @@
     mTracker->trackGraphicsLatency(inputEventId, connection1, expectedCT.graphicsTimeline);
 
     mTracker->trackListener(inputEventId, expected.isDown, expected.eventTime, expected.readTime);
+    triggerEventReporting(expected.eventTime);
     assertReceivedTimeline(
             InputEventTimeline{expected.isDown, expected.eventTime, expected.readTime});
 }
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..df4db19
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+
+cc_fuzz {
+    name: "inputflinger_latencytracker_fuzzer",
+    defaults: [
+        "inputflinger_defaults",
+    ],
+    include_dirs: [
+        "frameworks/native/services/inputflinger",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libui",
+        "libutils",
+        "libinput",
+        "libinputflinger",
+    ],
+    srcs: [
+        "LatencyTrackerFuzzer.cpp",
+    ],
+}
diff --git a/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
new file mode 100644
index 0000000..4f066ad
--- /dev/null
+++ b/services/inputflinger/tests/fuzzers/LatencyTrackerFuzzer.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include "dispatcher/LatencyTracker.h"
+
+namespace android {
+
+namespace inputdispatcher {
+
+/**
+ * A processor of InputEventTimelines that does nothing with the provided data.
+ */
+class EmptyProcessor : public InputEventTimelineProcessor {
+public:
+    /**
+     * Just ignore the provided timeline
+     */
+    void processTimeline(const InputEventTimeline& timeline) override {
+        for (const auto& [token, connectionTimeline] : timeline.connectionTimelines) {
+            connectionTimeline.isComplete();
+        }
+    };
+};
+
+static sp<IBinder> getConnectionToken(FuzzedDataProvider& fdp,
+                                      std::array<sp<IBinder>, 10>& tokens) {
+    const bool useExistingToken = fdp.ConsumeBool();
+    if (useExistingToken) {
+        return tokens[fdp.ConsumeIntegralInRange<size_t>(0ul, tokens.size() - 1)];
+    }
+    return new BBinder();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+
+    EmptyProcessor emptyProcessor;
+    LatencyTracker tracker(&emptyProcessor);
+
+    // Make some pre-defined tokens to ensure that some timelines are complete.
+    std::array<sp<IBinder> /*token*/, 10> predefinedTokens;
+    for (size_t i = 0; i < predefinedTokens.size(); i++) {
+        predefinedTokens[i] = new BBinder();
+    }
+
+    // Randomly invoke LatencyTracker api's until randomness is exhausted.
+    while (fdp.remaining_bytes() > 0) {
+        fdp.PickValueInArray<std::function<void()>>({
+                [&]() -> void {
+                    int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+                    int32_t isDown = fdp.ConsumeBool();
+                    nsecs_t eventTime = fdp.ConsumeIntegral<nsecs_t>();
+                    nsecs_t readTime = fdp.ConsumeIntegral<nsecs_t>();
+                    tracker.trackListener(inputEventId, isDown, eventTime, readTime);
+                },
+                [&]() -> void {
+                    int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+                    sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+                    nsecs_t deliveryTime = fdp.ConsumeIntegral<nsecs_t>();
+                    nsecs_t consumeTime = fdp.ConsumeIntegral<nsecs_t>();
+                    nsecs_t finishTime = fdp.ConsumeIntegral<nsecs_t>();
+                    tracker.trackFinishedEvent(inputEventId, connectionToken, deliveryTime,
+                                               consumeTime, finishTime);
+                },
+                [&]() -> void {
+                    int32_t inputEventId = fdp.ConsumeIntegral<int32_t>();
+                    sp<IBinder> connectionToken = getConnectionToken(fdp, predefinedTokens);
+                    std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+                    for (size_t i = 0; i < graphicsTimeline.size(); i++) {
+                        graphicsTimeline[i] = fdp.ConsumeIntegral<nsecs_t>();
+                    }
+                    tracker.trackGraphicsLatency(inputEventId, connectionToken, graphicsTimeline);
+                },
+        })();
+    }
+
+    return 0;
+}
+
+} // namespace inputdispatcher
+
+} // namespace android
\ No newline at end of file
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index bba6e22..1be5a96 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -77,7 +77,6 @@
         "libsensor",
         "libsensorprivacy",
         "libpermission",
-        "packagemanager_aidl-cpp",
     ],
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index e26ab11..82a9ae2 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -326,7 +326,7 @@
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
         PixelFormat format, uint64_t usage, int* sslot, sp<Fence>* fence) {
-    LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+    LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
 
     status_t result =
             mSource[source]->dequeueBuffer(sslot, fence, mSinkBufferWidth, mSinkBufferHeight,
@@ -641,7 +641,7 @@
 }
 
 status_t VirtualDisplaySurface::refreshOutputBuffer() {
-    LOG_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId));
+    LOG_ALWAYS_FATAL_IF(GpuVirtualDisplayId::tryCast(mDisplayId).has_value());
 
     if (mOutputProducerSlot >= 0) {
         mSource[SOURCE_SINK]->cancelBuffer(
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 230810c..abc49bf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -653,6 +653,17 @@
     return displayIds;
 }
 
+status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
+    Mutex::Autolock lock(mStateLock);
+    const auto display = getInternalDisplayIdLocked();
+    if (!display) {
+        return NAME_NOT_FOUND;
+    }
+
+    *id = *display;
+    return NO_ERROR;
+}
+
 sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
     Mutex::Autolock lock(mStateLock);
     return getPhysicalDisplayTokenLocked(displayId);
@@ -5238,6 +5249,7 @@
         case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
         case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
+        case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests,
             // which acquire the necessary permission dynamically. Don't use the permission cache
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 380f444..fa19b7f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -614,6 +614,7 @@
     sp<IBinder> createDisplay(const String8& displayName, bool secure) override;
     void destroyDisplay(const sp<IBinder>& displayToken) override;
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override;
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
     status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
                                  const Vector<ComposerState>& state,
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 4a69c8f..e15eae8 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -34,6 +34,8 @@
 using android::hardware::graphics::common::V1_2::PixelFormat;
 using android::ui::DisplayPrimaries;
 
+// Keep logic in sync with WindowManagerService functions that query SurfaceFlinger properties.
+// Consider exposing properties via ISurfaceComposer instead.
 int64_t vsync_event_phase_offset_ns(int64_t defaultValue) {
     auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns();
     if (temp.has_value()) {
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 673239d..caeff4a 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -63,18 +63,17 @@
     return OK;
 }
 
-static status_t startDisplayService() {
+static void startDisplayService() {
     using android::frameworks::displayservice::V1_0::implementation::DisplayService;
     using android::frameworks::displayservice::V1_0::IDisplayService;
 
     sp<IDisplayService> displayservice = new DisplayService();
     status_t err = displayservice->registerAsService();
 
+    // b/141930622
     if (err != OK) {
-        ALOGE("Could not register IDisplayService service.");
+        ALOGE("Did not register (deprecated) IDisplayService service.");
     }
-
-    return err;
 }
 
 int main(int, char**) {
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
new file mode 100644
index 0000000..d073e2b
--- /dev/null
+++ b/services/vibratorservice/OWNERS
@@ -0,0 +1 @@
+include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index 0de0f9e..1612743 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -2,4 +2,4 @@
   class core
   user system
   group system input uhid
-  writepid /dev/cpuset/system/tasks
+  task_profiles VrServiceCapacityNormal