Merge "Add cputimeinstate_fuzzer"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 7ef26bf..f708acb 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,8 +1,10 @@
 [Builtin Hooks]
+rustfmt = true
 bpfmt = true
 clang_format = true
 
 [Builtin Hooks Options]
+rustfmt = --config-path=rustfmt.toml
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
                cmds/idlcli/
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index b94f3da..9bd733d 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -1194,11 +1194,6 @@
     bool traceStream = false;
     bool onlyUserspace = false;
 
-    fprintf(stderr,
-            "** Warning: atrace will end vendor support in the next Android Release. **\n"
-            "** Perfetto is the suggested replacement tool. It will gain vendor      **\n"
-            "** support. See https://perfetto.dev/docs/quickstart/android-tracing    **\n\n");
-
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
         exit(0);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 942a17e..6dea91b 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "dumpstate"
+#define ATRACE_TAG ATRACE_TAG_ALWAYS
 
 #include <dirent.h>
 #include <errno.h>
@@ -76,6 +77,7 @@
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
 #include <cutils/sockets.h>
+#include <cutils/trace.h>
 #include <debuggerd/client.h>
 #include <dumpsys.h>
 #include <dumputils/dump_utils.h>
@@ -1506,7 +1508,6 @@
     dprintf(out_fd, "========================================================\n");
 
     RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd);
-    RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd);
     RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd);
     RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd);
@@ -3098,7 +3099,9 @@
     TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout)));
 
     // Zip the (now complete) .tmp file within the internal directory.
+    ATRACE_BEGIN("FinalizeFile");
     FinalizeFile();
+    ATRACE_END();
 
     // Share the final file with the caller if the user has consented or Shell is the caller.
     Dumpstate::RunStatus status = Dumpstate::RunStatus::OK;
@@ -3409,6 +3412,9 @@
         duration_fd_(duration_fd) {
     if (!title_.empty()) {
         started_ = Nanotime();
+        if (title_.find("SHOW MAP") == std::string::npos) {
+            ATRACE_ASYNC_BEGIN(title_.c_str(), 0);
+        }
     }
 }
 
@@ -3423,6 +3429,9 @@
             dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n",
                     elapsed, title_.c_str());
         }
+        if (title_.find("SHOW MAP") == std::string::npos) {
+            ATRACE_ASYNC_END(title_.c_str(), 0);
+        }
     }
 }
 
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index c7bea3f..65b25a4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -1182,8 +1182,8 @@
 int wait_child_with_timeout(pid_t pid, int timeout_ms) {
     int pidfd = pidfd_open(pid, /*flags=*/0);
     if (pidfd < 0) {
-        PLOG(ERROR) << "pidfd_open failed for pid " << pid;
-        kill(pid, SIGKILL);
+        PLOG(ERROR) << "pidfd_open failed for pid " << pid
+                    << ", waiting for child process without timeout";
         return wait_child(pid);
     }
 
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index b7e520f..711038c 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -30,6 +30,7 @@
 constexpr bool kIsVendor = false;
 #endif
 
+#ifdef __ANDROID__
 static std::string getPidcon(pid_t pid) {
     android_errorWriteLog(0x534e4554, "121035042");
 
@@ -45,7 +46,6 @@
 
 static struct selabel_handle* getSehandle() {
     static struct selabel_handle* gSehandle = nullptr;
-
     if (gSehandle != nullptr && selinux_status_updated()) {
         selabel_close(gSehandle);
         gSehandle = nullptr;
@@ -78,8 +78,10 @@
         ad->tname->c_str());
     return 0;
 }
+#endif
 
 Access::Access() {
+#ifdef __ANDROID__
     union selinux_callback cb;
 
     cb.func_audit = auditCallback;
@@ -91,6 +93,7 @@
     CHECK(selinux_status_open(true /*fallback*/) >= 0);
 
     CHECK(getcon(&mThisProcessContext) == 0);
+#endif
 }
 
 Access::~Access() {
@@ -98,6 +101,7 @@
 }
 
 Access::CallingContext Access::getCallingContext() {
+#ifdef __ANDROID__
     IPCThreadState* ipc = IPCThreadState::self();
 
     const char* callingSid = ipc->getCallingSid();
@@ -108,6 +112,9 @@
         .uid = ipc->getCallingUid(),
         .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid),
     };
+#else
+    return CallingContext();
+#endif
 }
 
 bool Access::canFind(const CallingContext& ctx,const std::string& name) {
@@ -124,6 +131,7 @@
 
 bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
         const std::string& tname) {
+#ifdef __ANDROID__
     const char* tclass = "service_manager";
 
     AuditCallbackData data = {
@@ -133,9 +141,18 @@
 
     return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
         reinterpret_cast<void*>(&data));
+#else
+    (void)sctx;
+    (void)tctx;
+    (void)perm;
+    (void)tname;
+
+    return true;
+#endif
 }
 
 bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
+#ifdef __ANDROID__
     char *tctx = nullptr;
     if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) {
         LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n";
@@ -145,6 +162,14 @@
     bool allowed = actionAllowed(sctx, tctx, perm, name);
     freecon(tctx);
     return allowed;
+#else
+    (void)sctx;
+    (void)name;
+    (void)perm;
+    (void)kIsVendor;
+
+    return true;
+#endif
 }
 
 }  // android
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp
index 32922ca..25bd9a3 100644
--- a/cmds/servicemanager/Android.bp
+++ b/cmds/servicemanager/Android.bp
@@ -44,6 +44,7 @@
     defaults: ["servicemanager_defaults"],
     init_rc: ["servicemanager.rc"],
     srcs: ["main.cpp"],
+    bootstrap: true,
 }
 
 cc_binary {
@@ -86,3 +87,35 @@
     ],
     static_libs: ["libgmock"],
 }
+
+cc_fuzz {
+    name: "servicemanager_fuzzer",
+    defaults: ["servicemanager_defaults"],
+    host_supported: true,
+    static_libs: [
+        "libbase",
+        "libbinder_random_parcel",
+        "libcutils",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libbinder_ndk",
+                "libbinder",
+            ],
+        },
+    },
+    srcs: ["ServiceManagerFuzzer.cpp"],
+    fuzz_config: {
+        cc: [
+            "smoreland@google.com",
+            "waghpawan@google.com",
+        ],
+    },
+}
diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp
new file mode 100644
index 0000000..9e2e53f
--- /dev/null
+++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <fuzzbinder/libbinder_driver.h>
+#include <utils/StrongPointer.h>
+
+#include "Access.h"
+#include "ServiceManager.h"
+
+using ::android::Access;
+using ::android::fuzzService;
+using ::android::ServiceManager;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size > 50000) {
+        return 0;
+    }
+
+    auto accessPtr = std::make_unique<Access>();
+    auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr));
+    fuzzService(serviceManager, FuzzedDataProvider(data, size));
+
+    return 0;
+}
\ No newline at end of file
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index 2fb9c2b..a831d1b 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <binder/IPCThreadState.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
@@ -26,15 +27,14 @@
 #include "ServiceManager.h"
 
 using ::android::Access;
-using ::android::sp;
+using ::android::IPCThreadState;
 using ::android::Looper;
 using ::android::LooperCallback;
 using ::android::ProcessState;
-using ::android::IPCThreadState;
-using ::android::ProcessState;
 using ::android::ServiceManager;
-using ::android::os::IServiceManager;
 using ::android::sp;
+using ::android::base::SetProperty;
+using ::android::os::IServiceManager;
 
 class BinderCallback : public LooperCallback {
 public:
@@ -121,6 +121,8 @@
 
     const char* driver = argc == 2 ? argv[1] : "/dev/binder";
 
+    LOG(INFO) << "Starting sm instance on " << driver;
+
     sp<ProcessState> ps = ProcessState::initWithDriver(driver);
     ps->setThreadPoolMaxThreadCount(0);
     ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
@@ -138,6 +140,12 @@
     BinderCallback::setupTo(looper);
     ClientCallbackCallback::setupTo(looper, manager);
 
+#ifndef VENDORSERVICEMANAGER
+    if (!SetProperty("servicemanager.ready", "true")) {
+        LOG(ERROR) << "Failed to set servicemanager ready property";
+    }
+#endif
+
     while(true) {
         looper->pollAll(-1);
     }
diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc
index e01f132..c516043 100644
--- a/cmds/servicemanager/servicemanager.microdroid.rc
+++ b/cmds/servicemanager/servicemanager.microdroid.rc
@@ -3,6 +3,7 @@
     user system
     group system readproc
     critical
+    onrestart setprop servicemanager.ready false
     onrestart restart apexd
     task_profiles ServiceCapacityLow
     shutdown critical
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index e5d689f..6b35265 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -3,6 +3,7 @@
     user system
     group system readproc
     critical
+    onrestart setprop servicemanager.ready false
     onrestart restart apexd
     onrestart restart audioserver
     onrestart restart gatekeeperd
diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc
index 067faf9..b927c01 100644
--- a/cmds/servicemanager/servicemanager.recovery.rc
+++ b/cmds/servicemanager/servicemanager.recovery.rc
@@ -1,4 +1,5 @@
 service servicemanager /system/bin/servicemanager
     disabled
     group system readproc
+    onrestart setprop servicemanager.ready false
     seclabel u:r:servicemanager:s0
diff --git a/headers/media_plugin/media/openmax/OMX_VideoExt.h b/headers/media_plugin/media/openmax/OMX_VideoExt.h
index e65b224..4746bc3 100644
--- a/headers/media_plugin/media/openmax/OMX_VideoExt.h
+++ b/headers/media_plugin/media/openmax/OMX_VideoExt.h
@@ -318,6 +318,9 @@
     OMX_VIDEO_DolbyVisionLevelUhd30   = 0x40,
     OMX_VIDEO_DolbyVisionLevelUhd48   = 0x80,
     OMX_VIDEO_DolbyVisionLevelUhd60   = 0x100,
+    OMX_VIDEO_DolbyVisionLevelUhd120  = 0x200,
+    OMX_VIDEO_DolbyVisionLevel8k30    = 0x400,
+    OMX_VIDEO_DolbyVisionLevel8k60    = 0x800,
     OMX_VIDEO_DolbyVisionLevelmax     = 0x7FFFFFFF
 } OMX_VIDEO_DOLBYVISIONLEVELTYPE;
 
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index 7584ca3..f9f042e 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -1,17 +1,17 @@
 LIBADBD_AUTH {
   global:
-    adbd_auth_new; # apex introduced=30
-    adbd_auth_delete; # apex introduced=30
-    adbd_auth_run; # apex introduced=30
-    adbd_auth_get_public_keys; #apex introduced=30
-    adbd_auth_notify_auth; # apex introduced=30
-    adbd_auth_notify_disconnect; # apex introduced=30
-    adbd_auth_prompt_user; # apex introduced=30
-    adbd_auth_prompt_user_with_id; # apex introduced=30
-    adbd_auth_tls_device_connected; # apex introduced=30
-    adbd_auth_tls_device_disconnected; # apex introduced=30
-    adbd_auth_get_max_version; # apex introduced=30
-    adbd_auth_supports_feature; # apex introduced=30
+    adbd_auth_new; # systemapi introduced=30
+    adbd_auth_delete; # systemapi introduced=30
+    adbd_auth_run; # systemapi introduced=30
+    adbd_auth_get_public_keys; # systemapi introduced=30
+    adbd_auth_notify_auth; # systemapi introduced=30
+    adbd_auth_notify_disconnect; # systemapi introduced=30
+    adbd_auth_prompt_user; # systemapi introduced=30
+    adbd_auth_prompt_user_with_id; # systemapi introduced=30
+    adbd_auth_tls_device_connected; # systemapi introduced=30
+    adbd_auth_tls_device_disconnected; # systemapi introduced=30
+    adbd_auth_get_max_version; # systemapi introduced=30
+    adbd_auth_supports_feature; # systemapi introduced=30
   local:
     *;
 };
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 27000e8..858600e 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,21 +70,9 @@
     ],
 }
 
