Merge "Add new fields for carrying classpath information"
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/service.cpp b/cmds/service/service.cpp
index 0b00c2d..fdbe85b 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -77,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)
@@ -88,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;
@@ -103,7 +106,7 @@
     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;
     }
 
@@ -117,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;
             }
@@ -152,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;
@@ -161,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;
@@ -170,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;
@@ -179,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;
@@ -188,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;
@@ -200,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;
@@ -208,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;
@@ -217,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;
@@ -226,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;
@@ -240,7 +244,8 @@
                         } 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;
@@ -327,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;
@@ -337,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/android_runtime_lazy/Android.bp b/libs/android_runtime_lazy/Android.bp
index b74923c..ac3e5b8 100644
--- a/libs/android_runtime_lazy/Android.bp
+++ b/libs/android_runtime_lazy/Android.bp
@@ -42,12 +42,13 @@
 cc_library {
     name: "libandroid_runtime_lazy",
     vendor_available: true,
+    recovery_available: true,
     double_loadable: true,
     host_supported: true,
     target: {
         darwin: {
             enabled: false,
-        }
+        },
     },
 
     cflags: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2ecb895..dc153c9 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -25,6 +25,7 @@
     name: "libbinder_headers",
     export_include_dirs: ["include"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
@@ -75,6 +76,7 @@
     vndk: {
         enabled: true,
     },
+    recovery_available: true,
     double_loadable: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
@@ -331,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/OWNERS b/libs/binder/OWNERS
index 1c8bdea..f954e74 100644
--- a/libs/binder/OWNERS
+++ b/libs/binder/OWNERS
@@ -1,5 +1,4 @@
 # Bug component: 32456
-arve@google.com
 ctate@google.com
 hackbod@google.com
 maco@google.com
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 805e576..631a4b6 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -548,21 +548,17 @@
     return mHasFds;
 }
 
-status_t Parcel::hasFileDescriptorsInRange(size_t offset, size_t len, bool& result) const {
+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 = offset + len;
-    if (offset > mDataSize || len > mDataSize || limit > mDataSize || offset > limit) {
+    size_t limit;
+    if (__builtin_add_overflow(offset, len, &limit) || limit > mDataSize) {
         return BAD_VALUE;
     }
-    result = hasFileDescriptorsInRangeUnchecked(offset, len);
-    return NO_ERROR;
-}
-
-bool Parcel::hasFileDescriptorsInRangeUnchecked(size_t offset, size_t len) const {
+    *result = false;
     for (size_t i = 0; i < mObjectsSize; i++) {
         size_t pos = mObjects[i];
         if (pos < offset) continue;
@@ -572,10 +568,11 @@
         }
         const flat_binder_object* flat = reinterpret_cast<const flat_binder_object*>(mData + pos);
         if (flat->hdr.type == BINDER_TYPE_FD) {
-            return true;
+            *result = true;
+            break;
         }
     }
-    return false;
+    return NO_ERROR;
 }
 
 void Parcel::markSensitive() const
@@ -614,6 +611,8 @@
 
 #if defined(__ANDROID_VNDK__)
 constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
+#elif defined(__ANDROID_RECOVERY__)
+constexpr int32_t kHeader = B_PACK_CHARS('R', 'E', 'C', 'O');
 #else
 constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
 #endif
@@ -2568,9 +2567,9 @@
     }
 }
 
-void Parcel::scanForFds() const
-{
-    mHasFds = hasFileDescriptorsInRangeUnchecked(0, dataSize());
+void Parcel::scanForFds() const {
+    status_t status = hasFileDescriptorsInRange(0, dataSize(), &mHasFds);
+    ALOGE_IF(status != NO_ERROR, "Error %d calling hasFileDescriptorsInRange()", status);
     mFdsKnown = true;
 }
 
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 9eef3e8..53c9b78 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -688,7 +688,8 @@
 
     status_t status = OK;
     if (init) {
-        mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+        status =
+                mRpcBinderState->sendConnectionInit(connection, sp<RpcSession>::fromExisting(this));
     }
 
     {
@@ -700,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);
@@ -713,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/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index cf30f17..d90e803 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -87,7 +87,7 @@
     void                restoreAllowFds(bool lastValue);
 
     bool                hasFileDescriptors() const;
-    status_t hasFileDescriptorsInRange(size_t offset, size_t length, bool& result) 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.
@@ -576,7 +576,6 @@
 
     status_t            writeRawNullableParcelable(const Parcelable*
                                                    parcelable);
-    bool hasFileDescriptorsInRangeUnchecked(size_t offset, size_t length) const;
 
     //-----------------------------------------------------------------------------
     // Generic type read and write methods for Parcel:
@@ -1237,7 +1236,9 @@
      */
     size_t getOpenAshmemSize() const;
 
-    // TODO(b/202029388): Remove 'getBlobAshmemSize' once ABI can be changed.
+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 f5505da..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;
@@ -140,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
@@ -220,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
@@ -256,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,
@@ -272,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; }
@@ -313,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;
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/Android.bp b/libs/binder/ndk/Android.bp
index 9c04e58..ee46fcb 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -54,6 +54,7 @@
 
     defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
