Merge "libbinder: Fix out-of-bounds abort in RpcServer"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 942a17e..f759674 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>
@@ -3098,7 +3100,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 +3413,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 +3430,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/main.cpp b/cmds/servicemanager/main.cpp
index 2fb9c2b..1d458b7 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -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);
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..532bacb 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -648,13 +648,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/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..537527e 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;
 }
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index f2a620d..096d5cc 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"
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 2d9c933..80f6a37 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"
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index bde3d90..0ae75cd 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -736,7 +736,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) {
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..7c6d6f1 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 {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index cd6a274..8ce3bc9 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:
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index e17a76c..882dfbf 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();
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 3824a1b..f3f2886 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -146,8 +146,8 @@
     AIBinder_Class_disableInterfaceTokenHeader;
     AIBinder_DeathRecipient_setOnUnlinked;
     AIBinder_isHandlingTransaction;
-    AIBinder_setInheritRt; # llndk
-    AIBinder_setMinSchedulerPolicy; # llndk
+    AIBinder_setInheritRt; # apex llndk
+    AIBinder_setMinSchedulerPolicy; # apex llndk
     AParcel_marshal;
     AParcel_unmarshal;
 };
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/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 3766278..4e41d8e 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,50 +38,14 @@
 
 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;
@@ -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;
@@ -1305,7 +935,7 @@
     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(); });
                 }
 
@@ -1434,20 +1074,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 +1240,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 +1253,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 +1281,7 @@
     return ret;
 }
 
-TEST_P(BinderRpc, Fds) {
+TEST_P(BinderRpcThreads, Fds) {
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
@@ -1766,7 +1417,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 +1483,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 +1518,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 +1823,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 +2032,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;
+}