-cc_library {
-    name: "libbinder",
-
-    version_script: "libbinder.map",
-
-    // for vndbinder
-    vendor_available: true,
-    vndk: {
-        enabled: true,
-    },
-    recovery_available: true,
-    double_loadable: true,
+cc_defaults {
+    name: "libbinder_defaults",
     host_supported: true,
-    // TODO(b/153609531): remove when no longer needed.
-    native_bridge_supported: true,
 
     // TODO(b/31559095): get headers from bionic on host
     include_dirs: [
@@ -92,73 +80,32 @@
         "bionic/libc/kernel/uapi/",
     ],
 
-    // libbinder does not offer a stable wire protocol.
-    // if a second copy of it is installed, then it may break after security
-    // or dessert updates. Instead, apex users should use libbinder_ndk.
-    apex_available: [
-        "//apex_available:platform",
-    ],
-
     srcs: [
         "Binder.cpp",
         "BpBinder.cpp",
-        "BufferedTextOutput.cpp",
         "Debug.cpp",
         "FdTrigger.cpp",
         "IInterface.cpp",
-        "IMemory.cpp",
-        "IPCThreadState.cpp",
         "IResultReceiver.cpp",
-        "IServiceManager.cpp",
-        "IShellCallback.cpp",
-        "LazyServiceRegistrar.cpp",
-        "MemoryBase.cpp",
-        "MemoryDealer.cpp",
-        "MemoryHeapBase.cpp",
+        "OS.cpp",
         "Parcel.cpp",
-        "ParcelableHolder.cpp",
         "ParcelFileDescriptor.cpp",
-        "PersistableBundle.cpp",
-        "ProcessState.cpp",
         "RpcSession.cpp",
         "RpcServer.cpp",
         "RpcState.cpp",
         "RpcTransportRaw.cpp",
-        "Static.cpp",
         "Stability.cpp",
         "Status.cpp",
         "TextOutput.cpp",
         "Utils.cpp",
-        ":libbinder_aidl",
-        ":libbinder_device_interface_sources",
     ],
 
     target: {
-        android: {
-            // NOT static to keep the wire protocol unfrozen
-            static: {
-                enabled: false,
-            },
-        },
-        vendor: {
-            exclude_srcs: [
-                ":libbinder_device_interface_sources",
-            ],
-        },
-        darwin: {
-            enabled: false,
-        },
         host: {
             srcs: [
-                "ServiceManagerHost.cpp",
                 "UtilsHost.cpp",
             ],
         },
-        recovery: {
-            exclude_header_libs: [
-                "libandroid_runtime_vm_headers",
-            ],
-        },
     },
 
     aidl: {
@@ -166,7 +113,6 @@
     },
 
     cflags: [
-        "-Wall",
         "-Wextra",
         "-Wextra-semi",
         "-Werror",
@@ -174,7 +120,6 @@
         "-Wreorder-init-list",
         "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION",
         "-DANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION",
-        "-DBINDER_WITH_KERNEL_IPC",
     ],
     product_variables: {
         binder32bit: {
@@ -230,10 +175,126 @@
         "performance*",
         "portability*",
     ],
+}
+
+cc_defaults {
+    name: "libbinder_kernel_defaults",
+    srcs: [
+        "BufferedTextOutput.cpp",
+        "IPCThreadState.cpp",
+        "IServiceManager.cpp",
+        "ProcessState.cpp",
+        "Static.cpp",
+        ":libbinder_aidl",
+        ":libbinder_device_interface_sources",
+    ],
+    target: {
+        vendor: {
+            exclude_srcs: [
+                ":libbinder_device_interface_sources",
+            ],
+        },
+        host: {
+            srcs: [
+                "ServiceManagerHost.cpp",
+            ],
+        },
+    },
+    cflags: [
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+}
+
+cc_library {
+    name: "libbinder",
+    defaults: [
+        "libbinder_defaults",
+        "libbinder_kernel_defaults",
+    ],
+
+    version_script: "libbinder.map",
+
+    // for vndbinder
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    recovery_available: true,
+    double_loadable: true,
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
+
+    // libbinder does not offer a stable wire protocol.
+    // if a second copy of it is installed, then it may break after security
+    // or dessert updates. Instead, apex users should use libbinder_ndk.
+    apex_available: [
+        "//apex_available:platform",
+    ],
+
+    srcs: [
+        "IMemory.cpp",
+        "IShellCallback.cpp",
+        "LazyServiceRegistrar.cpp",
+        "MemoryBase.cpp",
+        "MemoryDealer.cpp",
+        "MemoryHeapBase.cpp",
+        "ParcelableHolder.cpp",
+        "PersistableBundle.cpp",
+    ],
+
+    target: {
+        android: {
+            // NOT static to keep the wire protocol unfrozen
+            static: {
+                enabled: false,
+            },
+        },
+        darwin: {
+            enabled: false,
+        },
+        recovery: {
+            exclude_header_libs: [
+                "libandroid_runtime_vm_headers",
+            ],
+        },
+    },
 
     afdo: true,
 }
 
+cc_library_static {
+    name: "libbinder_rpc_no_kernel",
+    defaults: ["libbinder_defaults"],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_library_static {
+    name: "libbinder_rpc_single_threaded",
+    defaults: [
+        "libbinder_defaults",
+        "libbinder_kernel_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
+cc_library_static {
+    name: "libbinder_rpc_single_threaded_no_kernel",
+    defaults: ["libbinder_defaults"],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
 cc_defaults {
     name: "libbinder_tls_shared_deps",
     shared_libs: [
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index b9a8ba9..b5ea60f 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -610,8 +610,24 @@
 
 BBinder::~BBinder()
 {
-    if (!wasParceled() && getExtension()) {
-        ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+    if (!wasParceled()) {
+        if (getExtension()) {
+             ALOGW("Binder %p destroyed with extension attached before being parceled.", this);
+        }
+        if (isRequestingSid()) {
+             ALOGW("Binder %p destroyed when requesting SID before being parceled.", this);
+        }
+        if (isInheritRt()) {
+             ALOGW("Binder %p destroyed after setInheritRt before being parceled.", this);
+        }
+#ifdef __linux__
+        if (getMinSchedulerPolicy() != SCHED_NORMAL) {
+             ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+        }
+        if (getMinSchedulerPriority() != 0) {
+             ALOGW("Binder %p destroyed after setMinSchedulerPolicy before being parceled.", this);
+        }
+#endif // __linux__
     }
 
     Extras* e = mExtras.load(std::memory_order_relaxed);
@@ -648,13 +664,14 @@
             for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
                args.add(data.readString16());
             }
-            sp<IShellCallback> shellCallback = IShellCallback::asInterface(
-                    data.readStrongBinder());
+            sp<IBinder> shellCallbackBinder = data.readStrongBinder();
             sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
                     data.readStrongBinder());
 
             // XXX can't add virtuals until binaries are updated.
-            //return shellCommand(in, out, err, args, resultReceiver);
+            // sp<IShellCallback> shellCallback = IShellCallback::asInterface(
+            //        shellCallbackBinder);
+            // return shellCommand(in, out, err, args, resultReceiver);
             (void)in;
             (void)out;
             (void)err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 49fc195..b6d35ef 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -343,11 +343,23 @@
 status_t BpBinder::linkToDeath(
     const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
 {
-    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
-
-    if constexpr (!kEnableKernelIpc) {
+    if (isRpcBinder()) {
+        if (rpcSession()->getMaxIncomingThreads() < 1) {
+            LOG_ALWAYS_FATAL("Cannot register a DeathRecipient without any incoming connections.");
+            return INVALID_OPERATION;
+        }
+    } else if constexpr (!kEnableKernelIpc) {
         LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
         return INVALID_OPERATION;
+    } else {
+        if (ProcessState::self()->getThreadPoolMaxTotalThreadCount() == 0) {
+            ALOGW("Linking to death on %s but there are no threads (yet?) listening to incoming "
+                  "transactions. See ProcessState::startThreadPool and "
+                  "ProcessState::setThreadPoolMaxThreadCount. Generally you should setup the "
+                  "binder "
+                  "threadpool before other initialization steps.",
+                  String8(getInterfaceDescriptor()).c_str());
+        }
     }
 
     Obituary ob;
@@ -368,10 +380,14 @@
                     return NO_MEMORY;
                 }
                 ALOGV("Requesting death notification: %p handle %d\n", this, binderHandle());
-                getWeakRefs()->incWeak(this);
-                IPCThreadState* self = IPCThreadState::self();
-                self->requestDeathNotification(binderHandle(), this);
-                self->flushCommands();
+                if (!isRpcBinder()) {
+                    if constexpr (kEnableKernelIpc) {
+                        getWeakRefs()->incWeak(this);
+                        IPCThreadState* self = IPCThreadState::self();
+                        self->requestDeathNotification(binderHandle(), this);
+                        self->flushCommands();
+                    }
+                }
             }
             ssize_t res = mObituaries->add(ob);
             return res >= (ssize_t)NO_ERROR ? (status_t)NO_ERROR : res;
@@ -386,9 +402,7 @@
     const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
     wp<DeathRecipient>* outRecipient)
 {
-    if (isRpcBinder()) return UNKNOWN_TRANSACTION;
-
-    if constexpr (!kEnableKernelIpc) {
+    if (!kEnableKernelIpc && !isRpcBinder()) {
         LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
         return INVALID_OPERATION;
     }
@@ -411,9 +425,13 @@
             mObituaries->removeAt(i);
             if (mObituaries->size() == 0) {
                 ALOGV("Clearing death notification: %p handle %d\n", this, binderHandle());
-                IPCThreadState* self = IPCThreadState::self();
-                self->clearDeathNotification(binderHandle(), this);
-                self->flushCommands();
+                if (!isRpcBinder()) {
+                    if constexpr (kEnableKernelIpc) {
+                        IPCThreadState* self = IPCThreadState::self();
+                        self->clearDeathNotification(binderHandle(), this);
+                        self->flushCommands();
+                    }
+                }
                 delete mObituaries;
                 mObituaries = nullptr;
             }
@@ -426,9 +444,7 @@
 
 void BpBinder::sendObituary()
 {
-    LOG_ALWAYS_FATAL_IF(isRpcBinder(), "Cannot send obituary for remote binder.");
-
-    if constexpr (!kEnableKernelIpc) {
+    if (!kEnableKernelIpc && !isRpcBinder()) {
         LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
         return;
     }
@@ -443,9 +459,13 @@
     Vector<Obituary>* obits = mObituaries;
     if(obits != nullptr) {
         ALOGV("Clearing sent death notification: %p handle %d\n", this, binderHandle());
-        IPCThreadState* self = IPCThreadState::self();
-        self->clearDeathNotification(binderHandle(), this);
-        self->flushCommands();
+        if (!isRpcBinder()) {
+            if constexpr (kEnableKernelIpc) {
+                IPCThreadState* self = IPCThreadState::self();
+                self->clearDeathNotification(binderHandle(), this);
+                self->flushCommands();
+            }
+        }
         mObituaries = nullptr;
     }
     mObitsSent = 1;
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index 5c7102e..a25dc11 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <memory>
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d536219..b50cfb3 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -972,18 +972,15 @@
                             freeBuffer);
                     } else {
                         err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
-                        freeBuffer(nullptr,
-                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                            tr.data_size,
-                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                            tr.offsets_size/sizeof(binder_size_t));
+                        freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
+                                   tr.data_size,
+                                   reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                                   tr.offsets_size / sizeof(binder_size_t));
                     }
                 } else {
-                    freeBuffer(nullptr,
-                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
-                        tr.data_size,
-                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
-                        tr.offsets_size/sizeof(binder_size_t));
+                    freeBuffer(reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer), tr.data_size,
+                               reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
+                               tr.offsets_size / sizeof(binder_size_t));
                     continue;
                 }
             }
@@ -1473,17 +1470,13 @@
              ee.id, ee.command, ee.param);
 }
 
-void IPCThreadState::freeBuffer(Parcel* parcel, const uint8_t* data,
-                                size_t /*dataSize*/,
-                                const binder_size_t* /*objects*/,
-                                size_t /*objectsSize*/)
-{
+void IPCThreadState::freeBuffer(const uint8_t* data, size_t /*dataSize*/,
+                                const binder_size_t* /*objects*/, size_t /*objectsSize*/) {
     //ALOGI("Freeing parcel %p", &parcel);
     IF_LOG_COMMANDS() {
         alog << "Writing BC_FREE_BUFFER for " << data << endl;
     }
     ALOG_ASSERT(data != NULL, "Called with NULL data");
-    if (parcel != nullptr) parcel->closeFileDescriptors();
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
     state->mOut.writePointer((uintptr_t)data);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index fd47783..c0a8d74 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -21,6 +21,7 @@
 #include <inttypes.h>
 #include <unistd.h>
 
+#include <android-base/properties.h>
 #include <android/os/BnServiceCallback.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IPCThreadState.h>
@@ -140,6 +141,16 @@
 sp<IServiceManager> defaultServiceManager()
 {
     std::call_once(gSmOnce, []() {
+#if defined(__BIONIC__) && !defined(__ANDROID_VNDK__)
+        /* wait for service manager */ {
+            using std::literals::chrono_literals::operator""s;
+            using android::base::WaitForProperty;
+            while (!WaitForProperty("servicemanager.ready", "true", 1s)) {
+                ALOGE("Waited for servicemanager.ready for a second, waiting another...");
+            }
+        }
+#endif
+
         sp<AidlServiceManager> sm = nullptr;
         while (sm == nullptr) {
             sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
diff --git a/libs/binder/OS.cpp b/libs/binder/OS.cpp
new file mode 100644
index 0000000..6eb7272
--- /dev/null
+++ b/libs/binder/OS.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "OS.h"
+
+#include <android-base/file.h>
+#include <string.h>
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+    int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
+    if (flags == -1) {
+        return ErrnoError() << "Could not get flags for fd";
+    }
+    if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
+        return ErrnoError() << "Could not set non-blocking flag for fd";
+    }
+    return {};
+}
+
+status_t getRandomBytes(uint8_t* data, size_t size) {
+    int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+    if (ret == -1) {
+        return -errno;
+    }
+
+    base::unique_fd fd(ret);
+    if (!base::ReadFully(fd, data, size)) {
+        return -errno;
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/OS.h b/libs/binder/OS.h
new file mode 100644
index 0000000..e802e9c
--- /dev/null
+++ b/libs/binder/OS.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <stddef.h>
+#include <cstdint>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
+status_t getRandomBytes(uint8_t* data, size_t size);
+
+} // namespace android
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 3dccf20..8b5d118 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -503,8 +503,8 @@
 
     err = NO_ERROR;
 
-#ifdef BINDER_WITH_KERNEL_IPC
     if (auto* kernelFields = maybeKernelFields()) {
+#ifdef BINDER_WITH_KERNEL_IPC
         auto* otherKernelFields = parcel->maybeKernelFields();
         LOG_ALWAYS_FATAL_IF(otherKernelFields == nullptr);
 
@@ -564,6 +564,10 @@
                 }
             }
         }
+#else
+        LOG_ALWAYS_FATAL("Binder kernel driver disabled at build time");
+        return INVALID_OPERATION;
+#endif // BINDER_WITH_KERNEL_IPC
     } else {
         auto* rpcFields = maybeRpcFields();
         LOG_ALWAYS_FATAL_IF(rpcFields == nullptr);
@@ -622,7 +626,6 @@
             }
         }
     }
-#endif // BINDER_WITH_KERNEL_IPC
 
     return err;
 }
@@ -2587,6 +2590,22 @@
 
     LOG_ALWAYS_FATAL_IF(session == nullptr);
 
+    if (objectTableSize != ancillaryFds.size()) {
+        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
+        relFunc(data, dataSize, nullptr, 0);
+        return BAD_VALUE;
+    }
+    for (size_t i = 0; i < objectTableSize; i++) {
+        uint32_t minObjectEnd;
+        if (__builtin_add_overflow(objectTable[i], sizeof(RpcFields::ObjectType), &minObjectEnd) ||
+            minObjectEnd >= dataSize) {
+            ALOGE("received out of range object position: %" PRIu32 " (parcel size is %zu)",
+                  objectTable[i], dataSize);
+            relFunc(data, dataSize, nullptr, 0);
+            return BAD_VALUE;
+        }
+    }
+
     freeData();
     markForRpc(session);
 
@@ -2597,12 +2616,6 @@
     mDataSize = mDataCapacity = dataSize;
     mOwner = relFunc;
 
-    if (objectTableSize != ancillaryFds.size()) {
-        ALOGE("objectTableSize=%zu ancillaryFds.size=%zu", objectTableSize, ancillaryFds.size());
-        freeData(); // don't leak mData
-        return BAD_VALUE;
-    }
-
     rpcFields->mObjectPositions.reserve(objectTableSize);
     for (size_t i = 0; i < objectTableSize; i++) {
         rpcFields->mObjectPositions.push_back(objectTable[i]);
@@ -2703,7 +2716,9 @@
         LOG_ALLOC("Parcel %p: freeing other owner data", this);
         //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
         auto* kernelFields = maybeKernelFields();
-        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+        // Close FDs before freeing, otherwise they will leak for kernel binder.
+        closeFileDescriptors();
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
                kernelFields ? kernelFields->mObjectsSize : 0);
     } else {
         LOG_ALLOC("Parcel %p: freeing allocated data", this);
@@ -2888,8 +2903,13 @@
         if (objects && kernelFields && kernelFields->mObjects) {
             memcpy(objects, kernelFields->mObjects, objectsSize * sizeof(binder_size_t));
         }
-        //ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
-        mOwner(this, mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
+        // ALOGI("Freeing data ref of %p (pid=%d)", this, getpid());
+        if (kernelFields) {
+            // TODO(b/239222407): This seems wrong. We should only free FDs when
+            // they are in a truncated section of the parcel.
+            closeFileDescriptors();
+        }
+        mOwner(mData, mDataSize, kernelFields ? kernelFields->mObjects : nullptr,
                kernelFields ? kernelFields->mObjectsSize : 0);
         mOwner = nullptr;
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 7faff47..1f311ac 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -19,6 +19,7 @@
 #include <binder/ProcessState.h>
 
 #include <android-base/result.h>
+#include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
@@ -420,6 +421,9 @@
 }
 
 size_t ProcessState::getThreadPoolMaxTotalThreadCount() const {
+    pthread_mutex_lock(&mThreadCountLock);
+    base::ScopeGuard detachGuard = [&]() { pthread_mutex_unlock(&mThreadCountLock); };
+
     // may actually be one more than this, if join is called
     if (mThreadPoolStarted) {
         return mCurrentThreads < mKernelStartedThreads
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 1cd1fd3..49be4dd 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -34,6 +34,7 @@
 
 #include "BuildFlags.h"
 #include "FdTrigger.h"
+#include "OS.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
@@ -208,9 +209,10 @@
 
         {
             RpcMutexLockGuard _l(mLock);
-            RpcMaybeThread thread = RpcMaybeThread(&RpcServer::establishConnection,
-                                                   sp<RpcServer>::fromExisting(this),
-                                                   std::move(clientFd), addr, addrLen);
+            RpcMaybeThread thread =
+                    RpcMaybeThread(&RpcServer::establishConnection,
+                                   sp<RpcServer>::fromExisting(this), std::move(clientFd), addr,
+                                   addrLen, RpcSession::join);
 
             auto& threadRef = mConnectingThreads[thread.get_id()];
             threadRef = std::move(thread);
@@ -293,8 +295,10 @@
     return mConnectingThreads.size();
 }
 
-void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen) {
+void RpcServer::establishConnection(
+        sp<RpcServer>&& server, base::unique_fd clientFd, std::array<uint8_t, kRpcAddressSize> addr,
+        size_t addrLen,
+        std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn) {
     // 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);
@@ -420,7 +424,9 @@
             session->setMaxIncomingThreads(server->mMaxThreads);
             if (!session->setProtocolVersion(protocolVersion)) return;
 
-            if (server->mSupportedFileDescriptorTransportModes.test(
+            if (header.fileDescriptorTransportMode <
+                        server->mSupportedFileDescriptorTransportModes.size() &&
+                server->mSupportedFileDescriptorTransportModes.test(
                         header.fileDescriptorTransportMode)) {
                 session->setFileDescriptorTransportMode(
                         static_cast<RpcSession::FileDescriptorTransportMode>(
@@ -475,7 +481,7 @@
     // avoid strong cycle
     server = nullptr;
 
-    RpcSession::join(std::move(session), std::move(setupResult));
+    joinFn(std::move(session), std::move(setupResult));
 }
 
 status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 2d9c933..e6dbd79 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -37,6 +37,7 @@
 #include <utils/String8.h>
 
 #include "FdTrigger.h"
+#include "OS.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
@@ -222,6 +223,11 @@
 
     _l.unlock();
 
+    if (status_t res = state()->sendObituaries(sp<RpcSession>::fromExisting(this)); res != OK) {
+        ALOGE("Failed to send obituaries as the RpcSession is shutting down: %s",
+              statusToString(res).c_str());
+    }
+
     mRpcBinderState->clear();
 
     return true;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index bde3d90..c0e36c4 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -226,6 +226,30 @@
     return OK;
 }
 
+status_t RpcState::sendObituaries(const sp<RpcSession>& session) {
+    RpcMutexUniqueLock _l(mNodeMutex);
+
+    // Gather strong pointers to all of the remote binders for this session so
+    // we hold the strong references. remoteBinder() returns a raw pointer.
+    // Send the obituaries and drop the strong pointers outside of the lock so
+    // the destructors and the onBinderDied calls are not done while locked.
+    std::vector<sp<IBinder>> remoteBinders;
+    for (const auto& [_, binderNode] : mNodeForAddress) {
+        if (auto binder = binderNode.binder.promote()) {
+            remoteBinders.push_back(std::move(binder));
+        }
+    }
+    _l.unlock();
+
+    for (const auto& binder : remoteBinders) {
+        if (binder->remoteBinder() &&
+            binder->remoteBinder()->getPrivateAccessor().rpcSession() == session) {
+            binder->remoteBinder()->sendObituary();
+        }
+    }
+    return OK;
+}
+
 size_t RpcState::countBinders() {
     RpcMutexLockGuard _l(mNodeMutex);
     return mNodeForAddress.size();
@@ -244,60 +268,63 @@
                             "New state should be impossible after terminating!");
         return;
     }
+    mTerminated = true;
 
     if (SHOULD_LOG_RPC_DETAIL) {
         ALOGE("RpcState::clear()");
         dumpLocked();
     }
 
-    // if the destructor of a binder object makes another RPC call, then calling
-    // decStrong could deadlock. So, we must hold onto these binders until
-    // mNodeMutex is no longer taken.
-    std::vector<sp<IBinder>> tempHoldBinder;
-
-    mTerminated = true;
+    // invariants
     for (auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-        LOG_ALWAYS_FATAL_IF(binder == nullptr, "Binder %p expected to be owned.", binder.get());
-
-        if (node.sentRef != nullptr) {
-            tempHoldBinder.push_back(node.sentRef);
+        bool guaranteedHaveBinder = node.timesSent > 0;
+        if (guaranteedHaveBinder) {
+            LOG_ALWAYS_FATAL_IF(node.sentRef == nullptr,
+                                "Binder expected to be owned with address: %" PRIu64 " %s", address,
+                                node.toString().c_str());
         }
     }
 
-    mNodeForAddress.clear();
+    // if the destructor of a binder object makes another RPC call, then calling
+    // decStrong could deadlock. So, we must hold onto these binders until
+    // mNodeMutex is no longer taken.
+    auto temp = std::move(mNodeForAddress);
+    mNodeForAddress.clear(); // RpcState isn't reusable, but for future/explicit
 
     _l.unlock();
-    tempHoldBinder.clear(); // explicit
+    temp.clear(); // explicit
 }
 
 void RpcState::dumpLocked() {
     ALOGE("DUMP OF RpcState %p", this);
     ALOGE("DUMP OF RpcState (%zu nodes)", mNodeForAddress.size());
     for (const auto& [address, node] : mNodeForAddress) {
-        sp<IBinder> binder = node.binder.promote();
-
-        const char* desc;
-        if (binder) {
-            if (binder->remoteBinder()) {
-                if (binder->remoteBinder()->isRpcBinder()) {
-                    desc = "(rpc binder proxy)";
-                } else {
-                    desc = "(binder proxy)";
-                }
-            } else {
-                desc = "(local binder)";
-            }
-        } else {
-            desc = "(null)";
-        }
-
-        ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
-              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc);
+        ALOGE("- address: %" PRIu64 " %s", address, node.toString().c_str());
     }
     ALOGE("END DUMP OF RpcState");
 }
 
+std::string RpcState::BinderNode::toString() const {
+    sp<IBinder> strongBinder = this->binder.promote();
+
+    const char* desc;
+    if (strongBinder) {
+        if (strongBinder->remoteBinder()) {
+            if (strongBinder->remoteBinder()->isRpcBinder()) {
+                desc = "(rpc binder proxy)";
+            } else {
+                desc = "(binder proxy)";
+            }
+        } else {
+            desc = "(local binder)";
+        }
+    } else {
+        desc = "(not promotable)";
+    }
+
+    return StringPrintf("node{%p times sent: %zu times recd: %zu type: %s}",
+                        this->binder.unsafe_get(), this->timesSent, this->timesRecd, desc);
+}
 
 RpcState::CommandData::CommandData(size_t size) : mSize(size) {
     // The maximum size for regular binder is 1MB for all concurrent
@@ -581,13 +608,12 @@
     return waitForReply(connection, session, reply);
 }
 
-static void cleanup_reply_data(Parcel* p, const uint8_t* data, size_t dataSize,
-                               const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
+static void cleanup_reply_data(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                               size_t objectsCount) {
     delete[] const_cast<uint8_t*>(data);
     (void)dataSize;
     LOG_ALWAYS_FATAL_IF(objects != nullptr);
-    LOG_ALWAYS_FATAL_IF(objectsCount != 0, "%zu objects remaining", objectsCount);
+    (void)objectsCount;
 }
 
 status_t RpcState::waitForReply(const sp<RpcSession::RpcConnection>& connection,
@@ -643,14 +669,21 @@
     Span<const uint32_t> objectTableSpan;
     if (session->getProtocolVersion().value() >=
         RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-        Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(rpcReply.parcelDataSize);
+        std::optional<Span<const uint8_t>> objectTableBytes =
+                parcelSpan.splitOff(rpcReply.parcelDataSize);
+        if (!objectTableBytes.has_value()) {
+            ALOGE("Parcel size larger than available bytes: %" PRId32 " vs %zu. Terminating!",
+                  rpcReply.parcelDataSize, parcelSpan.byteSize());
+            (void)session->shutdownAndWait(false);
+            return BAD_VALUE;
+        }
         std::optional<Span<const uint32_t>> maybeSpan =
-                objectTableBytes.reinterpret<const uint32_t>();
+                objectTableBytes->reinterpret<const uint32_t>();
         if (!maybeSpan.has_value()) {
             ALOGE("Bad object table size inferred from RpcWireReply. Saw bodySize=%" PRId32
                   " sizeofHeader=%zu parcelSize=%" PRId32 " objectTableBytesSize=%zu. Terminating!",
                   command.bodySize, rpcReplyWireSize, rpcReply.parcelDataSize,
-                  objectTableBytes.size);
+                  objectTableBytes->size);
             return BAD_VALUE;
         }
         objectTableSpan = *maybeSpan;
@@ -736,7 +769,8 @@
     IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
     IPCThreadState::SpGuard spGuard{
             .address = __builtin_frame_address(0),
-            .context = "processing binder RPC command",
+            .context = "processing binder RPC command (where RpcServer::setPerSessionRootObject is "
+                       "used to distinguish callers)",
     };
     const IPCThreadState::SpGuard* origGuard;
     if (kernelBinderState != nullptr) {
@@ -786,9 +820,8 @@
                                    std::move(ancillaryFds));
 }
 
-static void do_nothing_to_transact_data(Parcel* p, const uint8_t* data, size_t dataSize,
+static void do_nothing_to_transact_data(const uint8_t* data, size_t dataSize,
                                         const binder_size_t* objects, size_t objectsCount) {
-    (void)p;
     (void)data;
     (void)dataSize;
     (void)objects;
@@ -892,15 +925,22 @@
         Span<const uint32_t> objectTableSpan;
         if (session->getProtocolVersion().value() >
             RPC_WIRE_PROTOCOL_VERSION_RPC_HEADER_FEATURE_EXPLICIT_PARCEL_SIZE) {
-            Span<const uint8_t> objectTableBytes = parcelSpan.splitOff(transaction->parcelDataSize);
+            std::optional<Span<const uint8_t>> objectTableBytes =
+                    parcelSpan.splitOff(transaction->parcelDataSize);
+            if (!objectTableBytes.has_value()) {
+                ALOGE("Parcel size (%" PRId32 ") greater than available bytes (%zu). Terminating!",
+                      transaction->parcelDataSize, parcelSpan.byteSize());
+                (void)session->shutdownAndWait(false);
+                return BAD_VALUE;
+            }
             std::optional<Span<const uint32_t>> maybeSpan =
-                    objectTableBytes.reinterpret<const uint32_t>();
+                    objectTableBytes->reinterpret<const uint32_t>();
             if (!maybeSpan.has_value()) {
                 ALOGE("Bad object table size inferred from RpcWireTransaction. Saw bodySize=%zu "
                       "sizeofHeader=%zu parcelSize=%" PRId32
                       " objectTableBytesSize=%zu. Terminating!",
                       transactionData.size(), sizeof(RpcWireTransaction),
-                      transaction->parcelDataSize, objectTableBytes.size);
+                      transaction->parcelDataSize, objectTableBytes->size);
                 return BAD_VALUE;
             }
             objectTableSpan = *maybeSpan;
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 6fb2e4a..7aab5ee 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -140,6 +140,11 @@
      */
     [[nodiscard]] status_t flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
                                                  const sp<IBinder>& binder);
+    /**
+     * Called when the RpcSession is shutdown.
+     * Send obituaries for each known remote binder with this session.
+     */
+    [[nodiscard]] status_t sendObituaries(const sp<RpcSession>& session);
 
     size_t countBinders();
     void dump();
@@ -258,6 +263,8 @@
         //
 
         // (no additional data specific to remote binders)
+
+        std::string toString() const;
     };
 
     // checks if there is any reference left to a node and erases it. If erase
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 7cc58cd..51326f6 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -24,6 +24,7 @@
 
 #include "FdTrigger.h"
 #include "RpcState.h"
+#include "RpcTransportUtils.h"
 
 namespace android {
 
@@ -55,90 +56,6 @@
         return OK;
     }
 
-    template <typename SendOrReceive>
-    status_t interruptableReadOrWrite(
-            FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
-            const char* funName, int16_t event,
-            const std::optional<android::base::function_ref<status_t()>>& altPoll) {
-        MAYBE_WAIT_IN_FLAKE_MODE;
-
-        if (niovs < 0) {
-            return BAD_VALUE;
-        }
-
-        // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
-        // may never know we should be shutting down.
-        if (fdTrigger->isTriggered()) {
-            return DEAD_OBJECT;
-        }
-
-        // If iovs has one or more empty vectors at the end and
-        // we somehow advance past all the preceding vectors and
-        // pass some or all of the empty ones to sendmsg/recvmsg,
-        // the call will return processSize == 0. In that case
-        // we should be returning OK but instead return DEAD_OBJECT.
-        // To avoid this problem, we make sure here that the last
-        // vector at iovs[niovs - 1] has a non-zero length.
-        while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
-            niovs--;
-        }
-        if (niovs == 0) {
-            // The vectors are all empty, so we have nothing to send.
-            return OK;
-        }
-
-        bool havePolled = false;
-        while (true) {
-            ssize_t processSize = sendOrReceiveFun(iovs, niovs);
-            if (processSize < 0) {
-                int savedErrno = errno;
-
-                // Still return the error on later passes, since it would expose
-                // a problem with polling
-                if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
-                    LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
-                    return -savedErrno;
-                }
-            } else if (processSize == 0) {
-                return DEAD_OBJECT;
-            } else {
-                while (processSize > 0 && niovs > 0) {
-                    auto& iov = iovs[0];
-                    if (static_cast<size_t>(processSize) < iov.iov_len) {
-                        // Advance the base of the current iovec
-                        iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
-                        iov.iov_len -= processSize;
-                        break;
-                    }
-
-                    // The current iovec was fully written
-                    processSize -= iov.iov_len;
-                    iovs++;
-                    niovs--;
-                }
-                if (niovs == 0) {
-                    LOG_ALWAYS_FATAL_IF(processSize > 0,
-                                        "Reached the end of iovecs "
-                                        "with %zd bytes remaining",
-                                        processSize);
-                    return OK;
-                }
-            }
-
-            if (altPoll) {
-                if (status_t status = (*altPoll)(); status != OK) return status;
-                if (fdTrigger->isTriggered()) {
-                    return DEAD_OBJECT;
-                }
-            } else {
-                if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
-                    status != OK)
-                    return status;
-                if (!havePolled) havePolled = true;
-            }
-        }
-    }
-
     status_t interruptableWriteFully(
             FdTrigger* fdTrigger, iovec* iovs, int niovs,
             const std::optional<android::base::function_ref<status_t()>>& altPoll,
@@ -198,7 +115,8 @@
             };
             return TEMP_FAILURE_RETRY(sendmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
         };
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, send, "sendmsg", POLLOUT, altPoll);
+        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, send, "sendmsg",
+                                        POLLOUT, altPoll);
     }
 
     status_t interruptableReadFully(
@@ -255,7 +173,8 @@
             };
             return TEMP_FAILURE_RETRY(recvmsg(mSocket.get(), &msg, MSG_NOSIGNAL));
         };
-        return interruptableReadOrWrite(fdTrigger, iovs, niovs, recv, "recvmsg", POLLIN, altPoll);
+        return interruptableReadOrWrite(mSocket.get(), fdTrigger, iovs, niovs, recv, "recvmsg",
+                                        POLLIN, altPoll);
     }
 
 private:
diff --git a/libs/binder/RpcTransportUtils.h b/libs/binder/RpcTransportUtils.h
new file mode 100644
index 0000000..00cb2af
--- /dev/null
+++ b/libs/binder/RpcTransportUtils.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <poll.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+namespace android {
+
+template <typename SendOrReceive>
+status_t interruptableReadOrWrite(
+        int socketFd, FdTrigger* fdTrigger, iovec* iovs, int niovs, SendOrReceive sendOrReceiveFun,
+        const char* funName, int16_t event,
+        const std::optional<android::base::function_ref<status_t()>>& altPoll) {
+    MAYBE_WAIT_IN_FLAKE_MODE;
+
+    if (niovs < 0) {
+        return BAD_VALUE;
+    }
+
+    // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+    // may never know we should be shutting down.
+    if (fdTrigger->isTriggered()) {
+        return DEAD_OBJECT;
+    }
+
+    // If iovs has one or more empty vectors at the end and
+    // we somehow advance past all the preceding vectors and
+    // pass some or all of the empty ones to sendmsg/recvmsg,
+    // the call will return processSize == 0. In that case
+    // we should be returning OK but instead return DEAD_OBJECT.
+    // To avoid this problem, we make sure here that the last
+    // vector at iovs[niovs - 1] has a non-zero length.
+    while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+        niovs--;
+    }
+    if (niovs == 0) {
+        // The vectors are all empty, so we have nothing to send.
+        return OK;
+    }
+
+    bool havePolled = false;
+    while (true) {
+        ssize_t processSize = sendOrReceiveFun(iovs, niovs);
+        if (processSize < 0) {
+            int savedErrno = errno;
+
+            // Still return the error on later passes, since it would expose
+            // a problem with polling
+            if (havePolled || (savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+                LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+                return -savedErrno;
+            }
+        } else if (processSize == 0) {
+            return DEAD_OBJECT;
+        } else {
+            while (processSize > 0 && niovs > 0) {
+                auto& iov = iovs[0];
+                if (static_cast<size_t>(processSize) < iov.iov_len) {
+                    // Advance the base of the current iovec
+                    iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+                    iov.iov_len -= processSize;
+                    break;
+                }
+
+                // The current iovec was fully written
+                processSize -= iov.iov_len;
+                iovs++;
+                niovs--;
+            }
+            if (niovs == 0) {
+                LOG_ALWAYS_FATAL_IF(processSize > 0,
+                                    "Reached the end of iovecs "
+                                    "with %zd bytes remaining",
+                                    processSize);
+                return OK;
+            }
+        }
+
+        if (altPoll) {
+            if (status_t status = (*altPoll)(); status != OK) return status;
+            if (fdTrigger->isTriggered()) {
+                return DEAD_OBJECT;
+            }
+        } else {
+            if (status_t status = fdTrigger->triggerablePoll(socketFd, event); status != OK)
+                return status;
+            if (!havePolled) havePolled = true;
+        }
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 0232f50..c91d56c 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -28,9 +28,6 @@
       "name": "binderLibTest"
     },
     {
-      "name": "binderRpcTest"
-    },
-    {
       "name": "binderStabilityTest"
     },
     {
@@ -84,7 +81,21 @@
       "name": "rustBinderSerializationTest"
     }
   ],
- "hwasan-presubmit": [
+  "presubmit-large": [
+    {
+      "name": "binderRpcTest"
+    },
+    {
+      "name": "binderRpcTestNoKernel"
+    },
+    {
+      "name": "binderRpcTestSingleThreaded"
+    },
+    {
+      "name": "binderRpcTestSingleThreadedNoKernel"
+    }
+  ],
+  "hwasan-presubmit": [
     {
       "name": "binderLibTest"
     }
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index b0289a7..0314b0f 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -16,40 +16,12 @@
 
 #include "Utils.h"
 
-#include <android-base/file.h>
 #include <string.h>
 
-using android::base::ErrnoError;
-using android::base::Result;
-
 namespace android {
 
 void zeroMemory(uint8_t* data, size_t size) {
     memset(data, 0, size);
 }
 
-Result<void> setNonBlocking(android::base::borrowed_fd fd) {
-    int flags = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_GETFL));
-    if (flags == -1) {
-        return ErrnoError() << "Could not get flags for fd";
-    }
-    if (int ret = TEMP_FAILURE_RETRY(fcntl(fd.get(), F_SETFL, flags | O_NONBLOCK)); ret == -1) {
-        return ErrnoError() << "Could not set non-blocking flag for fd";
-    }
-    return {};
-}
-
-status_t getRandomBytes(uint8_t* data, size_t size) {
-    int ret = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
-    if (ret == -1) {
-        return -errno;
-    }
-
-    base::unique_fd fd(ret);
-    if (!base::ReadFully(fd, data, size)) {
-        return -errno;
-    }
-    return OK;
-}
-
 } // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 37c1262..e04199c 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -15,11 +15,10 @@
  */
 
 #include <stddef.h>
+#include <sys/uio.h>
 #include <cstdint>
 #include <optional>
 
-#include <android-base/result.h>
-#include <android-base/unique_fd.h>
 #include <log/log.h>
 #include <utils/Errors.h>
 
@@ -36,10 +35,6 @@
 // avoid optimizations
 void zeroMemory(uint8_t* data, size_t size);
 
-android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
-
-status_t getRandomBytes(uint8_t* data, size_t size);
-
 // View of contiguous sequence. Similar to std::span.
 template <typename T>
 struct Span {
@@ -53,9 +48,11 @@
     // Truncates `this` to a length of `offset` and returns a span with the
     // remainder.
     //
-    // Aborts if offset > size.
-    Span<T> splitOff(size_t offset) {
-        LOG_ALWAYS_FATAL_IF(offset > size);
+    // `std::nullopt` iff offset > size.
+    std::optional<Span<T>> splitOff(size_t offset) {
+        if (offset > size) {
+            return std::nullopt;
+        }
         Span<T> rest = {data + offset, size - offset};
         size = offset;
         return rest;
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index cd6a274..c01e92f 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -28,6 +28,10 @@
 // ---------------------------------------------------------------------------
 namespace android {
 
+/**
+ * Kernel binder thread state. All operations here refer to kernel binder. This
+ * object is allocated per-thread.
+ */
 class IPCThreadState
 {
 public:
@@ -213,9 +217,8 @@
             void                clearCaller();
 
     static  void                threadDestructor(void *st);
-    static  void                freeBuffer(Parcel* parcel,
-                                           const uint8_t* data, size_t dataSize,
-                                           const binder_size_t* objects, size_t objectsSize);
+    static void freeBuffer(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                           size_t objectsSize);
     static  void                logExtendedError();
 
     const   sp<ProcessState>    mProcess;
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 32b0ded..5469239 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -598,9 +598,9 @@
     void                print(TextOutput& to, uint32_t flags = 0) const;
 
 private:
-    typedef void        (*release_func)(Parcel* parcel,
-                                        const uint8_t* data, size_t dataSize,
-                                        const binder_size_t* objects, size_t objectsSize);
+    // `objects` and `objectsSize` always 0 for RPC Parcels.
+    typedef void (*release_func)(const uint8_t* data, size_t dataSize, const binder_size_t* objects,
+                                 size_t objectsSize);
 
     uintptr_t           ipcData() const;
     size_t              ipcDataSize() const;
@@ -1184,10 +1184,20 @@
         c->clear(); // must clear before resizing/reserving otherwise move ctors may be called.
         if constexpr (is_pointer_equivalent_array_v<T>) {
             // could consider POD without gaps and alignment of 4.
-            auto data = reinterpret_cast<const T*>(
-                    readInplace(static_cast<size_t>(size) * sizeof(T)));
+            size_t dataLen;
+            if (__builtin_mul_overflow(size, sizeof(T), &dataLen)) {
+                return -EOVERFLOW;
+            }
+            auto data = reinterpret_cast<const T*>(readInplace(dataLen));
             if (data == nullptr) return BAD_VALUE;
-            c->insert(c->begin(), data, data + size); // insert should do a reserve().
+            // std::vector::insert and similar methods will require type-dependent
+            // byte alignment when inserting from a const iterator such as `data`,
+            // e.g. 8 byte alignment for int64_t, and so will not work if `data`
+            // is 4 byte aligned (which is all Parcel guarantees). Copying
+            // the contents into the vector directly, where possible, circumvents
+            // this.
+            c->resize(size);
+            memcpy(c->data(), data, dataLen);
         } else if constexpr (std::is_same_v<T, bool>
                 || std::is_same_v<T, char16_t>) {
             c->reserve(size); // avoids default initialization
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index e17a76c..9679a5f 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -29,6 +29,10 @@
 
 class IPCThreadState;
 
+/**
+ * Kernel binder process state. All operations here refer to kernel binder. This
+ * object is allocated per process.
+ */
 class ProcessState : public virtual RefBase {
 public:
     static sp<ProcessState> self();
@@ -126,7 +130,7 @@
     void* mVMStart;
 
     // Protects thread count and wait variables below.
-    pthread_mutex_t mThreadCountLock;
+    mutable pthread_mutex_t mThreadCountLock;
     // Broadcast whenever mWaitingForThreads > 0
     pthread_cond_t mThreadCountDecrement;
     // Number of binder threads current executing a command.
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 9318c27..52bda0e 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -29,6 +29,7 @@
 namespace android {
 
 class FdTrigger;
+class RpcServerTrusty;
 class RpcSocketAddress;
 
 /**
@@ -189,6 +190,7 @@
     ~RpcServer();
 
 private:
+    friend RpcServerTrusty;
     friend sp<RpcServer>;
     explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
 
@@ -196,8 +198,10 @@
     void onSessionIncomingThreadEnded() override;
 
     static constexpr size_t kRpcAddressSize = 128;
-    static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd,
-                                    std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen);
+    static void establishConnection(
+            sp<RpcServer>&& server, base::unique_fd clientFd,
+            std::array<uint8_t, kRpcAddressSize> addr, size_t addrLen,
+            std::function<void(sp<RpcSession>&&, RpcSession::PreJoinSetupResult&&)>&& joinFn);
     [[nodiscard]] status_t setupSocketServer(const RpcSocketAddress& address);
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index a2b28db..9d94e00 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -31,6 +31,7 @@
 
 class Parcel;
 class RpcServer;
+class RpcServerTrusty;
 class RpcSocketAddress;
 class RpcState;
 class RpcTransport;
@@ -202,6 +203,7 @@
 private:
     friend sp<RpcSession>;
     friend RpcServer;
+    friend RpcServerTrusty;
     friend RpcState;
     explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
 
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index b21a7e9..9778ec0 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -64,6 +64,9 @@
     wp<ABpBinder> binder;
 };
 void clean(const void* id, void* obj, void* cookie) {
+    // be weary of leaks!
+    // LOG(INFO) << "Deleting an ABpBinder";
+
     CHECK(id == kId) << id << " " << obj << " " << cookie;
 
     delete static_cast<Value*>(obj);
@@ -239,26 +242,11 @@
 }
 
 ABpBinder::ABpBinder(const ::android::sp<::android::IBinder>& binder)
-    : AIBinder(nullptr /*clazz*/), BpRefBase(binder) {
+    : AIBinder(nullptr /*clazz*/), mRemote(binder) {
     CHECK(binder != nullptr);
 }
 ABpBinder::~ABpBinder() {}
 
-void ABpBinder::onLastStrongRef(const void* id) {
-    // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
-    // the ABpBinder to be deleted. Even though we have no more references on the ABpBinder
-    // (BpRefBase), the remote object may still exist (for instance, if we
-    // receive it from another process, before the ABpBinder is attached).
-
-    ABpBinderTag::Value* value =
-            static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
-    CHECK_NE(nullptr, value) << "ABpBinder must always be attached";
-
-    remote()->withLock([&]() { value->binder = nullptr; });
-
-    BpRefBase::onLastStrongRef(id);
-}
-
 sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
     if (binder == nullptr) {
         return nullptr;
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 730e51b..d7098e8 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -91,7 +91,7 @@
 
 // This binder object may be remote or local (even though it is 'Bp'). The implication if it is
 // local is that it is an IBinder object created outside of the domain of libbinder_ndk.
-struct ABpBinder : public AIBinder, public ::android::BpRefBase {
+struct ABpBinder : public AIBinder {
     // Looks up to see if this object has or is an existing ABBinder or ABpBinder object, otherwise
     // it creates an ABpBinder object.
     static ::android::sp<AIBinder> lookupOrCreateFromBinder(
@@ -99,14 +99,13 @@
 
     virtual ~ABpBinder();
 
-    void onLastStrongRef(const void* id) override;
-
-    ::android::sp<::android::IBinder> getBinder() override { return remote(); }
+    ::android::sp<::android::IBinder> getBinder() override { return mRemote; }
     ABpBinder* asABpBinder() override { return this; }
 
    private:
     friend android::sp<ABpBinder>;
     explicit ABpBinder(const ::android::sp<::android::IBinder>& binder);
+    ::android::sp<::android::IBinder> mRemote;
 };
 
 struct AIBinder_Class {
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 3824a1b..6bc9814 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -89,12 +89,12 @@
     AStatus_getStatus;
     AStatus_isOk;
     AStatus_newOk;
-    ABinderProcess_joinThreadPool; # apex llndk
-    ABinderProcess_setThreadPoolMaxThreadCount; # apex llndk
-    ABinderProcess_startThreadPool; # apex llndk
-    AServiceManager_addService; # apex llndk
-    AServiceManager_checkService; # apex llndk
-    AServiceManager_getService; # apex llndk
+    ABinderProcess_joinThreadPool; # systemapi llndk
+    ABinderProcess_setThreadPoolMaxThreadCount; # systemapi llndk
+    ABinderProcess_startThreadPool; # systemapi llndk
+    AServiceManager_addService; # systemapi llndk
+    AServiceManager_checkService; # systemapi llndk
+    AServiceManager_getService; # systemapi llndk
 };
 
 LIBBINDER_NDK30 { # introduced=30
@@ -105,30 +105,30 @@
     AStatus_deleteDescription;
     AParcel_fromJavaParcel;
 
-    AIBinder_markSystemStability; # apex
+    AIBinder_markSystemStability; # systemapi
     AIBinder_markVendorStability; # llndk
-    AIBinder_markVintfStability; # apex llndk
-    AIBinder_Class_setHandleShellCommand; # apex llndk
+    AIBinder_markVintfStability; # systemapi llndk
+    AIBinder_Class_setHandleShellCommand; # systemapi llndk
 };
 
 LIBBINDER_NDK31 { # introduced=31
   global:
-    ABinderProcess_handlePolledCommands; # apex
-    ABinderProcess_setupPolling; # apex
-    AIBinder_getCallingSid; # apex
-    AIBinder_setRequestingSid; # apex
+    ABinderProcess_handlePolledCommands; # systemapi
+    ABinderProcess_setupPolling; # systemapi
+    AIBinder_getCallingSid; # systemapi
+    AIBinder_setRequestingSid; # systemapi
     AParcel_markSensitive; # systemapi llndk
-    AServiceManager_forEachDeclaredInstance; # apex llndk
-    AServiceManager_forceLazyServicesPersist; # apex llndk
-    AServiceManager_isDeclared; # apex llndk
-    AServiceManager_isUpdatableViaApex; # apex
+    AServiceManager_forEachDeclaredInstance; # systemapi llndk
+    AServiceManager_forceLazyServicesPersist; # systemapi llndk
+    AServiceManager_isDeclared; # systemapi llndk
+    AServiceManager_isUpdatableViaApex; # systemapi
     AServiceManager_reRegister; # llndk
-    AServiceManager_registerLazyService; # apex llndk
+    AServiceManager_registerLazyService; # systemapi llndk
     AServiceManager_setActiveServicesCallback; # llndk
     AServiceManager_tryUnregister; # llndk
-    AServiceManager_waitForService; # apex llndk
+    AServiceManager_waitForService; # systemapi llndk
 
-    AIBinder_forceDowngradeToSystemStability; # apex
+    AIBinder_forceDowngradeToSystemStability; # systemapi
     AIBinder_forceDowngradeToVendorStability; # llndk
 
     AIBinder_Class_getDescriptor;
@@ -146,8 +146,8 @@
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
     AIBinder_isHandlingTransaction;
-    AIBinder_setInheritRt; # llndk
-    AIBinder_setMinSchedulerPolicy; # llndk
+    AIBinder_setInheritRt; # systemapi llndk
+    AIBinder_setMinSchedulerPolicy; # systemapi llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 355b3b4..9042b3a 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -148,6 +148,7 @@
     name: "libbinder_rpc_unstable_bindgen",
     wrapper_src: ":libbinder_rpc_unstable_header",
     crate_name: "binder_rpc_unstable_bindgen",
+    visibility: ["//packages/modules/Virtualization:__subpackages__"],
     source_stem: "bindings",
     shared_libs: [
         "libutils",
diff --git a/libs/binder/rust/binder_tokio/lib.rs b/libs/binder/rust/binder_tokio/lib.rs
index 9dcef42..2d2bf7c 100644
--- a/libs/binder/rust/binder_tokio/lib.rs
+++ b/libs/binder/rust/binder_tokio/lib.rs
@@ -28,22 +28,22 @@
 //!
 //! [`Tokio`]: crate::Tokio
 
-use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
 use binder::binder_impl::BinderAsyncRuntime;
+use binder::{BinderAsyncPool, BoxFuture, FromIBinder, StatusCode, Strong};
 use std::future::Future;
 
 /// Retrieve an existing service for a particular interface, sleeping for a few
 /// seconds if it doesn't yet exist.
-pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn get_interface<T: FromIBinder + ?Sized + 'static>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
     if binder::is_handling_transaction() {
         // See comment in the BinderAsyncPool impl.
         return binder::get_interface::<T>(name);
     }
 
     let name = name.to_string();
-    let res = tokio::task::spawn_blocking(move || {
-        binder::get_interface::<T>(&name)
-    }).await;
+    let res = tokio::task::spawn_blocking(move || binder::get_interface::<T>(&name)).await;
 
     // The `is_panic` branch is not actually reachable in Android as we compile
     // with `panic = abort`.
@@ -58,16 +58,16 @@
 
 /// Retrieve an existing service for a particular interface, or start it if it
 /// is configured as a dynamic service and isn't yet started.
-pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(name: &str) -> Result<Strong<T>, StatusCode> {
+pub async fn wait_for_interface<T: FromIBinder + ?Sized + 'static>(
+    name: &str,
+) -> Result<Strong<T>, StatusCode> {
     if binder::is_handling_transaction() {
         // See comment in the BinderAsyncPool impl.
         return binder::wait_for_interface::<T>(name);
     }
 
     let name = name.to_string();
-    let res = tokio::task::spawn_blocking(move || {
-        binder::wait_for_interface::<T>(&name)
-    }).await;
+    let res = tokio::task::spawn_blocking(move || binder::wait_for_interface::<T>(&name)).await;
 
     // The `is_panic` branch is not actually reachable in Android as we compile
     // with `panic = abort`.
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index 5d6206d..63c8684 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, BorrowedParcel};
+use crate::parcel::{BorrowedParcel, Parcel};
 use crate::proxy::{DeathRecipient, SpIBinder, WpIBinder};
 use crate::sys;
 
@@ -133,7 +133,7 @@
         match stability {
             0 => Ok(Local),
             1 => Ok(Vintf),
-            _ => Err(StatusCode::BAD_VALUE)
+            _ => Err(StatusCode::BAD_VALUE),
         }
     }
 }
@@ -158,7 +158,12 @@
     /// Handle and reply to a request to invoke a transaction on this object.
     ///
     /// `reply` may be [`None`] if the sender does not expect a reply.
-    fn on_transact(&self, code: TransactionCode, data: &BorrowedParcel<'_>, reply: &mut BorrowedParcel<'_>) -> Result<()>;
+    fn on_transact(
+        &self,
+        code: TransactionCode,
+        data: &BorrowedParcel<'_>,
+        reply: &mut BorrowedParcel<'_>,
+    ) -> Result<()>;
 
     /// Handle a request to invoke the dump transaction on this
     /// object.
@@ -454,28 +459,19 @@
     /// Construct a new weak reference from a strong reference
     fn new(binder: &Strong<I>) -> Self {
         let weak_binder = binder.as_binder().downgrade();
-        Weak {
-            weak_binder,
-            interface_type: PhantomData,
-        }
+        Weak { weak_binder, interface_type: PhantomData }
     }
 
     /// Upgrade this weak reference to a strong reference if the binder object
     /// is still alive
     pub fn upgrade(&self) -> Result<Strong<I>> {
-        self.weak_binder
-            .promote()
-            .ok_or(StatusCode::DEAD_OBJECT)
-            .and_then(FromIBinder::try_from)
+        self.weak_binder.promote().ok_or(StatusCode::DEAD_OBJECT).and_then(FromIBinder::try_from)
     }
 }
 
 impl<I: FromIBinder + ?Sized> Clone for Weak<I> {
     fn clone(&self) -> Self {
-        Self {
-            weak_binder: self.weak_binder.clone(),
-            interface_type: PhantomData,
-        }
+        Self { weak_binder: self.weak_binder.clone(), interface_type: PhantomData }
     }
 }
 
@@ -614,7 +610,12 @@
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
     /// poiinters with length num_args.
-    unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t;
+    unsafe extern "C" fn on_dump(
+        binder: *mut sys::AIBinder,
+        fd: i32,
+        args: *mut *const c_char,
+        num_args: u32,
+    ) -> status_t;
 }
 
 /// Interface for transforming a generic SpIBinder into a specific remote
diff --git a/libs/binder/rust/src/binder_async.rs b/libs/binder/rust/src/binder_async.rs
index 579f9f9..d90acaf 100644
--- a/libs/binder/rust/src/binder_async.rs
+++ b/libs/binder/rust/src/binder_async.rs
@@ -41,7 +41,10 @@
     /// boxed `Future` trait object, and including `after_spawn` in the trait function
     /// allows the caller to avoid double-boxing if they want to do anything to the value
     /// returned from the spawned thread.
-    fn spawn<'a, F1, F2, Fut, A, B, E>(spawn_me: F1, after_spawn: F2) -> BoxFuture<'a, Result<B, E>>
+    fn spawn<'a, F1, F2, Fut, A, B, E>(
+        spawn_me: F1,
+        after_spawn: F2,
+    ) -> BoxFuture<'a, Result<B, E>>
     where
         F1: FnOnce() -> A,
         F2: FnOnce(A) -> Fut,
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index dbfb1c2..67872a9 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -106,8 +106,8 @@
 
 use binder_ndk_sys as sys;
 
-pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
 pub use crate::binder_async::{BinderAsyncPool, BoxFuture};
+pub use binder::{BinderFeatures, FromIBinder, IBinder, Interface, Strong, Weak};
 pub use error::{ExceptionCode, Status, StatusCode};
 pub use native::{
     add_service, force_lazy_services_persist, is_handling_transaction, register_lazy_service,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index 3edeebf..9e2cef1 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -97,10 +97,7 @@
             // ends.
             sys::AIBinder_new(class.into(), rust_object as *mut c_void)
         };
-        let mut binder = Binder {
-            ibinder,
-            rust_object,
-        };
+        let mut binder = Binder { ibinder, rust_object };
         binder.mark_stability(stability);
         binder
     }
@@ -343,7 +340,9 @@
             vec![]
         } else {
             slice::from_raw_parts(args, num_args as usize)
-                .iter().map(|s| CStr::from_ptr(*s)).collect()
+                .iter()
+                .map(|s| CStr::from_ptr(*s))
+                .collect()
         };
 
         let object = sys::AIBinder_getUserData(binder);
@@ -418,10 +417,7 @@
         // We are transferring the ownership of the AIBinder into the new Binder
         // object.
         let mut ibinder = ManuallyDrop::new(ibinder);
-        Ok(Binder {
-            ibinder: ibinder.as_native_mut(),
-            rust_object: userdata as *mut B,
-        })
+        Ok(Binder { ibinder: ibinder.as_native_mut(), rust_object: userdata as *mut B })
     }
 }
 
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index 256fa8b..53a24af 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -22,10 +22,10 @@
 use crate::sys;
 
 use std::convert::TryInto;
+use std::fmt;
 use std::marker::PhantomData;
 use std::mem::ManuallyDrop;
 use std::ptr::{self, NonNull};
-use std::fmt;
 
 mod file_descriptor;
 mod parcelable;
@@ -33,8 +33,8 @@
 
 pub use self::file_descriptor::ParcelFileDescriptor;
 pub use self::parcelable::{
-    Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
-    Parcelable, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
+    Deserialize, DeserializeArray, DeserializeOption, Parcelable, Serialize, SerializeArray,
+    SerializeOption, NON_NULL_PARCELABLE_FLAG, NULL_PARCELABLE_FLAG,
 };
 pub use self::parcelable_holder::{ParcelableHolder, ParcelableMetadata};
 
@@ -78,9 +78,7 @@
             // a valid pointer. If it fails, the process will crash.
             sys::AParcel_create()
         };
-        Self {
-            ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer")
-        }
+        Self { ptr: NonNull::new(ptr).expect("AParcel_create returned null pointer") }
     }
 
     /// Create an owned reference to a parcel object from a raw pointer.
@@ -116,10 +114,7 @@
         // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
         // borrow checker will ensure that the `AParcel` can only be accessed
         // via the `BorrowParcel` until it goes out of scope.
-        BorrowedParcel {
-            ptr: self.ptr,
-            _lifetime: PhantomData,
-        }
+        BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
     }
 
     /// Get an immutable borrowed view into the contents of this `Parcel`.
@@ -127,9 +122,7 @@
         // Safety: Parcel and BorrowedParcel are both represented in the same
         // way as a NonNull<sys::AParcel> due to their use of repr(transparent),
         // so casting references as done here is valid.
-        unsafe {
-            &*(self as *const Parcel as *const BorrowedParcel<'_>)
-        }
+        unsafe { &*(self as *const Parcel as *const BorrowedParcel<'_>) }
     }
 }
 
@@ -165,10 +158,7 @@
     /// since this is a mutable borrow, it must have exclusive access to the
     /// AParcel for the duration of the borrow.
     pub unsafe fn from_raw(ptr: *mut sys::AParcel) -> Option<BorrowedParcel<'a>> {
-        Some(Self {
-            ptr: NonNull::new(ptr)?,
-            _lifetime: PhantomData,
-        })
+        Some(Self { ptr: NonNull::new(ptr)?, _lifetime: PhantomData })
     }
 
     /// Get a sub-reference to this reference to the parcel.
@@ -177,10 +167,7 @@
         // lifetime of the returned `BorrowedParcel` is tied to `self`, so the
         // borrow checker will ensure that the `AParcel` can only be accessed
         // via the `BorrowParcel` until it goes out of scope.
-        BorrowedParcel {
-            ptr: self.ptr,
-            _lifetime: PhantomData,
-        }
+        BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData }
     }
 }
 
