Merge "binder: make recovery_available."
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index e3c4ede..01c4723 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -265,6 +265,22 @@
     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
 
 # Only create the tracing instance if persist.mm_events.enabled
 # Attempting to remove the tracing instance after it has been created
@@ -337,6 +353,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..157d259 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;
 }
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..fdbe85b 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -50,6 +50,7 @@
 {
     if (service != nullptr) {
         Parcel data, reply;
+        data.markForBinder(service);
         status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
         if (err == NO_ERROR) {
             return reply.readString16();
@@ -76,6 +77,9 @@
     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 +91,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 +100,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 +120,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;
             }
@@ -138,6 +145,7 @@
                 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 +155,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 +164,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 +173,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 +182,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 +191,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 +203,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 +211,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 +220,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 +229,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 +238,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 +332,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 +342,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/libs/binder/Android.bp b/libs/binder/Android.bp
index 3f82939..dc153c9 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -155,10 +155,6 @@
         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",
@@ -337,6 +333,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..1c8bdea 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,7 @@
+# Bug component: 32456
 arve@google.com
 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 7a30ff9..631a4b6 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
@@ -566,6 +548,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;
@@ -1337,7 +1346,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++;
         }
 
@@ -2227,7 +2236,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);
     }
 }
 
@@ -2244,7 +2253,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);
     }
 }
 
@@ -2449,7 +2458,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) {
@@ -2542,7 +2551,6 @@
     mAllowFds = true;
     mDeallocZero = false;
     mOwner = nullptr;
-    mOpenAshmemSize = 0;
     mWorkSourceRequestHeaderPosition = 0;
     mRequestHeaderPresent = false;
 
@@ -2559,18 +2567,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;
 }
 
@@ -2578,13 +2577,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..53c9b78 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -90,6 +90,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) {
@@ -473,6 +487,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 +500,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 +688,8 @@
 
     status_t status = OK;
     if (init) {
-        mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+        status =
+                mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
     {
@@ -677,7 +701,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 +715,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/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..d90e803 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -87,6 +87,7 @@
     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.
@@ -1141,6 +1142,7 @@
     release_func        mOwner;
 
     sp<RpcSession> mSession;
+    size_t mReserved;
 
     class Blob {
     public:
@@ -1225,13 +1227,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..34f1cbf 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,12 @@
 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 object.
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+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/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..81aa551 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -780,3 +780,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_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 563d011..2b18a0a 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -543,6 +543,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 +573,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 +585,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 +680,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_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..64170af 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -145,6 +145,7 @@
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
+    AIBinder_setMinSchedulerPolicy; # llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index d9d7caf..ecb044e 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -17,6 +17,7 @@
     rustlibs: [
         "liblibc",
         "libbinder_ndk_sys",
+        "libdowncast_rs",
     ],
     host_supported: true,
     target: {
@@ -133,6 +134,7 @@
     rustlibs: [
         "liblibc",
         "libbinder_ndk_sys",
+        "libdowncast_rs",
     ],
 }
 
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 41ceee5..cc5dd06 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::{OwnedParcel, Parcel};
 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
@@ -153,25 +177,25 @@
     fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
 
     /// Create a Parcel that can be used with `submit_transact`.
-    fn prepare_transact(&self) -> Result<Parcel>;
+    fn prepare_transact(&self) -> Result<OwnedParcel>;
 
     /// Perform a generic operation with the object.
     ///
-    /// The provided [`Parcel`] must have been created by a call to
+    /// The provided [`OwnedParcel`] must have been created by a call to
     /// `prepare_transact` on the same binder.
     ///
     /// # Arguments
     ///
     /// * `code` - Transaction code for the operation.
-    /// * `data` - [`Parcel`] with input data.
+    /// * `data` - [`OwnedParcel`] with input data.
     /// * `flags` - Transaction flags, e.g. marking the transaction as
     ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
     fn submit_transact(
         &self,
         code: TransactionCode,
-        data: Parcel,
+        data: OwnedParcel,
         flags: TransactionFlags,
-    ) -> Result<Parcel>;
+    ) -> Result<OwnedParcel>;
 
     /// Perform a generic operation with the object. This is a convenience
     /// method that internally calls `prepare_transact` followed by
@@ -189,8 +213,8 @@
         input_callback: F,
     ) -> Result<Parcel> {
         let mut parcel = self.prepare_transact()?;
-        input_callback(&mut parcel)?;
-        self.submit_transact(code, parcel, flags)
+        input_callback(&mut parcel.borrowed())?;
+        self.submit_transact(code, parcel, flags).map(OwnedParcel::into_parcel)
     }
 }
 
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 7e8e3a5..81b620e 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -113,7 +113,7 @@
 };
 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 parcel::{OwnedParcel, 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,7 +127,7 @@
 
 /// 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,
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index dad89ec..9dba950 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -23,17 +23,21 @@
 
 use std::cell::RefCell;
 use std::convert::TryInto;
+use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
 use std::ptr;
 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.
@@ -49,6 +53,106 @@
     Borrowed(*mut sys::AParcel),
 }
 