+    recovery_available: true,
 
     llndk: {
         symbol_file: "libbinder_ndk.map.txt",
@@ -155,6 +156,7 @@
     name: "libbinder_headers_platform_shared",
     export_include_dirs: ["include_cpp"],
     vendor_available: true,
+    recovery_available: true,
     host_supported: true,
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 49c7b7c..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 4a7b664..2b18a0a 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -550,8 +550,8 @@
                                                                 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));
+            static_cast<const std::optional<std::vector<P>>*>(vectorData);
+    return AParcel_writeNullableParcelable(parcel, (*vector)->at(index));
 }
 
 /**
@@ -561,7 +561,7 @@
 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));
+    return AParcel_readNullableParcelable(parcel, &(*vector)->at(index));
 }
 
 /**
@@ -573,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));
 }
 
 /**
@@ -589,15 +585,31 @@
         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));
 }
 
 /**
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/src/binder.rs b/libs/binder/rust/src/binder.rs
index 854b1f9..cc5dd06 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -17,7 +17,7 @@
 //! 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;
 
@@ -177,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
@@ -213,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 d1d37d7..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};
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 7391561..9dba950 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -23,6 +23,7 @@
 
 use std::cell::RefCell;
 use std::convert::TryInto;
+use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
 use std::ptr;
 use std::fmt;
@@ -52,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
@@ -95,33 +196,6 @@
     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))
-    }
-
-    /// 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 Default for Parcel {
@@ -478,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")
@@ -485,6 +571,13 @@
     }
 }
 
+impl fmt::Debug for OwnedParcel {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("OwnedParcel")
+            .finish()
+    }
+}
+
 #[test]
 fn test_read_write() {
     let mut parcel = Parcel::new();
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 499ef09..ec00e1d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -383,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;
@@ -537,8 +540,6 @@
     }
 }
 
-impl SerializeArray for Option<&str> {}
-
 impl Serialize for str {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         Some(self).serialize(parcel)
@@ -561,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;
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 3e75d1b..bccfd2d 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -16,13 +16,12 @@
 
 use crate::binder::Stability;
 use crate::error::{Result, StatusCode};
-use crate::parcel::{Parcel, Parcelable};
+use crate::parcel::{OwnedParcel, Parcel, Parcelable};
 use crate::{impl_deserialize_for_parcelable, impl_serialize_for_parcelable};
 
-use downcast_rs::{impl_downcast, Downcast};
+use downcast_rs::{impl_downcast, DowncastSync};
 use std::any::Any;
-use std::cell::RefCell;
-use std::rc::Rc;
+use std::sync::{Arc, Mutex};
 
 /// Metadata that `ParcelableHolder` needs for all parcelables.
 ///
@@ -40,18 +39,18 @@
     }
 }
 
-trait AnyParcelable: Downcast + Parcelable + std::fmt::Debug {}
-impl_downcast!(AnyParcelable);
-impl<T> AnyParcelable for T where T: Downcast + Parcelable + std::fmt::Debug {}
+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: Rc<dyn AnyParcelable>,
+        parcelable: Arc<dyn AnyParcelable>,
         name: String,
     },
-    Parcel(Parcel),
+    Parcel(OwnedParcel),
 }
 
 impl Default for ParcelableHolderData {
@@ -67,15 +66,15 @@
 /// `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, Clone)]
+#[derive(Debug, Default)]
 pub struct ParcelableHolder {
-    // This is a `RefCell` because of `get_parcelable`
+    // 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 `RefCell` here for a performance
+    // 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: RefCell<ParcelableHolderData>,
+    data: Mutex<ParcelableHolderData>,
     stability: Stability,
 }
 
@@ -83,7 +82,7 @@
     /// Construct a new `ParcelableHolder` with the given stability.
     pub fn new(stability: Stability) -> Self {
         Self {
-            data: RefCell::new(ParcelableHolderData::Empty),
+            data: Mutex::new(ParcelableHolderData::Empty),
             stability,
         }
     }
@@ -93,20 +92,20 @@
     /// Note that this method does not reset the stability,
     /// only the contents.
     pub fn reset(&mut self) {
-        *self.data.get_mut() = ParcelableHolderData::Empty;
+        *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: Rc<T>) -> Result<()>
+    pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
     where
-        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug,
+        T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
     {
         if self.stability > p.get_stability() {
             return Err(StatusCode::BAD_VALUE);
         }
 
-        *self.data.get_mut() = ParcelableHolderData::Parcelable {
+        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
             parcelable: p,
             name: T::get_descriptor().into(),
         };
@@ -127,12 +126,12 @@
     /// * `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<Rc<T>>>
+    pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
     where
-        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug,
+        T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
     {
         let parcelable_desc = T::get_descriptor();
-        let mut data = self.data.borrow_mut();
+        let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => Ok(None),
             ParcelableHolderData::Parcelable {
@@ -143,12 +142,13 @@
                     return Err(StatusCode::BAD_VALUE);
                 }
 
-                match Rc::clone(parcelable).downcast_rc::<T>() {
+                match Arc::clone(parcelable).downcast_arc::<T>() {
                     Err(_) => Err(StatusCode::BAD_VALUE),
                     Ok(x) => Ok(Some(x)),
                 }
             }
-            ParcelableHolderData::Parcel(ref parcel) => {
+            ParcelableHolderData::Parcel(ref mut parcel) => {
+                let parcel = parcel.borrowed();
                 unsafe {
                     // Safety: 0 should always be a valid position.
                     parcel.set_data_position(0)?;
@@ -160,10 +160,10 @@
                 }
 
                 let mut parcelable = T::default();
-                parcelable.read_from_parcel(parcel)?;
+                parcelable.read_from_parcel(&parcel)?;
 
-                let parcelable = Rc::new(parcelable);
-                let result = Rc::clone(&parcelable);
+                let parcelable = Arc::new(parcelable);
+                let result = Arc::clone(&parcelable);
                 *data = ParcelableHolderData::Parcelable { parcelable, name };
 
                 Ok(Some(result))
@@ -184,7 +184,8 @@
     fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
         parcel.write(&self.stability)?;
 
-        match *self.data.borrow() {
+        let mut data = self.data.lock().unwrap();
+        match *data {
             ParcelableHolderData::Empty => parcel.write(&0i32),
             ParcelableHolderData::Parcelable {
                 ref parcelable,
@@ -212,9 +213,10 @@
 
                 Ok(())
             }
-            ParcelableHolderData::Parcel(ref p) => {
+            ParcelableHolderData::Parcel(ref mut p) => {
+                let p = p.borrowed();
                 parcel.write(&p.get_data_size())?;
-                parcel.append_all_from(p)
+                parcel.append_all_from(&p)
             }
         }
     }
@@ -229,7 +231,7 @@
             return Err(StatusCode::BAD_VALUE);
         }
         if data_size == 0 {
-            *self.data.get_mut() = ParcelableHolderData::Empty;
+            *self.data.get_mut().unwrap() = ParcelableHolderData::Empty;
             return Ok(());
         }
 
@@ -240,9 +242,11 @@
             .checked_add(data_size)
             .ok_or(StatusCode::BAD_VALUE)?;
 
-        let mut new_parcel = Parcel::new();
-        new_parcel.append_from(parcel, data_start, data_size)?;
-        *self.data.get_mut() = ParcelableHolderData::Parcel(new_parcel);
+        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
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 6a4af07..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,8 +427,6 @@
 }
 
 impl SerializeArray for SpIBinder {}
-impl SerializeArray for Option<&SpIBinder> {}
-impl SerializeArray for Option<SpIBinder> {}
 
 impl Deserialize for SpIBinder {
     fn deserialize(parcel: &Parcel) -> Result<SpIBinder> {
@@ -448,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/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 8267702..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) {
@@ -538,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;
@@ -643,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;
@@ -682,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;
@@ -1251,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());
@@ -1307,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;
@@ -1400,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>();
 
@@ -1440,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();
@@ -1479,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";
@@ -1941,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 55eb847..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
@@ -306,7 +305,7 @@
         size_t offset = p.readUint32();
         size_t length = p.readUint32();
         bool result;
-        status_t status = p.hasFileDescriptorsInRange(offset, length, result);
+        status_t status = p.hasFileDescriptorsInRange(offset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
 };
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/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