@@ -269,7 +256,7 @@
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
     {
         let start = self.get_data_position();
         self.write(&0i32)?;
@@ -324,17 +311,17 @@
     ///
     /// This appends `size` bytes of data from `other` starting at offset
     /// `start` to the current parcel, or returns an error if not possible.
-    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+    pub fn append_from(
+        &mut self,
+        other: &impl AsNative<sys::AParcel>,
+        start: i32,
+        size: i32,
+    ) -> Result<()> {
         let status = unsafe {
             // Safety: `Parcel::appendFrom` from C++ checks that `start`
             // and `size` are in bounds, and returns an error otherwise.
             // Both `self` and `other` always contain valid pointers.
-            sys::AParcel_appendFrom(
-                other.as_native(),
-                self.as_native_mut(),
-                start,
-                size,
-            )
+            sys::AParcel_appendFrom(other.as_native(), self.as_native_mut(), start, size)
         };
         status_result(status)
     }
@@ -406,7 +393,7 @@
     /// ```
     pub fn sized_write<F>(&mut self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(&'b mut WritableSubParcel<'b>) -> Result<()>,
     {
         self.borrowed().sized_write(f)
     }
@@ -438,7 +425,12 @@
     ///
     /// This appends `size` bytes of data from `other` starting at offset
     /// `start` to the current parcel, or returns an error if not possible.
-    pub fn append_from(&mut self, other: &impl AsNative<sys::AParcel>, start: i32, size: i32) -> Result<()> {
+    pub fn append_from(
+        &mut self,
+        other: &impl AsNative<sys::AParcel>,
+        start: i32,
+        size: i32,
+    ) -> Result<()> {
         self.borrowed().append_from(other, start, size)
     }
 
@@ -492,7 +484,7 @@
     ///
     pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
     {
         let start = self.get_data_position();
         let parcelable_size: i32 = self.read()?;
@@ -500,17 +492,13 @@
             return Err(StatusCode::BAD_VALUE);
         }
 
-        let end = start.checked_add(parcelable_size)
-            .ok_or(StatusCode::BAD_VALUE)?;
+        let end = start.checked_add(parcelable_size).ok_or(StatusCode::BAD_VALUE)?;
         if end > self.get_data_size() {
             return Err(StatusCode::NOT_ENOUGH_DATA);
         }
 
         let subparcel = ReadableSubParcel {
-            parcel: BorrowedParcel {
-                ptr: self.ptr,
-                _lifetime: PhantomData,
-            },
+            parcel: BorrowedParcel { ptr: self.ptr, _lifetime: PhantomData },
             end_position: end,
         };
         f(subparcel)?;
@@ -633,7 +621,7 @@
     ///
     pub fn sized_read<F>(&self, f: F) -> Result<()>
     where
-        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>
+        for<'b> F: FnOnce(ReadableSubParcel<'b>) -> Result<()>,
     {
         self.borrowed_ref().sized_read(f)
     }
@@ -716,15 +704,13 @@
 
 impl fmt::Debug for Parcel {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("Parcel")
-            .finish()
+        f.debug_struct("Parcel").finish()
     }
 }
 
 impl<'a> fmt::Debug for BorrowedParcel<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("BorrowedParcel")
-            .finish()
+        f.debug_struct("BorrowedParcel").finish()
     }
 }
 
@@ -813,10 +799,7 @@
         assert!(parcel.set_data_position(start).is_ok());
     }
 
-    assert_eq!(
-        parcel.read::<f32>().unwrap(),
-        1143139100000000000000000000.0
-    );
+    assert_eq!(parcel.read::<f32>().unwrap(), 1143139100000000000000000000.0);
     assert_eq!(parcel.read::<f32>().unwrap(), 40.043392);
 
     unsafe {
@@ -842,10 +825,7 @@
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
-    assert_eq!(
-        parcel.read::<Option<String>>().unwrap().unwrap(),
-        "Hello, Binder!",
-    );
+    assert_eq!(parcel.read::<Option<String>>().unwrap().unwrap(), "Hello, Binder!",);
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
     }
@@ -864,13 +844,7 @@
 
     assert!(parcel.write(&["str1", "str2", "str3"][..]).is_ok());
     assert!(parcel
-        .write(
-            &[
-                String::from("str4"),
-                String::from("str5"),
-                String::from("str6"),
-            ][..]
-        )
+        .write(&[String::from("str4"), String::from("str5"), String::from("str6"),][..])
         .is_ok());
 
     let s1 = "Hello, Binder!";
@@ -882,14 +856,8 @@
         assert!(parcel.set_data_position(start).is_ok());
     }
 
-    assert_eq!(
-        parcel.read::<Vec<String>>().unwrap(),
-        ["str1", "str2", "str3"]
-    );
-    assert_eq!(
-        parcel.read::<Vec<String>>().unwrap(),
-        ["str4", "str5", "str6"]
-    );
+    assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str1", "str2", "str3"]);
+    assert_eq!(parcel.read::<Vec<String>>().unwrap(), ["str4", "str5", "str6"]);
     assert_eq!(parcel.read::<Vec<String>>().unwrap(), [s1, s2, s3]);
 }
 
@@ -900,9 +868,9 @@
 
     let arr = [1i32, 2i32, 3i32];
 
-    parcel.sized_write(|subparcel| {
-        subparcel.write(&arr[..])
-    }).expect("Could not perform sized write");
+    parcel
+        .sized_write(|subparcel| subparcel.write(&arr[..]))
+        .expect("Could not perform sized write");
 
     // i32 sub-parcel length + i32 array length + 3 i32 elements
     let expected_len = 20i32;
@@ -913,15 +881,9 @@
         parcel.set_data_position(start).unwrap();
     }
 
-    assert_eq!(
-        expected_len,
-        parcel.read().unwrap(),
-    );
+    assert_eq!(expected_len, parcel.read().unwrap(),);
 
-    assert_eq!(
-        parcel.read::<Vec<i32>>().unwrap(),
-        &arr,
-    );
+    assert_eq!(parcel.read::<Vec<i32>>().unwrap(), &arr,);
 }
 
 #[test]
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 4d3d59a..de6d649 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -15,7 +15,7 @@
  */
 
 use super::{
-    Deserialize, DeserializeArray, DeserializeOption, BorrowedParcel, Serialize, SerializeArray,
+    BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray,
     SerializeOption,
 };
 use crate::binder::AsNative;
@@ -115,10 +115,7 @@
             // descriptor. The read function passes ownership of the file
             // descriptor to its caller if it was non-null, so we must take
             // ownership of the file and ensure that it is eventually closed.
-            status_result(sys::AParcel_readParcelFileDescriptor(
-                parcel.as_native(),
-                &mut fd,
-            ))?;
+            status_result(sys::AParcel_readParcelFileDescriptor(parcel.as_native(), &mut fd))?;
         }
         if fd < 0 {
             Ok(None)
@@ -136,9 +133,7 @@
 
 impl Deserialize for ParcelFileDescriptor {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
-        Deserialize::deserialize(parcel)
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 0c7e48d..c241e4d 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -22,8 +22,8 @@
 
 use std::convert::{TryFrom, TryInto};
 use std::ffi::c_void;
+use std::mem::{self, ManuallyDrop, MaybeUninit};
 use std::os::raw::{c_char, c_ulong};
-use std::mem::{self, MaybeUninit, ManuallyDrop};
 use std::ptr;
 use std::slice;
 
@@ -109,17 +109,14 @@
     // so the function signature matches what bindgen generates.
     let index = index as usize;
 
-    let slice: &[T] = slice::from_raw_parts(array.cast(), index+1);
+    let slice: &[T] = slice::from_raw_parts(array.cast(), index + 1);
 
     let mut parcel = match BorrowedParcel::from_raw(parcel) {
         None => return StatusCode::UNEXPECTED_NULL as status_t,
         Some(p) => p,
     };
 
-    slice[index].serialize(&mut parcel)
-                .err()
-                .unwrap_or(StatusCode::OK)
-        as status_t
+    slice[index].serialize(&mut parcel).err().unwrap_or(StatusCode::OK) as status_t
 }
 
 /// Helper trait for types that can be deserialized as arrays.
@@ -265,10 +262,7 @@
 ///
 /// The opaque data pointer passed to the array read function must be a mutable
 /// pointer to an `Option<Vec<MaybeUninit<T>>>`.
-unsafe extern "C" fn allocate_vec<T>(
-    data: *mut c_void,
-    len: i32,
-) -> bool {
+unsafe extern "C" fn allocate_vec<T>(data: *mut c_void, len: i32) -> bool {
     let vec = &mut *(data as *mut Option<Vec<MaybeUninit<T>>>);
     if len < 0 {
         *vec = None;
@@ -286,7 +280,6 @@
     true
 }
 
-
 macro_rules! parcelable_primitives {
     {
         $(
@@ -303,11 +296,7 @@
     // has the same alignment and size as T, so the pointer to the vector
     // allocation will be compatible.
     let mut vec = ManuallyDrop::new(vec);
-    Vec::from_raw_parts(
-        vec.as_mut_ptr().cast(),
-        vec.len(),
-        vec.capacity(),
-    )
+    Vec::from_raw_parts(vec.as_mut_ptr().cast(), vec.len(), vec.capacity())
 }
 
 macro_rules! impl_parcelable {
@@ -522,11 +511,7 @@
                 // `AParcel`. If the string pointer is null,
                 // `AParcel_writeString` requires that the length is -1 to
                 // indicate that we want to serialize a null string.
-                status_result(sys::AParcel_writeString(
-                    parcel.as_native_mut(),
-                    ptr::null(),
-                    -1,
-                ))
+                status_result(sys::AParcel_writeString(parcel.as_native_mut(), ptr::null(), -1))
             },
             Some(s) => unsafe {
                 // Safety: `Parcel` always contains a valid pointer to an
@@ -540,10 +525,7 @@
                 status_result(sys::AParcel_writeString(
                     parcel.as_native_mut(),
                     s.as_ptr() as *const c_char,
-                    s.as_bytes()
-                        .len()
-                        .try_into()
-                        .or(Err(StatusCode::BAD_VALUE))?,
+                    s.as_bytes().len().try_into().or(Err(StatusCode::BAD_VALUE))?,
                 ))
             },
         }
@@ -602,9 +584,7 @@
 
 impl Deserialize for String {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
-        Deserialize::deserialize(parcel)
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        Deserialize::deserialize(parcel).transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
@@ -704,10 +684,7 @@
             // and `Status` always contains a valid pointer to an `AStatus`, so
             // both parameters are valid and safe. This call does not take
             // ownership of either of its parameters.
-            status_result(sys::AParcel_writeStatusHeader(
-                parcel.as_native_mut(),
-                self.as_native(),
-            ))
+            status_result(sys::AParcel_writeStatusHeader(parcel.as_native_mut(), self.as_native()))
         }
     }
 }
@@ -881,8 +858,7 @@
                     Ok(())
                 } else {
                     use $crate::Parcelable;
-                    this.get_or_insert_with(Self::default)
-                        .read_from_parcel(parcel)
+                    this.get_or_insert_with(Self::default).read_from_parcel(parcel)
                 }
             }
         }
@@ -915,8 +891,8 @@
 
 #[cfg(test)]
 mod tests {
-    use crate::parcel::Parcel;
     use super::*;
+    use crate::parcel::Parcel;
 
     #[test]
     fn test_custom_parcelable() {
@@ -934,11 +910,11 @@
         impl Deserialize for Custom {
             fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<Self> {
                 Ok(Custom(
-                        parcel.read()?,
-                        parcel.read()?,
-                        parcel.read()?,
-                        parcel.read::<Option<Vec<String>>>()?.unwrap(),
-                        ))
+                    parcel.read()?,
+                    parcel.read()?,
+                    parcel.read()?,
+                    parcel.read::<Option<Vec<String>>>()?.unwrap(),
+                ))
             }
         }
 
@@ -1157,12 +1133,7 @@
 
         assert_eq!(vec, [i64::max_value(), i64::min_value(), 42, -117]);
 
-        let f32s = [
-            std::f32::NAN,
-            std::f32::INFINITY,
-            1.23456789,
-            std::f32::EPSILON,
-        ];
+        let f32s = [std::f32::NAN, std::f32::INFINITY, 1.23456789, std::f32::EPSILON];
 
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
@@ -1178,12 +1149,7 @@
         assert!(vec[0].is_nan());
         assert_eq!(vec[1..], f32s[1..]);
 
-        let f64s = [
-            std::f64::NAN,
-            std::f64::INFINITY,
-            1.234567890123456789,
-            std::f64::EPSILON,
-        ];
+        let f64s = [std::f64::NAN, std::f64::INFINITY, 1.234567890123456789, std::f64::EPSILON];
 
         unsafe {
             assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/parcel/parcelable_holder.rs b/libs/binder/rust/src/parcel/parcelable_holder.rs
index 432da5d..c829d37 100644
--- a/libs/binder/rust/src/parcel/parcelable_holder.rs
+++ b/libs/binder/rust/src/parcel/parcelable_holder.rs
@@ -48,10 +48,7 @@
 #[derive(Debug, Clone)]
 enum ParcelableHolderData {
     Empty,
-    Parcelable {
-        parcelable: Arc<dyn AnyParcelable>,
-        name: String,
-    },
+    Parcelable { parcelable: Arc<dyn AnyParcelable>, name: String },
     Parcel(Parcel),
 }
 
@@ -77,10 +74,7 @@
 impl ParcelableHolder {
     /// Construct a new `ParcelableHolder` with the given stability.
     pub fn new(stability: Stability) -> Self {
-        Self {
-            data: Mutex::new(ParcelableHolderData::Empty),
-            stability,
-        }
+        Self { data: Mutex::new(ParcelableHolderData::Empty), stability }
     }
 
     /// Reset the contents of this `ParcelableHolder`.
@@ -101,10 +95,8 @@
             return Err(StatusCode::BAD_VALUE);
         }
 
-        *self.data.get_mut().unwrap() = ParcelableHolderData::Parcelable {
-            parcelable: p,
-            name: T::get_descriptor().into(),
-        };
+        *self.data.get_mut().unwrap() =
+            ParcelableHolderData::Parcelable { parcelable: p, name: T::get_descriptor().into() };
 
         Ok(())
     }