+/// A variant of Parcel that is known to be owned.
+pub struct OwnedParcel {
+    ptr: *mut sys::AParcel,
+}
+
+/// # Safety
+///
+/// This type guarantees that it owns the AParcel and that all access to
+/// the AParcel happens through the OwnedParcel, so it is ok to send across
+/// threads.
+unsafe impl Send for OwnedParcel {}
+
+/// A variant of Parcel that is known to be borrowed.
+pub struct BorrowedParcel<'a> {
+    inner: Parcel,
+    _lifetime: PhantomData<&'a mut Parcel>,
+}
+
+impl OwnedParcel {
+    /// Create a new empty `OwnedParcel`.
+    pub fn new() -> OwnedParcel {
+        let ptr = unsafe {
+            // Safety: If `AParcel_create` succeeds, it always returns
+            // a valid pointer. If it fails, the process will crash.
+            sys::AParcel_create()
+        };
+        assert!(!ptr.is_null());
+        Self { ptr }
+    }
+
+    /// Create an owned 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. 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.
+    ///
+    /// 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 `OwnedParcel`.
+    ///
+    /// Because `OwnedParcel` 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<OwnedParcel> {
+        ptr.as_mut().map(|ptr| Self { ptr })
+    }
+
+    /// Consume the parcel, transferring ownership to the caller.
+    pub(crate) fn into_raw(self) -> *mut sys::AParcel {
+        let ptr = self.ptr;
+        let _ = ManuallyDrop::new(self);
+        ptr
+    }
+
+    /// Convert this `OwnedParcel` into an owned `Parcel`.
+    pub fn into_parcel(self) -> Parcel {
+        Parcel::Owned(self.into_raw())
+    }
+
+    /// Get a borrowed view into the contents of this `Parcel`.
+    pub fn borrowed(&mut self) -> BorrowedParcel<'_> {
+        BorrowedParcel {
+            inner: Parcel::Borrowed(self.ptr),
+            _lifetime: PhantomData,
+        }
+    }
+}
+
+impl Default for OwnedParcel {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl Clone for OwnedParcel {
+    fn clone(&self) -> Self {
+        let mut new_parcel = Self::new();
+        new_parcel
+            .borrowed()
+            .append_all_from(&Parcel::Borrowed(self.ptr))
+            .expect("Failed to append from Parcel");
+        new_parcel
+    }
+}
+
+impl<'a> std::ops::Deref for BorrowedParcel<'a> {
+    type Target = Parcel;
+    fn deref(&self) -> &Parcel {
+        &self.inner
+    }
+}
+impl<'a> std::ops::DerefMut for BorrowedParcel<'a> {
+    fn deref_mut(&mut self) -> &mut Parcel {
+        &mut self.inner
+    }
+}
+
 /// # Safety
 ///
 /// The `Parcel` constructors guarantee that a `Parcel` object will always
@@ -68,6 +172,21 @@
 }
 
 impl Parcel {
+    /// Create a new empty `Parcel`.
+    ///
+    /// Creates a new owned empty parcel that can be written to
+    /// using the serialization methods and appended to and
+    /// from using `append_from` and `append_from_all`.
+    pub fn new() -> Parcel {
+        let parcel = unsafe {
+            // Safety: If `AParcel_create` succeeds, it always returns
+            // a valid pointer. If it fails, the process will crash.
+            sys::AParcel_create()
+        };
+        assert!(!parcel.is_null());
+        Self::Owned(parcel)
+    }
+
     /// Create a borrowed reference to a parcel object from a raw pointer.
     ///
     /// # Safety
@@ -77,32 +196,21 @@
     pub(crate) unsafe fn borrowed(ptr: *mut sys::AParcel) -> Option<Parcel> {
         ptr.as_mut().map(|ptr| Self::Borrowed(ptr))
     }
+}
 