@@ -130,10 +122,7 @@
         let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => Ok(None),
-            ParcelableHolderData::Parcelable {
-                ref parcelable,
-                ref name,
-            } => {
+            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
                 if name != parcelable_desc {
                     return Err(StatusCode::BAD_VALUE);
                 }
@@ -199,10 +188,7 @@
         let mut data = self.data.lock().unwrap();
         match *data {
             ParcelableHolderData::Empty => parcel.write(&0i32),
-            ParcelableHolderData::Parcelable {
-                ref parcelable,
-                ref name,
-            } => {
+            ParcelableHolderData::Parcelable { ref parcelable, ref name } => {
                 let length_start = parcel.get_data_position();
                 parcel.write(&0i32)?;
 
@@ -251,9 +237,7 @@
         // 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 data_end = data_start.checked_add(data_size).ok_or(StatusCode::BAD_VALUE)?;
 
         let mut new_parcel = Parcel::new();
         new_parcel.append_from(parcel, data_start, data_size)?;
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 4df557b..862fc2a 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -22,7 +22,8 @@
 };
 use crate::error::{status_result, Result, StatusCode};
 use crate::parcel::{
-    Parcel, BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Serialize, SerializeArray, SerializeOption,
+    BorrowedParcel, Deserialize, DeserializeArray, DeserializeOption, Parcel, Serialize,
+    SerializeArray, SerializeOption,
 };
 use crate::sys;
 
@@ -431,10 +432,7 @@
 
 impl Deserialize for SpIBinder {
     fn deserialize(parcel: &BorrowedParcel<'_>) -> Result<SpIBinder> {
-        parcel
-            .read_binder()
-            .transpose()
-            .unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
+        parcel.read_binder().transpose().unwrap_or(Err(StatusCode::UNEXPECTED_NULL))
     }
 }
 
@@ -563,6 +561,9 @@
 /// The cookie in this struct represents an Arc<F> for the owned callback.
 /// This struct owns a ref-count of it, and so does every binder that we
 /// have been linked with.
+///
+/// Dropping the `DeathRecipient` will `unlink_to_death` any binders it is
+/// currently linked to.
 #[repr(C)]
 pub struct DeathRecipient {
     recipient: *mut sys::AIBinder_DeathRecipient,
@@ -610,7 +611,10 @@
             //
             // All uses of linkToDeath in this file correctly increment the
             // ref-count that this onUnlinked callback will decrement.
-            sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+            sys::AIBinder_DeathRecipient_setOnUnlinked(
+                recipient,
+                Some(Self::cookie_decr_refcount::<F>),
+            );
         }
         DeathRecipient {
             recipient,
diff --git a/libs/binder/rust/src/state.rs b/libs/binder/rust/src/state.rs
index 0aef744..cc18741 100644
--- a/libs/binder/rust/src/state.rs
+++ b/libs/binder/rust/src/state.rs
@@ -124,7 +124,8 @@
     /// kernel is too old to support this feature.
     pub fn with_calling_sid<T, F>(check_permission: F) -> T
     where
-        for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T {
+        for<'a> F: FnOnce(Option<&'a std::ffi::CStr>) -> T,
+    {
         // Safety: AIBinder_getCallingSid returns a c-string pointer
         // that is valid for a transaction. Also, the string returned
         // is thread local. By restricting the lifetime of the CStr
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index c9d6af0..4e10fa9 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -60,9 +60,7 @@
         if let Some(extension_name) = extension_name {
             let extension =
                 BnTest::new_binder(TestService::new(&extension_name), BinderFeatures::default());
-            service
-                .set_extension(&mut extension.as_binder())
-                .expect("Could not add extension");
+            service.set_extension(&mut extension.as_binder()).expect("Could not add extension");
         }
         binder::add_service(&service_name, service.as_binder())
             .expect("Could not register service");
@@ -73,10 +71,7 @@
 }
 
 fn print_usage() {
-    eprintln!(
-        "Usage: {} SERVICE_NAME [EXTENSION_NAME]",
-        RUST_SERVICE_BINARY
-    );
+    eprintln!("Usage: {} SERVICE_NAME [EXTENSION_NAME]", RUST_SERVICE_BINARY);
     eprintln!(concat!(
         "Spawn a Binder test service identified by SERVICE_NAME,",
         " optionally with an extesion named EXTENSION_NAME",
@@ -90,10 +85,7 @@
 
 impl TestService {
     fn new(s: &str) -> Self {
-        Self {
-            s: s.to_string(),
-            dump_args: Mutex::new(Vec::new()),
-        }
+        Self { s: s.to_string(), dump_args: Mutex::new(Vec::new()) }
     }
 }
 
@@ -111,11 +103,15 @@
     fn try_from(c: u32) -> Result<Self, Self::Error> {
         match c {
             _ if c == TestTransactionCode::Test as u32 => Ok(TestTransactionCode::Test),
-            _ if c == TestTransactionCode::GetDumpArgs as u32 => Ok(TestTransactionCode::GetDumpArgs),
+            _ if c == TestTransactionCode::GetDumpArgs as u32 => {
+                Ok(TestTransactionCode::GetDumpArgs)
+            }
             _ if c == TestTransactionCode::GetSelinuxContext as u32 => {
                 Ok(TestTransactionCode::GetSelinuxContext)
             }
-            _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => Ok(TestTransactionCode::GetIsHandlingTransaction),
+            _ if c == TestTransactionCode::GetIsHandlingTransaction as u32 => {
+                Ok(TestTransactionCode::GetIsHandlingTransaction)
+            }
             _ => Err(StatusCode::UNKNOWN_TRANSACTION),
         }
     }
@@ -200,15 +196,16 @@
         TestTransactionCode::Test => reply.write(&service.test()?),
         TestTransactionCode::GetDumpArgs => reply.write(&service.get_dump_args()?),
         TestTransactionCode::GetSelinuxContext => reply.write(&service.get_selinux_context()?),
-        TestTransactionCode::GetIsHandlingTransaction => reply.write(&service.get_is_handling_transaction()?),
+        TestTransactionCode::GetIsHandlingTransaction => {
+            reply.write(&service.get_is_handling_transaction()?)
+        }
     }
 }
 
 impl ITest for BpTest {
     fn test(&self) -> Result<String, StatusCode> {
         let reply =
-            self.binder
-                .transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
+            self.binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(()))?;
         reply.read()
     }
 
@@ -243,31 +240,45 @@
         let binder = self.binder.clone();
         P::spawn(
             move || binder.transact(TestTransactionCode::Test as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_dump_args(&self) -> binder::BoxFuture<'static, Result<Vec<String>, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(TestTransactionCode::GetDumpArgs as TransactionCode, 0, |_| Ok(()))
+            },
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_selinux_context(&self) -> binder::BoxFuture<'static, Result<String, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetSelinuxContext as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(
+                    TestTransactionCode::GetSelinuxContext as TransactionCode,
+                    0,
+                    |_| Ok(()),
+                )
+            },
+            |reply| async move { reply?.read() },
         )
     }
 
     fn get_is_handling_transaction(&self) -> binder::BoxFuture<'static, Result<bool, StatusCode>> {
         let binder = self.binder.clone();
         P::spawn(
-            move || binder.transact(TestTransactionCode::GetIsHandlingTransaction as TransactionCode, 0, |_| Ok(())),
-            |reply| async move { reply?.read() }
+            move || {
+                binder.transact(
+                    TestTransactionCode::GetIsHandlingTransaction as TransactionCode,
+                    0,
+                    |_| Ok(()),
+                )
+            },
+            |reply| async move { reply?.read() },
         )
     }
 }
@@ -374,7 +385,7 @@
 
     use binder_tokio::Tokio;
 
-    use super::{BnTest, ITest, IATest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
+    use super::{BnTest, IATest, ITest, ITestSameDescriptor, TestService, RUST_SERVICE_BINARY};
 
     pub struct ScopedServiceProcess(Child);
 
@@ -405,9 +416,7 @@
     impl Drop for ScopedServiceProcess {
         fn drop(&mut self) {
             self.0.kill().expect("Could not kill child process");
-            self.0
-                .wait()
-                .expect("Could not wait for child process to die");
+            self.0.wait().expect("Could not wait for child process to die");
         }
     }
 
@@ -428,10 +437,7 @@
         );
 
         // The service manager service isn't an ITest, so this must fail.
-        assert_eq!(
-            binder::get_interface::<dyn ITest>("manager").err(),
-            Some(StatusCode::BAD_TYPE)
-        );
+        assert_eq!(binder::get_interface::<dyn ITest>("manager").err(), Some(StatusCode::BAD_TYPE));
         assert_eq!(
             binder::get_interface::<dyn IATest<Tokio>>("manager").err(),
             Some(StatusCode::BAD_TYPE)
@@ -450,7 +456,9 @@
             Some(StatusCode::NAME_NOT_FOUND)
         );
         assert_eq!(
-            binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist").await.err(),
+            binder_tokio::get_interface::<dyn IATest<Tokio>>("this_service_does_not_exist")
+                .await
+                .err(),
             Some(StatusCode::NAME_NOT_FOUND)
         );
 
@@ -511,8 +519,9 @@
     async fn trivial_client_async() {
         let service_name = "trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(test_client.test().await.unwrap(), "trivial_client_test");
     }
 
@@ -529,8 +538,9 @@
     async fn wait_for_trivial_client_async() {
         let service_name = "wait_for_trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::wait_for_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::wait_for_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(test_client.test().await.unwrap(), "wait_for_trivial_client_test");
     }
 
@@ -539,9 +549,7 @@
             let mut out_ptr = ptr::null_mut();
             assert_eq!(selinux_sys::getcon(&mut out_ptr), 0);
             assert!(!out_ptr.is_null());
-            CStr::from_ptr(out_ptr)
-                .to_str()
-                .expect("context was invalid UTF-8")
+            CStr::from_ptr(out_ptr).to_str().expect("context was invalid UTF-8")
         }
     }
 
@@ -551,18 +559,16 @@
         let _process = ScopedServiceProcess::new(service_name);
         let test_client: Strong<dyn ITest> =
             binder::get_interface(service_name).expect("Did not get manager binder service");
-        assert_eq!(
-            test_client.get_selinux_context().unwrap(),
-            get_expected_selinux_context()
-        );
+        assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
     }
 
     #[tokio::test]
     async fn get_selinux_context_async() {
         let service_name = "get_selinux_context_async";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         assert_eq!(
             test_client.get_selinux_context().await.unwrap(),
             get_expected_selinux_context()
@@ -586,13 +592,11 @@
     async fn get_selinux_context_async_to_sync() {
         let service_name = "get_selinux_context";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         let test_client = test_client.into_sync();
-        assert_eq!(
-            test_client.get_selinux_context().unwrap(),
-            get_expected_selinux_context()
-        );
+        assert_eq!(test_client.get_selinux_context().unwrap(), get_expected_selinux_context());
     }
 
     struct Bools {
@@ -605,10 +609,7 @@
             self.binder_died.load(Ordering::Relaxed)
         }
         fn assert_died(&self) {
-            assert!(
-                self.is_dead(),
-                "Did not receive death notification"
-            );
+            assert!(self.is_dead(), "Did not receive death notification");
         }
         fn assert_dropped(&self) {
             assert!(
@@ -639,9 +640,7 @@
 
         let mut death_recipient = {
             let flag = binder_died.clone();
-            let set_on_drop = SetOnDrop {
-                binder_dealloc: binder_dealloc.clone(),
-            };
+            let set_on_drop = SetOnDrop { binder_dealloc: binder_dealloc.clone() };
             DeathRecipient::new(move || {
                 flag.store(true, Ordering::Relaxed);
                 // Force the closure to take ownership of set_on_drop. When the closure is
@@ -650,14 +649,9 @@
             })
         };
 
-        binder
-            .link_to_death(&mut death_recipient)
-            .expect("link_to_death failed");
+        binder.link_to_death(&mut death_recipient).expect("link_to_death failed");
 
-        let bools = Bools {
-            binder_died,
-            binder_dealloc,
-        };
+        let bools = Bools { binder_died, binder_dealloc };
 
         (bools, death_recipient)
     }
@@ -675,9 +669,7 @@
         let (bools, recipient) = register_death_notification(&mut remote);
 
         drop(service_process);
-        remote
-            .ping_binder()
-            .expect_err("Service should have died already");
+        remote.ping_binder().expect_err("Service should have died already");
 
         // Pause to ensure any death notifications get delivered
         thread::sleep(Duration::from_secs(1));
@@ -701,22 +693,15 @@
 
         let (bools, mut recipient) = register_death_notification(&mut remote);
 
-        remote
-            .unlink_to_death(&mut recipient)
-            .expect("Could not unlink death notifications");
+        remote.unlink_to_death(&mut recipient).expect("Could not unlink death notifications");
 
         drop(service_process);
-        remote
-            .ping_binder()
-            .expect_err("Service should have died already");
+        remote.ping_binder().expect_err("Service should have died already");
 
         // Pause to ensure any death notifications get delivered
         thread::sleep(Duration::from_secs(1));
 
-        assert!(
-            !bools.is_dead(),
-            "Received unexpected death notification after unlinking",
-        );
+        assert!(!bools.is_dead(), "Received unexpected death notification after unlinking",);
 
         bools.assert_not_dropped();
         drop(recipient);
@@ -771,9 +756,7 @@
             let dump_args = ["dump", "args", "for", "testing"];
 
             let null_out = File::open("/dev/null").expect("Could not open /dev/null");
-            remote
-                .dump(&null_out, &dump_args)
-                .expect("Could not dump remote service");
+            remote.dump(&null_out, &dump_args).expect("Could not dump remote service");
 
             let remote_args = test_client.get_dump_args().expect("Could not fetched dumped args");
             assert_eq!(dump_args, remote_args[..], "Remote args don't match call to dump");
@@ -799,9 +782,7 @@
             let mut remote = binder::get_service(service_name);
             assert!(remote.is_binder_alive());
 
-            let extension = remote
-                .get_extension()
-                .expect("Could not check for an extension");
+            let extension = remote.get_extension().expect("Could not check for an extension");
             assert!(extension.is_none());
         }
 
@@ -811,9 +792,7 @@
             let mut remote = binder::get_service(service_name);
             assert!(remote.is_binder_alive());
 
-            let maybe_extension = remote
-                .get_extension()
-                .expect("Could not check for an extension");
+            let maybe_extension = remote.get_extension().expect("Could not check for an extension");
 
             let extension = maybe_extension.expect("Remote binder did not have an extension");
 
@@ -850,15 +829,12 @@
     #[test]
     fn reassociate_rust_binder() {
         let service_name = "testing_service";
-        let service_ibinder = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        )
-        .as_binder();
+        let service_ibinder =
+            BnTest::new_binder(TestService::new(service_name), BinderFeatures::default())
+                .as_binder();
 
-        let service: Strong<dyn ITest> = service_ibinder
-            .into_interface()
-            .expect("Could not reassociate the generic ibinder");
+        let service: Strong<dyn ITest> =
+            service_ibinder.into_interface().expect("Could not reassociate the generic ibinder");
 
         assert_eq!(service.test().unwrap(), service_name);
     }
@@ -866,10 +842,7 @@
     #[test]
     fn weak_binder_upgrade() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        );
+        let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
         let weak = Strong::downgrade(&service);
 
@@ -882,10 +855,8 @@
     fn weak_binder_upgrade_dead() {
         let service_name = "testing_service";
         let weak = {
-            let service = BnTest::new_binder(
-                TestService::new(service_name),
-                BinderFeatures::default(),
-            );
+            let service =
+                BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
             Strong::downgrade(&service)
         };
@@ -896,10 +867,7 @@
     #[test]
     fn weak_binder_clone() {
         let service_name = "testing_service";
-        let service = BnTest::new_binder(
-            TestService::new(service_name),
-            BinderFeatures::default(),
-        );
+        let service = BnTest::new_binder(TestService::new(service_name), BinderFeatures::default());
 
         let weak = Strong::downgrade(&service);
         let cloned = weak.clone();
@@ -915,14 +883,10 @@
     #[test]
     #[allow(clippy::eq_op)]
     fn binder_ord() {
-        let service1 = BnTest::new_binder(
-            TestService::new("testing_service1"),
-            BinderFeatures::default(),
-        );
-        let service2 = BnTest::new_binder(
-            TestService::new("testing_service2"),
-            BinderFeatures::default(),
-        );
+        let service1 =
+            BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+        let service2 =
+            BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
 
         assert!((service1 >= service1));
         assert!((service1 <= service1));
@@ -931,20 +895,20 @@
 
     #[test]
     fn binder_parcel_mixup() {
-        let service1 = BnTest::new_binder(
-            TestService::new("testing_service1"),
-            BinderFeatures::default(),
-        );
-        let service2 = BnTest::new_binder(
-            TestService::new("testing_service2"),
-            BinderFeatures::default(),
-        );
+        let service1 =
+            BnTest::new_binder(TestService::new("testing_service1"), BinderFeatures::default());
+        let service2 =
+            BnTest::new_binder(TestService::new("testing_service2"), BinderFeatures::default());
 
         let service1 = service1.as_binder();
         let service2 = service2.as_binder();
 
         let parcel = service1.prepare_transact().unwrap();
-        let res = service2.submit_transact(super::TestTransactionCode::Test as TransactionCode, parcel, 0);
+        let res = service2.submit_transact(
+            super::TestTransactionCode::Test as TransactionCode,
+            parcel,
+            0,
+        );
 
         match res {
             Ok(_) => panic!("submit_transact should fail"),
@@ -967,15 +931,18 @@
         // Should also be false in spawned thread.
         std::thread::spawn(|| {
             assert!(!binder::is_handling_transaction());
-        }).join().unwrap();
+        })
+        .join()
+        .unwrap();
     }
 
     #[tokio::test]
     async fn get_is_handling_transaction_async() {
         let service_name = "get_is_handling_transaction_async";
         let _process = ScopedServiceProcess::new(service_name);
-        let test_client: Strong<dyn IATest<Tokio>> =
-            binder_tokio::get_interface(service_name).await.expect("Did not get manager binder service");
+        let test_client: Strong<dyn IATest<Tokio>> = binder_tokio::get_interface(service_name)
+            .await
+            .expect("Did not get manager binder service");
         // Should be true externally.
         assert!(test_client.get_is_handling_transaction().await.unwrap());
 
@@ -985,11 +952,15 @@
         // Should also be false in spawned task.
         tokio::spawn(async {
             assert!(!binder::is_handling_transaction());
-        }).await.unwrap();
+        })
+        .await
+        .unwrap();
 
         // And in spawn_blocking task.
         tokio::task::spawn_blocking(|| {
             assert!(!binder::is_handling_transaction());
-        }).await.unwrap();
+        })
+        .await
+        .unwrap();
     }
 }
diff --git a/libs/binder/rust/tests/serialization.rs b/libs/binder/rust/tests/serialization.rs
index f6bdf5c..6220db4 100644
--- a/libs/binder/rust/tests/serialization.rs
+++ b/libs/binder/rust/tests/serialization.rs
@@ -23,7 +23,7 @@
 };
 // Import from impl API for testing only, should not be necessary as long as you
 // are using AIDL.
-use binder::binder_impl::{BorrowedParcel, Binder, TransactionCode};
+use binder::binder_impl::{Binder, BorrowedParcel, TransactionCode};
 
 use std::ffi::{c_void, CStr, CString};
 use std::sync::Once;
@@ -64,13 +64,7 @@
 macro_rules! assert {
     ($expr:expr) => {
         if !$expr {
-            eprintln!(
-                "assertion failed: `{:?}`, {}:{}:{}",
-                $expr,
-                file!(),
-                line!(),
-                column!()
-            );
+            eprintln!("assertion failed: `{:?}`, {}:{}:{}", $expr, file!(), line!(), column!());
             return Err(StatusCode::FAILED_TRANSACTION);
         }
     };
@@ -119,9 +113,7 @@
         bindings::Transaction_TEST_BOOL => {
             assert!(parcel.read::<bool>()?);
             assert!(!parcel.read::<bool>()?);
-            assert_eq!(parcel.read::<Vec<bool>>()?, unsafe {
-                bindings::TESTDATA_BOOL
-            });
+            assert_eq!(parcel.read::<Vec<bool>>()?, unsafe { bindings::TESTDATA_BOOL });
             assert_eq!(parcel.read::<Option<Vec<bool>>>()?, None);
 
             reply.write(&true)?;
@@ -148,9 +140,7 @@
             assert_eq!(parcel.read::<u16>()?, 0);
             assert_eq!(parcel.read::<u16>()?, 1);
             assert_eq!(parcel.read::<u16>()?, u16::max_value());
-            assert_eq!(parcel.read::<Vec<u16>>()?, unsafe {
-                bindings::TESTDATA_CHARS
-            });
+            assert_eq!(parcel.read::<Vec<u16>>()?, unsafe { bindings::TESTDATA_CHARS });
             assert_eq!(parcel.read::<Option<Vec<u16>>>()?, None);
 
             reply.write(&0u16)?;
@@ -163,9 +153,7 @@
             assert_eq!(parcel.read::<i32>()?, 0);
             assert_eq!(parcel.read::<i32>()?, 1);
             assert_eq!(parcel.read::<i32>()?, i32::max_value());
-            assert_eq!(parcel.read::<Vec<i32>>()?, unsafe {
-                bindings::TESTDATA_I32
-            });
+            assert_eq!(parcel.read::<Vec<i32>>()?, unsafe { bindings::TESTDATA_I32 });
             assert_eq!(parcel.read::<Option<Vec<i32>>>()?, None);
 
             reply.write(&0i32)?;
@@ -178,9 +166,7 @@
             assert_eq!(parcel.read::<i64>()?, 0);
             assert_eq!(parcel.read::<i64>()?, 1);
             assert_eq!(parcel.read::<i64>()?, i64::max_value());
-            assert_eq!(parcel.read::<Vec<i64>>()?, unsafe {
-                bindings::TESTDATA_I64
-            });
+            assert_eq!(parcel.read::<Vec<i64>>()?, unsafe { bindings::TESTDATA_I64 });
             assert_eq!(parcel.read::<Option<Vec<i64>>>()?, None);
 
             reply.write(&0i64)?;
@@ -193,9 +179,7 @@
             assert_eq!(parcel.read::<u64>()?, 0);
             assert_eq!(parcel.read::<u64>()?, 1);
             assert_eq!(parcel.read::<u64>()?, u64::max_value());
-            assert_eq!(parcel.read::<Vec<u64>>()?, unsafe {
-                bindings::TESTDATA_U64
-            });
+            assert_eq!(parcel.read::<Vec<u64>>()?, unsafe { bindings::TESTDATA_U64 });
             assert_eq!(parcel.read::<Option<Vec<u64>>>()?, None);
 
             reply.write(&0u64)?;
@@ -232,16 +216,9 @@
             let s: Option<String> = parcel.read()?;
             assert_eq!(s, None);
             let s: Option<Vec<Option<String>>> = parcel.read()?;
-            for (s, expected) in s
-                .unwrap()
-                .iter()
-                .zip(unsafe { bindings::TESTDATA_STRS }.iter())
-            {
-                let expected = unsafe {
-                    expected
-                        .as_ref()
-                        .and_then(|e| CStr::from_ptr(e).to_str().ok())
-                };
+            for (s, expected) in s.unwrap().iter().zip(unsafe { bindings::TESTDATA_STRS }.iter()) {
+                let expected =
+                    unsafe { expected.as_ref().and_then(|e| CStr::from_ptr(e).to_str().ok()) };
                 assert_eq!(s.as_deref(), expected);
             }
             let s: Option<Vec<Option<String>>> = parcel.read()?;
@@ -252,10 +229,7 @@
                     .iter()
                     .map(|s| {
                         s.as_ref().map(|s| {
-                            CStr::from_ptr(s)
-                                .to_str()
-                                .expect("String was not UTF-8")
-                                .to_owned()
+                            CStr::from_ptr(s).to_str().expect("String was not UTF-8").to_owned()
                         })
                     })
                     .collect()
@@ -284,12 +258,8 @@
             assert!(ibinders[1].is_none());
             assert!(parcel.read::<Option<Vec<Option<SpIBinder>>>>()?.is_none());
 
-            let service = unsafe {
-                SERVICE
-                    .as_ref()
-                    .expect("Global binder service not initialized")
-                    .clone()
-            };
+            let service =
+                unsafe { SERVICE.as_ref().expect("Global binder service not initialized").clone() };
             reply.write(&service)?;
             reply.write(&(None as Option<&SpIBinder>))?;
             reply.write(&[Some(&service), None][..])?;
@@ -300,10 +270,7 @@
             assert!(status.is_ok());
             let status: Status = parcel.read()?;
             assert_eq!(status.exception_code(), ExceptionCode::NULL_POINTER);
-            assert_eq!(
-                status.get_description(),
-                "Status(-4, EX_NULL_POINTER): 'a status message'"
-            );
+            assert_eq!(status.get_description(), "Status(-4, EX_NULL_POINTER): 'a status message'");
             let status: Status = parcel.read()?;
             assert_eq!(status.service_specific_error(), 42);
             assert_eq!(
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 2f96d0e..d7c6d49 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -141,6 +141,7 @@
     unstable: true,
     srcs: [
         "BinderRpcTestClientInfo.aidl",
+        "BinderRpcTestServerConfig.aidl",
         "BinderRpcTestServerInfo.aidl",
         "IBinderRpcCallback.aidl",
         "IBinderRpcSession.aidl",
@@ -167,7 +168,6 @@
         "libbinder_tls_shared_deps",
     ],
     shared_libs: [
-        "libbinder",
         "libbase",
         "liblog",
     ],
@@ -185,25 +185,72 @@
     ],
 }
 
-cc_test {
-    name: "binderRpcTest",
+cc_defaults {
+    name: "binderRpcTest_common_defaults",
     host_supported: true,
     target: {
         darwin: {
             enabled: false,
         },
+    },
+    defaults: [
+        "binder_test_defaults",
+    ],
+
+    static_libs: [
+        "libbinder_tls_static",
+        "libbinder_tls_test_utils",
+        "binderRpcTestIface-cpp",
+        "binderRpcTestIface-ndk",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_service_defaults",
+    defaults: [
+        "binderRpcTest_common_defaults",
+    ],
+    gtest: false,
+    auto_gen_config: false,
+    srcs: [
+        "binderRpcTestCommon.cpp",
+        "binderRpcTestService.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_defaults",
+    target: {
         android: {
             test_suites: ["vts"],
         },
     },
     defaults: [
-        "binder_test_defaults",
-        "libbinder_tls_shared_deps",
+        "binderRpcTest_common_defaults",
     ],
 
     srcs: [
         "binderRpcTest.cpp",
+        "binderRpcTestCommon.cpp",
     ],
+
+    test_suites: ["general-tests"],
+    require_root: true,
+
+    data_bins: [
+        "binder_rpc_test_service",
+        "binder_rpc_test_service_no_kernel",
+        "binder_rpc_test_service_single_threaded",
+        "binder_rpc_test_service_single_threaded_no_kernel",
+    ],
+}
+
+cc_defaults {
+    name: "binderRpcTest_shared_defaults",
+    cflags: [
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+
     shared_libs: [
         "libbinder",
         "libbinder_ndk",
@@ -212,14 +259,128 @@
         "libcutils",
         "liblog",
     ],
-    static_libs: [
-        "libbinder_tls_static",
-        "libbinder_tls_test_utils",
-        "binderRpcTestIface-cpp",
-        "binderRpcTestIface-ndk",
+}
+
+cc_defaults {
+    name: "binderRpcTest_static_defaults",
+
+    shared_libs: [
+        "libutils",
+        // libcrypto_static is not visible to this module
+        "libcrypto",
     ],
-    test_suites: ["general-tests"],
-    require_root: true,
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libssl",
+    ],
+
+    cflags: [
+        // Disable tests that require shared libraries,
+        // e.g., libbinder.so or libbinder_ndk.so
+        "-DBINDER_TEST_NO_SHARED_LIBS",
+    ],
+}
+
+cc_test {
+    // The module name cannot start with "binderRpcTest" because
+    // then atest tries to execute it as part of binderRpcTest
+    name: "binder_rpc_test_service",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_shared_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_no_kernel",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    static_libs: [
+        "libbinder_rpc_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_single_threaded",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded",
+    ],
+}
+
+cc_test {
+    name: "binder_rpc_test_service_single_threaded_no_kernel",
+    defaults: [
+        "binderRpcTest_service_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTest",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_shared_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestNoKernel",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    static_libs: [
+        "libbinder_rpc_no_kernel",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestSingleThreaded",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+        "-DBINDER_WITH_KERNEL_IPC",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded",
+    ],
+}
+
+cc_test {
+    name: "binderRpcTestSingleThreadedNoKernel",
+    defaults: [
+        "binderRpcTest_defaults",
+        "binderRpcTest_static_defaults",
+    ],
+    cflags: [
+        "-DBINDER_RPC_SINGLE_THREADED",
+    ],
+    static_libs: [
+        "libbinder_rpc_single_threaded_no_kernel",
+    ],
 }
 
 cc_test {
diff --git a/libs/binder/tests/BinderRpcTestServerConfig.aidl b/libs/binder/tests/BinderRpcTestServerConfig.aidl
new file mode 100644
index 0000000..34d74be
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerConfig.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcelable BinderRpcTestServerConfig {
+    int numThreads;
+    int[] serverSupportedFileDescriptorTransportModes;
+    int socketType;
+    int rpcSecurity;
+    int serverVersion;
+    int vsockPort;
+    @utf8InCpp String addr;
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4ed3309..e72f39c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1310,7 +1310,7 @@
      * not exceed 16 (15 Max + pool thread).
      */
     std::vector<std::thread> ts;
-    for (size_t i = 0; i < kKernelThreads - 1; i++) {
+    for (size_t i = 0; i < kKernelThreads; i++) {
         ts.push_back(std::thread([&] {
             Parcel local_reply;
             EXPECT_THAT(server->transact(BINDER_LIB_TEST_LOCK_UNLOCK, data, &local_reply),
@@ -1318,7 +1318,7 @@
         }));
     }
 
-    data.writeInt32(1);
+    data.writeInt32(100);
     // Give a chance for all threads to be used
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_UNLOCK_AFTER_MS, data, &reply), NO_ERROR);
 
@@ -1329,8 +1329,7 @@
     EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_MAX_THREAD_COUNT, data, &reply),
                 StatusEq(NO_ERROR));
     replyi = reply.readInt32();
-    // No more than 16 threads should exist.
-    EXPECT_TRUE(replyi == kKernelThreads || replyi == kKernelThreads + 1);
+    EXPECT_EQ(replyi, kKernelThreads + 1);
 }
 
 size_t epochMillis() {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3766278..501a604 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,30 +14,7 @@
  * limitations under the License.
  */
 
-#include <BinderRpcTestClientInfo.h>
-#include <BinderRpcTestServerInfo.h>
-#include <BnBinderRpcCallback.h>
-#include <BnBinderRpcSession.h>
-#include <BnBinderRpcTest.h>
-#include <aidl/IBinderRpcTest.h>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
-#include <android/binder_auto_utils.h>
-#include <android/binder_libbinder.h>
-#include <binder/Binder.h>
-#include <binder/BpBinder.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
-#include <binder/RpcTlsTestUtils.h>
-#include <binder/RpcTlsUtils.h>
-#include <binder/RpcTransport.h>
-#include <binder/RpcTransportRaw.h>
-#include <binder/RpcTransportTls.h>
 #include <gtest/gtest.h>
 
 #include <chrono>
@@ -46,16 +23,12 @@
 #include <thread>
 #include <type_traits>
 
+#include <dlfcn.h>
 #include <poll.h>
 #include <sys/prctl.h>
 #include <sys/socket.h>
-#include <unistd.h>
 
-#include "../FdTrigger.h"
-#include "../RpcSocketAddress.h" // for testing preconnected clients
-#include "../RpcState.h"         // for debugging
-#include "../vm_sockets.h"       // for VMADDR_*
-#include "utils/Errors.h"
+#include "binderRpcTestCommon.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -65,56 +38,20 @@
 
 namespace android {
 
+#ifdef BINDER_TEST_NO_SHARED_LIBS
+constexpr bool kEnableSharedLibs = false;
+#else
+constexpr bool kEnableSharedLibs = true;
+#endif
+
 static_assert(RPC_WIRE_PROTOCOL_VERSION + 1 == RPC_WIRE_PROTOCOL_VERSION_NEXT ||
               RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
-const char* kLocalInetAddress = "127.0.0.1";
-
-enum class RpcSecurity { RAW, TLS };
-
-static inline std::vector<RpcSecurity> RpcSecurityValues() {
-    return {RpcSecurity::RAW, RpcSecurity::TLS};
-}
-
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
-        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
-        std::unique_ptr<RpcAuth> auth = nullptr) {
-    switch (rpcSecurity) {
-        case RpcSecurity::RAW:
-            return RpcTransportCtxFactoryRaw::make();
-        case RpcSecurity::TLS: {
-            if (verifier == nullptr) {
-                verifier = std::make_shared<RpcCertificateVerifierSimple>();
-            }
-            if (auth == nullptr) {
-                auth = std::make_unique<RpcAuthSelfSigned>();
-            }
-            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
-        }
-        default:
-            LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
-    }
-}
-
-// Create an FD that returns `contents` when read.
-static base::unique_fd mockFileDescriptor(std::string contents) {
-    android::base::unique_fd readFd, writeFd;
-    CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
-    std::thread([writeFd = std::move(writeFd), contents = std::move(contents)]() {
-        signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write
-        if (!WriteStringToFd(contents, writeFd)) {
-            int savedErrno = errno;
-            EXPECT_EQ(EPIPE, savedErrno)
-                    << "mockFileDescriptor write failed: " << strerror(savedErrno);
-        }
-    }).detach();
-    return readFd;
-}
 
 TEST(BinderRpcParcel, EntireParcelFormatted) {
     Parcel p;
     p.writeInt32(3);
 
-    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
+    EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "format must be set before data is written");
 }
 
 class BinderRpcServerOnly : public ::testing::TestWithParam<std::tuple<RpcSecurity, uint32_t>> {
@@ -159,213 +96,6 @@
         EXPECT_TRUE(stat.isOk()) << stat; \
     } while (false)
 
-class MyBinderRpcSession : public BnBinderRpcSession {
-public:
-    static std::atomic<int32_t> gNum;
-
-    MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
-    Status getName(std::string* name) override {
-        *name = mName;
-        return Status::ok();
-    }
-    ~MyBinderRpcSession() { gNum--; }
-
-private:
-    std::string mName;
-};
-std::atomic<int32_t> MyBinderRpcSession::gNum;
-
-class MyBinderRpcCallback : public BnBinderRpcCallback {
-    Status sendCallback(const std::string& value) {
-        std::unique_lock _l(mMutex);
-        mValues.push_back(value);
-        _l.unlock();
-        mCv.notify_one();
-        return Status::ok();
-    }
-    Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
-
-public:
-    std::mutex mMutex;
-    std::condition_variable mCv;
-    std::vector<std::string> mValues;
-};
-
-class MyBinderRpcTest : public BnBinderRpcTest {
-public:
-    wp<RpcServer> server;
-    int port = 0;
-
-    Status sendString(const std::string& str) override {
-        (void)str;
-        return Status::ok();
-    }
-    Status doubleString(const std::string& str, std::string* strstr) override {
-        *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) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        out->clear();
-        for (auto session : spServer->listSessions()) {
-            size_t count = session->state()->countBinders();
-            out->push_back(count);
-        }
-        return Status::ok();
-    }
-    Status getNullBinder(sp<IBinder>* out) override {
-        out->clear();
-        return Status::ok();
-    }
-    Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
-        if (binder == nullptr) {
-            std::cout << "Received null binder!" << std::endl;
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        *out = binder->pingBinder();
-        return Status::ok();
-    }
-    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
-        *out = binder;
-        return Status::ok();
-    }
-    static sp<IBinder> mHeldBinder;
-    Status holdBinder(const sp<IBinder>& binder) override {
-        mHeldBinder = binder;
-        return Status::ok();
-    }
-    Status getHeldBinder(sp<IBinder>* held) override {
-        *held = mHeldBinder;
-        return Status::ok();
-    }
-    Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
-        if (count <= 0) return Status::ok();
-        return binder->nestMe(this, count - 1);
-    }
-    Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
-        static sp<IBinder> binder = new BBinder;
-        *out = binder;
-        return Status::ok();
-    }
-    Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
-        *out = new MyBinderRpcSession(name);
-        return Status::ok();
-    }
-    Status getNumOpenSessions(int32_t* out) override {
-        *out = MyBinderRpcSession::gNum;
-        return Status::ok();
-    }
-
-    std::mutex blockMutex;
-    Status lock() override {
-        blockMutex.lock();
-        return Status::ok();
-    }
-    Status unlockInMsAsync(int32_t ms) override {
-        usleep(ms * 1000);
-        blockMutex.unlock();
-        return Status::ok();
-    }
-    Status lockUnlock() override {
-        std::lock_guard<std::mutex> _l(blockMutex);
-        return Status::ok();
-    }
-
-    Status sleepMs(int32_t ms) override {
-        usleep(ms * 1000);
-        return Status::ok();
-    }
-
-    Status sleepMsAsync(int32_t ms) override {
-        // In-process binder calls are asynchronous, but the call to this method
-        // is synchronous wrt its client. This in/out-process threading model
-        // diffentiation is a classic binder leaky abstraction (for better or
-        // worse) and is preserved here the way binder sockets plugs itself
-        // into BpBinder, as nothing is changed at the higher levels
-        // (IInterface) which result in this behavior.
-        return sleepMs(ms);
-    }
-
-    Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
-                      const std::string& value) override {
-        if (callback == nullptr) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-
-        if (delayed) {
-            std::thread([=]() {
-                ALOGE("Executing delayed callback: '%s'", value.c_str());
-                Status status = doCallback(callback, oneway, false, value);
-                ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
-            }).detach();
-            return Status::ok();
-        }
-
-        if (oneway) {
-            return callback->sendOnewayCallback(value);
-        }
-
-        return callback->sendCallback(value);
-    }
-
-    Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
-                           const std::string& value) override {
-        return doCallback(callback, oneway, delayed, value);
-    }
-
-    Status die(bool cleanup) override {
-        if (cleanup) {
-            exit(1);
-        } else {
-            _exit(1);
-        }
-    }
-
-    Status scheduleShutdown() override {
-        sp<RpcServer> strongServer = server.promote();
-        if (strongServer == nullptr) {
-            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
-        }
-        std::thread([=] {
-            LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
-        }).detach();
-        return Status::ok();
-    }
-
-    Status useKernelBinderCallingId() override {
-        // this is WRONG! It does not make sense when using RPC binder, and
-        // because it is SO wrong, and so much code calls this, it should abort!
-
-        (void)IPCThreadState::self()->getCallingPid();
-        return Status::ok();
-    }
-
-    Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
-        out->reset(mockFileDescriptor(content));
-        return Status::ok();
-    }
-
-    Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
-                       android::os::ParcelFileDescriptor* out) override {
-        std::string acc;
-        for (const auto& file : files) {
-            std::string result;
-            CHECK(android::base::ReadFdToString(file.get(), &result));
-            acc.append(result);
-        }
-        out->reset(mockFileDescriptor(acc));
-        return Status::ok();
-    }
-};
-sp<IBinder> MyBinderRpcTest::mHeldBinder;
-
 static std::string WaitStatusToString(int wstatus) {
     if (WIFEXITED(wstatus)) {
         return base::StringPrintf("exit status %d", WEXITSTATUS(wstatus));
@@ -383,8 +113,8 @@
                                      android::base::borrowed_fd /* readEnd */)>& f) {
         android::base::unique_fd childWriteEnd;
         android::base::unique_fd childReadEnd;
-        CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
-        CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
+        CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd, 0)) << strerror(errno);
+        CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd, 0)) << strerror(errno);
         if (0 == (mPid = fork())) {
             // racey: assume parent doesn't crash before this is set
             prctl(PR_SET_PDEATHSIG, SIGHUP);
@@ -432,7 +162,7 @@
 };
 
 static unsigned int allocateVsockPort() {
-    static unsigned int vsockPort = 3456;
+    static unsigned int vsockPort = 34567;
     return vsockPort++;
 }
 
@@ -509,28 +239,6 @@
     }
 };
 
-enum class SocketType {
-    PRECONNECTED,
-    UNIX,
-    VSOCK,
-    INET,
-};
-static inline std::string PrintToString(SocketType socketType) {
-    switch (socketType) {
-        case SocketType::PRECONNECTED:
-            return "preconnected_uds";
-        case SocketType::UNIX:
-            return "unix_domain_socket";
-        case SocketType::VSOCK:
-            return "vm_socket";
-        case SocketType::INET:
-            return "inet_socket";
-        default:
-            LOG_ALWAYS_FATAL("Unknown socket type");
-            return "";
-    }
-}
-
 static base::unique_fd connectTo(const RpcSocketAddress& addr) {
     base::unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
@@ -546,29 +254,18 @@
     return serverFd;
 }
 
-class BinderRpc
-      : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t>> {
+using RunServiceFn = void (*)(android::base::borrowed_fd writeEnd,
+                              android::base::borrowed_fd readEnd);
+
+class BinderRpc : public ::testing::TestWithParam<
+                          std::tuple<SocketType, RpcSecurity, uint32_t, uint32_t, bool, bool>> {
 public:
-    struct Options {
-        size_t numThreads = 1;
-        size_t numSessions = 1;
-        size_t numIncomingConnections = 0;
-        size_t numOutgoingConnections = SIZE_MAX;
-        RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
-                RpcSession::FileDescriptorTransportMode::NONE;
-        std::vector<RpcSession::FileDescriptorTransportMode>
-                serverSupportedFileDescriptorTransportModes = {
-                        RpcSession::FileDescriptorTransportMode::NONE};
-
-        // If true, connection failures will result in `ProcessSession::sessions` being empty
-        // instead of a fatal error.
-        bool allowConnectFailure = false;
-    };
-
     SocketType socketType() const { return std::get<0>(GetParam()); }
     RpcSecurity rpcSecurity() const { return std::get<1>(GetParam()); }
     uint32_t clientVersion() const { return std::get<2>(GetParam()); }
     uint32_t serverVersion() const { return std::get<3>(GetParam()); }
+    bool singleThreaded() const { return std::get<4>(GetParam()); }
+    bool noKernel() const { return std::get<5>(GetParam()); }
 
     // Whether the test params support sending FDs in parcels.
     bool supportsFdTransport() const {
@@ -577,111 +274,59 @@
     }
 
     static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [type, security, clientVersion, serverVersion] = info.param;
-        return PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
+        auto [type, security, clientVersion, serverVersion, singleThreaded, noKernel] = info.param;
+        auto ret = PrintToString(type) + "_" + newFactory(security)->toCString() + "_clientV" +
                 std::to_string(clientVersion) + "_serverV" + std::to_string(serverVersion);
-    }
-
-    static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
-        uint64_t length = str.length();
-        CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
-        CHECK(android::base::WriteFully(fd, str.data(), str.length()));
-    }
-
-    static inline std::string readString(android::base::borrowed_fd fd) {
-        uint64_t length;
-        CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
-        std::string ret(length, '\0');
-        CHECK(android::base::ReadFully(fd, ret.data(), length));
+        if (singleThreaded) {
+            ret += "_single_threaded";
+        }
+        if (noKernel) {
+            ret += "_no_kernel";
+        }
         return ret;
     }
 
-    static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
-        Parcel parcel;
-        CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
-        writeString(fd,
-                    std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
-    }
-
-    template <typename T>
-    static inline T readFromFd(android::base::borrowed_fd fd) {
-        std::string data = readString(fd);
-        Parcel parcel;
-        CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
-        T object;
-        CHECK_EQ(OK, object.readFromParcel(&parcel));
-        return object;
-    }
-
     // This creates a new process serving an interface on a certain number of
     // threads.
-    ProcessSession createRpcTestSocketServerProcess(
-            const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
+    ProcessSession createRpcTestSocketServerProcessEtc(const BinderRpcOptions& options) {
         CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
 
         SocketType socketType = std::get<0>(GetParam());
         RpcSecurity rpcSecurity = std::get<1>(GetParam());
         uint32_t clientVersion = std::get<2>(GetParam());
         uint32_t serverVersion = std::get<3>(GetParam());
+        bool singleThreaded = std::get<4>(GetParam());
+        bool noKernel = std::get<5>(GetParam());
 
-        unsigned int vsockPort = allocateVsockPort();
-        std::string addr = allocateSocketAddress();
+        std::string path = android::base::GetExecutableDirectory();
+        auto servicePath =
+                android::base::StringPrintf("%s/binder_rpc_test_service%s%s", path.c_str(),
+                                            singleThreaded ? "_single_threaded" : "",
+                                            noKernel ? "_no_kernel" : "");
 
         auto ret = ProcessSession{
                 .host = Process([=](android::base::borrowed_fd writeEnd,
                                     android::base::borrowed_fd readEnd) {
-                    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
-                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
-
-                    server->setProtocolVersion(serverVersion);
-                    server->setMaxThreads(options.numThreads);
-                    server->setSupportedFileDescriptorTransportModes(
-                            options.serverSupportedFileDescriptorTransportModes);
-
-                    unsigned int outPort = 0;
-
-                    switch (socketType) {
-                        case SocketType::PRECONNECTED:
-                            [[fallthrough]];
-                        case SocketType::UNIX:
-                            CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
-                            break;
-                        case SocketType::VSOCK:
-                            CHECK_EQ(OK, server->setupVsockServer(vsockPort));
-                            break;
-                        case SocketType::INET: {
-                            CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
-                            CHECK_NE(0, outPort);
-                            break;
-                        }
-                        default:
-                            LOG_ALWAYS_FATAL("Unknown socket type");
-                    }
-
-                    BinderRpcTestServerInfo serverInfo;
-                    serverInfo.port = static_cast<int64_t>(outPort);
-                    serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
-                    writeToFd(writeEnd, serverInfo);
-                    auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
-
-                    if (rpcSecurity == RpcSecurity::TLS) {
-                        for (const auto& clientCert : clientInfo.certs) {
-                            CHECK_EQ(OK,
-                                     certVerifier
-                                             ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
-                                                                         clientCert.data));
-                        }
-                    }
-
-                    configure(server);
-
-                    server->join();
-
-                    // Another thread calls shutdown. Wait for it to complete.
-                    (void)server->shutdown();
+                    auto writeFd = std::to_string(writeEnd.get());
+                    auto readFd = std::to_string(readEnd.get());
+                    execl(servicePath.c_str(), servicePath.c_str(), writeFd.c_str(), readFd.c_str(),
+                          NULL);
                 }),
         };
 
+        BinderRpcTestServerConfig serverConfig;
+        serverConfig.numThreads = options.numThreads;
+        serverConfig.socketType = static_cast<int32_t>(socketType);
+        serverConfig.rpcSecurity = static_cast<int32_t>(rpcSecurity);
+        serverConfig.serverVersion = serverVersion;
+        serverConfig.vsockPort = allocateVsockPort();
+        serverConfig.addr = allocateSocketAddress();
+        for (auto mode : options.serverSupportedFileDescriptorTransportModes) {
+            serverConfig.serverSupportedFileDescriptorTransportModes.push_back(
+                    static_cast<int32_t>(mode));
+        }
+        writeToFd(ret.host.writeEnd(), serverConfig);
+
         std::vector<sp<RpcSession>> sessions;
         auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
         for (size_t i = 0; i < options.numSessions; i++) {
@@ -719,14 +364,14 @@
             switch (socketType) {
                 case SocketType::PRECONNECTED:
                     status = session->setupPreconnectedClient({}, [=]() {
-                        return connectTo(UnixSocketAddress(addr.c_str()));
+                        return connectTo(UnixSocketAddress(serverConfig.addr.c_str()));
                     });
                     break;
                 case SocketType::UNIX:
-                    status = session->setupUnixDomainClient(addr.c_str());
+                    status = session->setupUnixDomainClient(serverConfig.addr.c_str());
                     break;
                 case SocketType::VSOCK:
-                    status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+                    status = session->setupVsockClient(VMADDR_CID_LOCAL, serverConfig.vsockPort);
                     break;
                 case SocketType::INET:
                     status = session->setupInetClient("127.0.0.1", serverInfo.port);
@@ -744,46 +389,9 @@
         return ret;
     }
 
-    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
+    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const BinderRpcOptions& options) {
         BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcess(
-                        options,
-                        [&](const sp<RpcServer>& server) {
-                            server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
-                                // UNIX sockets with abstract addresses return
-                                // sizeof(sa_family_t)==2 in addrlen
-                                CHECK_GE(len, sizeof(sa_family_t));
-                                const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
-                                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;
-                            });
-                        }),
+                .proc = createRpcTestSocketServerProcessEtc(options),
         };
 
         ret.rootBinder = ret.proc.sessions.empty() ? nullptr : ret.proc.sessions.at(0).root;
@@ -796,6 +404,18 @@
                                      size_t sleepMs = 500);
 };
 
+// Test fixture for tests that start multiple threads.
+// This includes tests with one thread but multiple sessions,
+// since a server uses one thread per session.
+class BinderRpcThreads : public BinderRpc {
+public:
+    void SetUp() override {
+        if constexpr (!kEnableRpcThreads) {
+            GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+        }
+    }
+};
+
 TEST_P(BinderRpc, Ping) {
     auto proc = createRpcTestSocketServerProcess({});
     ASSERT_NE(proc.rootBinder, nullptr);
@@ -808,7 +428,7 @@
     EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
 }
 
-TEST_P(BinderRpc, MultipleSessions) {
+TEST_P(BinderRpcThreads, MultipleSessions) {
     auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
     for (auto session : proc.proc.sessions) {
         ASSERT_NE(nullptr, session.root);
@@ -816,7 +436,7 @@
     }
 }
 
-TEST_P(BinderRpc, SeparateRootObject) {
+TEST_P(BinderRpcThreads, SeparateRootObject) {
     SocketType type = std::get<0>(GetParam());
     if (type == SocketType::PRECONNECTED || type == SocketType::UNIX) {
         // we can't get port numbers for unix sockets
@@ -999,7 +619,7 @@
               proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
 }
 
-TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
+TEST_P(BinderRpcThreads, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
     auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
 
     sp<IBinder> outBinder;
@@ -1009,6 +629,11 @@
 }
 
 TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
+    if (!kEnableKernelIpc || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
@@ -1018,6 +643,11 @@
 }
 
 TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
+    if (!kEnableKernelIpc || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     // for historical reasons, IServiceManager interface only returns the
@@ -1145,7 +775,7 @@
     return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
 }
 
-TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
+TEST_P(BinderRpcThreads, ThreadPoolGreaterThanEqualRequested) {
     constexpr size_t kNumThreads = 10;
 
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
@@ -1196,14 +826,14 @@
     EXPECT_LE(epochMsAfter, epochMsBefore + 3 * sleepMs);
 }
 
-TEST_P(BinderRpc, ThreadPoolOverSaturated) {
+TEST_P(BinderRpcThreads, 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) {
+TEST_P(BinderRpcThreads, ThreadPoolLimitOutgoing) {
     constexpr size_t kNumThreads = 20;
     constexpr size_t kNumOutgoingConnections = 10;
     constexpr size_t kNumCalls = kNumOutgoingConnections + 3;
@@ -1212,7 +842,7 @@
     testThreadPoolOverSaturated(proc.rootIface, kNumCalls);
 }
 
-TEST_P(BinderRpc, ThreadingStressTest) {
+TEST_P(BinderRpcThreads, ThreadingStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 100;
@@ -1241,7 +871,7 @@
     for (auto& t : threads) t.join();
 }
 
-TEST_P(BinderRpc, OnewayStressTest) {
+TEST_P(BinderRpcThreads, OnewayStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 1000;
@@ -1276,7 +906,7 @@
     EXPECT_LT(epochMsAfter, epochMsBefore + kReallyLongTimeMs);
 }
 
-TEST_P(BinderRpc, OnewayCallQueueing) {
+TEST_P(BinderRpcThreads, OnewayCallQueueing) {
     constexpr size_t kNumSleeps = 10;
     constexpr size_t kNumExtraServerThreads = 4;
     constexpr size_t kSleepMs = 50;
@@ -1300,12 +930,12 @@
 
     size_t epochMsAfter = epochMillis();
 
-    EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
+    EXPECT_GE(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 
     saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
 }
 
-TEST_P(BinderRpc, OnewayCallExhaustion) {
+TEST_P(BinderRpcThreads, OnewayCallExhaustion) {
     constexpr size_t kNumClients = 2;
     constexpr size_t kTooLongMs = 1000;
 
@@ -1348,11 +978,21 @@
 TEST_P(BinderRpc, Callbacks) {
     const static std::string kTestString = "good afternoon!";
 
+    bool bothSingleThreaded = !kEnableRpcThreads || singleThreaded();
+
     for (bool callIsOneway : {true, false}) {
         for (bool callbackIsOneway : {true, false}) {
             for (bool delayed : {true, false}) {
+                if (bothSingleThreaded && (callIsOneway || callbackIsOneway || delayed)) {
+                    // we have no incoming connections to receive the callback
+                    continue;
+                }
+
+                size_t numIncomingConnections = bothSingleThreaded ? 0 : 1;
                 auto proc = createRpcTestSocketServerProcess(
-                        {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+                        {.numThreads = 1,
+                         .numSessions = 1,
+                         .numIncomingConnections = numIncomingConnections});
                 auto cb = sp<MyBinderRpcCallback>::make();
 
                 if (callIsOneway) {
@@ -1368,7 +1008,7 @@
                 // the callback will be processed on another thread.
                 if (callIsOneway || callbackIsOneway || delayed) {
                     using std::literals::chrono_literals::operator""s;
-                    std::unique_lock<std::mutex> _l(cb->mMutex);
+                    RpcMutexUniqueLock _l(cb->mMutex);
                     cb->mCv.wait_for(_l, 1s, [&] { return !cb->mValues.empty(); });
                 }
 
@@ -1389,19 +1029,131 @@
                 // since this session has an incoming connection w/ a threadpool, we
                 // need to manually shut it down
                 EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
-
-                proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
-                    // Flaky. Sometimes gets SIGABRT.
-                    EXPECT_TRUE((WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) ||
-                                (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGABRT))
-                            << "server process failed: " << WaitStatusToString(wstatus);
-                });
                 proc.expectAlreadyShutdown = true;
             }
         }
     }
 }
 
+TEST_P(BinderRpc, SingleDeathRecipient) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            dead = true;
+            mCv.notify_one();
+        }
+        std::mutex mMtx;
+        std::condition_variable mCv;
+        bool dead = false;
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+
+    if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+        EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+    }
+
+    std::unique_lock<std::mutex> lock(dr->mMtx);
+    if (!dr->dead) {
+        EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+    }
+    EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
+
+    // need to wait for the session to shutdown so we don't "Leak session"
+    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, SingleDeathRecipientOnShutdown) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            dead = true;
+            mCv.notify_one();
+        }
+        std::mutex mMtx;
+        std::condition_variable mCv;
+        bool dead = false;
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    EXPECT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+
+    // Explicitly calling shutDownAndWait will cause the death recipients
+    // to be called.
+    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+
+    std::unique_lock<std::mutex> lock(dr->mMtx);
+    if (!dr->dead) {
+        EXPECT_EQ(std::cv_status::no_timeout, dr->mCv.wait_for(lock, 1000ms));
+    }
+    EXPECT_TRUE(dr->dead) << "Failed to receive the death notification.";
+
+    proc.proc.host.terminate();
+    proc.proc.host.setCustomExitStatusCheck([](int wstatus) {
+        EXPECT_TRUE(WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGTERM)
+                << "server process failed incorrectly: " << WaitStatusToString(wstatus);
+    });
+    proc.expectAlreadyShutdown = true;
+}
+
+TEST_P(BinderRpc, DeathRecipientFatalWithoutIncoming) {
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {}
+    };
+
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 0});
+
+    auto dr = sp<MyDeathRec>::make();
+    EXPECT_DEATH(proc.rootBinder->linkToDeath(dr, (void*)1, 0),
+                 "Cannot register a DeathRecipient without any incoming connections.");
+}
+
+TEST_P(BinderRpc, UnlinkDeathRecipient) {
+    if (singleThreaded() || !kEnableRpcThreads) {
+        GTEST_SKIP() << "This test requires multiple threads";
+    }
+    class MyDeathRec : public IBinder::DeathRecipient {
+    public:
+        void binderDied(const wp<IBinder>& /* who */) override {
+            GTEST_FAIL() << "This should not be called after unlinkToDeath";
+        }
+    };
+
+    // Death recipient needs to have an incoming connection to be called
+    auto proc = createRpcTestSocketServerProcess(
+            {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
+
+    auto dr = sp<MyDeathRec>::make();
+    ASSERT_EQ(OK, proc.rootBinder->linkToDeath(dr, (void*)1, 0));
+    ASSERT_EQ(OK, proc.rootBinder->unlinkToDeath(dr, (void*)1, 0, nullptr));
+
+    if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+        EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+    }
+
+    // need to wait for the session to shutdown so we don't "Leak session"
+    EXPECT_TRUE(proc.proc.sessions.at(0).session->shutdownAndWait(true));
+    proc.expectAlreadyShutdown = true;
+}
+
 TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
     auto proc = createRpcTestSocketServerProcess({});
     auto cb = sp<MyBinderRpcCallback>::make();
@@ -1434,20 +1186,23 @@
 }
 
 TEST_P(BinderRpc, UseKernelBinderCallingId) {
-    bool okToFork = ProcessState::selfOrNull() == nullptr;
+    // This test only works if the current process shared the internal state of
+    // ProcessState with the service across the call to fork(). Both the static
+    // libraries and libbinder.so have their own separate copies of all the
+    // globals, so the test only works when the test client and service both use
+    // libbinder.so (when using static libraries, even a client and service
+    // using the same kind of static library should have separate copies of the
+    // variables).
+    if (!kEnableSharedLibs || singleThreaded() || noKernel()) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
 
     auto proc = createRpcTestSocketServerProcess({});
 
-    // 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());
-    }
+    // 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());
@@ -1597,6 +1352,10 @@
 }
 
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
+    if constexpr (!kEnableSharedLibs) {
+        GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1606,6 +1365,10 @@
 }
 
 TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
+    if constexpr (!kEnableSharedLibs) {
+        GTEST_SKIP() << "Test disabled because Binder was built as a static library";
+    }
+
     auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
@@ -1630,7 +1393,7 @@
     return ret;
 }
 
-TEST_P(BinderRpc, Fds) {
+TEST_P(BinderRpcThreads, Fds) {
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
@@ -1766,7 +1529,18 @@
                         ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
                                            ::testing::ValuesIn(RpcSecurityValues()),
                                            ::testing::ValuesIn(testVersions()),
-                                           ::testing::ValuesIn(testVersions())),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::Values(false, true),
+                                           ::testing::Values(false, true)),
+                        BinderRpc::PrintParamInfo);
+
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpcThreads,
+                        ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+                                           ::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::ValuesIn(testVersions()),
+                                           ::testing::Values(false),
+                                           ::testing::Values(false, true)),
                         BinderRpc::PrintParamInfo);
 
 class BinderRpcServerRootObject