-    /// Create an owned 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. 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))
+impl Default for Parcel {
+    fn default() -> Self {
+        Self::new()
     }
+}
 
-    /// 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();
-        let _ = ManuallyDrop::new(self);
-        ptr
-    }
-
-    pub(crate) fn is_owned(&self) -> bool {
-        match *self {
-            Self::Owned(_) => true,
-            Self::Borrowed(_) => false,
-        }
+impl Clone for Parcel {
+    fn clone(&self) -> Self {
+        let mut new_parcel = Self::new();
+        new_parcel
+            .append_all_from(self)
+            .expect("Failed to append from Parcel");
+        new_parcel
     }
 }
 
@@ -213,6 +321,30 @@
     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: &Self, 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: &Self) -> Result<()> {
+        self.append_from(other, 0, other.get_data_size())
+    }
 }
 
 /// A segment of a writable parcel, used for [`Parcel::sized_write`].
@@ -420,6 +552,18 @@
     }
 }
 
+impl Drop for OwnedParcel {
+    fn drop(&mut self) {
+        // Run the C++ Parcel complete object destructor
+        unsafe {
+            // Safety: `OwnedParcel` always contains a valid pointer to an
+            // `AParcel`. Since we own the parcel, we can safely delete it
+            // here.
+            sys::AParcel_delete(self.ptr)
+        }
+    }
+}
+
 impl fmt::Debug for Parcel {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("Parcel")
@@ -427,43 +571,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 fmt::Debug for OwnedParcel {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnedParcel")
+            .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));
@@ -493,11 +610,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 +685,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 +745,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 +773,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..8bcc5d0 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -94,8 +94,6 @@
     }
 }
 
-impl SerializeArray for Option<ParcelFileDescriptor> {}
-
 impl DeserializeOption for ParcelFileDescriptor {
     fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
         let mut fd = -1i32;
@@ -126,8 +124,6 @@
     }
 }
 
-impl DeserializeArray for Option<ParcelFileDescriptor> {}
-
 impl Deserialize for ParcelFileDescriptor {
     fn deserialize(parcel: &Parcel) -> Result<Self> {
         Deserialize::deserialize(parcel)
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 56c6165..ec00e1d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -14,19 +14,42 @@
  * 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::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::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 Parcel) -> 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: &Parcel) -> 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 {
@@ -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
@@ -173,10 +208,10 @@
     /// Serialize an Option of this type into the given [`Parcel`].
     fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> 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)
         }
     }
 }
@@ -186,7 +221,7 @@
     /// Deserialize an Option of this type from the given [`Parcel`].
     fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
         let null: i32 = parcel.read()?;
-        if null == 0 {
+        if null == NULL_PARCELABLE_FLAG {
             Ok(None)
         } else {
             parcel.read().map(Some)
@@ -348,6 +383,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;
@@ -502,8 +540,6 @@
     }
 }
 
-impl SerializeArray for Option<&str> {}
-
 impl Serialize for str {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         Some(self).serialize(parcel)
@@ -526,8 +562,6 @@
     }
 }
 
-impl SerializeArray for Option<String> {}
-
 impl Deserialize for Option<String> {
     fn deserialize(parcel: &Parcel) -> Result<Self> {
         let mut vec: Option<Vec<u8>> = None;
@@ -608,6 +642,18 @@
     }
 }
 
+impl Serialize for Stability {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        i32::from(*self).serialize(parcel)
+    }
+}
+
+impl Deserialize for Stability {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        i32::deserialize(parcel).and_then(Stability::try_from)
+    }
+}
+
 impl Serialize for Status {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         unsafe {
@@ -699,19 +745,53 @@
     }
 }
 
+/// 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::Parcel,
+            ) -> $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::Parcel,
+            ) -> $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 {
@@ -729,10 +809,11 @@
                 parcel: &$crate::parcel::Parcel,
             ) -> $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)
                 }
             }
         }