@@ -1821,6 +1595,10 @@
 };
 
 TEST_P(BinderRpcServerOnly, Shutdown) {
+    if constexpr (!kEnableRpcThreads) {
+        GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+    }
+
     auto addr = allocateSocketAddress();
     auto server = RpcServer::make(newFactory(std::get<0>(GetParam())));
     server->setProtocolVersion(std::get<1>(GetParam()));
@@ -1852,6 +1630,11 @@
                     "createRpcDelegateServiceManager() with a device attached, such test belongs "
                     "to binderHostDeviceTest. Hence, just disable this test on host.";
 #endif // !__ANDROID__
+    if constexpr (!kEnableKernelIpc) {
+        GTEST_SKIP() << "Test disabled because Binder kernel driver was disabled "
+                        "at build time.";
+    }
+
     sp<IServiceManager> sm = defaultServiceManager();
     ASSERT_NE(nullptr, sm);
     // Any Java service with non-empty getInterfaceDescriptor() would do.
@@ -2152,6 +1935,11 @@
         (void)serverVersion;
         return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
     }
+    void SetUp() override {
+        if constexpr (!kEnableRpcThreads) {
+            GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+        }
+    }
 };
 
 TEST_P(RpcTransportTest, GoodCertificate) {
@@ -2356,6 +2144,10 @@
 };
 
 TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
+    if constexpr (!kEnableRpcThreads) {
+        GTEST_SKIP() << "Test skipped because threads were disabled at build time";
+    }
+
     auto [socketType, certificateFormat, keyFormat, serverVersion] = GetParam();
 
     std::vector<uint8_t> pkeyData, certData;
diff --git a/libs/binder/tests/binderRpcTestCommon.cpp b/libs/binder/tests/binderRpcTestCommon.cpp
new file mode 100644
index 0000000..0d9aa95
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "binderRpcTestCommon.h"
+
+namespace android {
+
+std::atomic<int32_t> MyBinderRpcSession::gNum;
+sp<IBinder> MyBinderRpcTest::mHeldBinder;
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestCommon.h b/libs/binder/tests/binderRpcTestCommon.h
new file mode 100644
index 0000000..4513d36
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestCommon.h
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerConfig.h>
+#include <BinderRpcTestServerInfo.h>
+#include <BnBinderRpcCallback.h>
+#include <BnBinderRpcSession.h>
+#include <BnBinderRpcTest.h>
+#include <aidl/IBinderRpcTest.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_libbinder.h>
+#include <binder/Binder.h>
+#include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <signal.h>
+
+#include "../BuildFlags.h"
+#include "../FdTrigger.h"
+#include "../RpcSocketAddress.h" // for testing preconnected clients
+#include "../RpcState.h"         // for debugging
+#include "../vm_sockets.h"       // for VMADDR_*
+#include "utils/Errors.h"
+
+namespace android {
+
+constexpr char kLocalInetAddress[] = "127.0.0.1";
+
+enum class RpcSecurity { RAW, TLS };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+    return {RpcSecurity::RAW, RpcSecurity::TLS};
+}
+
+enum class SocketType {
+    PRECONNECTED,
+    UNIX,
+    VSOCK,
+    INET,
+};
+static inline std::string PrintToString(SocketType socketType) {
+    switch (socketType) {
+        case SocketType::PRECONNECTED:
+            return "preconnected_uds";
+        case SocketType::UNIX:
+            return "unix_domain_socket";
+        case SocketType::VSOCK:
+            return "vm_socket";
+        case SocketType::INET:
+            return "inet_socket";
+        default:
+            LOG_ALWAYS_FATAL("Unknown socket type");
+            return "";
+    }
+}
+
+struct BinderRpcOptions {
+    size_t numThreads = 1;
+    size_t numSessions = 1;
+    size_t numIncomingConnections = 0;
+    size_t numOutgoingConnections = SIZE_MAX;
+    RpcSession::FileDescriptorTransportMode clientFileDescriptorTransportMode =
+            RpcSession::FileDescriptorTransportMode::NONE;
+    std::vector<RpcSession::FileDescriptorTransportMode>
+            serverSupportedFileDescriptorTransportModes = {
+                    RpcSession::FileDescriptorTransportMode::NONE};
+
+    // If true, connection failures will result in `ProcessSession::sessions` being empty
+    // instead of a fatal error.
+    bool allowConnectFailure = false;
+};
+
+static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+    uint64_t length = str.length();
+    CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+    CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+}
+
+static inline std::string readString(android::base::borrowed_fd fd) {
+    uint64_t length;
+    CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+    std::string ret(length, '\0');
+    CHECK(android::base::ReadFully(fd, ret.data(), length));
+    return ret;
+}
+
+static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+    Parcel parcel;
+    CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+    writeString(fd, std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+}
+
+template <typename T>
+static inline T readFromFd(android::base::borrowed_fd fd) {
+    std::string data = readString(fd);
+    Parcel parcel;
+    CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+    T object;
+    CHECK_EQ(OK, object.readFromParcel(&parcel));
+    return object;
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+        std::unique_ptr<RpcAuth> auth = nullptr) {
+    switch (rpcSecurity) {
+        case RpcSecurity::RAW:
+            return RpcTransportCtxFactoryRaw::make();
+        case RpcSecurity::TLS: {
+            if (verifier == nullptr) {
+                verifier = std::make_shared<RpcCertificateVerifierSimple>();
+            }
+            if (auth == nullptr) {
+                auth = std::make_unique<RpcAuthSelfSigned>();
+            }
+            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+    }
+}
+
+// Create an FD that returns `contents` when read.
+static inline base::unique_fd mockFileDescriptor(std::string contents) {
+    android::base::unique_fd readFd, writeFd;
+    CHECK(android::base::Pipe(&readFd, &writeFd)) << strerror(errno);
+    RpcMaybeThread([writeFd = std::move(writeFd), contents = std::move(contents)]() {
+        signal(SIGPIPE, SIG_IGN); // ignore possible SIGPIPE from the write
+        if (!WriteStringToFd(contents, writeFd)) {
+            int savedErrno = errno;
+            LOG_ALWAYS_FATAL_IF(EPIPE != savedErrno, "mockFileDescriptor write failed: %s",
+                                strerror(savedErrno));
+        }
+    }).detach();
+    return readFd;
+}
+
+using android::binder::Status;
+
+class MyBinderRpcSession : public BnBinderRpcSession {
+public:
+    static std::atomic<int32_t> gNum;
+
+    MyBinderRpcSession(const std::string& name) : mName(name) { gNum++; }
+    Status getName(std::string* name) override {
+        *name = mName;
+        return Status::ok();
+    }
+    ~MyBinderRpcSession() { gNum--; }
+
+private:
+    std::string mName;
+};
+
+class MyBinderRpcCallback : public BnBinderRpcCallback {
+    Status sendCallback(const std::string& value) {
+        RpcMutexUniqueLock _l(mMutex);
+        mValues.push_back(value);
+        _l.unlock();
+        mCv.notify_one();
+        return Status::ok();
+    }
+    Status sendOnewayCallback(const std::string& value) { return sendCallback(value); }
+
+public:
+    RpcMutex mMutex;
+    RpcConditionVariable mCv;
+    std::vector<std::string> mValues;
+};
+
+class MyBinderRpcTest : public BnBinderRpcTest {
+public:
+    wp<RpcServer> server;
+    int port = 0;
+
+    Status sendString(const std::string& str) override {
+        (void)str;
+        return Status::ok();
+    }
+    Status doubleString(const std::string& str, std::string* strstr) override {
+        *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) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        out->clear();
+        for (auto session : spServer->listSessions()) {
+            size_t count = session->state()->countBinders();
+            out->push_back(count);
+        }
+        return Status::ok();
+    }
+    Status getNullBinder(sp<IBinder>* out) override {
+        out->clear();
+        return Status::ok();
+    }
+    Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
+        if (binder == nullptr) {
+            std::cout << "Received null binder!" << std::endl;
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        *out = binder->pingBinder();
+        return Status::ok();
+    }
+    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+        *out = binder;
+        return Status::ok();
+    }
+    static sp<IBinder> mHeldBinder;
+    Status holdBinder(const sp<IBinder>& binder) override {
+        mHeldBinder = binder;
+        return Status::ok();
+    }
+    Status getHeldBinder(sp<IBinder>* held) override {
+        *held = mHeldBinder;
+        return Status::ok();
+    }
+    Status nestMe(const sp<IBinderRpcTest>& binder, int count) override {
+        if (count <= 0) return Status::ok();
+        return binder->nestMe(this, count - 1);
+    }
+    Status alwaysGiveMeTheSameBinder(sp<IBinder>* out) override {
+        static sp<IBinder> binder = new BBinder;
+        *out = binder;
+        return Status::ok();
+    }
+    Status openSession(const std::string& name, sp<IBinderRpcSession>* out) override {
+        *out = new MyBinderRpcSession(name);
+        return Status::ok();
+    }
+    Status getNumOpenSessions(int32_t* out) override {
+        *out = MyBinderRpcSession::gNum;
+        return Status::ok();
+    }
+
+    RpcMutex blockMutex;
+    Status lock() override {
+        blockMutex.lock();
+        return Status::ok();
+    }
+    Status unlockInMsAsync(int32_t ms) override {
+        usleep(ms * 1000);
+        blockMutex.unlock();
+        return Status::ok();
+    }
+    Status lockUnlock() override {
+        RpcMutexLockGuard _l(blockMutex);
+        return Status::ok();
+    }
+
+    Status sleepMs(int32_t ms) override {
+        usleep(ms * 1000);
+        return Status::ok();
+    }
+
+    Status sleepMsAsync(int32_t ms) override {
+        // In-process binder calls are asynchronous, but the call to this method
+        // is synchronous wrt its client. This in/out-process threading model
+        // diffentiation is a classic binder leaky abstraction (for better or
+        // worse) and is preserved here the way binder sockets plugs itself
+        // into BpBinder, as nothing is changed at the higher levels
+        // (IInterface) which result in this behavior.
+        return sleepMs(ms);
+    }
+
+    Status doCallback(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+                      const std::string& value) override {
+        if (callback == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+
+        if (delayed) {
+            RpcMaybeThread([=]() {
+                ALOGE("Executing delayed callback: '%s'", value.c_str());
+                Status status = doCallback(callback, oneway, false, value);
+                ALOGE("Delayed callback status: '%s'", status.toString8().c_str());
+            }).detach();
+            return Status::ok();
+        }
+
+        if (oneway) {
+            return callback->sendOnewayCallback(value);
+        }
+
+        return callback->sendCallback(value);
+    }
+
+    Status doCallbackAsync(const sp<IBinderRpcCallback>& callback, bool oneway, bool delayed,
+                           const std::string& value) override {
+        return doCallback(callback, oneway, delayed, value);
+    }
+
+    Status die(bool cleanup) override {
+        if (cleanup) {
+            exit(1);
+        } else {
+            _exit(1);
+        }
+    }
+
+    Status scheduleShutdown() override {
+        sp<RpcServer> strongServer = server.promote();
+        if (strongServer == nullptr) {
+            return Status::fromExceptionCode(Status::EX_NULL_POINTER);
+        }
+        RpcMaybeThread([=] {
+            LOG_ALWAYS_FATAL_IF(!strongServer->shutdown(), "Could not shutdown");
+        }).detach();
+        return Status::ok();
+    }
+
+    Status useKernelBinderCallingId() override {
+        // this is WRONG! It does not make sense when using RPC binder, and
+        // because it is SO wrong, and so much code calls this, it should abort!
+
+        if constexpr (kEnableKernelIpc) {
+            (void)IPCThreadState::self()->getCallingPid();
+        }
+        return Status::ok();
+    }
+
+    Status echoAsFile(const std::string& content, android::os::ParcelFileDescriptor* out) override {
+        out->reset(mockFileDescriptor(content));
+        return Status::ok();
+    }
+
+    Status concatFiles(const std::vector<android::os::ParcelFileDescriptor>& files,
+                       android::os::ParcelFileDescriptor* out) override {
+        std::string acc;
+        for (const auto& file : files) {
+            std::string result;
+            CHECK(android::base::ReadFdToString(file.get(), &result));
+            acc.append(result);
+        }
+        out->reset(mockFileDescriptor(acc));
+        return Status::ok();
+    }
+};
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTestService.cpp b/libs/binder/tests/binderRpcTestService.cpp
new file mode 100644
index 0000000..31eb5da
--- /dev/null
+++ b/libs/binder/tests/binderRpcTestService.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "binderRpcTestCommon.h"
+
+using namespace android;
+
+int main(int argc, const char* argv[]) {
+    LOG_ALWAYS_FATAL_IF(argc != 3, "Invalid number of arguments: %d", argc);
+    base::unique_fd writeEnd(atoi(argv[1]));
+    base::unique_fd readEnd(atoi(argv[2]));
+
+    auto serverConfig = readFromFd<BinderRpcTestServerConfig>(readEnd);
+    auto socketType = static_cast<SocketType>(serverConfig.socketType);
+    auto rpcSecurity = static_cast<RpcSecurity>(serverConfig.rpcSecurity);
+
+    std::vector<RpcSession::FileDescriptorTransportMode>
+            serverSupportedFileDescriptorTransportModes;
+    for (auto mode : serverConfig.serverSupportedFileDescriptorTransportModes) {
+        serverSupportedFileDescriptorTransportModes.push_back(
+                static_cast<RpcSession::FileDescriptorTransportMode>(mode));
+    }
+
+    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
+
+    server->setProtocolVersion(serverConfig.serverVersion);
+    server->setMaxThreads(serverConfig.numThreads);
+    server->setSupportedFileDescriptorTransportModes(serverSupportedFileDescriptorTransportModes);
+
+    unsigned int outPort = 0;
+
+    switch (socketType) {
+        case SocketType::PRECONNECTED:
+            [[fallthrough]];
+        case SocketType::UNIX:
+            CHECK_EQ(OK, server->setupUnixDomainServer(serverConfig.addr.c_str()))
+                    << serverConfig.addr;
+            break;
+        case SocketType::VSOCK:
+            CHECK_EQ(OK, server->setupVsockServer(serverConfig.vsockPort));
+            break;
+        case SocketType::INET: {
+            CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
+            CHECK_NE(0, outPort);
+            break;
+        }
+        default:
+            LOG_ALWAYS_FATAL("Unknown socket type");
+    }
+
+    BinderRpcTestServerInfo serverInfo;
+    serverInfo.port = static_cast<int64_t>(outPort);
+    serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+    writeToFd(writeEnd, serverInfo);
+    auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+    if (rpcSecurity == RpcSecurity::TLS) {
+        for (const auto& clientCert : clientInfo.certs) {
+            CHECK_EQ(OK,
+                     certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+                                                             clientCert.data));
+        }
+    }
+
+    server->setPerSessionRootObject([&](const void* addrPtr, size_t len) {
+        // UNIX sockets with abstract addresses return
+        // sizeof(sa_family_t)==2 in addrlen
+        CHECK_GE(len, sizeof(sa_family_t));
+        const sockaddr* addr = reinterpret_cast<const sockaddr*>(addrPtr);
+        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;
+    });
+
+    server->join();
+
+    // Another thread calls shutdown. Wait for it to complete.
+    (void)server->shutdown();
+
+    return 0;
+}
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
index 3b1faa8..cfaf2a9 100644
--- a/libs/binder/tests/binderThroughputTest.cpp
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -249,12 +249,13 @@
     pid_t pid = fork();
     if (pid) {
         /* parent */
-        return move(get<0>(pipe_pair));
+        return std::move(get<0>(pipe_pair));
     } else {
         /* child */
-        worker_fx(num, worker_count, iterations, payload_size, cs_pair, move(get<1>(pipe_pair)));
+        worker_fx(num, worker_count, iterations, payload_size, cs_pair,
+                  std::move(get<1>(pipe_pair)));
         /* never get here */
-        return move(get<0>(pipe_pair));
+        return std::move(get<0>(pipe_pair));
     }
 
 }
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 2ca6ebd..0210237 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -7,6 +7,22 @@
     default_applicable_licenses: ["frameworks_native_license"],
 }
 
+aidl_interface {
+    name: "binderReadParcelIface",
+    host_supported: true,
+    unstable: true,
+    srcs: [
+        "EmptyParcelable.aidl",
+        "SingleDataParcelable.aidl",
+        "GenericDataParcelable.aidl",
+    ],
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
+
 cc_fuzz {
     name: "binder_parcel_fuzzer",
     host_supported: true,
@@ -29,6 +45,8 @@
         "libcutils",
         "libhidlbase",
         "liblog",
+        "binderReadParcelIface-cpp",
+        "binderReadParcelIface-ndk",
     ],
 
     target: {
diff --git a/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
new file mode 100644
index 0000000..96d6223
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/EmptyParcelable.aidl
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcelable EmptyParcelable{
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
new file mode 100644
index 0000000..fc2542b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/GenericDataParcelable.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcelable GenericDataParcelable {
+    int data;
+    float majorVersion;
+    float minorVersion;
+    IBinder binder;
+    ParcelFileDescriptor fileDescriptor;
+    int[] array;
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
new file mode 100644
index 0000000..d62891b
--- /dev/null
+++ b/libs/binder/tests/parcel_fuzzer/SingleDataParcelable.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcelable SingleDataParcelable{
+   int data;
+}
\ No newline at end of file
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 7059d30..9dac2c9 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -16,6 +16,9 @@
 #define FUZZ_LOG_TAG "binder"
 
 #include "binder.h"
+#include "EmptyParcelable.h"
+#include "GenericDataParcelable.h"
+#include "SingleDataParcelable.h"
 #include "util.h"
 
 #include <android-base/hex.h>
@@ -354,6 +357,24 @@
         status_t status = p.compareDataInRange(thisOffset, p, otherOffset, length, &result);
         FUZZ_LOG() << " status: " << status  << " result: " << result;
     },
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for EmptyParcelable";
+        EmptyParcelable emptyParcelable{};
+        status_t status = emptyParcelable.readFromParcel(&p);
+        FUZZ_LOG() << " status: " << status;
+    },
+    [] (const ::android::Parcel& p , FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for SingleDataParcelable";
+        SingleDataParcelable singleDataParcelable;
+        status_t status = singleDataParcelable.readFromParcel(&p);
+        FUZZ_LOG() <<" status: " << status;
+    },
+    [] (const ::android::Parcel& p, FuzzedDataProvider& /*provider*/) {
+        FUZZ_LOG() << "about to call readFromParcel() with status for GenericDataParcelable";
+        GenericDataParcelable genericDataParcelable;
+        status_t status = genericDataParcelable.readFromParcel(&p);
+        FUZZ_LOG() <<" status: " << status;
+    },
 };
 // 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 26d6770..af773a0 100644
--- a/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
@@ -16,6 +16,9 @@
 #define FUZZ_LOG_TAG "binder_ndk"
 
 #include "binder_ndk.h"
+#include "aidl/EmptyParcelable.h"
+#include "aidl/GenericDataParcelable.h"
+#include "aidl/SingleDataParcelable.h"
 
 #include <android/binder_parcel_utils.h>
 #include <android/binder_parcelable_utils.h>
@@ -177,5 +180,24 @@
         PARCEL_READ(std::array<ndk::ScopedFileDescriptor COMMA 3>, ndk::AParcel_readData),
         PARCEL_READ(std::array<std::shared_ptr<ISomeInterface> COMMA 3>, ndk::AParcel_readData),
 #undef COMMA
+
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for EmptyParcelable";
+            aidl::EmptyParcelable emptyParcelable;
+            binder_status_t status = emptyParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for SingleDataParcelable";
+            aidl::SingleDataParcelable singleDataParcelable;
+            binder_status_t status = singleDataParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
+        [](const NdkParcelAdapter& p, FuzzedDataProvider& /*provider*/) {
+            FUZZ_LOG() << "about to read parcel using readFromParcel for GenericDataParcelable";
+            aidl::GenericDataParcelable genericDataParcelable;
+            binder_status_t status = genericDataParcelable.readFromParcel(p.aParcel());
+            FUZZ_LOG() << "status: " << status;
+        },
 };
 // clang-format on
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
index 843b6e3..6ea9708 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
@@ -19,10 +19,14 @@
 #include <android-base/unique_fd.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <vector>
+
 namespace android {
 
 // always valid or aborts
 // get a random FD for use in fuzzing, of a few different specific types
-base::unique_fd getRandomFd(FuzzedDataProvider* provider);
+//
+// may return multiple FDs (e.g. pipe), but will always return at least one
+std::vector<base::unique_fd> getRandomFds(FuzzedDataProvider* provider);
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 459fb12..27587a9 100644
--- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
+++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -33,10 +33,13 @@
 /**
  * Fill parcel data, including some random binder objects and FDs
  *
+ * May insert additional FDs/binders if they own data related to the Parcel (e.g. the other
+ * end of a pipe).
+ *
  * p - the Parcel to fill
  * provider - takes ownership and completely consumes provider
  * writeHeader - optional function to write a specific header once the format of the parcel is
  *     picked (for instance, to write an interface header)
  */
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, const RandomParcelOptions& = {});
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options);
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index d5aa353..32494e3 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -44,7 +44,7 @@
 
         std::vector<uint8_t> subData = provider.ConsumeBytes<uint8_t>(
                 provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
-        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), options);
+        fillRandomParcel(&data, FuzzedDataProvider(subData.data(), subData.size()), &options);
 
         Parcel reply;
         (void)target->transact(code, data, &reply, flags);
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index 180a177..bef4ab6 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -35,17 +35,22 @@
 #include <sys/time.h>
 
 using android::fillRandomParcel;
+using android::RandomParcelOptions;
 using android::sp;
 using android::base::HexString;
 
-void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider,
+                      RandomParcelOptions* options) {
     // TODO: functionality to create random parcels for libhwbinder parcels
+    (void)options;
+
     std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
     p->setData(input.data(), input.size());
 }
-static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider,
+                             RandomParcelOptions* options) {
     // fill underlying parcel using functions to fill random libbinder parcel
-    fillRandomParcel(p->parcel(), std::move(provider));
+    fillRandomParcel(p->parcel(), std::move(provider), options);
 }
 
 template <typename P, typename B>
@@ -55,9 +60,11 @@
 
     FUZZ_LOG() << "backend: " << backend;
 
+    RandomParcelOptions options;
+
     P reply;
     P data;
-    fillRandomParcel(&data, std::move(provider));
+    fillRandomParcel(&data, std::move(provider), &options);
     (void)binder->transact(code, data, &reply, flag);
 }
 
@@ -73,8 +80,10 @@
     std::vector<uint8_t> instructions = provider.ConsumeBytes<uint8_t>(
             provider.ConsumeIntegralInRange<size_t>(0, maxInstructions));
 
+    RandomParcelOptions options;
+
     P p;
-    fillRandomParcel(&p, std::move(provider));
+    fillRandomParcel(&p, std::move(provider), &options);
 
     // since we are only using a byte to index
     CHECK(reads.size() <= 255) << reads.size();
@@ -103,9 +112,12 @@
     std::vector<uint8_t> bytes = provider.ConsumeBytes<uint8_t>(
             provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
 
+    // same options so that FDs and binders could be shared in both Parcels
+    RandomParcelOptions options;
+
     P p0, p1;
-    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()));
-    fillRandomParcel(&p1, std::move(provider));
+    fillRandomParcel(&p0, FuzzedDataProvider(bytes.data(), bytes.size()), &options);
+    fillRandomParcel(&p1, std::move(provider), &options);
 
     FUZZ_LOG() << "backend: " << backend;
     FUZZ_LOG() << "start: " << start << " len: " << len;
diff --git a/libs/binder/tests/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
index ab0b7e3..3fcf104 100644
--- a/libs/binder/tests/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
@@ -23,13 +23,44 @@
 
 namespace android {
 
-base::unique_fd getRandomFd(FuzzedDataProvider* provider) {
-    int fd = provider->PickValueInArray<std::function<int()>>({
-            []() { return ashmem_create_region("binder test region", 1024); },
-            []() { return open("/dev/null", O_RDWR); },
+using base::unique_fd;
+
+std::vector<unique_fd> getRandomFds(FuzzedDataProvider* provider) {
+    std::vector<unique_fd> fds = provider->PickValueInArray<
+            std::function<std::vector<unique_fd>()>>({
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(
+                        ashmem_create_region("binder test region",
+                                             provider->ConsumeIntegralInRange<size_t>(0, 4096))));
+                return ret;
+            },
+            [&]() {
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(open("/dev/null", O_RDWR)));
+                return ret;
+            },
+            [&]() {
+                int pipefds[2];
+
+                int flags = O_CLOEXEC;
+                if (provider->ConsumeBool()) flags |= O_DIRECT;
+                if (provider->ConsumeBool()) flags |= O_NONBLOCK;
+
+                CHECK_EQ(0, pipe2(pipefds, flags));
+
+                if (provider->ConsumeBool()) std::swap(pipefds[0], pipefds[1]);
+
+                std::vector<unique_fd> ret;
+                ret.push_back(unique_fd(pipefds[0]));
+                ret.push_back(unique_fd(pipefds[1]));
+                return ret;
+            },
     })();
-    CHECK(fd >= 0);
-    return base::unique_fd(fd);
+
+    for (const auto& fd : fds) CHECK(fd.ok()) << fd.get();
+
+    return fds;
 }
 
 } // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 0204f5e..51cb768 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -39,23 +39,24 @@
     CHECK(OK == p->write(data.data(), data.size()));
 }
 
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider,
-                      const RandomParcelOptions& options) {
+void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) {
+    CHECK_NE(options, nullptr);
+
     if (provider.ConsumeBool()) {
         auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
 
-        if (options.writeHeader) {
-            options.writeHeader(p, provider);
+        if (options->writeHeader) {
+            options->writeHeader(p, provider);
         }
 
         fillRandomParcelData(p, std::move(provider));
         return;
     }
 
-    if (options.writeHeader) {
-        options.writeHeader(p, provider);
+    if (options->writeHeader) {
+        options->writeHeader(p, provider);
     }
 
     while (provider.remaining_bytes() > 0) {
@@ -69,15 +70,21 @@
                 },
                 // write FD
                 [&]() {
-                    if (options.extraFds.size() > 0 && provider.ConsumeBool()) {
-                        const base::unique_fd& fd = options.extraFds.at(
+                    if (options->extraFds.size() > 0 && provider.ConsumeBool()) {
+                        const base::unique_fd& fd = options->extraFds.at(
                                 provider.ConsumeIntegralInRange<size_t>(0,
-                                                                        options.extraFds.size() -
+                                                                        options->extraFds.size() -
                                                                                 1));
                         CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                     } else {
-                        base::unique_fd fd = getRandomFd(&provider);
-                        CHECK(OK == p->writeFileDescriptor(fd.release(), true /*takeOwnership*/));
+                        std::vector<base::unique_fd> fds = getRandomFds(&provider);
+                        CHECK(OK ==
+                              p->writeFileDescriptor(fds.begin()->release(),
+                                                     true /*takeOwnership*/));
+
+                        options->extraFds.insert(options->extraFds.end(),
+                                                 std::make_move_iterator(fds.begin() + 1),
+                                                 std::make_move_iterator(fds.end()));
                     }
                 },
                 // write binder
@@ -98,10 +105,10 @@
                                 return IInterface::asBinder(defaultServiceManager());
                             },
                             [&]() -> sp<IBinder> {
-                                if (options.extraBinders.size() > 0 && provider.ConsumeBool()) {
-                                    return options.extraBinders.at(
+                                if (options->extraBinders.size() > 0 && provider.ConsumeBool()) {
+                                    return options->extraBinders.at(
                                             provider.ConsumeIntegralInRange<
-                                                    size_t>(0, options.extraBinders.size() - 1));
+                                                    size_t>(0, options->extraBinders.size() - 1));
                                 } else {
                                     return nullptr;
                                 }
diff --git a/libs/binder/tests/schd-dbg.cpp b/libs/binder/tests/schd-dbg.cpp
index 56d958c..0035e4e 100644
--- a/libs/binder/tests/schd-dbg.cpp
+++ b/libs/binder/tests/schd-dbg.cpp
@@ -398,14 +398,13 @@
   pid_t pid = fork();
   if (pid) {
     // parent
-    return move(get<0>(pipe_pair));
+    return std::move(get<0>(pipe_pair));
   } else {
     // child
     thread_dump(is_client(num) ? "client" : "server");
-    worker_fx(num, no_process, iterations, payload_size,
-              move(get<1>(pipe_pair)));
+    worker_fx(num, no_process, iterations, payload_size, std::move(get<1>(pipe_pair)));
     // never get here
-    return move(get<0>(pipe_pair));
+    return std::move(get<0>(pipe_pair));
   }
 }
 
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index e77c55c..910c9dc 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -49,6 +49,7 @@
     });
 
     sp<RpcSession> session = RpcSession::make();
+    session->setMaxIncomingThreads(1);
     status_t status;
     for (size_t tries = 0; tries < 5; tries++) {
         usleep(10000);
diff --git a/libs/binder/trusty/OS.cpp b/libs/binder/trusty/OS.cpp
new file mode 100644
index 0000000..187add4
--- /dev/null
+++ b/libs/binder/trusty/OS.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <openssl/rand.h>
+
+#include "../OS.h"
+
+using android::base::Result;
+
+namespace android {
+
+Result<void> setNonBlocking(android::base::borrowed_fd fd) {
+    // Trusty IPC syscalls are all non-blocking by default.
+    return {};
+}
+
+status_t getRandomBytes(uint8_t* data, size_t size) {
+    int res = RAND_bytes(data, size);
+    return res == 1 ? OK : UNKNOWN_ERROR;
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/README.md b/libs/binder/trusty/README.md
new file mode 100644
index 0000000..1a273aa
--- /dev/null
+++ b/libs/binder/trusty/README.md
@@ -0,0 +1,39 @@
+# Binder for Trusty
+
+This is the Trusty port of the libbinder library.
+To build it, take the following steps:
+
+* Check out copies of the Trusty and AOSP repositories.
+* Apply the patches from the `trusty_binder` topic on both repositories.
+* Build Trusty normally using `build.py`.
+* Run the sample AIDL test for Trusty:
+  ```shell
+  $ ./build-root/.../run --headless --boot-test com.android.trusty.aidl.test
+  ```
+
+To run the Android-Trusty IPC test, do the following:
+
+* Build AOSP for the `qemu_trusty_arm64-userdebug` target:
+  ```shell
+  $ lunch qemu_trusty_arm64-userdebug
+  $ m
+  ```
+* In the Trusty directory, run the emulator with the newly built Android:
+  ```shell
+  $ ./build-root/.../run --android /path/to/aosp
+  ```
+* Using either `adb` or the shell inside the emulator itself, run the Trusty
+  Binder test as root:
+  ```shell
+  # /data/nativetest64/vendor/trusty_binder_test/trusty_binder_test
+  ```
+
+## Running the AIDL compiler
+For now, you will need to run the AIDL compiler manually to generate the C++
+source code for Trusty clients and services. The general syntax is:
+```shell
+$ aidl --lang=cpp -o <output directory> -h <output header directory> <AIDL files...>
+```
+
+The compiler will emit some `.cpp` files in the output directory and their
+corresponding `.h` files in the header directory.
diff --git a/libs/binder/trusty/RpcServerTrusty.cpp b/libs/binder/trusty/RpcServerTrusty.cpp
new file mode 100644
index 0000000..e8b91e7
--- /dev/null
+++ b/libs/binder/trusty/RpcServerTrusty.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcServerTrusty"
+
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcServerTrusty.h>
+#include <binder/RpcThreads.h>
+#include <binder/RpcTransportTipcTrusty.h>
+#include <log/log.h>
+
+#include "../FdTrigger.h"
+#include "../RpcState.h"
+#include "TrustyStatus.h"
+
+using android::base::unexpected;
+
+namespace android {
+
+android::base::expected<sp<RpcServerTrusty>, int> RpcServerTrusty::make(
+        tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl,
+        size_t msgMaxSize, std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+    // Default is without TLS.
+    if (rpcTransportCtxFactory == nullptr)
+        rpcTransportCtxFactory = RpcTransportCtxFactoryTipcTrusty::make();
+    auto ctx = rpcTransportCtxFactory->newServerCtx();
+    if (ctx == nullptr) {
+        return unexpected(ERR_NO_MEMORY);
+    }
+
+    auto srv = sp<RpcServerTrusty>::make(std::move(ctx), std::move(portName), std::move(portAcl),
+                                         msgMaxSize);
+    if (srv == nullptr) {
+        return unexpected(ERR_NO_MEMORY);
+    }
+
+    int rc = tipc_add_service(handleSet, &srv->mTipcPort, 1, 0, &kTipcOps);
+    if (rc != NO_ERROR) {
+        return unexpected(rc);
+    }
+    return srv;
+}
+
+RpcServerTrusty::RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName,
+                                 std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize)
+      : mRpcServer(sp<RpcServer>::make(std::move(ctx))),
+        mPortName(std::move(portName)),
+        mPortAcl(std::move(portAcl)) {
+    mTipcPort.name = mPortName.c_str();
+    mTipcPort.msg_max_size = msgMaxSize;
+    mTipcPort.msg_queue_len = 6; // Three each way
+    mTipcPort.priv = this;
+
+    if (mPortAcl) {
+        // Initialize the array of pointers to uuids.
+        // The pointers in mUuidPtrs should stay valid across moves of
+        // RpcServerTrusty (the addresses of a std::vector's elements
+        // shouldn't change when the vector is moved), but would be invalidated
+        // by a copy which is why we disable the copy constructor and assignment
+        // operator for RpcServerTrusty.
+        auto numUuids = mPortAcl->uuids.size();
+        mUuidPtrs.resize(numUuids);
+        for (size_t i = 0; i < numUuids; i++) {
+            mUuidPtrs[i] = &mPortAcl->uuids[i];
+        }
+
+        // Copy the contents of portAcl into the tipc_port_acl structure that we
+        // pass to tipc_add_service
+        mTipcPortAcl.flags = mPortAcl->flags;
+        mTipcPortAcl.uuid_num = numUuids;
+        mTipcPortAcl.uuids = mUuidPtrs.data();
+        mTipcPortAcl.extra_data = mPortAcl->extraData;
+
+        mTipcPort.acl = &mTipcPortAcl;
+    } else {
+        mTipcPort.acl = nullptr;
+    }
+}
+
+int RpcServerTrusty::handleConnect(const tipc_port* port, handle_t chan, const uuid* peer,
+                                   void** ctx_p) {
+    auto* server = reinterpret_cast<RpcServerTrusty*>(const_cast<void*>(port->priv));
+    server->mRpcServer->mShutdownTrigger = FdTrigger::make();
+    server->mRpcServer->mConnectingThreads[rpc_this_thread::get_id()] = RpcMaybeThread();
+
+    int rc = NO_ERROR;
+    auto joinFn = [&](sp<RpcSession>&& session, RpcSession::PreJoinSetupResult&& result) {
+        if (result.status != OK) {
+            rc = statusToTrusty(result.status);
+            return;
+        }
+
+        /* Save the session for easy access */
+        *ctx_p = session.get();
+    };
+
+    base::unique_fd clientFd(chan);
+    std::array<uint8_t, RpcServer::kRpcAddressSize> addr;
+    constexpr size_t addrLen = sizeof(*peer);
+    memcpy(addr.data(), peer, addrLen);
+    RpcServer::establishConnection(sp(server->mRpcServer), std::move(clientFd), addr, addrLen,
+                                   joinFn);
+
+    return rc;
+}
+
+int RpcServerTrusty::handleMessage(const tipc_port* port, handle_t chan, void* ctx) {
+    auto* session = reinterpret_cast<RpcSession*>(ctx);
+    status_t status = session->state()->drainCommands(session->mConnections.mIncoming[0], session,
+                                                      RpcState::CommandType::ANY);
+    if (status != OK) {
+        LOG_RPC_DETAIL("Binder connection thread closing w/ status %s",
+                       statusToString(status).c_str());
+    }
+
+    return NO_ERROR;
+}
+
+void RpcServerTrusty::handleDisconnect(const tipc_port* port, handle_t chan, void* ctx) {}
+
+void RpcServerTrusty::handleChannelCleanup(void* ctx) {
+    auto* session = reinterpret_cast<RpcSession*>(ctx);
+    auto& connection = session->mConnections.mIncoming.at(0);
+    LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
+                        "bad state: connection object guaranteed to be in list");
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/RpcTransportTipcTrusty.cpp b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
new file mode 100644
index 0000000..e0d80fb
--- /dev/null
+++ b/libs/binder/trusty/RpcTransportTipcTrusty.cpp
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RpcTransportTipcTrusty"
+
+#include <trusty_ipc.h>
+
+#include <binder/RpcSession.h>
+#include <binder/RpcTransportTipcTrusty.h>
+#include <log/log.h>
+
+#include "../FdTrigger.h"
+#include "../RpcState.h"
+#include "TrustyStatus.h"
+
+namespace android {
+
+namespace {
+
+// RpcTransport for Trusty.
+class RpcTransportTipcTrusty : public RpcTransport {
+public:
+    explicit RpcTransportTipcTrusty(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+    ~RpcTransportTipcTrusty() { releaseMessage(); }
+
+    status_t pollRead() override {
+        auto status = ensureMessage(false);
+        if (status != OK) {
+            return status;
+        }
+        return mHaveMessage ? OK : WOULD_BLOCK;
+    }
+
+    status_t interruptableWriteFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            const std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds)
+            override {
+        if (niovs < 0) {
+            return BAD_VALUE;
+        }
+
+        size_t size = 0;
+        for (int i = 0; i < niovs; i++) {
+            size += iovs[i].iov_len;
+        }
+
+        ipc_msg_t msg{
+                .num_iov = static_cast<uint32_t>(niovs),
+                .iov = iovs,
+                .num_handles = 0, // TODO: add ancillaryFds
+                .handles = nullptr,
+        };
+        int rc = send_msg(mSocket.get(), &msg);
+        if (rc == ERR_NOT_ENOUGH_BUFFER) {
+            // Peer is blocked, wait until it unblocks.
+            // TODO: when tipc supports a send-unblocked handler,
+            // save the message here in a queue and retry it asynchronously
+            // when the handler gets called by the library
+            uevent uevt;
+            do {
+                rc = ::wait(mSocket.get(), &uevt, INFINITE_TIME);
+                if (rc < 0) {
+                    return statusFromTrusty(rc);
+                }
+                if (uevt.event & IPC_HANDLE_POLL_HUP) {
+                    return DEAD_OBJECT;
+                }
+            } while (!(uevt.event & IPC_HANDLE_POLL_SEND_UNBLOCKED));
+
+            // Retry the send, it should go through this time because
+            // sending is now unblocked
+            rc = send_msg(mSocket.get(), &msg);
+        }
+        if (rc < 0) {
+            return statusFromTrusty(rc);
+        }
+        LOG_ALWAYS_FATAL_IF(static_cast<size_t>(rc) != size,
+                            "Sent the wrong number of bytes %d!=%zu", rc, size);
+
+        return OK;
+    }
+
+    status_t interruptableReadFully(
+            FdTrigger* fdTrigger, iovec* iovs, int niovs,
+            const std::optional<android::base::function_ref<status_t()>>& altPoll,
+            std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override {
+        if (niovs < 0) {
+            return BAD_VALUE;
+        }
+
+        // If iovs has one or more empty vectors at the end and
+        // we somehow advance past all the preceding vectors and
+        // pass some or all of the empty ones to sendmsg/recvmsg,
+        // the call will return processSize == 0. In that case
+        // we should be returning OK but instead return DEAD_OBJECT.
+        // To avoid this problem, we make sure here that the last
+        // vector at iovs[niovs - 1] has a non-zero length.
+        while (niovs > 0 && iovs[niovs - 1].iov_len == 0) {
+            niovs--;
+        }
+        if (niovs == 0) {
+            // The vectors are all empty, so we have nothing to read.
+            return OK;
+        }
+
+        while (true) {
+            auto status = ensureMessage(true);
+            if (status != OK) {
+                return status;
+            }
+
+            ipc_msg_t msg{
+                    .num_iov = static_cast<uint32_t>(niovs),
+                    .iov = iovs,
+                    .num_handles = 0, // TODO: support ancillaryFds
+                    .handles = nullptr,
+            };
+            int rc = read_msg(mSocket.get(), mMessageInfo.id, mMessageOffset, &msg);
+            if (rc < 0) {
+                return statusFromTrusty(rc);
+            }
+
+            size_t processSize = static_cast<size_t>(rc);
+            mMessageOffset += processSize;
+            LOG_ALWAYS_FATAL_IF(mMessageOffset > mMessageInfo.len,
+                                "Message offset exceeds length %zu/%zu", mMessageOffset,
+                                mMessageInfo.len);
+
+            // Release the message if all of it has been read
+            if (mMessageOffset == mMessageInfo.len) {
+                releaseMessage();
+            }
+
+            while (processSize > 0 && niovs > 0) {
+                auto& iov = iovs[0];
+                if (processSize < iov.iov_len) {
+                    // Advance the base of the current iovec
+                    iov.iov_base = reinterpret_cast<char*>(iov.iov_base) + processSize;
+                    iov.iov_len -= processSize;
+                    break;
+                }
+
+                // The current iovec was fully written
+                processSize -= iov.iov_len;
+                iovs++;
+                niovs--;
+            }
+            if (niovs == 0) {
+                LOG_ALWAYS_FATAL_IF(processSize > 0,
+                                    "Reached the end of iovecs "
+                                    "with %zd bytes remaining",
+                                    processSize);
+                return OK;
+            }
+        }
+    }
+
+private:
+    status_t ensureMessage(bool wait) {
+        int rc;
+        if (mHaveMessage) {
+            LOG_ALWAYS_FATAL_IF(mMessageOffset >= mMessageInfo.len, "No data left in message");
+            return OK;
+        }
+
+        /* TODO: interruptible wait, maybe with a timeout??? */
+        uevent uevt;
+        rc = ::wait(mSocket.get(), &uevt, wait ? INFINITE_TIME : 0);
+        if (rc < 0) {
+            if (rc == ERR_TIMED_OUT && !wait) {
+                // If we timed out with wait==false, then there's no message
+                return OK;
+            }
+            return statusFromTrusty(rc);
+        }
+        if (!(uevt.event & IPC_HANDLE_POLL_MSG)) {
+            /* No message, terminate here and leave mHaveMessage false */
+            return OK;
+        }
+
+        rc = get_msg(mSocket.get(), &mMessageInfo);
+        if (rc < 0) {
+            return statusFromTrusty(rc);
+        }
+
+        mHaveMessage = true;
+        mMessageOffset = 0;
+        return OK;
+    }
+
+    void releaseMessage() {
+        if (mHaveMessage) {
+            put_msg(mSocket.get(), mMessageInfo.id);
+            mHaveMessage = false;
+        }
+    }
+
+    base::unique_fd mSocket;
+
+    bool mHaveMessage = false;
+    ipc_msg_info mMessageInfo;
+    size_t mMessageOffset;
+};
+
+// RpcTransportCtx for Trusty.
+class RpcTransportCtxTipcTrusty : public RpcTransportCtx {
+public:
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
+                                               FdTrigger*) const override {
+        return std::make_unique<RpcTransportTipcTrusty>(std::move(fd));
+    }
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
+};
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newServerCtx() const {
+    return std::make_unique<RpcTransportCtxTipcTrusty>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTipcTrusty::newClientCtx() const {
+    return std::make_unique<RpcTransportCtxTipcTrusty>();
+}
+
+const char* RpcTransportCtxFactoryTipcTrusty::toCString() const {
+    return "trusty";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTipcTrusty::make() {
+    return std::unique_ptr<RpcTransportCtxFactoryTipcTrusty>(
+            new RpcTransportCtxFactoryTipcTrusty());
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/TrustyStatus.cpp b/libs/binder/trusty/TrustyStatus.cpp
new file mode 100644
index 0000000..b1caf61
--- /dev/null
+++ b/libs/binder/trusty/TrustyStatus.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TrustyStatus.h"
+#include "../RpcState.h"
+
+namespace android {
+
+status_t statusFromTrusty(int rc) {
+    LOG_RPC_DETAIL("Trusty error: %d", rc);
+    switch (rc) {
+        case NO_ERROR:
+            return OK;
+        case ERR_NOT_FOUND:
+            return NAME_NOT_FOUND;
+        case ERR_NOT_READY:
+            // We get this error if we try to perform an IPC operation when the
+            // channel is not ready
+            return INVALID_OPERATION;
+        case ERR_NO_MSG:
+            return WOULD_BLOCK;
+        case ERR_NO_MEMORY:
+            return NO_MEMORY;
+        case ERR_INVALID_ARGS:
+            return BAD_VALUE;
+        case ERR_NOT_ENOUGH_BUFFER:
+            return WOULD_BLOCK;
+        case ERR_TIMED_OUT:
+            return TIMED_OUT;
+        case ERR_ALREADY_EXISTS:
+            return ALREADY_EXISTS;
+        case ERR_CHANNEL_CLOSED:
+            return DEAD_OBJECT;
+        case ERR_NOT_ALLOWED:
+            return INVALID_OPERATION;
+        case ERR_NOT_SUPPORTED:
+            return INVALID_OPERATION;
+        case ERR_TOO_BIG:
+            return BAD_INDEX;
+        case ERR_CMD_UNKNOWN:
+            return UNKNOWN_TRANSACTION;
+        case ERR_BAD_STATE:
+            return INVALID_OPERATION;
+        case ERR_BAD_LEN:
+            return NOT_ENOUGH_DATA;
+        case ERR_BAD_HANDLE:
+            return BAD_VALUE;
+        case ERR_ACCESS_DENIED:
+            return PERMISSION_DENIED;
+        default:
+            return UNKNOWN_ERROR;
+    }
+}
+
+int statusToTrusty(status_t status) {
+    switch (status) {
+        case OK:
+            return NO_ERROR;
+        case NO_MEMORY:
+            return ERR_NO_MEMORY;
+        case INVALID_OPERATION:
+        case BAD_VALUE:
+        case BAD_TYPE:
+            return ERR_NOT_VALID;
+        case NAME_NOT_FOUND:
+            return ERR_NOT_FOUND;
+        case PERMISSION_DENIED:
+            return ERR_ACCESS_DENIED;
+        case NO_INIT:
+            return ERR_NOT_CONFIGURED;
+        case ALREADY_EXISTS:
+            return ERR_ALREADY_EXISTS;
+        case DEAD_OBJECT:
+            return ERR_CHANNEL_CLOSED;
+        case BAD_INDEX:
+            return ERR_TOO_BIG;
+        case NOT_ENOUGH_DATA:
+            return ERR_BAD_LEN;
+        case WOULD_BLOCK:
+            return ERR_NO_MSG;
+        case TIMED_OUT:
+            return ERR_TIMED_OUT;
+        case UNKNOWN_TRANSACTION:
+            return ERR_CMD_UNKNOWN;
+        case FDS_NOT_ALLOWED:
+            return ERR_NOT_SUPPORTED;
+        case UNEXPECTED_NULL:
+            return ERR_NOT_VALID;
+        default:
+            return ERR_GENERIC;
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/trusty/TrustyStatus.h b/libs/binder/trusty/TrustyStatus.h
new file mode 100644
index 0000000..fcb43f8
--- /dev/null
+++ b/libs/binder/trusty/TrustyStatus.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <uapi/err.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+status_t statusFromTrusty(int rc);
+int statusToTrusty(status_t status);
+
+} // namespace android
diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h
new file mode 100644
index 0000000..e8fc9f9
--- /dev/null
+++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/expected.h>
+#include <android-base/macros.h>
+#include <android-base/unique_fd.h>
+#include <binder/IBinder.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+#include <map>
+#include <vector>
+
+#include <lib/tipc/tipc_srv.h>
+
+namespace android {
+
+/**
+ * This is the Trusty-specific RPC server code.
+ */
+class RpcServerTrusty final : public virtual RefBase {
+public:
+    // C++ equivalent to tipc_port_acl that uses safe data structures instead of
+    // raw pointers, except for |extraData| which doesn't have a good
+    // equivalent.
+    struct PortAcl {
+        uint32_t flags;
+        std::vector<const uuid> uuids;
+        const void* extraData;
+    };
+
+    /**
+     * Creates an RPC server listening on the given port and adds it to the
+     * Trusty handle set at |handleSet|.
+     *
+     * The caller is responsible for calling tipc_run_event_loop() to start
+     * the TIPC event loop after creating one or more services here.
+     */
+    static android::base::expected<sp<RpcServerTrusty>, int> make(
+            tipc_hset* handleSet, std::string&& portName, std::shared_ptr<const PortAcl>&& portAcl,
+            size_t msgMaxSize,
+            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
+
+    void setProtocolVersion(uint32_t version) { mRpcServer->setProtocolVersion(version); }
+    void setRootObject(const sp<IBinder>& binder) { mRpcServer->setRootObject(binder); }
+    void setRootObjectWeak(const wp<IBinder>& binder) { mRpcServer->setRootObjectWeak(binder); }
+    void setPerSessionRootObject(std::function<sp<IBinder>(const void*, size_t)>&& object) {
+        mRpcServer->setPerSessionRootObject(std::move(object));
+    }
+    sp<IBinder> getRootObject() { return mRpcServer->getRootObject(); }
+
+private:
+    // Both this class and RpcServer have multiple non-copyable fields,
+    // including mPortAcl below which can't be copied because mUuidPtrs
+    // holds pointers into it
+    DISALLOW_COPY_AND_ASSIGN(RpcServerTrusty);
+
+    friend sp<RpcServerTrusty>;
+    explicit RpcServerTrusty(std::unique_ptr<RpcTransportCtx> ctx, std::string&& portName,
+                             std::shared_ptr<const PortAcl>&& portAcl, size_t msgMaxSize);
+
+    static int handleConnect(const tipc_port* port, handle_t chan, const uuid* peer, void** ctx_p);
+    static int handleMessage(const tipc_port* port, handle_t chan, void* ctx);
+    static void handleDisconnect(const tipc_port* port, handle_t chan, void* ctx);
+    static void handleChannelCleanup(void* ctx);
+
+    static constexpr tipc_srv_ops kTipcOps = {
+            .on_connect = &handleConnect,
+            .on_message = &handleMessage,
+            .on_disconnect = &handleDisconnect,
+            .on_channel_cleanup = &handleChannelCleanup,
+    };
+
+    sp<RpcServer> mRpcServer;
+    std::string mPortName;
+    std::shared_ptr<const PortAcl> mPortAcl;
+    std::vector<const uuid*> mUuidPtrs;
+    tipc_port_acl mTipcPortAcl;
+    tipc_port mTipcPort;
+};
+
+} // namespace android
diff --git a/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h
new file mode 100644
index 0000000..8eae8c2
--- /dev/null
+++ b/libs/binder/trusty/include/binder/RpcTransportTipcTrusty.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses plain sockets.
+// Note: don't use directly. You probably want newServerRpcTransportCtx / newClientRpcTransportCtx.
+
+#pragma once
+
+#include <memory>
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS disabled.
+class RpcTransportCtxFactoryTipcTrusty : public RpcTransportCtxFactory {
+public:
+    static std::unique_ptr<RpcTransportCtxFactory> make();
+
+    std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
+    std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
+    const char* toCString() const override;
+
+private:
+    RpcTransportCtxFactoryTipcTrusty() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/trusty/include/log/log.h b/libs/binder/trusty/include/log/log.h
new file mode 100644
index 0000000..bf877a3
--- /dev/null
+++ b/libs/binder/trusty/include/log/log.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define BINDER_LOG_LEVEL_NONE 0
+#define BINDER_LOG_LEVEL_NORMAL 1
+#define BINDER_LOG_LEVEL_VERBOSE 2
+
+#ifndef BINDER_LOG_LEVEL
+#define BINDER_LOG_LEVEL BINDER_LOG_LEVEL_NORMAL
+#endif // BINDER_LOG_LEVEL
+
+#ifndef TLOG_TAG
+#ifdef LOG_TAG
+#define TLOG_TAG "libbinder-" LOG_TAG
+#else // LOG_TAG
+#define TLOG_TAG "libbinder"
+#endif // LOG_TAG
+#endif // TLOG_TAG
+
+#include <stdlib.h>
+#include <trusty_log.h>
+
+static inline void __ignore_va_args__(...) {}
+
+#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+#define ALOGD(fmt, ...) TLOGD(fmt "\n", ##__VA_ARGS__)
+#define ALOGI(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__)
+#define ALOGW(fmt, ...) TLOGW(fmt "\n", ##__VA_ARGS__)
+#define ALOGE(fmt, ...) TLOGE(fmt "\n", ##__VA_ARGS__)
+#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+#define ALOGD(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGI(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGW(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#define ALOGE(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_NORMAL
+
+#if BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+#define IF_ALOGV() if (TLOG_LVL >= TLOG_LVL_INFO)
+#define ALOGV(fmt, ...) TLOGI(fmt "\n", ##__VA_ARGS__)
+#else // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+#define IF_ALOGV() if (false)
+#define ALOGV(fmt, ...)                  \
+    while (0) {                          \
+        __ignore_va_args__(__VA_ARGS__); \
+    }
+#endif // BINDER_LOG_LEVEL >= BINDER_LOG_LEVEL_VERBOSE
+
+#define ALOGI_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGI(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+#define ALOGE_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGE(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+#define ALOGW_IF(cond, ...)                \
+    do {                                   \
+        if (cond) {                        \
+            ALOGW(#cond ": " __VA_ARGS__); \
+        }                                  \
+    } while (0)
+
+#define LOG_ALWAYS_FATAL(fmt, ...)                                \
+    do {                                                          \
+        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \
+        abort();                                                  \
+    } while (0)
+#define LOG_ALWAYS_FATAL_IF(cond, ...)                \
+    do {                                              \
+        if (cond) {                                   \
+            LOG_ALWAYS_FATAL(#cond ": " __VA_ARGS__); \
+        }                                             \
+    } while (0)
+#define LOG_FATAL(fmt, ...)                                       \
+    do {                                                          \
+        TLOGE("libbinder fatal error: " fmt "\n", ##__VA_ARGS__); \
+        abort();                                                  \
+    } while (0)
+#define LOG_FATAL_IF(cond, ...)                \
+    do {                                       \
+        if (cond) {                            \
+            LOG_FATAL(#cond ": " __VA_ARGS__); \
+        }                                      \
+    } while (0)
+
+#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
+
+#define android_errorWriteLog(tag, subTag)                               \
+    do {                                                                 \
+        TLOGE("android_errorWriteLog: tag:%x subTag:%s\n", tag, subTag); \
+    } while (0)
diff --git a/libs/binder/trusty/logging.cpp b/libs/binder/trusty/logging.cpp
new file mode 100644
index 0000000..fd54744
--- /dev/null
+++ b/libs/binder/trusty/logging.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TLOG_TAG "libbinder"
+
+#include "android-base/logging.h"
+
+#include <trusty_log.h>
+#include <iostream>
+#include <string>
+
+#include <android-base/macros.h>
+#include <android-base/strings.h>
+
+namespace android {
+namespace base {
+
+static const char* GetFileBasename(const char* file) {
+    const char* last_slash = strrchr(file, '/');
+    if (last_slash != nullptr) {
+        return last_slash + 1;
+    }
+    return file;
+}
+
+// This splits the message up line by line, by calling log_function with a pointer to the start of
+// each line and the size up to the newline character.  It sends size = -1 for the final line.
+template <typename F, typename... Args>
+static void SplitByLines(const char* msg, const F& log_function, Args&&... args) {
+    const char* newline;
+    while ((newline = strchr(msg, '\n')) != nullptr) {
+        log_function(msg, newline - msg, args...);
+        msg = newline + 1;
+    }
+
+    log_function(msg, -1, args...);
+}
+
+void DefaultAborter(const char* abort_message) {
+    TLOGC("aborting: %s\n", abort_message);
+    abort();
+}
+
+static void TrustyLogLine(const char* msg, int length, android::base::LogSeverity severity,
+                          const char* tag) {
+    switch (severity) {
+        case VERBOSE:
+        case DEBUG:
+            TLOGD("%s: %s\n", tag, msg);
+            break;
+        case INFO:
+            TLOGI("%s: %s\n", tag, msg);
+            break;
+        case WARNING:
+            TLOGW("%s: %s\n", tag, msg);
+            break;
+        case ERROR:
+            TLOGE("%s: %s\n", tag, msg);
+            break;
+        case FATAL_WITHOUT_ABORT:
+        case FATAL:
+            TLOGC("%s: %s\n", tag, msg);
+            break;
+    }
+}
+
+void TrustyLogger(android::base::LogId, android::base::LogSeverity severity, const char* tag,
+                  const char*, unsigned int, const char* full_message) {
+    SplitByLines(full_message, TrustyLogLine, severity, tag);
+}
+
+// This indirection greatly reduces the stack impact of having lots of
+// checks/logging in a function.
+class LogMessageData {
+public:
+    LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                   int error)
+          : file_(GetFileBasename(file)),
+            line_number_(line),
+            severity_(severity),
+            tag_(tag),
+            error_(error) {}
+
+    const char* GetFile() const { return file_; }
+
+    unsigned int GetLineNumber() const { return line_number_; }
+
+    LogSeverity GetSeverity() const { return severity_; }
+
+    const char* GetTag() const { return tag_; }
+
+    int GetError() const { return error_; }
+
+    std::ostream& GetBuffer() { return buffer_; }
+
+    std::string ToString() const { return buffer_.str(); }
+
+private:
+    std::ostringstream buffer_;
+    const char* const file_;
+    const unsigned int line_number_;
+    const LogSeverity severity_;
+    const char* const tag_;
+    const int error_;
+
+    DISALLOW_COPY_AND_ASSIGN(LogMessageData);
+};
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity,
+                       const char* tag, int error)
+      : LogMessage(file, line, severity, tag, error) {}
+
+LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                       int error)
+      : data_(new LogMessageData(file, line, severity, tag, error)) {}
+
+LogMessage::~LogMessage() {
+    // Check severity again. This is duplicate work wrt/ LOG macros, but not LOG_STREAM.
+    if (!WOULD_LOG(data_->GetSeverity())) {
+        return;
+    }
+
+    // Finish constructing the message.
+    if (data_->GetError() != -1) {
+        data_->GetBuffer() << ": " << strerror(data_->GetError());
+    }
+    std::string msg(data_->ToString());
+
+    LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(),
+            msg.c_str());
+
+    // Abort if necessary.
+    if (data_->GetSeverity() == FATAL) {
+        DefaultAborter(msg.c_str());
+    }
+}
+
+std::ostream& LogMessage::stream() {
+    return data_->GetBuffer();
+}
+
+void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
+                         const char* message) {
+    TrustyLogger(DEFAULT, severity, tag ?: "<unknown>", file, line, message);
+}
+
+bool ShouldLog(LogSeverity severity, const char* tag) {
+    // This is controlled by Trusty's log level.
+    return true;
+}
+
+} // namespace base
+} // namespace android
diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk
new file mode 100644
index 0000000..83475f5
--- /dev/null
+++ b/libs/binder/trusty/rules.mk
@@ -0,0 +1,87 @@
+# 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.
+#
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+LIBBINDER_DIR := frameworks/native/libs/binder
+LIBBASE_DIR := system/libbase
+LIBCUTILS_DIR := system/core/libcutils
+LIBUTILS_DIR := system/core/libutils
+FMTLIB_DIR := external/fmtlib
+
+MODULE_SRCS := \
+	$(LOCAL_DIR)/logging.cpp \
+	$(LOCAL_DIR)/OS.cpp \
+	$(LOCAL_DIR)/RpcServerTrusty.cpp \
+	$(LOCAL_DIR)/RpcTransportTipcTrusty.cpp \
+	$(LOCAL_DIR)/TrustyStatus.cpp \
+	$(LOCAL_DIR)/socket.cpp \
+	$(LIBBINDER_DIR)/Binder.cpp \
+	$(LIBBINDER_DIR)/BpBinder.cpp \
+	$(LIBBINDER_DIR)/FdTrigger.cpp \
+	$(LIBBINDER_DIR)/IInterface.cpp \
+	$(LIBBINDER_DIR)/IResultReceiver.cpp \
+	$(LIBBINDER_DIR)/Parcel.cpp \
+	$(LIBBINDER_DIR)/RpcServer.cpp \
+	$(LIBBINDER_DIR)/RpcSession.cpp \
+	$(LIBBINDER_DIR)/RpcState.cpp \
+	$(LIBBINDER_DIR)/Stability.cpp \
+	$(LIBBINDER_DIR)/Status.cpp \
+	$(LIBBINDER_DIR)/Utils.cpp \
+	$(LIBBASE_DIR)/hex.cpp \
+	$(LIBBASE_DIR)/stringprintf.cpp \
+	$(LIBUTILS_DIR)/Errors.cpp \
+	$(LIBUTILS_DIR)/misc.cpp \
+	$(LIBUTILS_DIR)/RefBase.cpp \
+	$(LIBUTILS_DIR)/StrongPointer.cpp \
+	$(LIBUTILS_DIR)/Unicode.cpp \
+
+# TODO: remove the following when libbinder supports std::string
+# instead of String16 and String8 for Status and descriptors
+MODULE_SRCS += \
+	$(LIBUTILS_DIR)/SharedBuffer.cpp \
+	$(LIBUTILS_DIR)/String16.cpp \
+	$(LIBUTILS_DIR)/String8.cpp \
+
+# TODO: disable dump() transactions to get rid of Vector
+MODULE_SRCS += \
+	$(LIBUTILS_DIR)/VectorImpl.cpp \
+
+MODULE_EXPORT_INCLUDES += \
+	$(LOCAL_DIR)/include \
+	$(LIBBINDER_DIR)/include \
+	$(LIBBASE_DIR)/include \
+	$(LIBCUTILS_DIR)/include \
+	$(LIBUTILS_DIR)/include \
+	$(FMTLIB_DIR)/include \
+
+# The android/binder_to_string.h header is shared between libbinder and
+# libbinder_ndk and included by auto-generated AIDL C++ files
+MODULE_EXPORT_INCLUDES += \
+	$(LIBBINDER_DIR)/ndk/include_cpp \
+
+MODULE_EXPORT_COMPILEFLAGS += \
+	-DBINDER_NO_KERNEL_IPC \
+	-DBINDER_RPC_SINGLE_THREADED \
+	-D__ANDROID_VNDK__ \
+
+MODULE_LIBRARY_DEPS += \
+	trusty/user/base/lib/libstdc++-trusty \
+	trusty/user/base/lib/tipc \
+	external/boringssl \
+
+include make/library.mk
diff --git a/libs/binder/trusty/socket.cpp b/libs/binder/trusty/socket.cpp
new file mode 100644
index 0000000..02df8af
--- /dev/null
+++ b/libs/binder/trusty/socket.cpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <log/log.h>
+
+// On some versions of clang, RpcServer.cpp refuses to link without accept4
+__attribute__((weak)) extern "C" int accept4(int, void*, void*, int) {
+    LOG_ALWAYS_FATAL("accept4 called on Trusty");
+    return 0;
+}
+
+// Placeholder for poll used by FdTrigger
+__attribute__((weak)) extern "C" int poll(void*, long, int) {
+    LOG_ALWAYS_FATAL("poll called on Trusty");
+    return 0;
+}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index d169043..706704a 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -131,24 +131,24 @@
     }
 
     gTisTotalMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_total_time_in_state_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_total_time_in_state_map")};
     if (gTisTotalMapFd < 0) return false;
 
-    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+    gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
     if (gTisMapFd < 0) return false;
 
     gConcurrentMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
     if (gConcurrentMapFd < 0) return false;
 
     gUidLastUpdateMapFd =
-            unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_last_update_map")};
+            unique_fd{bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_last_update_map")};
     if (gUidLastUpdateMapFd < 0) return false;
 
-    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_time_in_state_pid_time_in_state_map")};
+    gPidTisMapFd = unique_fd{mapRetrieveRO(BPF_FS_PATH "map_timeInState_pid_time_in_state_map")};
     if (gPidTisMapFd < 0) return false;
 
-    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
     if (trackedPidMapFd < 0) return false;
 
     gInitialized = true;
@@ -156,7 +156,7 @@
 }
 
 static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
-    std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
+    std::string path = StringPrintf(BPF_FS_PATH "prog_timeInState_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
     return retrieveProgram(path.c_str());
 }
@@ -200,7 +200,7 @@
     if (!initGlobals()) return false;
     if (gTracking) return true;
 
-    unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    unique_fd cpuPolicyFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_policy_map"));
     if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
@@ -209,7 +209,7 @@
         }
     }
 
-    unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    unique_fd freqToIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_freq_to_idx_map"));
     if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
@@ -224,23 +224,23 @@
         }
     }
 
-    unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    unique_fd cpuLastUpdateFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_cpu_last_update_map"));
     if (cpuLastUpdateFd < 0) return false;
     std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
     uint32_t zero = 0;
     if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
 
-    unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    unique_fd nrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_nr_active_map"));
     if (nrActiveFd < 0) return false;
     if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
 
-    unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    unique_fd policyNrActiveFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_nr_active_map"));
     if (policyNrActiveFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
     }
 
-    unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    unique_fd policyFreqIdxFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_policy_freq_idx_map"));
     if (policyFreqIdxFd < 0) return false;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         auto freqIdx = getPolicyFreqIdx(i);
@@ -560,10 +560,10 @@
     if (!gInitialized && !initGlobals()) return false;
 
     unique_fd trackedPidHashMapFd(
-            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_hash_map"));
+            mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_hash_map"));
     if (trackedPidHashMapFd < 0) return false;
 
-    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_tracked_map"));
+    unique_fd trackedPidMapFd(mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_tracked_map"));
     if (trackedPidMapFd < 0) return false;
 
     for (uint32_t index = 0; index < MAX_TRACKED_PIDS; index++) {
@@ -590,7 +590,7 @@
     if (!gInitialized && !initGlobals()) return false;
 
     unique_fd taskAggregationMapFd(
-            mapRetrieveWO(BPF_FS_PATH "map_time_in_state_pid_task_aggregation_map"));
+            mapRetrieveWO(BPF_FS_PATH "map_timeInState_pid_task_aggregation_map"));
     if (taskAggregationMapFd < 0) return false;
 
     return writeToMapEntry(taskAggregationMapFd, &pid, &aggregationKey, BPF_ANY) == 0;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 45a6d47..6ccc6ca 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -462,7 +462,7 @@
         ++uid;
     }
     android::base::unique_fd fd{
-        bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+        bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
     ASSERT_GE(fd, 0);
     uint32_t nCpus = get_nprocs_conf();
     uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
@@ -504,7 +504,7 @@
     {
         // Add a map entry for our fake UID by copying a real map entry
         android::base::unique_fd fd{
-                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+                bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_time_in_state_map")};
         ASSERT_GE(fd, 0);
         time_key_t k;
         ASSERT_FALSE(getFirstMapKey(fd, &k));
@@ -515,7 +515,7 @@
         ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
 
         android::base::unique_fd fd2{
-                bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+                bpf_obj_get(BPF_FS_PATH "map_timeInState_uid_concurrent_times_map")};
         k.uid = copiedUid;
         k.bucket = 0;
         std::vector<concurrent_val_t> cvals(get_nprocs_conf());
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 353a91d..0460e79 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1924,6 +1924,7 @@
         mReqHeight = 0;
         mReqUsage = 0;
         mCrop.clear();
+        mDataSpace = Dataspace::UNKNOWN;
         mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
         mTransform = 0;
         mStickyTransform = 0;
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 988132c..da42a96 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,10 +2,10 @@
   global:
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
-    AHardwareBuffer_createFromHandle; # llndk # apex
+    AHardwareBuffer_createFromHandle; # llndk # systemapi
     AHardwareBuffer_describe;
     AHardwareBuffer_getId; # introduced=31
-    AHardwareBuffer_getNativeHandle; # llndk # apex
+    AHardwareBuffer_getNativeHandle; # llndk # systemapi
     AHardwareBuffer_isSupported; # introduced=29
     AHardwareBuffer_lock;
     AHardwareBuffer_lockAndGetInfo; # introduced=29
@@ -23,18 +23,18 @@
     ANativeWindow_getBuffersDataSpace; # introduced=28
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
-    ANativeWindow_getLastDequeueDuration; # apex # introduced=30
-    ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
-    ANativeWindow_getLastQueueDuration; # apex # introduced=30
+    ANativeWindow_getLastDequeueDuration; # systemapi # introduced=30
+    ANativeWindow_getLastDequeueStartTime; # systemapi # introduced=30
+    ANativeWindow_getLastQueueDuration; # systemapi # introduced=30
     ANativeWindow_getWidth;
     ANativeWindow_lock;
     ANativeWindow_query; # llndk
     ANativeWindow_queryf; # llndk
     ANativeWindow_queueBuffer; # llndk
-    ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30
-    ANativeWindow_setPerformInterceptor; # apex # introduced=30
-    ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30
+    ANativeWindow_setCancelBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setDequeueBufferInterceptor; # systemapi # introduced=30
+    ANativeWindow_setPerformInterceptor; # systemapi # introduced=30
+    ANativeWindow_setQueueBufferInterceptor; # systemapi # introduced=30
     ANativeWindow_release;
     ANativeWindow_setAutoPrerotation; # llndk
     ANativeWindow_setAutoRefresh; # llndk
@@ -45,7 +45,7 @@
     ANativeWindow_setBuffersGeometry;
     ANativeWindow_setBuffersTimestamp; # llndk
     ANativeWindow_setBuffersTransform;
-    ANativeWindow_setDequeueTimeout; # apex # introduced=30
+    ANativeWindow_setDequeueTimeout; # systemapi # introduced=30
     ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
     ANativeWindow_setSharedBufferMode; # llndk
diff --git a/libs/sensor/fuzz/bittube_fuzzer/Android.bp b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
new file mode 100644
index 0000000..5d8f401
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/Android.bp
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+cc_fuzz {
+    name: "bittube_fuzzer",
+    srcs: [
+        "bittube_fuzzer.cpp",
+    ],
+    static_libs: [
+    ],
+    shared_libs: [
+        "libsensor",
+        "libbinder",
+        "libcutils",
+        "libutils",
+        "liblog",
+        "libhardware",
+        "libpermission",
+    ],
+    export_shared_lib_headers: [
+        "libbinder",
+        "libpermission",
+        "libhardware",
+    ],
+    header_libs: [
+    ],
+}
diff --git a/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
new file mode 100644
index 0000000..6f10a67
--- /dev/null
+++ b/libs/sensor/fuzz/bittube_fuzzer/bittube_fuzzer.cpp
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *****************************************************************************
+ */
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include <sensor/BitTube.h>
+#include <binder/Parcel.h>
+using namespace android;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    FuzzedDataProvider fdp(data, size);
+    BitTube bittube(size);
+    Parcel parcel[5];
+    bittube.writeToParcel(parcel);
+    sp<BitTube> tube(new BitTube(size));
+    bittube.sendObjects<uint8_t>(tube, data, size);
+    uint8_t recvData[size];
+    for (int i = 0; i < size; i++) recvData[i] = fdp.ConsumeIntegral<uint8_t>();
+    bittube.recvObjects<uint8_t>(tube, recvData, size);
+
+    return 0;
+}
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 120000
index 0000000..ee92d9e
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1 @@
+../../build/soong/scripts/rustfmt.toml
\ No newline at end of file
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index b9b6a19..0411b31 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -98,7 +98,7 @@
     init_rc: ["gpuservice.rc"],
     required: [
         "bpfloader",
-        "gpu_mem.o",
+        "gpuMem.o",
     ],
     srcs: [":gpuservice_binary_sources"],
     shared_libs: [
diff --git a/services/gpuservice/CleanSpec.mk b/services/gpuservice/CleanSpec.mk
index 482fc6d..c51f6aa 100644
--- a/services/gpuservice/CleanSpec.mk
+++ b/services/gpuservice/CleanSpec.mk
@@ -44,9 +44,9 @@
 #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
 #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
 
-# Remove gpu_mem.o
+# Remove gpuMem.o
 $(call add-clean-step, rm -rf $(OUT_DIR)/soong/.intermediates/frameworks/native/services/gpuservice/bpf)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpu_mem.o_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpu_mem.o_gpu_mem.o_intermediates)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpu_mem.o)
-$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpu_mem.o-timestamp)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/FAKE/gpuMem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/ETC/gpuMem.o_gpuMem.o_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/etc/bpf/gpuMem.o)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/fake_packages/gpuMem.o-timestamp)
diff --git a/services/gpuservice/bpfprogs/Android.bp b/services/gpuservice/bpfprogs/Android.bp
index 076affd..680b291 100644
--- a/services/gpuservice/bpfprogs/Android.bp
+++ b/services/gpuservice/bpfprogs/Android.bp
@@ -22,8 +22,8 @@
 }
 
 bpf {
-    name: "gpu_mem.o",
-    srcs: ["gpu_mem.c"],
+    name: "gpuMem.o",
+    srcs: ["gpuMem.c"],
     btf: true,
     cflags: [
         "-Wall",
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpuMem.c
similarity index 100%
rename from services/gpuservice/bpfprogs/gpu_mem.c
rename to services/gpuservice/bpfprogs/gpuMem.c
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index de691e2..7588b54 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -57,9 +57,9 @@
     static constexpr char kGpuMemTotalTracepoint[] = "gpu_mem_total";
     // pinned gpu memory total bpf c program path in bpf sysfs
     static constexpr char kGpuMemTotalProgPath[] =
-            "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
+            "/sys/fs/bpf/prog_gpuMem_tracepoint_gpu_mem_gpu_mem_total";
     // pinned gpu memory total bpf map path in bpf sysfs
-    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+    static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpuMem_gpu_mem_total_map";
     // 30 seconds timeout for trying to attach bpf program to tracepoint
     static constexpr int kGpuWaitTimeout = 30;
 };
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index 36ae179..8dabe4f 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -90,8 +90,8 @@
     EXPECT_EQ(mTestableGpuMem.getGpuMemTraceGroup(), "gpu_mem");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalTracepoint(), "gpu_mem_total");
     EXPECT_EQ(mTestableGpuMem.getGpuMemTotalProgPath(),
-              "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total");
-    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map");
+              "/sys/fs/bpf/prog_gpuMem_tracepoint_gpu_mem_gpu_mem_total");
+    EXPECT_EQ(mTestableGpuMem.getGpuMemTotalMapPath(), "/sys/fs/bpf/map_gpuMem_gpu_mem_total_map");
 }
 
 TEST_F(GpuMemTest, bpfInitializationFailed) {
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 2ac41b1..231f825 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -64,7 +64,11 @@
 CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext)
       : InputMapper(deviceContext) {}
 
-CursorInputMapper::~CursorInputMapper() {}
+CursorInputMapper::~CursorInputMapper() {
+    if (mPointerController != nullptr) {
+        mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE);
+    }
+}
 
 uint32_t CursorInputMapper::getSources() {
     return mSource;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 17bbff8..ffc1d8c 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -395,6 +395,10 @@
     }
 
     if (changes && resetNeeded) {
+        // If device was reset, cancel touch event and update touch spot state.
+        cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime);
+        mCurrentCookedState.clear();
+        updateTouchSpots();
         // Send reset, unless this is the first time the device has been configured,
         // in which case the reader will call reset itself after all mappers are ready.
         NotifyDeviceResetArgs args(getContext()->getNextId(), when, getDeviceId());
@@ -679,6 +683,7 @@
     bool skipViewportUpdate = false;
     if (viewportChanged) {
         bool viewportOrientationChanged = mViewport.orientation != newViewport->orientation;
+        const bool viewportDisplayIdChanged = mViewport.displayId != newViewport->displayId;
         mViewport = *newViewport;
 
         if (mDeviceMode == DeviceMode::DIRECT || mDeviceMode == DeviceMode::POINTER) {
@@ -792,6 +797,8 @@
             mSurfaceTop = 0;
             mSurfaceOrientation = DISPLAY_ORIENTATION_0;
         }
+        // If displayId changed, do not skip viewport update.
+        skipViewportUpdate &= !viewportDisplayIdChanged;
     }
 
     // If moving between pointer modes, need to reset some state.
@@ -1927,6 +1934,10 @@
 }
 
 void TouchInputMapper::abortTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) {
+    if (mCurrentMotionAborted) {
+        // Current motion event was already aborted.
+        return;
+    }
     BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits;
     if (!currentIdBits.isEmpty()) {
         int32_t metaState = getContext()->getGlobalMetaState();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0d5d06a..38e328b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -6251,6 +6251,36 @@
             toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
 }
 
+TEST_F(SingleTouchInputMapperTest,
+       Process_WhenViewportDisplayIdChanged_TouchIsCanceledAndDeviceIsReset) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    prepareDisplay(DISPLAY_ORIENTATION_0);
+    prepareButtons();
+    prepareAxes(POSITION);
+    SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
+    NotifyMotionArgs motionArgs;
+
+    // Down.
+    int32_t x = 100;
+    int32_t y = 200;
+    processDown(mapper, x, y);
+    processSync(mapper);
+
+    // We should receive a down event
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action);
+
+    // Change display id
+    clearViewports();
+    prepareSecondaryDisplay(ViewportType::INTERNAL);
+
+    // We should receive a cancel event
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
+    ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action);
+    // Then receive reset called
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
+}
+
 // --- MultiTouchInputMapperTest ---
 
 class MultiTouchInputMapperTest : public TouchInputMapperTest {
@@ -8072,6 +8102,10 @@
         // window's coordinate space.
         frames[0].rotate(getInverseRotation(orientation));
         ASSERT_EQ(frames, motionArgs.videoFrames);
+
+        // Release finger.
+        processSync(mapper);
+        ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
     }
 }
 