@@ -752,12 +833,13 @@
                 parcel: &$crate::parcel::Parcel,
             ) -> $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)
                 }
             }
         }
@@ -790,10 +872,6 @@
 
 #[test]
 fn test_custom_parcelable() {
-    use crate::binder::Interface;
-    use crate::native::Binder;
-    let mut service = Binder::new(()).as_binder();
-
     struct Custom(u32, bool, String, Vec<String>);
 
     impl Serialize for Custom {
@@ -826,7 +904,7 @@
 
     let custom = Custom(123_456_789, true, string8, strs);
 
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     assert!(custom.serialize(&mut parcel).is_ok());
@@ -846,13 +924,9 @@
 #[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 mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     assert!(bools.serialize(&mut parcel).is_ok());
@@ -876,7 +950,7 @@
 
     let u8s = [101u8, 255, 42, 117];
 
-    let mut parcel = Parcel::new_for_test(&mut service).unwrap();
+    let mut parcel = Parcel::new();
     let start = parcel.get_data_position();
 
     assert!(parcel.write(&u8s[..]).is_ok());
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..bccfd2d
--- /dev/null
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -0,0 +1,261 @@
+/*
+ * 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::{OwnedParcel, Parcel, 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(OwnedParcel),
+}
+
+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) => {
+                let parcel = parcel.borrowed();
+                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)?;
+
+                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 Parcel) -> 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) => {
+                let p = p.borrowed();
+                parcel.write(&p.get_data_size())?;
+                parcel.append_all_from(&p)
+            }
+        }
+    }
+
+    fn read_from_parcel(&mut self, parcel: &Parcel) -> 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 = OwnedParcel::new();
+        new_parcel
+            .borrowed()
+            .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..a8d0c33 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,7 @@
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
-    Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize, SerializeArray,
+    Deserialize, DeserializeArray, DeserializeOption, OwnedParcel, Parcel, Serialize, SerializeArray,
     SerializeOption,
 };
 use crate::sys;
@@ -235,7 +235,7 @@
 }
 
 impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
-    fn prepare_transact(&self) -> Result<Parcel> {
+    fn prepare_transact(&self) -> Result<OwnedParcel> {
         let mut input = ptr::null_mut();
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
@@ -253,20 +253,19 @@
 
         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)
+            OwnedParcel::from_raw(input).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
     fn submit_transact(
         &self,
         code: TransactionCode,
-        data: Parcel,
+        data: OwnedParcel,
         flags: TransactionFlags,
-    ) -> Result<Parcel> {
+    ) -> Result<OwnedParcel> {
         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 +298,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.
+            OwnedParcel::from_raw(reply).ok_or(StatusCode::UNEXPECTED_NULL)
         }
     }
 
@@ -429,7 +427,6 @@
 }
 
 impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
 
 impl Deserialize for SpIBinder {
     fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
@@ -447,7 +444,6 @@
 }
 
 impl DeserializeArray for SpIBinder {}
-impl DeserializeArray for Option<SpIBinder> {}
 
 /// A weak reference to a Binder remote object.
 ///
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..55ad3c6 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -109,7 +109,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 +173,7 @@
 class MyBinderRpcTest : public BnBinderRpcTest {
 public:
     wp<RpcServer> server;
+    int port = 0;
 
     Status sendString(const std::string& str) override {
         (void)str;
@@ -183,6 +183,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 +485,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 +542,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 +618,7 @@
 
         for (const auto& session : sessions) {
             session->setMaxIncomingThreads(options.numIncomingConnections);
+            session->setMaxOutgoingThreads(options.numOutgoingConnections);
 
             switch (socketType) {
                 case SocketType::PRECONNECTED:
@@ -641,13 +646,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 +688,9 @@
 
         return ret;
     }
+
+    void testThreadPoolOverSaturated(sp<IBinderRpcTest> iface, size_t numCalls,
+                                     size_t sleepMs = 500);
 };
 
 TEST_P(BinderRpc, Ping) {
@@ -677,6 +713,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 +742,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 +1061,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 +1303,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 +1368,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 +1470,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,7 +1509,6 @@
     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();
@@ -1455,7 +1547,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 +2008,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..e4f57b0 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -284,7 +284,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 +300,14 @@
         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;
+    },
 };
 // 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..c0a762d 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -95,6 +95,11 @@
         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<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/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/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/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/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