diff --git a/services/powermanager/tests/IThermalManagerTest.cpp b/services/powermanager/tests/IThermalManagerTest.cpp
index b62be5f..7414958 100644
--- a/services/powermanager/tests/IThermalManagerTest.cpp
+++ b/services/powermanager/tests/IThermalManagerTest.cpp
@@ -33,26 +33,38 @@
 using namespace android::os;
 using namespace std::chrono_literals;
 
-class IThermalServiceTest : public testing::Test,
-                            public BnThermalStatusListener{
+class IThermalServiceTestListener : public BnThermalStatusListener {
+    public:
+        virtual binder::Status onStatusChange(int status) override;
+        std::condition_variable mCondition;
+        int mListenerStatus = 0;
+        std::mutex mMutex;
+};
+
+binder::Status IThermalServiceTestListener::onStatusChange(int status) {
+    std::unique_lock<std::mutex> lock(mMutex);
+    mListenerStatus = status;
+    ALOGI("IThermalServiceTestListener::notifyListener %d", mListenerStatus);
+    mCondition.notify_all();
+    return binder::Status::ok();
+}
+
+class IThermalServiceTest : public testing::Test {
     public:
         IThermalServiceTest();
         void setThermalOverride(int level);
-        virtual binder::Status onStatusChange(int status) override;
         int getStatusFromService();
         void SetUp() override;
         void TearDown() override;
     protected:
         sp<IThermalService> mThermalSvc;
-        std::condition_variable mCondition;
-        int mListenerStatus;
         int mServiceStatus;
-        std::mutex mMutex;
+        sp<IThermalServiceTestListener> mCallback;
 };
 
 IThermalServiceTest::IThermalServiceTest()
- : mListenerStatus(0),
-   mServiceStatus(0) {
+ : mServiceStatus(0),
+   mCallback(sp<IThermalServiceTestListener>::make()) {
 }
 
 void IThermalServiceTest::setThermalOverride(int level) {
@@ -60,14 +72,6 @@
     system(cmdStr.c_str());
 }
 
-binder::Status IThermalServiceTest::onStatusChange(int status) {
-    std::unique_lock<std::mutex> lock(mMutex);
-    mListenerStatus = status;
-    ALOGI("IThermalServiceTest::notifyListener %d", mListenerStatus);
-    mCondition.notify_all();
-    return binder::Status::ok();
-}
-
 int IThermalServiceTest::getStatusFromService() {
     int status;
     binder::Status ret = mThermalSvc->getCurrentThermalStatus(&status);
@@ -87,19 +91,19 @@
     mThermalSvc = interface_cast<IThermalService>(binder);
     EXPECT_NE(mThermalSvc, nullptr);
     // Lock mutex for operation, so listener will only be processed after wait_for is called
-    std::unique_lock<std::mutex> lock(mMutex);
+    std::unique_lock<std::mutex> lock(mCallback->mMutex);
     bool success = false;
-    binder::Status ret = mThermalSvc->registerThermalStatusListener(this, &success);
+    binder::Status ret = mThermalSvc->registerThermalStatusListener(mCallback, &success);
     // Check the result
     ASSERT_TRUE(success);
     ASSERT_TRUE(ret.isOk());
     // Wait for listener called after registration, shouldn't timeout
-    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+    EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
 }
 
 void IThermalServiceTest::TearDown() {
     bool success = false;
-    binder::Status ret = mThermalSvc->unregisterThermalStatusListener(this, &success);
+    binder::Status ret = mThermalSvc->unregisterThermalStatusListener(mCallback, &success);
     ASSERT_TRUE(success);
     ASSERT_TRUE(ret.isOk());
 }
@@ -114,14 +118,14 @@
 TEST_P(IThermalListenerTest, TestListener) {
     int level = GetParam();
     // Lock mutex for operation, so listener will only be processed after wait_for is called
-    std::unique_lock<std::mutex> lock(mMutex);
+    std::unique_lock<std::mutex> lock(mCallback->mMutex);
     // Set the override thermal status
     setThermalOverride(level);
     // Wait for listener called, shouldn't timeout
-    EXPECT_NE(mCondition.wait_for(lock, 1s), std::cv_status::timeout);
+    EXPECT_NE(mCallback->mCondition.wait_for(lock, 1s), std::cv_status::timeout);
     // Check the result
-    EXPECT_EQ(level, mListenerStatus);
-    ALOGI("Thermal listener status %d, expecting %d", mListenerStatus, level);
+    EXPECT_EQ(level, mCallback->mListenerStatus);
+    ALOGI("Thermal listener status %d, expecting %d", mCallback->mListenerStatus, level);
 }
 
 INSTANTIATE_TEST_SUITE_P(TestListenerLevels, IThermalListenerTest, testing::Range(
@@ -158,4 +162,4 @@
     ALOGV("Test result = %d\n", status);
 
     return status;
-}
\ No newline at end of file
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index e60625b..b6a1199 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -755,7 +755,11 @@
     // We must support R8G8B8A8
     std::vector<VkSurfaceFormatKHR> all_formats = {
         {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
-        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
+        // Also allow to use PASS_THROUGH + HAL_DATASPACE_ARBITRARY
+        {VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+        {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_PASS_THROUGH_EXT},
+    };
 
     if (colorspace_ext) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
@@ -777,12 +781,16 @@
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R5G6B5_UNORM_PACK16, VK_COLOR_SPACE_PASS_THROUGH_EXT});
     }
 
     desc.format = AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT;
     if (AHardwareBuffer_isSupported(&desc)) {
         all_formats.emplace_back(VkSurfaceFormatKHR{
             VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(VkSurfaceFormatKHR{
+            VK_FORMAT_R16G16B16A16_SFLOAT, VK_COLOR_SPACE_PASS_THROUGH_EXT});
         if (wide_color_support) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_R16G16B16A16_SFLOAT,
@@ -798,6 +806,9 @@
         all_formats.emplace_back(
             VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
                                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR});
+        all_formats.emplace_back(
+            VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
+                               VK_COLOR_SPACE_PASS_THROUGH_EXT});
         if (wide_color_support) {
             all_formats.emplace_back(
                 VkSurfaceFormatKHR{VK_FORMAT_A2B10G10R10_UNORM_PACK32,
@@ -1207,11 +1218,15 @@
               native_pixel_format, strerror(-err), err);
         return VK_ERROR_SURFACE_LOST_KHR;
     }
-    err = native_window_set_buffers_data_space(window, native_dataspace);
-    if (err != android::OK) {
-        ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
-              native_dataspace, strerror(-err), err);
-        return VK_ERROR_SURFACE_LOST_KHR;
+
+    /* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */
+    if (native_dataspace != HAL_DATASPACE_ARBITRARY) {
+        err = native_window_set_buffers_data_space(window, native_dataspace);
+        if (err != android::OK) {
+            ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
+                  native_dataspace, strerror(-err), err);
+            return VK_ERROR_SURFACE_LOST_KHR;
+        }
     }
 
     err = native_window_set_buffers_dimensions(