Merge "Tilt scale correction for certain resolutions"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 6f5f70d..287dd48 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -124,7 +124,6 @@
     { "aidl",       "AIDL calls",               ATRACE_TAG_AIDL, { } },
     { "nnapi",      "NNAPI",                    ATRACE_TAG_NNAPI, { } },
     { "rro",        "Runtime Resource Overlay", ATRACE_TAG_RRO, { } },
-    { "sysprop",    "System Property",          ATRACE_TAG_SYSPROP, { } },
     { k_coreServiceCategory, "Core services", 0, { } },
     { k_pdxServiceCategory, "PDX services", 0, { } },
     { "sched",      "CPU Scheduling",   0, {
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 37fc9a9..e3c4ede 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -266,7 +266,10 @@
     chmod 0666 /sys/kernel/debug/tracing/per_cpu/cpu15/trace
     chmod 0666 /sys/kernel/tracing/per_cpu/cpu15/trace
 
-on post-fs-data
+# Only create the tracing instance if persist.mm_events.enabled
+# Attempting to remove the tracing instance after it has been created
+# will likely fail with EBUSY as it would be in use by traced_probes.
+on post-fs-data && property:persist.mm_events.enabled=true
 # Create MM Events Tracing Instance for Kmem Activity Trigger
     mkdir /sys/kernel/debug/tracing/instances/mm_events 0755 system system
     mkdir /sys/kernel/tracing/instances/mm_events 0755 system system
@@ -275,10 +278,18 @@
     chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb
     chmod 0666 /sys/kernel/tracing/instances/mm_events/buffer_size_kb
 
+# Set the default buffer size to the minimum
+    write /sys/kernel/debug/tracing/instances/mm_events/buffer_size_kb 1
+    write /sys/kernel/tracing/instances/mm_events/buffer_size_kb 1
+
 # Read and enable tracing
     chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/tracing_on
     chmod 0666 /sys/kernel/tracing/instances/mm_events/tracing_on
 
+# Tracing disabled by default
+    write /sys/kernel/debug/tracing/instances/mm_events/tracing_on 0
+    write /sys/kernel/tracing/instances/mm_events/tracing_on 0
+
 # Read and truncate kernel trace
     chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/trace
     chmod 0666 /sys/kernel/tracing/instances/mm_events/trace
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
new file mode 100644
index 0000000..8262bc2
--- /dev/null
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_cmds_cmd_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_cmds_cmd_license"],
+}
+
+cc_fuzz {
+    name: "cmd_fuzzer",
+    srcs: [
+        "cmd_fuzzer.cpp",
+    ],
+    static_libs: [
+        "libcmd",
+        "libutils",
+        "liblog",
+        "libselinux",
+    ],
+    shared_libs: [
+        "libbinder",
+    ],
+    fuzz_config: {
+        cc: [
+            "android-media-fuzzing-reports@google.com",
+        ],
+        componentid: 155276,
+    },
+}
diff --git a/cmds/cmd/fuzzer/README.md b/cmds/cmd/fuzzer/README.md
new file mode 100644
index 0000000..db37ece
--- /dev/null
+++ b/cmds/cmd/fuzzer/README.md
@@ -0,0 +1,51 @@
+# Fuzzer for libcmd_fuzzer
+
+## Plugin Design Considerations
+The fuzzer plugin for libcmd is designed based on the understanding of the library and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+libcmd supports the following parameters:
+1. In (parameter name: `in`)
+2. Out (parameter name: `out`)
+3. Err (parameter name: `err`)
+4. Run Mode (parameter name: `runMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `in` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `out` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `err` | `INT32_MIN` to `INT32_MAX` | Value obtained from FuzzedDataProvider|
+| `runMode` | 1.`RunMode::kStandalone` 2. `RunMode::kLibrary` | Value chosen from valid values using FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the cmd module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build cmd_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+  $ mm -j$(nproc) cmd_fuzzer
+```
+#### Steps to run
+To run on device
+```
+  $ adb sync data
+  $ adb shell /data/fuzz/${TARGET_ARCH}/cmd_fuzzer/cmd_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/cmds/cmd/fuzzer/cmd_fuzzer.cpp b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
new file mode 100644
index 0000000..ab514a1
--- /dev/null
+++ b/cmds/cmd/fuzzer/cmd_fuzzer.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#include <binder/TextOutput.h>
+#include <cmd.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+using namespace std;
+using namespace android;
+
+class TestTextOutput : public TextOutput {
+public:
+    TestTextOutput() {}
+    virtual ~TestTextOutput() {}
+
+    virtual status_t print(const char* /*txt*/, size_t /*len*/) { return NO_ERROR; }
+    virtual void moveIndent(int /*delta*/) { return; }
+    virtual void pushBundle() { return; }
+    virtual void popBundle() { return; }
+};
+
+class CmdFuzzer {
+public:
+    void process(const uint8_t* data, size_t size);
+
+private:
+    FuzzedDataProvider* mFDP = nullptr;
+};
+
+void CmdFuzzer::process(const uint8_t* data, size_t size) {
+    mFDP = new FuzzedDataProvider(data, size);
+    vector<string> arguments;
+    if (mFDP->ConsumeBool()) {
+        if (mFDP->ConsumeBool()) {
+            arguments = {"-w", "media.aaudio"};
+        } else {
+            arguments = {"-l"};
+        }
+    } else {
+        while (mFDP->remaining_bytes() > 0) {
+            size_t sizestr = mFDP->ConsumeIntegralInRange<size_t>(1, mFDP->remaining_bytes());
+            string argument = mFDP->ConsumeBytesAsString(sizestr);
+            arguments.emplace_back(argument);
+        }
+    }
+    vector<string_view> argSV;
+    for (auto& argument : arguments) {
+        argSV.emplace_back(argument.c_str());
+    }
+    int32_t in = open("/dev/null", O_RDWR | O_CREAT);
+    int32_t out = open("/dev/null", O_RDWR | O_CREAT);
+    int32_t err = open("/dev/null", O_RDWR | O_CREAT);
+    TestTextOutput output;
+    TestTextOutput error;
+    RunMode runMode = mFDP->ConsumeBool() ? RunMode::kStandalone : RunMode::kLibrary;
+    cmdMain(argSV, output, error, in, out, err, runMode);
+    delete mFDP;
+    close(in);
+    close(out);
+    close(err);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    CmdFuzzer cmdFuzzer;
+    cmdFuzzer.process(data, size);
+    return 0;
+}
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index c9a7c7b..1db2867 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1236,12 +1236,19 @@
         std::string path(title);
         path.append(" - ").append(String8(service).c_str());
         size_t bytes_written = 0;
-        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
         if (status == OK) {
             dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
             std::chrono::duration<double> elapsed_seconds;
-            status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
-                                       /* as_proto = */ false, elapsed_seconds, bytes_written);
+            if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+                service == String16("meminfo")) {
+                // Use a longer timeout for meminfo, since 30s is not always enough.
+                status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
+            } else {
+                status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
+            }
             dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
             bool dump_complete = (status == OK);
             dumpsys.stopDumpThread(dump_complete);
@@ -1308,7 +1315,7 @@
             path.append("_HIGH");
         }
         path.append(kProtoExt);
-        status_t status = dumpsys.startDumpThread(Dumpsys::Type::DUMP, service, args);
+        status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
         if (status == OK) {
             status = ds.AddZipEntryFromFd(path, dumpsys.getDumpFd(), service_timeout);
             bool dumpTerminated = (status == OK);
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 83a52b8..3d2bdf1 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -21,7 +21,9 @@
 
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <binder/BpBinder.h>
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/Stability.h>
@@ -58,26 +60,30 @@
 }
 
 static void usage() {
-    fprintf(stderr,
-            "usage: dumpsys\n"
-            "         To dump all services.\n"
-            "or:\n"
-            "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--pid] [--thread] [--help | -l | "
-            "--skip SERVICES "
-            "| SERVICE [ARGS]]\n"
-            "         --help: shows this help\n"
-            "         -l: only list services, do not dump them\n"
-            "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
-            "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
-            "         --pid: dump PID instead of usual dump\n"
-            "         --proto: filter services that support dumping data in proto format. Dumps\n"
-            "               will be in proto format.\n"
-            "         --priority LEVEL: filter services based on specified priority\n"
-            "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
-            "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
-            "         --stability: dump binder stability information instead of usual dump\n"
-            "         --thread: dump thread usage instead of usual dump\n"
-            "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
+    fprintf(
+        stderr,
+        "usage: dumpsys\n"
+        "         To dump all services.\n"
+        "or:\n"
+        "       dumpsys [-t TIMEOUT] [--priority LEVEL] [--clients] [--dump] [--pid] [--thread] "
+        "[--help | "
+        "-l | --skip SERVICES "
+        "| SERVICE [ARGS]]\n"
+        "         --help: shows this help\n"
+        "         -l: only list services, do not dump them\n"
+        "         -t TIMEOUT_SEC: TIMEOUT to use in seconds instead of default 10 seconds\n"
+        "         -T TIMEOUT_MS: TIMEOUT to use in milliseconds instead of default 10 seconds\n"
+        "         --clients: dump client PIDs instead of usual dump\n"
+        "         --dump: ask the service to dump itself (this is the default)\n"
+        "         --pid: dump PID instead of usual dump\n"
+        "         --proto: filter services that support dumping data in proto format. Dumps\n"
+        "               will be in proto format.\n"
+        "         --priority LEVEL: filter services based on specified priority\n"
+        "               LEVEL must be one of CRITICAL | HIGH | NORMAL\n"
+        "         --skip SERVICES: dumps all services but SERVICES (comma-separated list)\n"
+        "         --stability: dump binder stability information instead of usual dump\n"
+        "         --thread: dump thread usage instead of usual dump\n"
+        "         SERVICE [ARGS]: dumps only service SERVICE, optionally passing ARGS to it\n");
 }
 
 static bool IsSkipped(const Vector<String16>& skipped, const String16& service) {
@@ -127,17 +133,15 @@
     bool showListOnly = false;
     bool skipServices = false;
     bool asProto = false;
-    Type type = Type::DUMP;
+    int dumpTypeFlags = 0;
     int timeoutArgMs = 10000;
     int priorityFlags = IServiceManager::DUMP_FLAG_PRIORITY_ALL;
-    static struct option longOptions[] = {{"help", no_argument, 0, 0},
-                                          {"pid", no_argument, 0, 0},
-                                          {"priority", required_argument, 0, 0},
-                                          {"proto", no_argument, 0, 0},
-                                          {"skip", no_argument, 0, 0},
-                                          {"stability", no_argument, 0, 0},
-                                          {"thread", no_argument, 0, 0},
-                                          {0, 0, 0, 0}};
+    static struct option longOptions[] = {
+        {"help", no_argument, 0, 0},           {"clients", no_argument, 0, 0},
+        {"dump", no_argument, 0, 0},           {"pid", no_argument, 0, 0},
+        {"priority", required_argument, 0, 0}, {"proto", no_argument, 0, 0},
+        {"skip", no_argument, 0, 0},           {"stability", no_argument, 0, 0},
+        {"thread", no_argument, 0, 0},         {0, 0, 0, 0}};
 
     // Must reset optind, otherwise subsequent calls will fail (wouldn't happen on main.cpp, but
     // happens on test cases).
@@ -168,12 +172,16 @@
                     usage();
                     return -1;
                 }
+            } else if (!strcmp(longOptions[optionIndex].name, "dump")) {
+                dumpTypeFlags |= TYPE_DUMP;
             } else if (!strcmp(longOptions[optionIndex].name, "pid")) {
-                type = Type::PID;
+                dumpTypeFlags |= TYPE_PID;
             } else if (!strcmp(longOptions[optionIndex].name, "stability")) {
-                type = Type::STABILITY;
+                dumpTypeFlags |= TYPE_STABILITY;
             } else if (!strcmp(longOptions[optionIndex].name, "thread")) {
-                type = Type::THREAD;
+                dumpTypeFlags |= TYPE_THREAD;
+            } else if (!strcmp(longOptions[optionIndex].name, "clients")) {
+                dumpTypeFlags |= TYPE_CLIENTS;
             }
             break;
 
@@ -211,6 +219,10 @@
         }
     }
 
+    if (dumpTypeFlags == 0) {
+        dumpTypeFlags = TYPE_DUMP;
+    }
+
     for (int i = optind; i < argc; i++) {
         if (skipServices) {
             skippedServices.add(String16(argv[i]));
@@ -263,7 +275,7 @@
         const String16& serviceName = services[i];
         if (IsSkipped(skippedServices, serviceName)) continue;
 
-        if (startDumpThread(type, serviceName, args) == OK) {
+        if (startDumpThread(dumpTypeFlags, serviceName, args) == OK) {
             bool addSeparator = (N > 1);
             if (addSeparator) {
                 writeDumpHeader(STDOUT_FILENO, serviceName, priorityFlags);
@@ -330,18 +342,21 @@
     }
 }
 
-static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd) {
+static status_t dumpPidToFd(const sp<IBinder>& service, const unique_fd& fd, bool exclusive) {
      pid_t pid;
      status_t status = service->getDebugPid(&pid);
      if (status != OK) {
          return status;
      }
+     if (!exclusive) {
+        WriteStringToFd("Service host process PID: ", fd.get());
+     }
      WriteStringToFd(std::to_string(pid) + "\n", fd.get());
      return OK;
 }
 
 static status_t dumpStabilityToFd(const sp<IBinder>& service, const unique_fd& fd) {
-     WriteStringToFd(internal::Stability::debugToString(service) + "\n", fd);
+     WriteStringToFd("Stability: " + internal::Stability::debugToString(service) + "\n", fd);
      return OK;
 }
 
@@ -362,7 +377,43 @@
     return OK;
 }
 
-status_t Dumpsys::startDumpThread(Type type, const String16& serviceName,
+static status_t dumpClientsToFd(const sp<IBinder>& service, const unique_fd& fd) {
+    std::string clientPids;
+    const auto remoteBinder = service->remoteBinder();
+    if (remoteBinder == nullptr) {
+        WriteStringToFd("Client PIDs are not available for local binders.\n", fd.get());
+        return OK;
+    }
+    const auto handle = remoteBinder->getDebugBinderHandle();
+    if (handle == std::nullopt) {
+        return OK;
+    }
+    std::vector<pid_t> pids;
+    pid_t myPid = getpid();
+    pid_t servicePid;
+    status_t status = service->getDebugPid(&servicePid);
+    if (status != OK) {
+        return status;
+    }
+    status =
+        getBinderClientPids(BinderDebugContext::BINDER, myPid, servicePid, handle.value(), &pids);
+    if (status != OK) {
+        return status;
+    }
+    pids.erase(std::remove_if(pids.begin(), pids.end(), [&](pid_t pid) { return pid == myPid; }),
+               pids.end());
+    WriteStringToFd("Client PIDs: " + ::android::base::Join(pids, ", ") + "\n", fd.get());
+    return OK;
+}
+
+static void reportDumpError(const String16& serviceName, status_t error, const char* context) {
+    if (error == OK) return;
+
+    std::cerr << "Error with service '" << serviceName << "' while " << context << ": "
+              << statusToString(error) << std::endl;
+}
+
+status_t Dumpsys::startDumpThread(int dumpTypeFlags, const String16& serviceName,
                                   const Vector<String16>& args) {
     sp<IBinder> service = sm_->checkService(serviceName);
     if (service == nullptr) {
@@ -383,29 +434,27 @@
 
     // dump blocks until completion, so spawn a thread..
     activeThread_ = std::thread([=, remote_end{std::move(remote_end)}]() mutable {
-        status_t err = 0;
-
-        switch (type) {
-        case Type::DUMP:
-            err = service->dump(remote_end.get(), args);
-            break;
-        case Type::PID:
-            err = dumpPidToFd(service, remote_end);
-            break;
-        case Type::STABILITY:
-            err = dumpStabilityToFd(service, remote_end);
-            break;
-        case Type::THREAD:
-            err = dumpThreadsToFd(service, remote_end);
-            break;
-        default:
-            std::cerr << "Unknown dump type" << static_cast<int>(type) << std::endl;
-            return;
+        if (dumpTypeFlags & TYPE_PID) {
+            status_t err = dumpPidToFd(service, remote_end, dumpTypeFlags == TYPE_PID);
+            reportDumpError(serviceName, err, "dumping PID");
+        }
+        if (dumpTypeFlags & TYPE_STABILITY) {
+            status_t err = dumpStabilityToFd(service, remote_end);
+            reportDumpError(serviceName, err, "dumping stability");
+        }
+        if (dumpTypeFlags & TYPE_THREAD) {
+            status_t err = dumpThreadsToFd(service, remote_end);
+            reportDumpError(serviceName, err, "dumping thread info");
+        }
+        if (dumpTypeFlags & TYPE_CLIENTS) {
+            status_t err = dumpClientsToFd(service, remote_end);
+            reportDumpError(serviceName, err, "dumping clients info");
         }
 
-        if (err != OK) {
-            std::cerr << "Error dumping service info status_t: " << statusToString(err) << " "
-                 << serviceName << std::endl;
+        // other types always act as a header, this is usually longer
+        if (dumpTypeFlags & TYPE_DUMP) {
+            status_t err = service->dump(remote_end.get(), args);
+            reportDumpError(serviceName, err, "dumping");
         }
     });
     return OK;
diff --git a/cmds/dumpsys/dumpsys.h b/cmds/dumpsys/dumpsys.h
index 1b3ae6a..6ab1a7d 100644
--- a/cmds/dumpsys/dumpsys.h
+++ b/cmds/dumpsys/dumpsys.h
@@ -51,24 +51,26 @@
      */
     static void setServiceArgs(Vector<String16>& args, bool asProto, int priorityFlags);
 
-    enum class Type {
-        DUMP,      // dump using `dump` function
-        PID,       // dump pid of server only
-        STABILITY, // dump stability information of server
-        THREAD,    // dump thread usage of server only
+    enum Type {
+        TYPE_DUMP = 0x1,       // dump using `dump` function
+        TYPE_PID = 0x2,        // dump pid of server only
+        TYPE_STABILITY = 0x4,  // dump stability information of server
+        TYPE_THREAD = 0x8,     // dump thread usage of server only
+        TYPE_CLIENTS = 0x10,   // dump pid of clients
     };
 
     /**
      * Starts a thread to connect to a service and get its dump output. The thread redirects
      * the output to a pipe. Thread must be stopped by a subsequent call to {@code
      * stopDumpThread}.
+     * @param dumpTypeFlags operations to perform
      * @param serviceName
      * @param args list of arguments to pass to service dump method.
      * @return {@code OK} thread is started successfully.
      *         {@code NAME_NOT_FOUND} service could not be found.
      *         {@code != OK} error
      */
-    status_t startDumpThread(Type type, const String16& serviceName,
+    status_t startDumpThread(int dumpTypeFlags, const String16& serviceName,
                              const Vector<String16>& args);
 
     /**
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 277f445..fa63db5 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -200,7 +200,7 @@
         CaptureStdout();
         CaptureStderr();
         dump_.setServiceArgs(args, supportsProto, priorityFlags);
-        status_t status = dump_.startDumpThread(Dumpsys::Type::DUMP, serviceName, args);
+        status_t status = dump_.startDumpThread(Dumpsys::TYPE_DUMP, serviceName, args);
         EXPECT_THAT(status, Eq(0));
         status = dump_.writeDump(STDOUT_FILENO, serviceName, std::chrono::milliseconds(500), false,
                                  elapsedDuration, bytesWritten);
@@ -627,6 +627,51 @@
     AssertOutputFormat(format);
 }
 
+// Tests 'dumpsys --clients'
+TEST_F(DumpsysTest, ListAllServicesWithClients) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"--clients"});
+
+    AssertRunningServices({"Locksmith", "Valet"});
+
+    const std::string format("(.|\n)*((Client PIDs are not available for local binders.)(.|\n)*){2}");
+    AssertOutputFormat(format);
+}
+
+// Tests 'dumpsys --clients service_name'
+TEST_F(DumpsysTest, ListServiceWithClients) {
+    ExpectCheckService("Locksmith");
+
+    CallMain({"--clients", "Locksmith"});
+
+    const std::string format("Client PIDs are not available for local binders.\n");
+    AssertOutputFormat(format);
+}
+// Tests 'dumpsys --thread --stability'
+TEST_F(DumpsysTest, ListAllServicesWithMultipleOptions) {
+    ExpectListServices({"Locksmith", "Valet"});
+    ExpectCheckService("Locksmith");
+    ExpectCheckService("Valet");
+
+    CallMain({"--pid", "--stability"});
+    AssertRunningServices({"Locksmith", "Valet"});
+
+    AssertOutputContains(std::to_string(getpid()));
+    AssertOutputContains("stability");
+}
+
+// Tests 'dumpsys --pid --stability service_name'
+TEST_F(DumpsysTest, ListServiceWithMultipleOptions) {
+    ExpectCheckService("Locksmith");
+    CallMain({"--pid", "--stability", "Locksmith"});
+
+    AssertOutputContains(std::to_string(getpid()));
+    AssertOutputContains("stability");
+}
+
 TEST_F(DumpsysTest, GetBytesWritten) {
     const char* serviceName = "service2";
     const char* dumpContents = "dump1";
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 15f0c5b..210f977 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1231,6 +1231,14 @@
             }
         }
 
+        // On-device signing related. odsign sets the system property odsign.verification.success if
+        // AOT artifacts have the expected signatures.
+        const bool trust_art_apex_data_files =
+                ::android::base::GetBoolProperty("odsign.verification.success", false);
+        if (!trust_art_apex_data_files) {
+            AddRuntimeArg("-Xdeny-art-apex-data-files");
+        }
+
         PrepareArgs(dexoptanalyzer_bin);
     }
 
@@ -1363,10 +1371,12 @@
         return kSecondaryDexAccessReadOk;
     } else {
         if (errno == ENOENT) {
-            LOG(INFO) << "Secondary dex does not exist: " <<  dex_path;
+            async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG,
+                    "Secondary dex does not exist: %s", dex_path.c_str());
             return kSecondaryDexAccessDoesNotExist;
         } else {
-            PLOG(ERROR) << "Could not access secondary dex " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not access secondary dex: %s (%d)", dex_path.c_str(), errno);
             return errno == EACCES
                 ? kSecondaryDexAccessPermissionError
                 : kSecondaryDexAccessIOError;
diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp
index e847626..b661684 100644
--- a/cmds/installd/run_dex2oat.cpp
+++ b/cmds/installd/run_dex2oat.cpp
@@ -283,6 +283,13 @@
         }
     }
 
+    // On-device signing related. odsign sets the system property odsign.verification.success if
+    // AOT artifacts have the expected signatures.
+    const bool trust_art_apex_data_files = GetBoolProperty("odsign.verification.success", false);
+    if (!trust_art_apex_data_files) {
+        AddRuntimeArg("-Xdeny-art-apex-data-files");
+    }
+
     if (target_sdk_version != 0) {
         AddRuntimeArg(StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version));
     }
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 2722e21..ff73c94 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -28,6 +28,7 @@
 #include <sstream>
 
 #include <android-base/file.h>
+#include <android-base/hex.h>
 #include <android-base/logging.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
@@ -691,8 +692,7 @@
             }
 
             auto&& hashArray = hashChain[hashIndex];
-            std::vector<uint8_t> hashVec{hashArray.data(), hashArray.data() + hashArray.size()};
-            entry->hash = Hash::hexString(hashVec);
+            entry->hash = android::base::HexString(hashArray.data(), hashArray.size());
         });
         if (!hashRet.isOk()) {
             handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index 8e21975..1753343 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -18,6 +18,7 @@
 
 #include <map>
 
+#include <android-base/hex.h>
 #include <android-base/strings.h>
 #include <hidl-hash/Hash.h>
 #include <vintf/parse_string.h>
@@ -104,7 +105,8 @@
 }
 
 std::string TableEntry::isReleased() const {
-    static const std::string unreleased = Hash::hexString(Hash::kEmptyHash);
+    static const std::string unreleased = android::base::HexString(Hash::kEmptyHash.data(),
+                                                                   Hash::kEmptyHash.size());
 
     if (hash.empty()) {
         return "?";
diff --git a/docs/Doxyfile b/docs/Doxyfile
index a1bd960..ea22337 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -1638,6 +1638,7 @@
     "__attribute__(x)=" \
     __ANDROID__ \
     __BIONIC__ \
+    "U_IN_DOXYGEN=1" \ # Required by the ICU4C module only
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
 # this tag can be used to specify a list of macro names that should be expanded.
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index da570f3..72d8afd 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -104,6 +104,7 @@
         "BpBinder.cpp",
         "BufferedTextOutput.cpp",
         "Debug.cpp",
+        "FdTrigger.cpp",
         "IInterface.cpp",
         "IMemory.cpp",
         "IPCThreadState.cpp",
@@ -123,6 +124,7 @@
         "RpcSession.cpp",
         "RpcServer.cpp",
         "RpcState.cpp",
+        "RpcTransportRaw.cpp",
         "Static.cpp",
         "Stability.cpp",
         "Status.cpp",
@@ -147,9 +149,6 @@
             enabled: false,
         },
         host: {
-            static_libs: [
-                "libbase",
-            ],
             srcs: [
                 "ServiceManagerHost.cpp",
                 "UtilsHost.cpp",
@@ -190,8 +189,13 @@
         "libutils",
     ],
 
+    static_libs: [
+        "libbase",
+    ],
+
     header_libs: [
         "libbinder_headers",
+        "libandroid_runtime_vm_headers",
     ],
 
     export_header_lib_headers: [
@@ -231,6 +235,42 @@
     },
 }
 
+cc_defaults {
+    name: "libbinder_tls_shared_deps",
+    shared_libs: [
+        "libbinder",
+        "libcrypto",
+        "liblog",
+        "libssl",
+        "libutils",
+    ],
+}
+
+cc_defaults {
+    name: "libbinder_tls_defaults",
+    defaults: ["libbinder_tls_shared_deps"],
+    host_supported: true,
+
+    header_libs: [
+        "libbinder_headers",
+    ],
+    export_header_lib_headers: [
+        "libbinder_headers",
+    ],
+    export_include_dirs: ["include_tls"],
+    static_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "RpcTransportTls.cpp",
+    ],
+}
+
+cc_library_shared {
+    name: "libbinder_tls",
+    defaults: ["libbinder_tls_defaults"],
+}
+
 // AIDL interface between libbinder and framework.jar
 filegroup {
     name: "libbinder_aidl",
@@ -287,7 +327,7 @@
     // Do not expand the visibility.
     visibility: [
         "//packages/modules/Virtualization/authfs:__subpackages__",
-        "//packages/modules/Virtualization/compos",
+        "//packages/modules/Virtualization/compos:__subpackages__",
         "//packages/modules/Virtualization/microdroid",
     ],
 }
@@ -356,5 +396,6 @@
         "libbinder",
         "liblog",
         "libutils",
+        "android.debug_aidl-cpp",
     ],
 }
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 628381c..d3eef4e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -555,7 +555,9 @@
         return status;
     }
     rpcServer->setRootObjectWeak(weakThis);
-    rpcServer->setupExternalServer(std::move(socketFd));
+    if (auto status = rpcServer->setupExternalServer(std::move(socketFd)); status != OK) {
+        return status;
+    }
     rpcServer->setMaxThreads(binderThreadPoolMaxCount);
     rpcServer->start();
     e->mRpcServerLinks.emplace(link);
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 3099296..55566e2 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -188,6 +188,14 @@
     return std::get<BinderHandle>(mHandle).handle;
 }
 
+std::optional<int32_t> BpBinder::getDebugBinderHandle() const {
+    if (!isRpcBinder()) {
+        return binderHandle();
+    } else {
+        return std::nullopt;
+    }
+}
+
 bool BpBinder::isDescriptorCached() const {
     Mutex::Autolock _l(mLock);
     return mDescriptorCache.size() ? true : false;
@@ -261,15 +269,15 @@
         if (code >= FIRST_CALL_TRANSACTION && code <= LAST_CALL_TRANSACTION) {
             using android::internal::Stability;
 
-            auto category = Stability::getCategory(this);
+            int16_t stability = Stability::getRepr(this);
             Stability::Level required = privateVendor ? Stability::VENDOR
                 : Stability::getLocalLevel();
 
-            if (CC_UNLIKELY(!Stability::check(category, required))) {
+            if (CC_UNLIKELY(!Stability::check(stability, required))) {
                 ALOGE("Cannot do a user transaction on a %s binder (%s) in a %s context.",
-                    category.debugString().c_str(),
-                    String8(getInterfaceDescriptor()).c_str(),
-                    Stability::levelString(required).c_str());
+                      Stability::levelString(stability).c_str(),
+                      String8(getInterfaceDescriptor()).c_str(),
+                      Stability::levelString(required).c_str());
                 return BAD_TYPE;
             }
         }
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index 8676955..e4ac4b4 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -26,22 +26,6 @@
 
 namespace android {
 
-std::string hexString(const void* bytes, size_t len) {
-    if (bytes == nullptr) return "<null>";
-
-    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
-    const char chars[] = "0123456789abcdef";
-    std::string result;
-    result.resize(len * 2);
-
-    for (size_t i = 0; i < len; i++) {
-        result[2 * i] = chars[bytes8[i] >> 4];
-        result[2 * i + 1] = chars[bytes8[i] & 0xf];
-    }
-
-    return result;
-}
-
 // ---------------------------------------------------------------------
 
 static const char indentStr[] =
diff --git a/libs/binder/Debug.h b/libs/binder/Debug.h
index 7ca087e..262dfba 100644
--- a/libs/binder/Debug.h
+++ b/libs/binder/Debug.h
@@ -23,8 +23,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-std::string hexString(const void* data, size_t size);
-
 const char* stringForIndent(int32_t indentLevel);
 
 typedef void (*debugPrintFunc)(void* cookie, const char* txt);
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
new file mode 100644
index 0000000..b197a6a
--- /dev/null
+++ b/libs/binder/FdTrigger.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "FdTrigger"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <android-base/macros.h>
+
+#include "FdTrigger.h"
+namespace android {
+
+std::unique_ptr<FdTrigger> FdTrigger::make() {
+    auto ret = std::make_unique<FdTrigger>();
+    if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
+        ALOGE("Could not create pipe %s", strerror(errno));
+        return nullptr;
+    }
+    return ret;
+}
+
+void FdTrigger::trigger() {
+    mWrite.reset();
+}
+
+bool FdTrigger::isTriggered() {
+    return mWrite == -1;
+}
+
+status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
+    while (true) {
+        pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+                     {.fd = mRead.get(), .events = 0, .revents = 0}};
+        int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
+        if (ret < 0) {
+            return -errno;
+        }
+        if (ret == 0) {
+            continue;
+        }
+        if (pfd[1].revents & POLLHUP) {
+            return -ECANCELED;
+        }
+        return pfd[0].revents & event ? OK : DEAD_OBJECT;
+    }
+}
+
+android::base::Result<bool> FdTrigger::isTriggeredPolled() {
+    pollfd pfd{.fd = mRead.get(), .events = 0, .revents = 0};
+    int ret = TEMP_FAILURE_RETRY(poll(&pfd, 1, 0));
+    if (ret < 0) {
+        return android::base::ErrnoError() << "FdTrigger::isTriggeredPolled: Error in poll()";
+    }
+    if (ret == 0) {
+        return false;
+    }
+    if (pfd.revents & POLLHUP) {
+        return true;
+    }
+    return android::base::Error() << "FdTrigger::isTriggeredPolled: poll() returns " << pfd.revents;
+}
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
new file mode 100644
index 0000000..a428417
--- /dev/null
+++ b/libs/binder/FdTrigger.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+/** This is not a pipe. */
+class FdTrigger {
+public:
+    /** Returns nullptr for error case */
+    static std::unique_ptr<FdTrigger> make();
+
+    /**
+     * Close the write end of the pipe so that the read end receives POLLHUP.
+     * Not threadsafe.
+     */
+    void trigger();
+
+    /**
+     * Check whether this has been triggered by checking the write end.
+     */
+    bool isTriggered();
+
+    /**
+     * Poll for a read event.
+     *
+     * event - for pollfd
+     *
+     * Return:
+     *   true - time to read!
+     *   false - trigger happened
+     */
+    status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
+
+    /**
+     * Check whether this has been triggered by poll()ing the read end.
+     *
+     * Return:
+     *   true - triggered
+     *   false - not triggered
+     *   error - error when polling
+     */
+    android::base::Result<bool> isTriggeredPolled();
+
+private:
+    base::unique_fd mWrite;
+    base::unique_fd mRead;
+};
+} // namespace android
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 2175fd4..6e318ea 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -154,8 +154,7 @@
     return checkPermission(permission, pid, uid);
 }
 
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
-{
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid, bool logPermissionFailure) {
     static Mutex gPermissionControllerLock;
     static sp<IPermissionController> gPermissionController;
 
@@ -180,8 +179,10 @@
 
             // Is this a permission failure, or did the controller go away?
             if (IInterface::asBinder(pc)->isBinderAlive()) {
-                ALOGW("Permission failure: %s from uid=%d pid=%d",
-                        String8(permission).string(), uid, pid);
+                if (logPermissionFailure) {
+                    ALOGW("Permission failure: %s from uid=%d pid=%d", String8(permission).string(),
+                          uid, pid);
+                }
                 return false;
             }
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index ebba375..956524a 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -173,7 +173,7 @@
 status_t Parcel::finishFlattenBinder(const sp<IBinder>& binder)
 {
     internal::Stability::tryMarkCompilationUnit(binder.get());
-    int16_t rep = internal::Stability::getCategory(binder.get()).repr();
+    int16_t rep = internal::Stability::getRepr(binder.get());
     return writeInt32(rep);
 }
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 8ef4341..caa00a5 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -409,7 +409,7 @@
         uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
         result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
         if (result == -1) {
-            ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
+            ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
         }
     } else {
         ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
index 98dee9a..ffc94b9 100644
--- a/libs/binder/RpcAddress.cpp
+++ b/libs/binder/RpcAddress.cpp
@@ -16,6 +16,7 @@
 
 #include <binder/RpcAddress.h>
 
+#include <android-base/hex.h>
 #include <binder/Parcel.h>
 
 #include "Debug.h"
@@ -94,7 +95,7 @@
 }
 
 std::string RpcAddress::toString() const {
-    return hexString(mRawAddr.get(), sizeof(RpcWireAddress));
+    return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress));
 }
 
 status_t RpcAddress::writeToParcel(Parcel* parcel) const {
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 2a87ae4..a20445b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "RpcServer"
 
+#include <poll.h>
 #include <sys/socket.h>
 #include <sys/un.h>
 
@@ -25,8 +26,10 @@
 #include <android-base/scopeguard.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
 #include <log/log.h>
 
+#include "FdTrigger.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
@@ -36,39 +39,42 @@
 using base::ScopeGuard;
 using base::unique_fd;
 
-RpcServer::RpcServer() {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+      : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
 RpcServer::~RpcServer() {
     (void)shutdown();
 }
 
-sp<RpcServer> RpcServer::make() {
-    return sp<RpcServer>::make();
+sp<RpcServer> RpcServer::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+    // Default is without TLS.
+    if (rpcTransportCtxFactory == nullptr)
+        rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+    return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
 }
 
 void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
     mAgreedExperimental = true;
 }
 
-bool RpcServer::setupUnixDomainServer(const char* path) {
+status_t RpcServer::setupUnixDomainServer(const char* path) {
     return setupSocketServer(UnixSocketAddress(path));
 }
 
-bool RpcServer::setupVsockServer(unsigned int port) {
+status_t RpcServer::setupVsockServer(unsigned int port) {
     // realizing value w/ this type at compile time to avoid ubsan abort
     constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
 
     return setupSocketServer(VsockSocketAddress(kAnyCid, port));
 }
 
-bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
-    const char* kAddr = "127.0.0.1";
-
+status_t RpcServer::setupInetServer(const char* address, unsigned int port,
+                                    unsigned int* assignedPort) {
     if (assignedPort != nullptr) *assignedPort = 0;
-    auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
-    if (aiStart == nullptr) return false;
+    auto aiStart = InetSocketAddress::getAddrInfo(address, port);
+    if (aiStart == nullptr) return UNKNOWN_ERROR;
     for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
-        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
-        if (!setupSocketServer(socketAddress)) {
+        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, address, port);
+        if (status_t status = setupSocketServer(socketAddress); status != OK) {
             continue;
         }
 
@@ -79,7 +85,7 @@
             int savedErrno = errno;
             ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
                   strerror(savedErrno));
-            return false;
+            return -savedErrno;
         }
         LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
                             static_cast<size_t>(len), sizeof(addr));
@@ -92,11 +98,11 @@
             *assignedPort = realPort;
         }
 
-        return true;
+        return OK;
     }
-    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", address,
           port);
-    return false;
+    return UNKNOWN_ERROR;
 }
 
 void RpcServer::setMaxThreads(size_t threads) {
@@ -109,6 +115,10 @@
     return mMaxThreads;
 }
 
+void RpcServer::setProtocolVersion(uint32_t version) {
+    mProtocolVersion = version;
+}
+
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
     std::lock_guard<std::mutex> _l(mLock);
     mRootObjectWeak = mRootObject = binder;
@@ -147,14 +157,18 @@
         LOG_ALWAYS_FATAL_IF(!mServer.ok(), "RpcServer must be setup to join.");
         LOG_ALWAYS_FATAL_IF(mShutdownTrigger != nullptr, "Already joined");
         mJoinThreadRunning = true;
-        mShutdownTrigger = RpcSession::FdTrigger::make();
+        mShutdownTrigger = FdTrigger::make();
         LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
+
+        mCtx = mRpcTransportCtxFactory->newServerCtx();
+        LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
+                            mRpcTransportCtxFactory->toCString());
     }
 
     status_t status;
-    while ((status = mShutdownTrigger->triggerablePollRead(mServer)) == OK) {
+    while ((status = mShutdownTrigger->triggerablePoll(mServer, POLLIN)) == OK) {
         unique_fd clientFd(TEMP_FAILURE_RETRY(
-                accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+                accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC | SOCK_NONBLOCK)));
 
         if (clientFd < 0) {
             ALOGE("Could not accept4 socket: %s", strerror(errno));
@@ -182,7 +196,7 @@
 bool RpcServer::shutdown() {
     std::unique_lock<std::mutex> _l(mLock);
     if (mShutdownTrigger == nullptr) {
-        LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed.");
+        LOG_RPC_DETAIL("Cannot shutdown. No shutdown trigger installed (already shutdown?)");
         return false;
     }
 
@@ -212,7 +226,10 @@
         mJoinThread.reset();
     }
 
+    LOG_RPC_DETAIL("Finished waiting on shutdown.");
+
     mShutdownTrigger = nullptr;
+    mCtx = nullptr;
     return true;
 }
 
@@ -238,17 +255,56 @@
     // 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);
+    LOG_ALWAYS_FATAL_IF(server->mCtx == nullptr);
+
+    status_t status = OK;
+
+    int clientFdForLog = clientFd.get();
+    auto client = server->mCtx->newTransport(std::move(clientFd), server->mShutdownTrigger.get());
+    if (client == nullptr) {
+        ALOGE("Dropping accept4()-ed socket because sslAccept fails");
+        status = DEAD_OBJECT;
+        // still need to cleanup before we can return
+    } else {
+        LOG_RPC_DETAIL("Created RpcTransport %p for client fd %d", client.get(), clientFdForLog);
+    }
 
     RpcConnectionHeader header;
-    status_t status = server->mShutdownTrigger->interruptableReadFully(clientFd.get(), &header,
-                                                                       sizeof(header));
-    bool idValid = status == OK;
-    if (!idValid) {
-        ALOGE("Failed to read ID for client connecting to RPC server: %s",
-              statusToString(status).c_str());
-        // still need to cleanup before we can return
+    if (status == OK) {
+        status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header,
+                                                sizeof(header));
+        if (status != OK) {
+            ALOGE("Failed to read ID for client connecting to RPC server: %s",
+                  statusToString(status).c_str());
+            // still need to cleanup before we can return
+        }
     }
-    bool reverse = header.options & RPC_CONNECTION_OPTION_REVERSE;
+
+    bool incoming = false;
+    uint32_t protocolVersion = 0;
+    RpcAddress sessionId = RpcAddress::zero();
+    bool requestingNewSession = false;
+
+    if (status == OK) {
+        incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
+        protocolVersion = std::min(header.version,
+                                   server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION));
+        sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
+        requestingNewSession = sessionId.isZero();
+
+        if (requestingNewSession) {
+            RpcNewSessionResponse response{
+                    .version = protocolVersion,
+            };
+
+            status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response,
+                                                     sizeof(response));
+            if (status != OK) {
+                ALOGE("Failed to send new session response: %s", statusToString(status).c_str());
+                // still need to cleanup before we can return
+            }
+        }
+    }
 
     std::thread thisThread;
     sp<RpcSession> session;
@@ -266,19 +322,16 @@
         };
         server->mConnectingThreads.erase(threadId);
 
-        if (!idValid || server->mShutdownTrigger->isTriggered()) {
+        if (status != OK || server->mShutdownTrigger->isTriggered()) {
             return;
         }
 
-        RpcAddress sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
-
-        if (sessionId.isZero()) {
-            if (reverse) {
-                ALOGE("Cannot create a new session with a reverse connection, would leak");
+        if (requestingNewSession) {
+            if (incoming) {
+                ALOGE("Cannot create a new session with an incoming connection, would leak");
                 return;
             }
 
-            sessionId = RpcAddress::zero();
             size_t tries = 0;
             do {
                 // don't block if there is some entropy issue
@@ -292,6 +345,7 @@
 
             session = RpcSession::make();
             session->setMaxThreads(server->mMaxThreads);
+            if (!session->setProtocolVersion(protocolVersion)) return;
             if (!session->setForServer(server,
                                        sp<RpcServer::EventListener>::fromExisting(
                                                static_cast<RpcServer::EventListener*>(
@@ -312,8 +366,8 @@
             session = it->second;
         }
 
-        if (reverse) {
-            LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(clientFd), true),
+        if (incoming) {
+            LOG_ALWAYS_FATAL_IF(OK != session->addOutgoingConnection(std::move(client), true),
                                 "server state must already be initialized");
             return;
         }
@@ -322,7 +376,7 @@
         session->preJoinThreadOwnership(std::move(thisThread));
     }
 
-    auto setupResult = session->preJoinSetup(std::move(clientFd));
+    auto setupResult = session->preJoinSetup(std::move(client));
 
     // avoid strong cycle
     server = nullptr;
@@ -330,39 +384,44 @@
     RpcSession::join(std::move(session), std::move(setupResult));
 }
 
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+status_t RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
     LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
     LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
 
-    unique_fd serverFd(
-            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    unique_fd serverFd(TEMP_FAILURE_RETRY(
+            socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
     if (serverFd == -1) {
-        ALOGE("Could not create socket: %s", strerror(errno));
-        return false;
+        int savedErrno = errno;
+        ALOGE("Could not create socket: %s", strerror(savedErrno));
+        return -savedErrno;
     }
 
     if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
         int savedErrno = errno;
         ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
-        return false;
+        return -savedErrno;
     }
 
-    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+    // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
+    // the backlog is increased to a large number.
+    // TODO(b/189955605): Once we create threads dynamically & lazily, the backlog can be reduced
+    //  to 1.
+    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 50 /*backlog*/))) {
         int savedErrno = errno;
         ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
-        return false;
+        return -savedErrno;
     }
 
     LOG_RPC_DETAIL("Successfully setup socket server %s", addr.toString().c_str());
 
-    if (!setupExternalServer(std::move(serverFd))) {
+    if (status_t status = setupExternalServer(std::move(serverFd)); status != OK) {
         ALOGE("Another thread has set up server while calling setupSocketServer. Race?");
-        return false;
+        return status;
     }
-    return true;
+    return OK;
 }
 
-void RpcServer::onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) {
+void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
     auto id = session->mId;
     LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
     LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str());
@@ -392,15 +451,15 @@
     return std::move(mServer);
 }
 
-bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
+status_t RpcServer::setupExternalServer(base::unique_fd serverFd) {
     LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
     std::lock_guard<std::mutex> _l(mLock);
     if (mServer.ok()) {
         ALOGE("Each RpcServer can only have one server.");
-        return false;
+        return INVALID_OPERATION;
     }
     mServer = std::move(serverFd);
-    return true;
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index ee5e8bb..4c47005 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -18,21 +18,28 @@
 
 #include <binder/RpcSession.h>
 
+#include <dlfcn.h>
 #include <inttypes.h>
 #include <poll.h>
+#include <pthread.h>
 #include <unistd.h>
 
 #include <string_view>
 
 #include <android-base/macros.h>
+#include <android_runtime/vm.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
+#include <binder/RpcTransportRaw.h>
 #include <binder/Stability.h>
+#include <jni.h>
 #include <utils/String8.h>
 
+#include "FdTrigger.h"
 #include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
+#include "Utils.h"
 
 #ifdef __GLIBC__
 extern "C" pid_t gettid();
@@ -42,7 +49,8 @@
 
 using base::unique_fd;
 
-RpcSession::RpcSession() {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
+      : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
     LOG_RPC_DETAIL("RpcSession created %p", this);
 
     mState = std::make_unique<RpcState>();
@@ -55,8 +63,11 @@
                         "Should not be able to destroy a session with servers in use.");
 }
 
-sp<RpcSession> RpcSession::make() {
-    return sp<RpcSession>::make();
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+    // Default is without TLS.
+    if (rpcTransportCtxFactory == nullptr)
+        rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
+    return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
 }
 
 void RpcSession::setMaxThreads(size_t threads) {
@@ -73,34 +84,88 @@
     return mMaxThreads;
 }
 
-bool RpcSession::setupUnixDomainClient(const char* path) {
-    return setupSocketClient(UnixSocketAddress(path));
-}
-
-bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
-    return setupSocketClient(VsockSocketAddress(cid, port));
-}
-
-bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
-    auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
-    if (aiStart == nullptr) return false;
-    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
-        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
-        if (setupSocketClient(socketAddress)) return true;
-    }
-    ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
-    return false;
-}
-
-bool RpcSession::addNullDebuggingClient() {
-    unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
-
-    if (serverFd == -1) {
-        ALOGE("Could not connect to /dev/null: %s", strerror(errno));
+bool RpcSession::setProtocolVersion(uint32_t version) {
+    if (version >= RPC_WIRE_PROTOCOL_VERSION_NEXT &&
+        version != RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+        ALOGE("Cannot start RPC session with version %u which is unknown (current protocol version "
+              "is %u).",
+              version, RPC_WIRE_PROTOCOL_VERSION);
         return false;
     }
 
-    return addOutgoingConnection(std::move(serverFd), false);
+    std::lock_guard<std::mutex> _l(mMutex);
+    if (mProtocolVersion && version > *mProtocolVersion) {
+        ALOGE("Cannot upgrade explicitly capped protocol version %u to newer version %u",
+              *mProtocolVersion, version);
+        return false;
+    }
+
+    mProtocolVersion = version;
+    return true;
+}
+
+std::optional<uint32_t> RpcSession::getProtocolVersion() {
+    std::lock_guard<std::mutex> _l(mMutex);
+    return mProtocolVersion;
+}
+
+status_t RpcSession::setupUnixDomainClient(const char* path) {
+    return setupSocketClient(UnixSocketAddress(path));
+}
+
+status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
+    return setupSocketClient(VsockSocketAddress(cid, port));
+}
+
+status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
+    auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+    if (aiStart == nullptr) return UNKNOWN_ERROR;
+    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
+        if (status_t status = setupSocketClient(socketAddress); status == OK) return OK;
+    }
+    ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
+    return NAME_NOT_FOUND;
+}
+
+status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
+    return setupClient([&](const RpcAddress& sessionId, bool incoming) -> status_t {
+        // std::move'd from fd becomes -1 (!ok())
+        if (!fd.ok()) {
+            fd = request();
+            if (!fd.ok()) return BAD_VALUE;
+        }
+        if (auto res = setNonBlocking(fd); !res.ok()) {
+            ALOGE("setupPreconnectedClient: %s", res.error().message().c_str());
+            return res.error().code() == 0 ? UNKNOWN_ERROR : -res.error().code();
+        }
+        return initAndAddConnection(std::move(fd), sessionId, incoming);
+    });
+}
+
+status_t RpcSession::addNullDebuggingClient() {
+    // Note: only works on raw sockets.
+    if (auto status = initShutdownTrigger(); status != OK) return status;
+
+    unique_fd serverFd(TEMP_FAILURE_RETRY(open("/dev/null", O_WRONLY | O_CLOEXEC)));
+
+    if (serverFd == -1) {
+        int savedErrno = errno;
+        ALOGE("Could not connect to /dev/null: %s", strerror(savedErrno));
+        return -savedErrno;
+    }
+
+    auto ctx = mRpcTransportCtxFactory->newClientCtx();
+    if (ctx == nullptr) {
+        ALOGE("Unable to create RpcTransportCtx for null debugging client");
+        return NO_MEMORY;
+    }
+    auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+    if (server == nullptr) {
+        ALOGE("Unable to set up RpcTransport");
+        return UNKNOWN_ERROR;
+    }
+    return addOutgoingConnection(std::move(server), false);
 }
 
 sp<IBinder> RpcSession::getRootObject() {
@@ -128,6 +193,7 @@
     if (wait) {
         LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
         mShutdownListener->waitForShutdown(_l);
+
         LOG_ALWAYS_FATAL_IF(!mThreads.empty(), "Shutdown failed");
     }
 
@@ -158,62 +224,6 @@
     return state()->sendDecStrong(connection.get(), sp<RpcSession>::fromExisting(this), address);
 }
 
-std::unique_ptr<RpcSession::FdTrigger> RpcSession::FdTrigger::make() {
-    auto ret = std::make_unique<RpcSession::FdTrigger>();
-    if (!android::base::Pipe(&ret->mRead, &ret->mWrite)) {
-        ALOGE("Could not create pipe %s", strerror(errno));
-        return nullptr;
-    }
-    return ret;
-}
-
-void RpcSession::FdTrigger::trigger() {
-    mWrite.reset();
-}
-
-bool RpcSession::FdTrigger::isTriggered() {
-    return mWrite == -1;
-}
-
-status_t RpcSession::FdTrigger::triggerablePollRead(base::borrowed_fd fd) {
-    while (true) {
-        pollfd pfd[]{{.fd = fd.get(), .events = POLLIN | POLLHUP, .revents = 0},
-                     {.fd = mRead.get(), .events = POLLHUP, .revents = 0}};
-        int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
-        if (ret < 0) {
-            return -errno;
-        }
-        if (ret == 0) {
-            continue;
-        }
-        if (pfd[1].revents & POLLHUP) {
-            return -ECANCELED;
-        }
-        return pfd[0].revents & POLLIN ? OK : DEAD_OBJECT;
-    }
-}
-
-status_t RpcSession::FdTrigger::interruptableReadFully(base::borrowed_fd fd, void* data,
-                                                       size_t size) {
-    uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
-    uint8_t* end = buffer + size;
-
-    MAYBE_WAIT_IN_FLAKE_MODE;
-
-    status_t status;
-    while ((status = triggerablePollRead(fd)) == OK) {
-        ssize_t readSize = TEMP_FAILURE_RETRY(recv(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
-        if (readSize == 0) return DEAD_OBJECT; // EOF
-
-        if (readSize < 0) {
-            return -errno;
-        }
-        buffer += readSize;
-        if (buffer == end) return OK;
-    }
-    return status;
-}
-
 status_t RpcSession::readId() {
     {
         std::lock_guard<std::mutex> _l(mMutex);
@@ -234,7 +244,7 @@
     return OK;
 }
 
-void RpcSession::WaitForShutdownListener::onSessionLockedAllIncomingThreadsEnded(
+void RpcSession::WaitForShutdownListener::onSessionAllIncomingThreadsEnded(
         const sp<RpcSession>& session) {
     (void)session;
     mShutdown = true;
@@ -261,12 +271,19 @@
     }
 }
 
-RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(base::unique_fd fd) {
+RpcSession::PreJoinSetupResult RpcSession::preJoinSetup(
+        std::unique_ptr<RpcTransport> rpcTransport) {
     // must be registered to allow arbitrary client code executing commands to
     // be able to do nested calls (we can't only read from it)
-    sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(fd));
+    sp<RpcConnection> connection = assignIncomingConnectionToThisThread(std::move(rpcTransport));
 
-    status_t status = mState->readConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+    status_t status;
+
+    if (connection == nullptr) {
+        status = DEAD_OBJECT;
+    } else {
+        status = mState->readConnectionInit(connection, sp<RpcSession>::fromExisting(this));
+    }
 
     return PreJoinSetupResult{
             .connection = std::move(connection),
@@ -274,10 +291,67 @@
     };
 }
 
+namespace {
+// RAII object for attaching / detaching current thread to JVM if Android Runtime exists. If
+// Android Runtime doesn't exist, no-op.
+class JavaThreadAttacher {
+public:
+    JavaThreadAttacher() {
+        // Use dlsym to find androidJavaAttachThread because libandroid_runtime is loaded after
+        // libbinder.
+        auto vm = getJavaVM();
+        if (vm == nullptr) return;
+
+        char threadName[16];
+        if (0 != pthread_getname_np(pthread_self(), threadName, sizeof(threadName))) {
+            constexpr const char* defaultThreadName = "UnknownRpcSessionThread";
+            memcpy(threadName, defaultThreadName,
+                   std::min<size_t>(sizeof(threadName), strlen(defaultThreadName) + 1));
+        }
+        LOG_RPC_DETAIL("Attaching current thread %s to JVM", threadName);
+        JavaVMAttachArgs args;
+        args.version = JNI_VERSION_1_2;
+        args.name = threadName;
+        args.group = nullptr;
+        JNIEnv* env;
+
+        LOG_ALWAYS_FATAL_IF(vm->AttachCurrentThread(&env, &args) != JNI_OK,
+                            "Cannot attach thread %s to JVM", threadName);
+        mAttached = true;
+    }
+    ~JavaThreadAttacher() {
+        if (!mAttached) return;
+        auto vm = getJavaVM();
+        LOG_ALWAYS_FATAL_IF(vm == nullptr,
+                            "Unable to detach thread. No JavaVM, but it was present before!");
+
+        LOG_RPC_DETAIL("Detaching current thread from JVM");
+        if (vm->DetachCurrentThread() != JNI_OK) {
+            mAttached = false;
+        } else {
+            ALOGW("Unable to detach current thread from JVM");
+        }
+    }
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(JavaThreadAttacher);
+    bool mAttached = false;
+
+    static JavaVM* getJavaVM() {
+        static auto fn = reinterpret_cast<decltype(&AndroidRuntimeGetJavaVM)>(
+                dlsym(RTLD_DEFAULT, "AndroidRuntimeGetJavaVM"));
+        if (fn == nullptr) return nullptr;
+        return fn();
+    }
+};
+} // namespace
+
 void RpcSession::join(sp<RpcSession>&& session, PreJoinSetupResult&& setupResult) {
     sp<RpcConnection>& connection = setupResult.connection;
 
     if (setupResult.status == OK) {
+        LOG_ALWAYS_FATAL_IF(!connection, "must have connection if setup succeeded");
+        JavaThreadAttacher javaThreadAttacher;
         while (true) {
             status_t status = session->state()->getAndExecuteCommand(connection, session,
                                                                      RpcState::CommandType::ANY);
@@ -292,9 +366,6 @@
               statusToString(setupResult.status).c_str());
     }
 
-    LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
-                        "bad state: connection object guaranteed to be in list");
-
     sp<RpcSession::EventListener> listener;
     {
         std::lock_guard<std::mutex> _l(session->mMutex);
@@ -306,6 +377,12 @@
         listener = session->mEventListener.promote();
     }
 
+    // done after all cleanup, since session shutdown progresses via callbacks here
+    if (connection != nullptr) {
+        LOG_ALWAYS_FATAL_IF(!session->removeIncomingConnection(connection),
+                            "bad state: connection object guaranteed to be in list");
+    }
+
     session = nullptr;
 
     if (listener != nullptr) {
@@ -322,36 +399,48 @@
     return server;
 }
 
-bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+status_t RpcSession::setupClient(
+        const std::function<status_t(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
     {
         std::lock_guard<std::mutex> _l(mMutex);
         LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
                             "Must only setup session once, but already has %zu clients",
                             mOutgoingConnections.size());
     }
+    if (auto status = initShutdownTrigger(); status != OK) return status;
 
-    if (!setupOneSocketConnection(addr, RpcAddress::zero(), false /*reverse*/)) return false;
+    if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
+        return status;
+
+    {
+        ExclusiveConnection connection;
+        if (status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                        ConnectionUse::CLIENT, &connection);
+            status != OK)
+            return status;
+
+        uint32_t version;
+        if (status_t status =
+                    state()->readNewSessionResponse(connection.get(),
+                                                    sp<RpcSession>::fromExisting(this), &version);
+            status != OK)
+            return status;
+        if (!setProtocolVersion(version)) return BAD_VALUE;
+    }
 
     // TODO(b/189955605): we should add additional sessions dynamically
     // instead of all at once.
-    // TODO(b/186470974): first risk of blocking
     size_t numThreadsAvailable;
     if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
-        ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
+        ALOGE("Could not get max threads after initial session setup: %s",
               statusToString(status).c_str());
-        return false;
+        return status;
     }
 
     if (status_t status = readId(); status != OK) {
-        ALOGE("Could not get session id after initial session to %s; %s", addr.toString().c_str(),
+        ALOGE("Could not get session id after initial session setup: %s",
               statusToString(status).c_str());
-        return false;
-    }
-
-    // we've already setup one client
-    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
-        // TODO(b/189955605): shutdown existing connections?
-        if (!setupOneSocketConnection(addr, mId.value(), false /*reverse*/)) return false;
+        return status;
     }
 
     // TODO(b/189955605): we should add additional sessions dynamically
@@ -360,25 +449,38 @@
     // requested to be set) in order to allow the other side to reliably make
     // any requests at all.
 
-    for (size_t i = 0; i < mMaxThreads; i++) {
-        if (!setupOneSocketConnection(addr, mId.value(), true /*reverse*/)) return false;
+    // we've already setup one client
+    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+        if (status_t status = connectAndInit(mId.value(), false /*incoming*/); status != OK)
+            return status;
     }
 
-    return true;
+    for (size_t i = 0; i < mMaxThreads; i++) {
+        if (status_t status = connectAndInit(mId.value(), true /*incoming*/); status != OK)
+            return status;
+    }
+
+    return OK;
 }
 
-bool RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr, const RpcAddress& id,
-                                          bool reverse) {
+status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
+    return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+        return setupOneSocketConnection(addr, sessionId, incoming);
+    });
+}
+
+status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
+                                              const RpcAddress& sessionId, bool incoming) {
     for (size_t tries = 0; tries < 5; tries++) {
         if (tries > 0) usleep(10000);
 
-        unique_fd serverFd(
-                TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+        unique_fd serverFd(TEMP_FAILURE_RETRY(
+                socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)));
         if (serverFd == -1) {
             int savedErrno = errno;
             ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
                   strerror(savedErrno));
-            return false;
+            return -savedErrno;
         }
 
         if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
@@ -386,76 +488,131 @@
                 ALOGW("Connection reset on %s", addr.toString().c_str());
                 continue;
             }
-            int savedErrno = errno;
-            ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
-                  strerror(savedErrno));
-            return false;
+            if (errno != EAGAIN && errno != EINPROGRESS) {
+                int savedErrno = errno;
+                ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
+                      strerror(savedErrno));
+                return -savedErrno;
+            }
+            // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+            // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+            status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+            if (pollStatus != OK) {
+                ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+                      statusToString(pollStatus).c_str());
+                return pollStatus;
+            }
+            int soError;
+            socklen_t soErrorLen = sizeof(soError);
+            int ret = getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &soError, &soErrorLen);
+            if (ret == -1) {
+                int savedErrno = errno;
+                ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s",
+                      strerror(savedErrno));
+                return -savedErrno;
+            }
+            if (soError != 0) {
+                ALOGE("After connect(), getsockopt() returns error for socket at %s: %s",
+                      addr.toString().c_str(), strerror(soError));
+                return -soError;
+            }
         }
-
-        RpcConnectionHeader header{.options = 0};
-        memcpy(&header.sessionId, &id.viewRawEmbedded(), sizeof(RpcWireAddress));
-
-        if (reverse) header.options |= RPC_CONNECTION_OPTION_REVERSE;
-
-        if (sizeof(header) != TEMP_FAILURE_RETRY(write(serverFd.get(), &header, sizeof(header)))) {
-            int savedErrno = errno;
-            ALOGE("Could not write connection header to socket at %s: %s", addr.toString().c_str(),
-                  strerror(savedErrno));
-            return false;
-        }
-
         LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
 
-        if (reverse) {
-            std::mutex mutex;
-            std::condition_variable joinCv;
-            std::unique_lock<std::mutex> lock(mutex);
-            std::thread thread;
-            sp<RpcSession> thiz = sp<RpcSession>::fromExisting(this);
-            bool ownershipTransferred = false;
-            thread = std::thread([&]() {
-                std::unique_lock<std::mutex> threadLock(mutex);
-                unique_fd fd = std::move(serverFd);
-                // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
-                sp<RpcSession> session = thiz;
-                session->preJoinThreadOwnership(std::move(thread));
-
-                // only continue once we have a response or the connection fails
-                auto setupResult = session->preJoinSetup(std::move(fd));
-
-                ownershipTransferred = true;
-                threadLock.unlock();
-                joinCv.notify_one();
-                // do not use & vars below
-
-                RpcSession::join(std::move(session), std::move(setupResult));
-            });
-            joinCv.wait(lock, [&] { return ownershipTransferred; });
-            LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
-            return true;
-        } else {
-            return addOutgoingConnection(std::move(serverFd), true);
-        }
+        return initAndAddConnection(std::move(serverFd), sessionId, incoming);
     }
 
     ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
-    return false;
+    return UNKNOWN_ERROR;
 }
 
-bool RpcSession::addOutgoingConnection(unique_fd fd, bool init) {
+status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
+                                          bool incoming) {
+    LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
+    auto ctx = mRpcTransportCtxFactory->newClientCtx();
+    if (ctx == nullptr) {
+        ALOGE("Unable to create client RpcTransportCtx with %s sockets",
+              mRpcTransportCtxFactory->toCString());
+        return NO_MEMORY;
+    }
+    auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+    if (server == nullptr) {
+        ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+        return UNKNOWN_ERROR;
+    }
+
+    LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
+
+    RpcConnectionHeader header{
+            .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
+            .options = 0,
+    };
+    memcpy(&header.sessionId, &sessionId.viewRawEmbedded(), sizeof(RpcWireAddress));
+
+    if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
+
+    auto sendHeaderStatus =
+            server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
+    if (sendHeaderStatus != OK) {
+        ALOGE("Could not write connection header to socket: %s",
+              statusToString(sendHeaderStatus).c_str());
+        return sendHeaderStatus;
+    }
+
+    LOG_RPC_DETAIL("Socket at client: header sent");
+
+    if (incoming) {
+        return addIncomingConnection(std::move(server));
+    } else {
+        return addOutgoingConnection(std::move(server), true /*init*/);
+    }
+}
+
+status_t RpcSession::addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport) {
+    std::mutex mutex;
+    std::condition_variable joinCv;
+    std::unique_lock<std::mutex> lock(mutex);
+    std::thread thread;
+    sp<RpcSession> thiz = sp<RpcSession>::fromExisting(this);
+    bool ownershipTransferred = false;
+    thread = std::thread([&]() {
+        std::unique_lock<std::mutex> threadLock(mutex);
+        std::unique_ptr<RpcTransport> movedRpcTransport = std::move(rpcTransport);
+        // NOLINTNEXTLINE(performance-unnecessary-copy-initialization)
+        sp<RpcSession> session = thiz;
+        session->preJoinThreadOwnership(std::move(thread));
+
+        // only continue once we have a response or the connection fails
+        auto setupResult = session->preJoinSetup(std::move(movedRpcTransport));
+
+        ownershipTransferred = true;
+        threadLock.unlock();
+        joinCv.notify_one();
+        // do not use & vars below
+
+        RpcSession::join(std::move(session), std::move(setupResult));
+    });
+    joinCv.wait(lock, [&] { return ownershipTransferred; });
+    LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
+    return OK;
+}
+
+status_t RpcSession::initShutdownTrigger() {
+    // first client connection added, but setForServer not called, so
+    // initializaing for a client.
+    if (mShutdownTrigger == nullptr) {
+        mShutdownTrigger = FdTrigger::make();
+        mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
+        if (mShutdownTrigger == nullptr) return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t RpcSession::addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport, bool init) {
     sp<RpcConnection> connection = sp<RpcConnection>::make();
     {
         std::lock_guard<std::mutex> _l(mMutex);
-
-        // first client connection added, but setForServer not called, so
-        // initializaing for a client.
-        if (mShutdownTrigger == nullptr) {
-            mShutdownTrigger = FdTrigger::make();
-            mEventListener = mShutdownListener = sp<WaitForShutdownListener>::make();
-            if (mShutdownTrigger == nullptr) return false;
-        }
-
-        connection->fd = std::move(fd);
+        connection->rpcTransport = std::move(rpcTransport);
         connection->exclusiveTid = gettid();
         mOutgoingConnections.push_back(connection);
     }
@@ -470,7 +627,7 @@
         connection->exclusiveTid = std::nullopt;
     }
 
-    return status == OK;
+    return status;
 }
 
 bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
@@ -490,26 +647,44 @@
     return true;
 }
 
-sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(unique_fd fd) {
+sp<RpcSession::RpcConnection> RpcSession::assignIncomingConnectionToThisThread(
+        std::unique_ptr<RpcTransport> rpcTransport) {
     std::lock_guard<std::mutex> _l(mMutex);
+
+    if (mIncomingConnections.size() >= mMaxThreads) {
+        ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
+              mIncomingConnections.size(), mMaxThreads);
+        return nullptr;
+    }
+
+    // Don't accept any more connections, some have shutdown. Usually this
+    // happens when new connections are still being established as part of a
+    // very short-lived session which shuts down after it already started
+    // accepting new connections.
+    if (mIncomingConnections.size() < mMaxIncomingConnections) {
+        return nullptr;
+    }
+
     sp<RpcConnection> session = sp<RpcConnection>::make();
-    session->fd = std::move(fd);
+    session->rpcTransport = std::move(rpcTransport);
     session->exclusiveTid = gettid();
+
     mIncomingConnections.push_back(session);
+    mMaxIncomingConnections = mIncomingConnections.size();
 
     return session;
 }
 
 bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
-    std::lock_guard<std::mutex> _l(mMutex);
+    std::unique_lock<std::mutex> _l(mMutex);
     if (auto it = std::find(mIncomingConnections.begin(), mIncomingConnections.end(), connection);
         it != mIncomingConnections.end()) {
         mIncomingConnections.erase(it);
         if (mIncomingConnections.size() == 0) {
             sp<EventListener> listener = mEventListener.promote();
             if (listener) {
-                listener->onSessionLockedAllIncomingThreadsEnded(
-                        sp<RpcSession>::fromExisting(this));
+                _l.unlock();
+                listener->onSessionAllIncomingThreadsEnded(sp<RpcSession>::fromExisting(this));
             }
         }
         return true;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b5eaaa3..b58f1b3 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,6 +18,7 @@
 
 #include "RpcState.h"
 
+#include <android-base/hex.h>
 #include <android-base/scopeguard.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
@@ -34,11 +35,10 @@
 
 using base::ScopeGuard;
 
-#ifdef RPC_FLAKE_PRONE
+#if RPC_FLAKE_PRONE
 void rpcMaybeWaitToFlake() {
-    static std::random_device r;
-    static std::mutex m;
-
+    [[clang::no_destroy]] static std::random_device r;
+    [[clang::no_destroy]] static std::mutex m;
     unsigned num;
     {
         std::lock_guard<std::mutex> lock(m);
@@ -273,10 +273,8 @@
 status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
                            const sp<RpcSession>& session, const char* what, const void* data,
                            size_t size) {
-    LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, connection->fd.get(),
-                   hexString(data, size).c_str());
-
-    MAYBE_WAIT_IN_FLAKE_MODE;
+    LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+                   android::base::HexString(data, size).c_str());
 
     if (size > std::numeric_limits<ssize_t>::max()) {
         ALOGE("Cannot send %s at size %zu (too big)", what, size);
@@ -284,15 +282,14 @@
         return BAD_VALUE;
     }
 
-    ssize_t sent = TEMP_FAILURE_RETRY(send(connection->fd.get(), data, size, MSG_NOSIGNAL));
-
-    if (sent < 0 || sent != static_cast<ssize_t>(size)) {
-        int savedErrno = errno;
-        LOG_RPC_DETAIL("Failed to send %s (sent %zd of %zu bytes) on fd %d, error: %s", what, sent,
-                       size, connection->fd.get(), strerror(savedErrno));
-
+    if (status_t status =
+                connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
+                                                                  data, size);
+        status != OK) {
+        LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+                       connection->rpcTransport.get(), statusToString(status).c_str());
         (void)session->shutdownAndWait(false);
-        return -savedErrno;
+        return status;
     }
 
     return OK;
@@ -308,15 +305,28 @@
     }
 
     if (status_t status =
-                session->mShutdownTrigger->interruptableReadFully(connection->fd.get(), data, size);
+                connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
+                                                                 data, size);
         status != OK) {
-        LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on fd %d, error: %s", what, size,
-                       connection->fd.get(), statusToString(status).c_str());
+        LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
+                       connection->rpcTransport.get(), statusToString(status).c_str());
         return status;
     }
 
-    LOG_RPC_DETAIL("Received %s on fd %d: %s", what, connection->fd.get(),
-                   hexString(data, size).c_str());
+    LOG_RPC_DETAIL("Received %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
+                   android::base::HexString(data, size).c_str());
+    return OK;
+}
+
+status_t RpcState::readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+                                          const sp<RpcSession>& session, uint32_t* version) {
+    RpcNewSessionResponse response;
+    if (status_t status =
+                rpcRec(connection, session, "new session response", &response, sizeof(response));
+        status != OK) {
+        return status;
+    }
+    *version = response.version;
     return OK;
 }
 
@@ -482,7 +492,8 @@
         return status;
 
     if (flags & IBinder::FLAG_ONEWAY) {
-        LOG_RPC_DETAIL("Oneway command, so no longer waiting on %d", connection->fd.get());
+        LOG_RPC_DETAIL("Oneway command, so no longer waiting on RpcTransport %p",
+                       connection->rpcTransport.get());
 
         // Do not wait on result.
         // However, too many oneway calls may cause refcounts to build up and fill up the socket,
@@ -577,7 +588,7 @@
 
 status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
                                         const sp<RpcSession>& session, CommandType type) {
-    LOG_RPC_DETAIL("getAndExecuteCommand on fd %d", connection->fd.get());
+    LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
 
     RpcWireHeader command;
     if (status_t status = rpcRec(connection, session, "command header", &command, sizeof(command));
@@ -590,8 +601,7 @@
 status_t RpcState::drainCommands(const sp<RpcSession::RpcConnection>& connection,
                                  const sp<RpcSession>& session, CommandType type) {
     uint8_t buf;
-    while (0 < TEMP_FAILURE_RETRY(
-                       recv(connection->fd.get(), &buf, sizeof(buf), MSG_PEEK | MSG_DONTWAIT))) {
+    while (connection->rpcTransport->peek(&buf, sizeof(buf)).value_or(0) > 0) {
         status_t status = getAndExecuteCommand(connection, session, type);
         if (status != OK) return status;
     }
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 8201eba..1446eec 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -44,7 +44,7 @@
 
 #define RPC_FLAKE_PRONE false
 
-#ifdef RPC_FLAKE_PRONE
+#if RPC_FLAKE_PRONE
 void rpcMaybeWaitToFlake();
 #define MAYBE_WAIT_IN_FLAKE_MODE rpcMaybeWaitToFlake()
 #else
@@ -60,6 +60,8 @@
     RpcState();
     ~RpcState();
 
+    status_t readNewSessionResponse(const sp<RpcSession::RpcConnection>& connection,
+                                    const sp<RpcSession>& session, uint32_t* version);
     status_t sendConnectionInit(const sp<RpcSession::RpcConnection>& connection,
                                 const sp<RpcSession>& session);
     status_t readConnectionInit(const sp<RpcSession::RpcConnection>& connection,
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
new file mode 100644
index 0000000..d77fc52
--- /dev/null
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcRawTransport"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <binder/RpcTransportRaw.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+using android::base::ErrnoError;
+using android::base::Result;
+
+namespace android {
+
+namespace {
+
+// RpcTransport with TLS disabled.
+class RpcTransportRaw : public RpcTransport {
+public:
+    explicit RpcTransportRaw(android::base::unique_fd socket) : mSocket(std::move(socket)) {}
+    Result<size_t> send(const void* buf, size_t size) {
+        ssize_t ret = TEMP_FAILURE_RETRY(::send(mSocket.get(), buf, size, MSG_NOSIGNAL));
+        if (ret < 0) {
+            return ErrnoError() << "send()";
+        }
+        return ret;
+    }
+    Result<size_t> recv(void* buf, size_t size) {
+        ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_NOSIGNAL));
+        if (ret < 0) {
+            return ErrnoError() << "recv()";
+        }
+        return ret;
+    }
+    Result<size_t> peek(void *buf, size_t size) override {
+        ssize_t ret = TEMP_FAILURE_RETRY(::recv(mSocket.get(), buf, size, MSG_PEEK));
+        if (ret < 0) {
+            return ErrnoError() << "recv(MSG_PEEK)";
+        }
+        return ret;
+    }
+
+    status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override {
+        const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data);
+        const uint8_t* end = buffer + size;
+
+        MAYBE_WAIT_IN_FLAKE_MODE;
+
+        status_t status;
+        while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLOUT)) == OK) {
+            auto writeSize = this->send(buffer, end - buffer);
+            if (!writeSize.ok()) {
+                LOG_RPC_DETAIL("RpcTransport::send(): %s", writeSize.error().message().c_str());
+                return writeSize.error().code() == 0 ? UNKNOWN_ERROR : -writeSize.error().code();
+            }
+
+            if (*writeSize == 0) return DEAD_OBJECT;
+
+            buffer += *writeSize;
+            if (buffer == end) return OK;
+        }
+        return status;
+    }
+
+    status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override {
+        uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
+        uint8_t* end = buffer + size;
+
+        MAYBE_WAIT_IN_FLAKE_MODE;
+
+        status_t status;
+        while ((status = fdTrigger->triggerablePoll(mSocket.get(), POLLIN)) == OK) {
+            auto readSize = this->recv(buffer, end - buffer);
+            if (!readSize.ok()) {
+                LOG_RPC_DETAIL("RpcTransport::recv(): %s", readSize.error().message().c_str());
+                return readSize.error().code() == 0 ? UNKNOWN_ERROR : -readSize.error().code();
+            }
+
+            if (*readSize == 0) return DEAD_OBJECT; // EOF
+
+            buffer += *readSize;
+            if (buffer == end) return OK;
+        }
+        return status;
+    }
+
+private:
+    android::base::unique_fd mSocket;
+};
+
+// RpcTransportCtx with TLS disabled.
+class RpcTransportCtxRaw : public RpcTransportCtx {
+public:
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
+        return std::make_unique<RpcTransportRaw>(std::move(fd));
+    }
+};
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
+    return std::make_unique<RpcTransportCtxRaw>();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newClientCtx() const {
+    return std::make_unique<RpcTransportCtxRaw>();
+}
+
+const char *RpcTransportCtxFactoryRaw::toCString() const {
+    return "raw";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryRaw::make() {
+    return std::unique_ptr<RpcTransportCtxFactoryRaw>(new RpcTransportCtxFactoryRaw());
+}
+
+} // namespace android
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
new file mode 100644
index 0000000..a102913
--- /dev/null
+++ b/libs/binder/RpcTransportTls.cpp
@@ -0,0 +1,535 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTransportTls"
+#include <log/log.h>
+
+#include <poll.h>
+
+#include <openssl/bn.h>
+#include <openssl/ssl.h>
+
+#include <binder/RpcTransportTls.h>
+
+#include "FdTrigger.h"
+#include "RpcState.h"
+
+#define SHOULD_LOG_TLS_DETAIL false
+
+#if SHOULD_LOG_TLS_DETAIL
+#define LOG_TLS_DETAIL(...) ALOGI(__VA_ARGS__)
+#else
+#define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
+#endif
+
+#define TEST_AND_RETURN(value, expr)            \
+    do {                                        \
+        if (!(expr)) {                          \
+            ALOGE("Failed to call: %s", #expr); \
+            return value;                       \
+        }                                       \
+    } while (0)
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+namespace android {
+namespace {
+
+constexpr const int kCertValidDays = 30;
+
+// Implement BIO for socket that ignores SIGPIPE.
+int socketNew(BIO* bio) {
+    BIO_set_data(bio, reinterpret_cast<void*>(-1));
+    BIO_set_init(bio, 0);
+    return 1;
+}
+int socketFree(BIO* bio) {
+    LOG_ALWAYS_FATAL_IF(bio == nullptr);
+    return 1;
+}
+int socketRead(BIO* bio, char* buf, int size) {
+    android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+    int ret = TEMP_FAILURE_RETRY(::recv(fd.get(), buf, size, MSG_NOSIGNAL));
+    BIO_clear_retry_flags(bio);
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+        BIO_set_retry_read(bio);
+    }
+    return ret;
+}
+
+int socketWrite(BIO* bio, const char* buf, int size) {
+    android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+    int ret = TEMP_FAILURE_RETRY(::send(fd.get(), buf, size, MSG_NOSIGNAL));
+    BIO_clear_retry_flags(bio);
+    if (errno == EAGAIN || errno == EWOULDBLOCK) {
+        BIO_set_retry_write(bio);
+    }
+    return ret;
+}
+
+long socketCtrl(BIO* bio, int cmd, long num, void*) { // NOLINT
+    android::base::borrowed_fd fd(static_cast<int>(reinterpret_cast<intptr_t>(BIO_get_data(bio))));
+    if (cmd == BIO_CTRL_FLUSH) return 1;
+    LOG_ALWAYS_FATAL("sockCtrl(fd=%d, %d, %ld)", fd.get(), cmd, num);
+    return 0;
+}
+
+bssl::UniquePtr<BIO> newSocketBio(android::base::borrowed_fd fd) {
+    static const BIO_METHOD* gMethods = ([] {
+        auto methods = BIO_meth_new(BIO_get_new_index(), "socket_no_signal");
+        LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_write(methods, socketWrite), "BIO_meth_set_write");
+        LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_read(methods, socketRead), "BIO_meth_set_read");
+        LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_ctrl(methods, socketCtrl), "BIO_meth_set_ctrl");
+        LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_create(methods, socketNew), "BIO_meth_set_create");
+        LOG_ALWAYS_FATAL_IF(0 == BIO_meth_set_destroy(methods, socketFree), "BIO_meth_set_destroy");
+        return methods;
+    })();
+    bssl::UniquePtr<BIO> ret(BIO_new(gMethods));
+    if (ret == nullptr) return nullptr;
+    BIO_set_data(ret.get(), reinterpret_cast<void*>(fd.get()));
+    BIO_set_init(ret.get(), 1);
+    return ret;
+}
+
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
+    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
+        ALOGE("Failed to generate key pair.");
+        return nullptr;
+    }
+    bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
+    // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
+    // the refcount of the ec_key, so it is okay to release it at the end of this function.
+    if (evp_pkey == nullptr || !EVP_PKEY_set1_EC_KEY(evp_pkey.get(), ec_key.get())) {
+        ALOGE("Failed to assign key pair.");
+        return nullptr;
+    }
+    return evp_pkey;
+}
+
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* evp_pkey, const int valid_days) {
+    bssl::UniquePtr<X509> x509(X509_new());
+    bssl::UniquePtr<BIGNUM> serial(BN_new());
+    bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
+    TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
+    TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
+    TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
+    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
+    TEST_AND_RETURN(nullptr,
+                    X509_gmtime_adj(X509_getm_notAfter(x509.get()), 60 * 60 * 24 * valid_days));
+
+    X509_NAME* subject = X509_get_subject_name(x509.get());
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("Android"), -1, -1,
+                                               0));
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
+                                               -1, 0));
+    TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
+
+    TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), evp_pkey));
+    TEST_AND_RETURN(nullptr, X509_sign(x509.get(), evp_pkey, EVP_sha256()));
+    return x509;
+}
+
+[[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) {
+    switch (type) {
+        case SSL_CB_HANDSHAKE_START:
+            LOG_TLS_DETAIL("Handshake started.");
+            break;
+        case SSL_CB_HANDSHAKE_DONE:
+            LOG_TLS_DETAIL("Handshake done.");
+            break;
+        case SSL_CB_ACCEPT_LOOP:
+            LOG_TLS_DETAIL("Handshake progress: %s", SSL_state_string_long(ssl));
+            break;
+        default:
+            LOG_TLS_DETAIL("SSL Debug Log: type = %d, value = %d", type, value);
+            break;
+    }
+}
+
+// Handles libssl's error queue.
+//
+// Call into any of its member functions to ensure the error queue is properly handled or cleared.
+// If the error queue is not handled or cleared, the destructor will abort.
+class ErrorQueue {
+public:
+    ~ErrorQueue() { LOG_ALWAYS_FATAL_IF(!mHandled); }
+
+    // Clear the error queue.
+    void clear() {
+        ERR_clear_error();
+        mHandled = true;
+    }
+
+    // Stores the error queue in |ssl| into a string, then clears the error queue.
+    std::string toString() {
+        std::stringstream ss;
+        ERR_print_errors_cb(
+                [](const char* str, size_t len, void* ctx) {
+                    auto ss = (std::stringstream*)ctx;
+                    (*ss) << std::string_view(str, len) << "\n";
+                    return 1; // continue
+                },
+                &ss);
+        // Though ERR_print_errors_cb should have cleared it, it is okay to clear again.
+        clear();
+        return ss.str();
+    }
+
+    // |sslError| should be from Ssl::getError().
+    // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
+    // return error. Also return error if |fdTrigger| is triggered before or during poll().
+    status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
+                             const char* fnString, int additionalEvent = 0) {
+        switch (sslError) {
+            case SSL_ERROR_WANT_READ:
+                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString);
+            case SSL_ERROR_WANT_WRITE:
+                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString);
+            case SSL_ERROR_SYSCALL: {
+                auto queue = toString();
+                LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
+                               SSL_error_description(sslError), queue.c_str());
+                return DEAD_OBJECT;
+            }
+            default: {
+                auto queue = toString();
+                ALOGE("%s(): %s. Error queue: %s", fnString, SSL_error_description(sslError),
+                      queue.c_str());
+                return UNKNOWN_ERROR;
+            }
+        }
+    }
+
+private:
+    bool mHandled = false;
+
+    status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
+                        const char* fnString) {
+        status_t ret = fdTrigger->triggerablePoll(fd, event);
+        if (ret != OK && ret != DEAD_OBJECT && ret != -ECANCELED) {
+            ALOGE("triggerablePoll error while poll()-ing after %s(): %s", fnString,
+                  statusToString(ret).c_str());
+        }
+        clear();
+        return ret;
+    }
+};
+
+// Helper to call a function, with its return value instantiable.
+template <typename Fn, typename... Args>
+struct FuncCaller {
+    struct Monostate {};
+    static constexpr bool sIsVoid = std::is_void_v<std::invoke_result_t<Fn, Args...>>;
+    using Result = std::conditional_t<sIsVoid, Monostate, std::invoke_result_t<Fn, Args...>>;
+    static inline Result call(Fn fn, Args&&... args) {
+        if constexpr (std::is_void_v<std::invoke_result_t<Fn, Args...>>) {
+            std::invoke(fn, std::forward<Args>(args)...);
+            return {};
+        } else {
+            return std::invoke(fn, std::forward<Args>(args)...);
+        }
+    }
+};
+
+// Helper to Ssl::call(). Returns the result to the SSL_* function as well as an ErrorQueue object.
+template <typename Fn, typename... Args>
+struct SslCaller {
+    using RawCaller = FuncCaller<Fn, SSL*, Args...>;
+    struct ResultAndErrorQueue {
+        typename RawCaller::Result result;
+        ErrorQueue errorQueue;
+    };
+    static inline ResultAndErrorQueue call(Fn fn, SSL* ssl, Args&&... args) {
+        LOG_ALWAYS_FATAL_IF(ssl == nullptr);
+        auto result = RawCaller::call(fn, std::forward<SSL*>(ssl), std::forward<Args>(args)...);
+        return ResultAndErrorQueue{std::move(result), ErrorQueue()};
+    }
+};
+
+// A wrapper over bssl::UniquePtr<SSL>. This class ensures that all SSL_* functions are called
+// through call(), which returns an ErrorQueue object that requires the caller to either handle
+// or clear it.
+// Example:
+//   auto [ret, errorQueue] = ssl.call(SSL_read, buf, size);
+//   if (ret >= 0) errorQueue.clear();
+//   else ALOGE("%s", errorQueue.toString().c_str());
+class Ssl {
+public:
+    explicit Ssl(bssl::UniquePtr<SSL> ssl) : mSsl(std::move(ssl)) {
+        LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+    }
+
+    template <typename Fn, typename... Args>
+    inline typename SslCaller<Fn, Args...>::ResultAndErrorQueue call(Fn fn, Args&&... args) {
+        return SslCaller<Fn, Args...>::call(fn, mSsl.get(), std::forward<Args>(args)...);
+    }
+
+    int getError(int ret) {
+        LOG_ALWAYS_FATAL_IF(mSsl == nullptr);
+        return SSL_get_error(mSsl.get(), ret);
+    }
+
+private:
+    bssl::UniquePtr<SSL> mSsl;
+};
+
+class RpcTransportTls : public RpcTransport {
+public:
+    RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
+          : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
+    Result<size_t> peek(void* buf, size_t size) override;
+    status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override;
+    status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override;
+
+private:
+    android::base::unique_fd mSocket;
+    Ssl mSsl;
+
+    static status_t isTriggered(FdTrigger* fdTrigger);
+};
+
+// Error code is errno.
+Result<size_t> RpcTransportTls::peek(void* buf, size_t size) {
+    size_t todo = std::min<size_t>(size, std::numeric_limits<int>::max());
+    auto [ret, errorQueue] = mSsl.call(SSL_peek, buf, static_cast<int>(todo));
+    if (ret < 0) {
+        int err = mSsl.getError(ret);
+        if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
+            // Seen EAGAIN / EWOULDBLOCK on recv(2) / send(2).
+            // Like RpcTransportRaw::peek(), don't handle it here.
+            return Error(EWOULDBLOCK) << "SSL_peek(): " << errorQueue.toString();
+        }
+        return Error() << "SSL_peek(): " << errorQueue.toString();
+    }
+    errorQueue.clear();
+    LOG_TLS_DETAIL("TLS: Peeked %d bytes!", ret);
+    return ret;
+}
+
+status_t RpcTransportTls::isTriggered(FdTrigger* fdTrigger) {
+    auto ret = fdTrigger->isTriggeredPolled();
+    if (!ret.ok()) {
+        ALOGE("%s: %s", __PRETTY_FUNCTION__, ret.error().message().c_str());
+        return ret.error().code() == 0 ? UNKNOWN_ERROR : -ret.error().code();
+    }
+    return OK;
+}
+
+status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
+                                                  size_t size) {
+    auto buffer = reinterpret_cast<const uint8_t*>(data);
+    const uint8_t* end = buffer + size;
+
+    MAYBE_WAIT_IN_FLAKE_MODE;
+
+    // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+    // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+    if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+
+    while (buffer < end) {
+        size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+        auto [writeSize, errorQueue] = mSsl.call(SSL_write, buffer, todo);
+        if (writeSize > 0) {
+            buffer += writeSize;
+            errorQueue.clear();
+            continue;
+        }
+        // SSL_write() should never return 0 unless BIO_write were to return 0.
+        int sslError = mSsl.getError(writeSize);
+        // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
+        //   triggerablePoll()-ed. Then additionalEvent is no longer necessary.
+        status_t pollStatus =
+                errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_write", POLLIN);
+        if (pollStatus != OK) return pollStatus;
+        // Do not advance buffer. Try SSL_write() again.
+    }
+    LOG_TLS_DETAIL("TLS: Sent %zu bytes!", size);
+    return OK;
+}
+
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) {
+    auto buffer = reinterpret_cast<uint8_t*>(data);
+    uint8_t* end = buffer + size;
+
+    MAYBE_WAIT_IN_FLAKE_MODE;
+
+    // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
+    // once. The trigger is also checked via triggerablePoll() after every SSL_write().
+    if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+
+    while (buffer < end) {
+        size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
+        auto [readSize, errorQueue] = mSsl.call(SSL_read, buffer, todo);
+        if (readSize > 0) {
+            buffer += readSize;
+            errorQueue.clear();
+            continue;
+        }
+        if (readSize == 0) {
+            // SSL_read() only returns 0 on EOF.
+            errorQueue.clear();
+            return DEAD_OBJECT;
+        }
+        int sslError = mSsl.getError(readSize);
+        status_t pollStatus =
+                errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_read");
+        if (pollStatus != OK) return pollStatus;
+        // Do not advance buffer. Try SSL_read() again.
+    }
+    LOG_TLS_DETAIL("TLS: Received %zu bytes!", size);
+    return OK;
+}
+
+// For |ssl|, set internal FD to |fd|, and do handshake. Handshake is triggerable by |fdTrigger|.
+bool setFdAndDoHandshake(Ssl* ssl, android::base::borrowed_fd fd, FdTrigger* fdTrigger) {
+    bssl::UniquePtr<BIO> bio = newSocketBio(fd);
+    TEST_AND_RETURN(false, bio != nullptr);
+    auto [_, errorQueue] = ssl->call(SSL_set_bio, bio.get(), bio.get());
+    (void)bio.release(); // SSL_set_bio takes ownership.
+    errorQueue.clear();
+
+    MAYBE_WAIT_IN_FLAKE_MODE;
+
+    while (true) {
+        auto [ret, errorQueue] = ssl->call(SSL_do_handshake);
+        if (ret > 0) {
+            errorQueue.clear();
+            return true;
+        }
+        if (ret == 0) {
+            // SSL_do_handshake() only returns 0 on EOF.
+            ALOGE("SSL_do_handshake(): EOF: %s", errorQueue.toString().c_str());
+            return false;
+        }
+        int sslError = ssl->getError(ret);
+        status_t pollStatus =
+                errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake");
+        if (pollStatus != OK) return false;
+    }
+}
+
+class RpcTransportCtxTlsServer : public RpcTransportCtx {
+public:
+    static std::unique_ptr<RpcTransportCtxTlsServer> create();
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd acceptedFd,
+                                               FdTrigger* fdTrigger) const override;
+
+private:
+    bssl::UniquePtr<SSL_CTX> mCtx;
+};
+
+std::unique_ptr<RpcTransportCtxTlsServer> RpcTransportCtxTlsServer::create() {
+    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+    TEST_AND_RETURN(nullptr, ctx != nullptr);
+
+    // Server use self-signing cert
+    auto evp_pkey = makeKeyPairForSelfSignedCert();
+    TEST_AND_RETURN(nullptr, evp_pkey != nullptr);
+    auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays);
+    TEST_AND_RETURN(nullptr, cert != nullptr);
+    TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
+    TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
+    // Require at least TLS 1.3
+    TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
+
+    if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
+        SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+    }
+
+    auto rpcTransportTlsServerCtx = std::make_unique<RpcTransportCtxTlsServer>();
+    rpcTransportTlsServerCtx->mCtx = std::move(ctx);
+    return rpcTransportTlsServerCtx;
+}
+
+std::unique_ptr<RpcTransport> RpcTransportCtxTlsServer::newTransport(
+        android::base::unique_fd acceptedFd, FdTrigger* fdTrigger) const {
+    bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
+    TEST_AND_RETURN(nullptr, ssl != nullptr);
+    Ssl wrapped(std::move(ssl));
+
+    wrapped.call(SSL_set_accept_state).errorQueue.clear();
+    TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, acceptedFd, fdTrigger));
+    return std::make_unique<RpcTransportTls>(std::move(acceptedFd), std::move(wrapped));
+}
+
+class RpcTransportCtxTlsClient : public RpcTransportCtx {
+public:
+    static std::unique_ptr<RpcTransportCtxTlsClient> create();
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd connectedFd,
+                                               FdTrigger* fdTrigger) const override;
+
+private:
+    bssl::UniquePtr<SSL_CTX> mCtx;
+};
+
+std::unique_ptr<RpcTransportCtxTlsClient> RpcTransportCtxTlsClient::create() {
+    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+    TEST_AND_RETURN(nullptr, ctx != nullptr);
+
+    // TODO(b/195166979): server should send certificate in a different channel, and client
+    //  should verify it here.
+    SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
+                              [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
+
+    // Require at least TLS 1.3
+    TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
+
+    if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
+        SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+    }
+
+    auto rpcTransportTlsClientCtx = std::make_unique<RpcTransportCtxTlsClient>();
+    rpcTransportTlsClientCtx->mCtx = std::move(ctx);
+    return rpcTransportTlsClientCtx;
+}
+
+std::unique_ptr<RpcTransport> RpcTransportCtxTlsClient::newTransport(
+        android::base::unique_fd connectedFd, FdTrigger* fdTrigger) const {
+    bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
+    TEST_AND_RETURN(nullptr, ssl != nullptr);
+    Ssl wrapped(std::move(ssl));
+
+    wrapped.call(SSL_set_connect_state).errorQueue.clear();
+    TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, connectedFd, fdTrigger));
+    return std::make_unique<RpcTransportTls>(std::move(connectedFd), std::move(wrapped));
+}
+
+} // namespace
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
+    return android::RpcTransportCtxTlsServer::create();
+}
+
+std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
+    return android::RpcTransportCtxTlsClient::create();
+}
+
+const char* RpcTransportCtxFactoryTls::toCString() const {
+    return "tls";
+}
+
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make() {
+    return std::unique_ptr<RpcTransportCtxFactoryTls>(new RpcTransportCtxFactoryTls());
+}
+
+} // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 2016483..0f8efd2 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -21,7 +21,7 @@
 #pragma clang diagnostic error "-Wpadded"
 
 enum : uint8_t {
-    RPC_CONNECTION_OPTION_REVERSE = 0x1,
+    RPC_CONNECTION_OPTION_INCOMING = 0x1, // default is outgoing
 };
 
 constexpr uint64_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
@@ -37,9 +37,20 @@
  * either as part of a new session or an existing session
  */
 struct RpcConnectionHeader {
+    uint32_t version; // maximum supported by caller
+    uint8_t reserver0[4];
     RpcWireAddress sessionId;
     uint8_t options;
-    uint8_t reserved[7];
+    uint8_t reserved1[7];
+};
+
+/**
+ * In response to an RpcConnectionHeader which corresponds to a new session,
+ * this returns information to the server.
+ */
+struct RpcNewSessionResponse {
+    uint32_t version; // maximum supported by callee <= maximum supported by caller
+    uint8_t reserved[4];
 };
 
 #define RPC_CONNECTION_INIT_OKAY "cci"
@@ -47,7 +58,7 @@
 /**
  * Whenever a client connection is setup, this is sent as the initial
  * transaction. The main use of this is in order to control the timing for when
- * a reverse connection is setup.
+ * an incoming connection is setup.
  */
 struct RpcOutgoingConnectionInit {
     char msg[4];
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 07f5778..59334b7 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -158,8 +158,10 @@
     LOG_ALWAYS_FATAL_IF(!forwardResult->hostPort().has_value());
 
     auto rpcSession = RpcSession::make();
-    if (!rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort())) {
-        ALOGE("Unable to set up inet client on host port %u", *forwardResult->hostPort());
+    if (status_t status = rpcSession->setupInetClient("127.0.0.1", *forwardResult->hostPort());
+        status != OK) {
+        ALOGE("Unable to set up inet client on host port %u: %s", *forwardResult->hostPort(),
+              statusToString(status).c_str());
         return nullptr;
     }
     auto binder = rpcSession->getRootObject();
@@ -167,9 +169,12 @@
         ALOGE("RpcSession::getRootObject returns nullptr");
         return nullptr;
     }
-    binder->attachObject(kDeviceServiceExtraId,
-                         static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
-                         &cleanupCommandResult);
+
+    LOG_ALWAYS_FATAL_IF(
+            nullptr !=
+            binder->attachObject(kDeviceServiceExtraId,
+                                 static_cast<void*>(new CommandResult(std::move(*result))), nullptr,
+                                 &cleanupCommandResult));
     return binder;
 }
 
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index dac3819..d25c038 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -23,20 +23,6 @@
 namespace android {
 namespace internal {
 
-// the libbinder parcel format is currently unstable
-
-// oldest version which is supported
-constexpr uint8_t kBinderWireFormatOldest = 1;
-// current version
-constexpr uint8_t kBinderWireFormatVersion = 1;
-
-Stability::Category Stability::Category::currentFromLevel(Level level) {
-    return {
-        .version = kBinderWireFormatVersion,
-        .level = level,
-    };
-}
-
 void Stability::forceDowngradeToStability(const sp<IBinder>& binder, Level level) {
     // Downgrading a remote binder would require also copying the version from
     // the binder sent here. In practice though, we don't need to downgrade the
@@ -44,8 +30,7 @@
     // what we can do to it.
     LOG_ALWAYS_FATAL_IF(!binder || !binder->localBinder(), "Can only downgrade local binder");
 
-    auto stability = Category::currentFromLevel(level);
-    status_t result = setRepr(binder.get(), stability.repr(), REPR_LOG | REPR_ALLOW_DOWNGRADE);
+    status_t result = setRepr(binder.get(), level, REPR_LOG | REPR_ALLOW_DOWNGRADE);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
@@ -61,41 +46,31 @@
     forceDowngradeToStability(binder, Level::VENDOR);
 }
 
-std::string Stability::Category::debugString() {
-    return levelString(level) + " wire protocol version "
-        + std::to_string(version);
-}
-
 void Stability::markCompilationUnit(IBinder* binder) {
-    auto stability = Category::currentFromLevel(getLocalLevel());
-    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+    status_t result = setRepr(binder, getLocalLevel(), REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 void Stability::markVintf(IBinder* binder) {
-    auto stability = Category::currentFromLevel(Level::VINTF);
-    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+    status_t result = setRepr(binder, Level::VINTF, REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 std::string Stability::debugToString(const sp<IBinder>& binder) {
-    auto stability = getCategory(binder.get());
-    return stability.debugString();
+    return levelString(getRepr(binder.get()));
 }
 
 void Stability::markVndk(IBinder* binder) {
-    auto stability = Category::currentFromLevel(Level::VENDOR);
-    status_t result = setRepr(binder, stability.repr(), REPR_LOG);
+    status_t result = setRepr(binder, Level::VENDOR, REPR_LOG);
     LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
 }
 
 bool Stability::requiresVintfDeclaration(const sp<IBinder>& binder) {
-    return check(getCategory(binder.get()), Level::VINTF);
+    return check(getRepr(binder.get()), Level::VINTF);
 }
 
 void Stability::tryMarkCompilationUnit(IBinder* binder) {
-    auto stability = Category::currentFromLevel(getLocalLevel());
-    (void) setRepr(binder, stability.repr(), REPR_NONE);
+    (void)setRepr(binder, getLocalLevel(), REPR_NONE);
 }
 
 Stability::Level Stability::getLocalLevel() {
@@ -117,92 +92,77 @@
 #endif
 }
 
-status_t Stability::setRepr(IBinder* binder, int32_t representation, uint32_t flags) {
+status_t Stability::setRepr(IBinder* binder, int32_t setting, uint32_t flags) {
     bool log = flags & REPR_LOG;
     bool allowDowngrade = flags & REPR_ALLOW_DOWNGRADE;
 
-    auto current = getCategory(binder);
-    auto setting = Category::fromRepr(representation);
-
-    // If we have ahold of a binder with a newer declared version, then it
-    // should support older versions, and we will simply write our parcels with
-    // the current wire parcel format.
-    if (setting.version < kBinderWireFormatOldest) {
-        // always log, because this shouldn't happen
-        ALOGE("Cannot accept binder with older binder wire protocol version "
-              "%u. Versions less than %u are unsupported.", setting.version,
-               kBinderWireFormatOldest);
-        return BAD_TYPE;
-    }
+    int16_t current = getRepr(binder);
 
     // null binder is always written w/ 'UNDECLARED' stability
     if (binder == nullptr) {
-        if (setting.level == UNDECLARED) {
+        if (setting == UNDECLARED) {
             return OK;
         } else {
             if (log) {
-                ALOGE("Null binder written with stability %s.",
-                    levelString(setting.level).c_str());
+                ALOGE("Null binder written with stability %s.", levelString(setting).c_str());
             }
             return BAD_TYPE;
         }
     }
 
-    if (!isDeclaredLevel(setting.level)) {
+    if (!isDeclaredLevel(setting)) {
         if (log) {
-            ALOGE("Can only set known stability, not %u.", setting.level);
+            ALOGE("Can only set known stability, not %d.", setting);
         }
         return BAD_TYPE;
     }
+    Level levelSetting = static_cast<Level>(setting);
 
     if (current == setting) return OK;
 
-    bool hasAlreadyBeenSet = current.repr() != 0;
-    bool isAllowedDowngrade = allowDowngrade && check(current, setting.level);
+    bool hasAlreadyBeenSet = current != Level::UNDECLARED;
+    bool isAllowedDowngrade = allowDowngrade && check(current, levelSetting);
     if (hasAlreadyBeenSet && !isAllowedDowngrade) {
         if (log) {
             ALOGE("Interface being set with %s but it is already marked as %s",
-                  setting.debugString().c_str(),
-                  current.debugString().c_str());
+                  levelString(setting).c_str(), levelString(current).c_str());
         }
         return BAD_TYPE;
     }
 
     if (isAllowedDowngrade) {
-        ALOGI("Interface set with %s downgraded to %s stability",
-              current.debugString().c_str(),
-              setting.debugString().c_str());
+        ALOGI("Interface set with %s downgraded to %s stability", levelString(current).c_str(),
+              levelString(setting).c_str());
     }
 
     BBinder* local = binder->localBinder();
     if (local != nullptr) {
-        local->mStability = setting.repr();
+        local->mStability = setting;
     } else {
-        binder->remoteBinder()->mStability = setting.repr();
+        binder->remoteBinder()->mStability = setting;
     }
 
     return OK;
 }
 
-Stability::Category Stability::getCategory(IBinder* binder) {
+int16_t Stability::getRepr(IBinder* binder) {
     if (binder == nullptr) {
-        return Category::currentFromLevel(Level::UNDECLARED);
+        return Level::UNDECLARED;
     }
 
     BBinder* local = binder->localBinder();
     if (local != nullptr) {
-        return Category::fromRepr(local->mStability);
+        return local->mStability;
     }
 
-    return Category::fromRepr(binder->remoteBinder()->mStability);
+    return binder->remoteBinder()->mStability;
 }
 
-bool Stability::check(Category provided, Level required) {
-    bool stable = (provided.level & required) == required;
+bool Stability::check(int16_t provided, Level required) {
+    bool stable = (provided & required) == required;
 
-    if (provided.level != UNDECLARED && !isDeclaredLevel(provided.level)) {
-        ALOGE("Unknown stability when checking interface stability %d.",
-              provided.level);
+    if (provided != UNDECLARED && !isDeclaredLevel(provided)) {
+        ALOGE("Unknown stability when checking interface stability %d.", provided);
 
         stable = false;
     }
@@ -210,11 +170,11 @@
     return stable;
 }
 
-bool Stability::isDeclaredLevel(Level stability) {
+bool Stability::isDeclaredLevel(int32_t stability) {
     return stability == VENDOR || stability == SYSTEM || stability == VINTF;
 }
 
-std::string Stability::levelString(Level level) {
+std::string Stability::levelString(int32_t level) {
     switch (level) {
         case Level::UNDECLARED: return "undeclared stability";
         case Level::VENDOR: return "vendor stability";
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index b5a078c..a44c578 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -130,13 +130,13 @@
     }
 
     // The remote threw an exception.  Get the message back.
-    String16 message;
+    std::optional<String16> message;
     status = parcel.readString16(&message);
     if (status != OK) {
         setFromStatusT(status);
         return status;
     }
-    mMessage = String8(message);
+    mMessage = String8(message.value_or(String16()));
 
     // Skip over the remote stack trace data
     int32_t remote_stack_trace_header_size;
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 748fa72..9c5ce67 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -16,6 +16,9 @@
       "name": "binderDriverInterfaceTest"
     },
     {
+      "name": "binderHostDeviceTest"
+    },
+    {
       "name": "binderTextOutputTest"
     },
     {
@@ -55,6 +58,9 @@
       "name": "CtsOsTestCases",
       "options": [
         {
+          "exclude-annotation": "android.platform.test.annotations.LargeTest"
+        },
+        {
           "exclude-filter": "android.os.cts.BuildTest#testSdkInt"
         },
         {
diff --git a/libs/binder/Utils.cpp b/libs/binder/Utils.cpp
index 90a4502..d2a5be1 100644
--- a/libs/binder/Utils.cpp
+++ b/libs/binder/Utils.cpp
@@ -18,10 +18,24 @@
 
 #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);
 }
 
-}   // 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 {};
+}
+
+} // namespace android
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index f94b158..1e383da 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -17,9 +17,14 @@
 #include <cstdint>
 #include <stddef.h>
 
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+
 namespace android {
 
 // avoid optimizations
 void zeroMemory(uint8_t* data, size_t size);
 
+android::base::Result<void> setNonBlocking(android::base::borrowed_fd fd);
+
 }   // namespace android
diff --git a/libs/binder/UtilsHost.cpp b/libs/binder/UtilsHost.cpp
index e524dab..d121ce2 100644
--- a/libs/binder/UtilsHost.cpp
+++ b/libs/binder/UtilsHost.cpp
@@ -111,15 +111,15 @@
     errWrite.reset();
     ret.pid = pid;
 
-    auto handlePoll = [](android::base::unique_fd* fd, const pollfd& pfd, std::string* s) {
+    auto handlePoll = [](android::base::unique_fd* fd, const pollfd* pfd, std::string* s) {
         if (!fd->ok()) return true;
-        if (pfd.revents & POLLIN) {
+        if (pfd->revents & POLLIN) {
             char buf[1024];
             ssize_t n = TEMP_FAILURE_RETRY(read(fd->get(), buf, sizeof(buf)));
             if (n < 0) return false;
             if (n > 0) *s += std::string_view(buf, n);
         }
-        if (pfd.revents & POLLHUP) {
+        if (pfd->revents & POLLHUP) {
             fd->reset();
         }
         return true;
@@ -142,9 +142,9 @@
         int pollRet = poll(fds, nfds, 1000 /* ms timeout */);
         if (pollRet == -1) return android::base::ErrnoError() << "poll()";
 
-        if (!handlePoll(&ret.outPipe, *outPollFd, &ret.stdout))
+        if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdout))
             return android::base::ErrnoError() << "read(stdout)";
-        if (!handlePoll(&ret.errPipe, *errPollFd, &ret.stderr))
+        if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderr))
             return android::base::ErrnoError() << "read(stderr)";
 
         if (end && end(ret)) return ret;
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index c69bb9e..a6d35c7 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -90,6 +90,8 @@
     static void         setLimitCallback(binder_proxy_limit_callback cb);
     static void         setBinderProxyCountWatermarks(int high, int low);
 
+    std::optional<int32_t> getDebugBinderHandle() const;
+
     class ObjectManager {
     public:
         ObjectManager();
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index c484d83..43fc5ff 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -259,21 +259,20 @@
      * but calls from different threads are allowed to be interleaved.
      *
      * This returns the object which is already attached. If this returns a
-     * non-null value, it means that attachObject failed. TODO(b/192023359):
-     * remove logs and add [[nodiscard]]
+     * non-null value, it means that attachObject failed (a given objectID can
+     * only be used once).
      */
-    virtual void* attachObject(const void* objectID, void* object, void* cleanupCookie,
-                               object_cleanup_func func) = 0;
+    [[nodiscard]] virtual void* attachObject(const void* objectID, void* object,
+                                             void* cleanupCookie, object_cleanup_func func) = 0;
     /**
      * Returns object attached with attachObject.
      */
-    virtual void*           findObject(const void* objectID) const = 0;
+    [[nodiscard]] virtual void* findObject(const void* objectID) const = 0;
     /**
      * Returns object attached with attachObject, and detaches it. This does not
-     * delete the object. This is equivalent to using attachObject to attach a null
-     * object.
+     * delete the object.
      */
-    virtual void* detachObject(const void* objectID) = 0;
+    [[nodiscard]] virtual void* detachObject(const void* objectID) = 0;
 
     /**
      * Use the lock that this binder contains internally. For instance, this can
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 8e46147..d152005 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -167,7 +167,8 @@
 bool checkCallingPermission(const String16& permission);
 bool checkCallingPermission(const String16& permission,
                             int32_t* outPid, int32_t* outUid);
-bool checkPermission(const String16& permission, pid_t pid, uid_t uid);
+bool checkPermission(const String16& permission, pid_t pid, uid_t uid,
+                     bool logPermissionFailure = true);
 
 #ifndef __ANDROID__
 // Create an IServiceManager that delegates the service manager on the device via adb.
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 02052ad..fd8ac62 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -245,9 +245,10 @@
     template<typename T>
     status_t            writeNullableParcelable(const std::optional<T>& parcelable)
             { return writeData(parcelable); }
-    template<typename T>
-    status_t            writeNullableParcelable(const std::unique_ptr<T>& parcelable) __attribute__((deprecated("use std::optional version instead")))
-            { return writeData(parcelable); }
+    template <typename T>
+    status_t writeNullableParcelable(const std::unique_ptr<T>& parcelable) {
+        return writeData(parcelable);
+    }
 
     status_t            writeParcelable(const Parcelable& parcelable);
 
@@ -401,9 +402,10 @@
     template<typename T>
     status_t            readParcelable(std::optional<T>* parcelable) const
             { return readData(parcelable); }
-    template<typename T>
-    status_t            readParcelable(std::unique_ptr<T>* parcelable) const __attribute__((deprecated("use std::optional version instead")))
-            { return readData(parcelable); }
+    template <typename T>
+    status_t readParcelable(std::unique_ptr<T>* parcelable) const {
+        return readData(parcelable);
+    }
 
     // If strong binder would be nullptr, readStrongBinder() returns an error.
     // TODO: T must be derived from IInterface, fix for clarity.
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index 9e4475c..42c85f9 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -42,6 +42,7 @@
         }
         mStability = other.mStability;
     }
+    ParcelableHolder(ParcelableHolder&& other) = default;
 
     status_t writeToParcel(Parcel* parcel) const override;
     status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c8d2857..bf3e7e0 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -19,6 +19,7 @@
 #include <binder/IBinder.h>
 #include <binder/RpcAddress.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -31,6 +32,7 @@
 
 namespace android {
 
+class FdTrigger;
 class RpcSocketAddress;
 
 /**
@@ -47,7 +49,8 @@
  */
 class RpcServer final : public virtual RefBase, private RpcSession::EventListener {
 public:
-    static sp<RpcServer> make();
+    static sp<RpcServer> make(
+            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
 
     /**
      * This represents a session for responses, e.g.:
@@ -57,12 +60,12 @@
      *     process B makes binder b and sends it to A
      *     A uses this 'back session' to send things back to B
      */
-    [[nodiscard]] bool setupUnixDomainServer(const char* path);
+    [[nodiscard]] status_t setupUnixDomainServer(const char* path);
 
     /**
      * Creates an RPC server at the current port.
      */
-    [[nodiscard]] bool setupVsockServer(unsigned int port);
+    [[nodiscard]] status_t setupVsockServer(unsigned int port);
 
     /**
      * Creates an RPC server at the current port using IPv4.
@@ -72,8 +75,14 @@
      * Set |port| to 0 to pick an ephemeral port; see discussion of
      * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
      * will be set to the picked port number, if it is not null.
+     *
+     * Set the IPv4 address for the socket to be listening on.
+     * "127.0.0.1" allows for local connections from the same device.
+     * "0.0.0.0" allows for connections on any IP address that the device may
+     * have
      */
-    [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+    [[nodiscard]] status_t setupInetServer(const char* address, unsigned int port,
+                                           unsigned int* assignedPort);
 
     /**
      * If setup*Server has been successful, return true. Otherwise return false.
@@ -89,7 +98,7 @@
      * Set up server using an external FD previously set up by releaseServer().
      * Return false if there's already a server.
      */
-    bool setupExternalServer(base::unique_fd serverFd);
+    [[nodiscard]] status_t setupExternalServer(base::unique_fd serverFd);
 
     void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
 
@@ -105,6 +114,13 @@
     size_t getMaxThreads();
 
     /**
+     * By default, the latest protocol version which is supported by a client is
+     * used. However, this can be used in order to prevent newer protocol
+     * versions from ever being used. This is expected to be useful for testing.
+     */
+    void setProtocolVersion(uint32_t version);
+
+    /**
      * The root object can be retrieved by any client, without any
      * authentication. TODO(b/183988761)
      *
@@ -154,16 +170,18 @@
 
 private:
     friend sp<RpcServer>;
-    RpcServer();
+    explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
 
-    void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+    void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
 
     static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
-    bool setupSocketServer(const RpcSocketAddress& address);
+    status_t setupSocketServer(const RpcSocketAddress& address);
 
+    const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
     bool mAgreedExperimental = false;
     size_t mMaxThreads = 1;
+    std::optional<uint32_t> mProtocolVersion;
     base::unique_fd mServer; // socket we are accepting sessions on
 
     std::mutex mLock; // for below
@@ -173,8 +191,9 @@
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
     std::map<RpcAddress, sp<RpcSession>> mSessions;
-    std::unique_ptr<RpcSession::FdTrigger> mShutdownTrigger;
+    std::unique_ptr<FdTrigger> mShutdownTrigger;
     std::condition_variable mShutdownCv;
+    std::unique_ptr<RpcTransportCtx> mCtx;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 69c2a1a..6e6eb74 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,6 +18,7 @@
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
 #include <binder/RpcAddress.h>
+#include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -36,6 +37,12 @@
 class RpcServer;
 class RpcSocketAddress;
 class RpcState;
+class RpcTransport;
+class FdTrigger;
+
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_NEXT = 0;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL = 0xF0000000;
+constexpr uint32_t RPC_WIRE_PROTOCOL_VERSION = RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL;
 
 /**
  * This represents a session (group of connections) between a client
@@ -44,7 +51,8 @@
  */
 class RpcSession final : public virtual RefBase {
 public:
-    static sp<RpcSession> make();
+    static sp<RpcSession> make(
+            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
 
     /**
      * Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -60,20 +68,40 @@
     size_t getMaxThreads();
 
     /**
+     * By default, the minimum of the supported versions of the client and the
+     * server will be used. Usually, this API should only be used for debugging.
+     */
+    [[nodiscard]] bool setProtocolVersion(uint32_t version);
+    std::optional<uint32_t> getProtocolVersion();
+
+    /**
      * This should be called once per thread, matching 'join' in the remote
      * process.
      */
-    [[nodiscard]] bool setupUnixDomainClient(const char* path);
+    [[nodiscard]] status_t setupUnixDomainClient(const char* path);
 
     /**
      * Connects to an RPC server at the CVD & port.
      */
-    [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
+    [[nodiscard]] status_t setupVsockClient(unsigned int cvd, unsigned int port);
 
     /**
      * Connects to an RPC server at the given address and port.
      */
-    [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
+    [[nodiscard]] status_t setupInetClient(const char* addr, unsigned int port);
+
+    /**
+     * Starts talking to an RPC server which has already been connected to. This
+     * is expected to be used when another process has permission to connect to
+     * a binder RPC service, but this process only has permission to talk to
+     * that service.
+     *
+     * For convenience, if 'fd' is -1, 'request' will be called.
+     *
+     * For future compatibility, 'request' should not reference any stack data.
+     */
+    [[nodiscard]] status_t setupPreconnectedClient(base::unique_fd fd,
+                                                   std::function<base::unique_fd()>&& request);
 
     /**
      * For debugging!
@@ -82,7 +110,7 @@
      * response will never be satisfied. All data sent here will be
      * unceremoniously cast down the bottomless pit, /dev/null.
      */
-    [[nodiscard]] bool addNullDebuggingClient();
+    [[nodiscard]] status_t addNullDebuggingClient();
 
     /**
      * Query the other side of the session for the root object hosted by that
@@ -131,66 +159,27 @@
     friend sp<RpcSession>;
     friend RpcServer;
     friend RpcState;
-    RpcSession();
-
-    /** This is not a pipe. */
-    struct FdTrigger {
-        /** Returns nullptr for error case */
-        static std::unique_ptr<FdTrigger> make();
-
-        /**
-         * Close the write end of the pipe so that the read end receives POLLHUP.
-         * Not threadsafe.
-         */
-        void trigger();
-
-        /**
-         * Whether this has been triggered.
-         */
-        bool isTriggered();
-
-        /**
-         * Poll for a read event.
-         *
-         * Return:
-         *   true - time to read!
-         *   false - trigger happened
-         */
-        status_t triggerablePollRead(base::borrowed_fd fd);
-
-        /**
-         * Read, but allow the read to be interrupted by this trigger.
-         *
-         * Return:
-         *   true - read succeeded at 'size'
-         *   false - interrupted (failure or trigger)
-         */
-        status_t interruptableReadFully(base::borrowed_fd fd, void* data, size_t size);
-
-    private:
-        base::unique_fd mWrite;
-        base::unique_fd mRead;
-    };
+    explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
 
     class EventListener : public virtual RefBase {
     public:
-        virtual void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
+        virtual void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
         virtual void onSessionIncomingThreadEnded() = 0;
     };
 
     class WaitForShutdownListener : public EventListener {
     public:
-        void onSessionLockedAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
+        void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
         void onSessionIncomingThreadEnded() override;
         void waitForShutdown(std::unique_lock<std::mutex>& lock);
 
     private:
         std::condition_variable mCv;
-        bool mShutdown = false;
+        volatile bool mShutdown = false;
     };
 
     struct RpcConnection : public RefBase {
-        base::unique_fd fd;
+        std::unique_ptr<RpcTransport> rpcTransport;
 
         // whether this or another thread is currently using this fd to make
         // or receive transactions.
@@ -216,20 +205,30 @@
         // Status of setup
         status_t status;
     };
-    PreJoinSetupResult preJoinSetup(base::unique_fd fd);
+    PreJoinSetupResult preJoinSetup(std::unique_ptr<RpcTransport> rpcTransport);
     // join on thread passed to preJoinThreadOwnership
     static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
 
-    [[nodiscard]] bool setupSocketClient(const RpcSocketAddress& address);
-    [[nodiscard]] bool setupOneSocketConnection(const RpcSocketAddress& address,
-                                                const RpcAddress& sessionId, bool server);
-    [[nodiscard]] bool addOutgoingConnection(base::unique_fd fd, bool init);
+    [[nodiscard]] status_t setupClient(
+            const std::function<status_t(const RpcAddress& sessionId, bool incoming)>&
+                    connectAndInit);
+    [[nodiscard]] status_t setupSocketClient(const RpcSocketAddress& address);
+    [[nodiscard]] status_t setupOneSocketConnection(const RpcSocketAddress& address,
+                                                    const RpcAddress& sessionId, bool incoming);
+    [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd, const RpcAddress& sessionId,
+                                                bool incoming);
+    [[nodiscard]] status_t addIncomingConnection(std::unique_ptr<RpcTransport> rpcTransport);
+    [[nodiscard]] status_t addOutgoingConnection(std::unique_ptr<RpcTransport> rpcTransport,
+                                                 bool init);
     [[nodiscard]] bool setForServer(const wp<RpcServer>& server,
                                     const wp<RpcSession::EventListener>& eventListener,
                                     const RpcAddress& sessionId);
-    sp<RpcConnection> assignIncomingConnectionToThisThread(base::unique_fd fd);
+    sp<RpcConnection> assignIncomingConnectionToThisThread(
+            std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
 
+    status_t initShutdownTrigger();
+
     enum class ConnectionUse {
         CLIENT,
         CLIENT_ASYNC,
@@ -260,6 +259,8 @@
         bool mReentrant = false;
     };
 
+    const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+
     // On the other side of a session, for each of mOutgoingConnections here, there should
     // be one of mIncomingConnections on the other side (and vice versa).
     //
@@ -287,12 +288,14 @@
     std::mutex mMutex; // for all below
 
     size_t mMaxThreads = 0;
+    std::optional<uint32_t> mProtocolVersion;
 
     std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
     size_t mWaitingThreads = 0;
     // hint index into clients, ++ when sending an async transaction
     size_t mOutgoingConnectionsOffset = 0;
     std::vector<sp<RpcConnection>> mOutgoingConnections;
+    size_t mMaxIncomingConnections = 0;
     std::vector<sp<RpcConnection>> mIncomingConnections;
     std::map<std::thread::id, std::thread> mThreads;
 };
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
new file mode 100644
index 0000000..1b69519
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation may use plain sockets or TLS.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+class FdTrigger;
+
+// Represents a socket connection.
+class RpcTransport {
+public:
+    virtual ~RpcTransport() = default;
+
+    // replacement of ::recv(MSG_PEEK). Error code may not be set if TLS is enabled.
+    virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
+
+    /**
+     * Read (or write), but allow to be interrupted by a trigger.
+     *
+     * Return:
+     *   OK - succeeded in completely processing 'size'
+     *   error - interrupted (failure or trigger)
+     */
+    virtual status_t interruptableWriteFully(FdTrigger *fdTrigger, const void *buf,
+                                             size_t size) = 0;
+    virtual status_t interruptableReadFully(FdTrigger *fdTrigger, void *buf, size_t size) = 0;
+
+protected:
+    RpcTransport() = default;
+};
+
+// Represents the context that generates the socket connection.
+class RpcTransportCtx {
+public:
+    virtual ~RpcTransportCtx() = default;
+
+    // Create a new RpcTransport object.
+    //
+    // Implemenion details: for TLS, this function may incur I/O. |fdTrigger| may be used
+    // to interrupt I/O. This function blocks until handshake is finished.
+    [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
+            android::base::unique_fd fd, FdTrigger *fdTrigger) const = 0;
+
+protected:
+    RpcTransportCtx() = default;
+};
+
+// A factory class that generates RpcTransportCtx.
+class RpcTransportCtxFactory {
+public:
+    virtual ~RpcTransportCtxFactory() = default;
+    // Creates server context.
+    [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newServerCtx() const = 0;
+
+    // Creates client context.
+    [[nodiscard]] virtual std::unique_ptr<RpcTransportCtx> newClientCtx() const = 0;
+
+    // Return a short description of this transport (e.g. "raw"). For logging / debugging / testing
+    // only.
+    [[nodiscard]] virtual const char *toCString() const = 0;
+
+protected:
+    RpcTransportCtxFactory() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcTransportRaw.h b/libs/binder/include/binder/RpcTransportRaw.h
new file mode 100644
index 0000000..6fb1f92
--- /dev/null
+++ b/libs/binder/include/binder/RpcTransportRaw.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+// 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 RpcTransportCtxFactoryRaw : 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:
+    RpcTransportCtxFactoryRaw() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index 629b565..ce4362f 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -44,10 +44,9 @@
 //   to old servers, and new servers know how to interpret the 8-byte result,
 //   they can still communicate.
 //
-// Every binder object has a stability level associated with it, and when
-// communicating with a binder, we make sure that the command we sent is one
-// that it knows how to process. The summary of stability of a binder is
-// represented by a Stability::Category object.
+// This class is specifically about (1). (2) is not currently tracked by
+// libbinder for regular binder calls, and everything on the system uses the
+// same copy of libbinder.
 
 class Stability final {
 public:
@@ -128,7 +127,10 @@
 
     static void tryMarkCompilationUnit(IBinder* binder);
 
-    enum Level : uint8_t {
+    // Currently, we use int16_t for Level so that it can fit in BBinder.
+    // However, on the wire, we have 4 bytes reserved for stability, so whenever
+    // we ingest a Level, we always accept an int32_t.
+    enum Level : int16_t {
         UNDECLARED = 0,
 
         VENDOR = 0b000011,
@@ -136,37 +138,6 @@
         VINTF = 0b111111,
     };
 
-    // This is the format of stability passed on the wire. It is only 2 bytes
-    // long, but 2 bytes in addition to this are reserved here. The difference
-    // in size is in order to free up space in BBinder, which is fixed by
-    // prebuilts inheriting from it.
-    struct Category {
-        static inline Category fromRepr(int16_t representation) {
-            return *reinterpret_cast<Category*>(&representation);
-        }
-        int16_t repr() const { return *reinterpret_cast<const int16_t*>(this); }
-        static inline Category currentFromLevel(Level level);
-
-        bool operator== (const Category& o) const {
-            return repr() == o.repr();
-        }
-        bool operator!= (const Category& o) const {
-            return !(*this == o);
-        }
-
-        std::string debugString();
-
-        // This is the version of the wire protocol associated with the host
-        // process of a particular binder. As the wire protocol changes, if
-        // sending a transaction to a binder with an old version, the Parcel
-        // class must write parcels according to the version documented here.
-        uint8_t version;
-
-        // bitmask of Stability::Level
-        Level level;
-    };
-    static_assert(sizeof(Category) == sizeof(int16_t));
-
     // returns the stability according to how this was built
     static Level getLocalLevel();
 
@@ -179,18 +150,18 @@
       REPR_ALLOW_DOWNGRADE = 2,
     };
     // applies stability to binder if stability level is known
-    __attribute__((warn_unused_result))
-    static status_t setRepr(IBinder* binder, int32_t representation, uint32_t flags);
+    __attribute__((warn_unused_result)) static status_t setRepr(IBinder* binder, int32_t setting,
+                                                                uint32_t flags);
 
     // get stability information as encoded on the wire
-    static Category getCategory(IBinder* binder);
+    static int16_t getRepr(IBinder* binder);
 
     // whether a transaction on binder is allowed, if the transaction
     // is done from a context with a specific stability level
-    static bool check(Category provided, Level required);
+    static bool check(int16_t provided, Level required);
 
-    static bool isDeclaredLevel(Level level);
-    static std::string levelString(Level level);
+    static bool isDeclaredLevel(int32_t level);
+    static std::string levelString(int32_t level);
 
     Stability();
 };
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
new file mode 100644
index 0000000..531aaa9
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+// Wraps the transport layer of RPC. Implementation uses TLS.
+
+#pragma once
+
+#include <binder/RpcTransport.h>
+
+namespace android {
+
+// RpcTransportCtxFactory with TLS enabled with self-signed certificate.
+class RpcTransportCtxFactoryTls : 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:
+    RpcTransportCtxFactoryTls() = default;
+};
+
+} // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index 68ec669..bcb13ae 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -19,16 +19,20 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
 
+using android::OK;
 using android::RpcServer;
 using android::RpcSession;
+using android::status_t;
+using android::statusToString;
 
 extern "C" {
 
 bool RunRpcServer(AIBinder* service, unsigned int port) {
     auto server = RpcServer::make();
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-    if (!server->setupVsockServer(port)) {
-        LOG(ERROR) << "Failed to set up vsock server with port " << port;
+    if (status_t status = server->setupVsockServer(port); status != OK) {
+        LOG(ERROR) << "Failed to set up vsock server with port " << port
+                   << " error: " << statusToString(status).c_str();
         return false;
     }
     server->setRootObject(AIBinder_toPlatformBinder(service));
@@ -41,8 +45,9 @@
 
 AIBinder* RpcClient(unsigned int cid, unsigned int port) {
     auto session = RpcSession::make();
-    if (!session->setupVsockClient(cid, port)) {
-        LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port;
+    if (status_t status = session->setupVsockClient(cid, port); status != OK) {
+        LOG(ERROR) << "Failed to set up vsock client with CID " << cid << " and port " << port
+                   << " error: " << statusToString(status).c_str();
         return nullptr;
     }
     return AIBinder_fromPlatformBinder(session->getRootObject());
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 266ef37..11e9fc5 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -47,7 +47,8 @@
 void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
 
 static void attach(const sp<IBinder>& binder) {
-    binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
+    // can only attach once
+    CHECK_EQ(nullptr, binder->attachObject(kId, kValue, nullptr /*cookie*/, clean));
 }
 static bool has(const sp<IBinder>& binder) {
     return binder != nullptr && binder->findObject(kId) == kValue;
@@ -81,8 +82,8 @@
         const String16& currentDescriptor = mClazz->getInterfaceDescriptor();
         if (newDescriptor == currentDescriptor) {
             LOG(ERROR) << __func__ << ": Class descriptors '" << currentDescriptor
-                       << "' match during associateClass, but they are different class objects. "
-                          "Class descriptor collision?";
+                       << "' match during associateClass, but they are different class objects ("
+                       << clazz << " vs " << mClazz << "). Class descriptor collision?";
         } else {
             LOG(ERROR) << __func__
                        << ": Class cannot be associated on object which already has a class. "
@@ -232,13 +233,15 @@
 
 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. Since a strong reference to this ABpBinder object should no
-    // longer be able to exist at the time of this method call, there is no longer a need to
-    // recover it.
+    // 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()->detachObject(ABpBinderTag::kId));
-    if (value) ABpBinderTag::clean(ABpBinderTag::kId, value, nullptr /*cookie*/);
+            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);
 }
@@ -251,6 +254,9 @@
         return static_cast<ABBinder*>(binder.get());
     }
 
+    // The following code ensures that for a given binder object (remote or local), if it is not an
+    // ABBinder then at most one ABpBinder object exists in a given process representing it.
+
     auto* value = static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
     if (value == nullptr) {
         value = new ABpBinderTag::Value;
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index 6c44726..5de64f8 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -55,6 +55,12 @@
         std::call_once(mFlagThis, [&]() {
             __assert(__FILE__, __LINE__, "SharedRefBase: no ref created during lifetime");
         });
+
+        if (ref() != nullptr) {
+            __assert(__FILE__, __LINE__,
+                     "SharedRefBase: destructed but still able to lock weak_ptr. Is this object "
+                     "double-owned?");
+        }
     }
 
     /**
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 5092d87..563d011 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -469,6 +469,22 @@
 }
 
 /**
+ * Convenience API for writing a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_writeNullableParcelable(AParcel* parcel,
+                                                              const std::unique_ptr<P>& p) {
+    if (!p) {
+        return AParcel_writeInt32(parcel, 0);  // null
+    }
+    binder_status_t status = AParcel_writeInt32(parcel, 1);  // non-null
+    if (status != STATUS_OK) {
+        return status;
+    }
+    return p->writeToParcel(parcel);
+}
+
+/**
  * Convenience API for reading a nullable parcelable.
  */
 template <typename P>
@@ -488,6 +504,25 @@
 }
 
 /**
+ * Convenience API for reading a nullable parcelable.
+ */
+template <typename P>
+static inline binder_status_t AParcel_readNullableParcelable(const AParcel* parcel,
+                                                             std::unique_ptr<P>* p) {
+    int32_t null;
+    binder_status_t status = AParcel_readInt32(parcel, &null);
+    if (status != STATUS_OK) {
+        return status;
+    }
+    if (null == 0) {
+        p->reset();
+        return STATUS_OK;
+    }
+    *p = std::make_unique<P>();
+    return (*p)->readFromParcel(parcel);
+}
+
+/**
  * Writes a parcelable object of type P inside a std::vector<P> at index 'index' to 'parcel'.
  */
 template <typename P>
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 2277148..aa3b978 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -46,7 +46,7 @@
     AParcelableHolder() = delete;
     explicit AParcelableHolder(parcelable_stability_t stability)
         : mParcel(AParcel_create()), mStability(stability) {}
-
+    AParcelableHolder(AParcelableHolder&& other) = default;
     virtual ~AParcelableHolder() = default;
 
     binder_status_t writeToParcel(AParcel* parcel) const {
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 1c43948..b5c06e9 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -39,6 +39,7 @@
 #include <condition_variable>
 #include <iostream>
 #include <mutex>
+#include <thread>
 #include "android/binder_ibinder.h"
 
 using namespace android;
@@ -223,6 +224,17 @@
     return true;
 }
 
+TEST(NdkBinder, DetectDoubleOwn) {
+    auto badService = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+    EXPECT_DEATH(std::shared_ptr<MyBinderNdkUnitTest>(badService.get()),
+                 "Is this object double-owned?");
+}
+
+TEST(NdkBinder, DetectNoSharedRefBaseCreated) {
+    EXPECT_DEATH(std::make_shared<MyBinderNdkUnitTest>(),
+                 "SharedRefBase: no ref created during lifetime");
+}
+
 TEST(NdkBinder, GetServiceThatDoesntExist) {
     sp<IFoo> foo = IFoo::getService("asdfghkl;");
     EXPECT_EQ(nullptr, foo.get());
@@ -250,6 +262,27 @@
     EXPECT_EQ(2, out);
 }
 
+TEST(NdkBinder, GetTestServiceStressTest) {
+    // libbinder has some complicated logic to make sure only one instance of
+    // ABpBinder is associated with each binder.
+
+    constexpr size_t kNumThreads = 10;
+    constexpr size_t kNumCalls = 1000;
+    std::vector<std::thread> threads;
+
+    for (size_t i = 0; i < kNumThreads; i++) {
+        threads.push_back(std::thread([&]() {
+            for (size_t j = 0; j < kNumCalls; j++) {
+                auto binder =
+                        ndk::SpAIBinder(AServiceManager_checkService(IFoo::kSomeInstanceName));
+                EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get()));
+            }
+        }));
+    }
+
+    for (auto& thread : threads) thread.join();
+}
+
 void defaultInstanceCounter(const char* instance, void* context) {
     if (strcmp(instance, "default") == 0) {
         ++*(size_t*)(context);
diff --git a/libs/binder/run_rpc_tests.sh b/libs/binder/run_rpc_tests.sh
new file mode 100755
index 0000000..7ba682d
--- /dev/null
+++ b/libs/binder/run_rpc_tests.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+set -ex
+
+if [ $# -eq 0 ]; then
+  :
+elif [ $# -eq 1 ] && [[ "$1" =~ ^host|device$ ]]; then
+  :
+else
+  echo "usage: $0 [device|host]"
+  false
+fi
+
+# Script maintained for RPC development, while it is active, to quickly run
+# tests. Generally, to match VTS/presubmit behavior, 'atest' should be used.
+
+function dtest () { adb shell /data/nativetest64/$1/$@; }
+function hbench () { $AT/out/host/linux-x86/benchmarktest/$1/$@; }
+function hfuzz () { time $ANDROID_HOST_OUT/fuzz/x86_64/$1/$@; }
+function htest () { time $ANDROID_BUILD_TOP/out/host/linux-x86/nativetest/$1/$@; }
+function pdtest () { adb wait-for-device && adb shell mkdir -p /data/nativetest64/$1 && adb push $OUT/data/nativetest64/$1/$1 /data/nativetest64/$1/$1 && dtest $@; }
+function dbench () { adb shell /data/benchmarktest64/$1/$@; }
+function pdbench () { adb wait-for-device && adb shell mkdir -p /data/benchmarktest64/$1 && adb push $OUT/data/benchmarktest64/$1/$1 /data/benchmarktest64/$1/$1 && dbench $@; }
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode \
+  binderRpcTest \
+  binder_rpc_fuzzer \
+  binder_parcel_fuzzer \
+  binderLibTest \
+  binderRpcBenchmark
+
+if ! [ "$1" = "device" ]; then
+  htest binderRpcTest
+  hbench binderRpcBenchmark
+  hfuzz binder_rpc_fuzzer -max_total_time=30
+  hfuzz binder_parcel_fuzzer -max_total_time=30
+fi
+
+if ! [ "$1" = "host" ]; then
+  pdtest binderRpcTest
+  pdtest binderLibTest
+  pdbench binderRpcBenchmark
+fi
+
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index f79b1b7..dd0c7b8 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -897,7 +897,7 @@
 #[macro_export]
 macro_rules! declare_binder_enum {
     {
-        $enum:ident : $backing:ty {
+        $enum:ident : [$backing:ty; $size:expr] {
             $( $name:ident = $value:expr, )*
         }
     } => {
@@ -905,6 +905,11 @@
         pub struct $enum(pub $backing);
         impl $enum {
             $( pub const $name: Self = Self($value); )*
+
+            #[inline(always)]
+            pub const fn enum_values() -> [Self; $size] {
+                [$(Self::$name),*]
+            }
         }
 
         impl $crate::parcel::Serialize for $enum {
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a3f7620..a0e991c 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -493,7 +493,7 @@
     assert_eq!(parcel.read::<i32>().unwrap(), 15);
     let start = parcel.get_data_position();
 
-    assert_eq!(parcel.read::<bool>().unwrap(), true);
+    assert!(parcel.read::<bool>().unwrap());
 
     unsafe {
         assert!(parcel.set_data_position(start).is_ok());
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 20e9178..179b7c8 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -23,7 +23,7 @@
 use crate::sys;
 
 use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 
 /// Rust version of the Java class android.os.ParcelFileDescriptor
 #[derive(Debug)]
@@ -48,6 +48,12 @@
     }
 }
 
+impl AsRawFd for ParcelFileDescriptor {
+    fn as_raw_fd(&self) -> RawFd {
+        self.0.as_raw_fd()
+    }
+}
+
 impl Serialize for ParcelFileDescriptor {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         let fd = self.0.as_raw_fd();
diff --git a/libs/binder/rust/src/parcel/parcelable.rs b/libs/binder/rust/src/parcel/parcelable.rs
index 956ecfe..56c6165 100644
--- a/libs/binder/rust/src/parcel/parcelable.rs
+++ b/libs/binder/rust/src/parcel/parcelable.rs
@@ -764,6 +764,30 @@
     }
 }
 
+impl<T: Serialize> Serialize for Box<T> {
+    fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
+        Serialize::serialize(&**self, parcel)
+    }
+}
+
+impl<T: Deserialize> Deserialize for Box<T> {
+    fn deserialize(parcel: &Parcel) -> Result<Self> {
+        Deserialize::deserialize(parcel).map(Box::new)
+    }
+}
+
+impl<T: SerializeOption> SerializeOption for Box<T> {
+    fn serialize_option(this: Option<&Self>, parcel: &mut Parcel) -> Result<()> {
+        SerializeOption::serialize_option(this.map(|inner| &**inner), parcel)
+    }
+}
+
+impl<T: DeserializeOption> DeserializeOption for Box<T> {
+    fn deserialize_option(parcel: &Parcel) -> Result<Option<Self>> {
+        DeserializeOption::deserialize_option(parcel).map(|t| t.map(Box::new))
+    }
+}
+
 #[test]
 fn test_custom_parcelable() {
     use crate::binder::Interface;
diff --git a/libs/binder/rust/tests/ndk_rust_interop.rs b/libs/binder/rust/tests/ndk_rust_interop.rs
index 4702e45..415ede1 100644
--- a/libs/binder/rust/tests/ndk_rust_interop.rs
+++ b/libs/binder/rust/tests/ndk_rust_interop.rs
@@ -90,7 +90,7 @@
 pub unsafe extern "C" fn rust_start_service(service_name: *const c_char) -> c_int {
     let service_name = CStr::from_ptr(service_name).to_str().unwrap();
     let service = BnBinderRustNdkInteropTest::new_binder(Service, BinderFeatures::default());
-    match binder::add_service(&service_name, service.as_binder()) {
+    match binder::add_service(service_name, service.as_binder()) {
         Ok(_) => StatusCode::OK as c_int,
         Err(e) => e as c_int,
     }
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 62df9b7..9811cdf 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -23,9 +23,12 @@
 #include <android-base/logging.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
+#include <android/debug/BnAdbCallback.h>
+#include <android/debug/IAdbManager.h>
 #include <android/os/BnServiceManager.h>
 #include <android/os/IServiceManager.h>
 #include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
 
 using android::BBinder;
@@ -33,6 +36,7 @@
 using android::OK;
 using android::RpcServer;
 using android::sp;
+using android::status_t;
 using android::statusToString;
 using android::String16;
 using android::base::Basename;
@@ -47,7 +51,9 @@
 
 namespace {
 
+const char* kLocalInetAddress = "127.0.0.1";
 using ServiceRetriever = decltype(&android::IServiceManager::checkService);
+using android::debug::IAdbManager;
 
 int Usage(const char* program) {
     auto basename = Basename(program);
@@ -86,8 +92,8 @@
     }
     rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     unsigned int port;
-    if (!rpcServer->setupInetServer(0, &port)) {
-        LOG(ERROR) << "setupInetServer failed";
+    if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+        LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
         return EX_SOFTWARE;
     }
     auto socket = rpcServer->releaseServer();
@@ -199,8 +205,8 @@
     rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     rpcServer->setRootObject(service);
     unsigned int port;
-    if (!rpcServer->setupInetServer(0, &port)) {
-        LOG(ERROR) << "Unable to set up inet server";
+    if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+        LOG(ERROR) << "Unable to set up inet server: " << statusToString(status);
         return EX_SOFTWARE;
     }
     LOG(INFO) << "Finish wrapping servicemanager with RPC on port " << port;
@@ -211,6 +217,25 @@
     __builtin_unreachable();
 }
 
+class AdbCallback : public android::debug::BnAdbCallback {
+public:
+    android::binder::Status onDebuggingChanged(bool enabled,
+                                               android::debug::AdbTransportType) override {
+        if (!enabled) {
+            LOG(ERROR) << "ADB debugging disabled, exiting.";
+            exit(EX_SOFTWARE);
+        }
+        return android::binder::Status::ok();
+    }
+};
+
+void exitOnAdbDebuggingDisabled() {
+    auto adb = android::waitForService<IAdbManager>(String16("adb"));
+    CHECK(adb != nullptr) << "Unable to retrieve service adb";
+    auto status = adb->registerCallback(sp<AdbCallback>::make());
+    CHECK(status.isOk()) << "Unable to call IAdbManager::registerCallback: " << status;
+}
+
 // Log to logd. For warning and more severe messages, also log to stderr.
 class ServiceDispatcherLogger {
 public:
@@ -251,6 +276,10 @@
         }
     }
 
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    android::ProcessState::self()->startThreadPool();
+    exitOnAdbDebuggingDisabled();
+
     if (optind + 1 != argc) return Usage(argv[0]);
     auto name = argv[optind];
 
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 565f88e..24afcf6 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -348,3 +348,49 @@
         },
     },
 }
+
+cc_test_host {
+    name: "binderHostDeviceTest",
+    defaults: ["binder_test_defaults"],
+    srcs: ["binderHostDeviceTest.cpp"],
+    test_config: "binderHostDeviceTest.xml",
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "libgmock",
+    ],
+    target_required: [
+        "binderHostDeviceTestService",
+    ],
+    test_suites: ["general-tests"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    test_options: {
+        unit_test: false,
+    },
+}
+
+cc_test {
+    name: "binderHostDeviceTestService",
+    // The binary is named differently from the module so that PushFilePreparer pushes the binary
+    // directly, not the test module directory.
+    stem: "binderHostDeviceTest-service",
+    defaults: ["binder_test_defaults"],
+    gtest: false,
+    auto_gen_config: false,
+    srcs: ["binderHostDeviceTestService.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+    test_suites: ["general-tests"],
+}
diff --git a/libs/binder/tests/IBinderRpcBenchmark.aidl b/libs/binder/tests/IBinderRpcBenchmark.aidl
index 1457422..2baf680 100644
--- a/libs/binder/tests/IBinderRpcBenchmark.aidl
+++ b/libs/binder/tests/IBinderRpcBenchmark.aidl
@@ -17,4 +17,5 @@
 interface IBinderRpcBenchmark {
     @utf8InCpp String repeatString(@utf8InCpp String str);
     IBinder repeatBinder(IBinder binder);
+    byte[] repeatBytes(in byte[] bytes);
 }
diff --git a/libs/binder/tests/binderClearBufTest.cpp b/libs/binder/tests/binderClearBufTest.cpp
index 2d30c8d..307151c 100644
--- a/libs/binder/tests/binderClearBufTest.cpp
+++ b/libs/binder/tests/binderClearBufTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/hex.h>
 #include <android-base/logging.h>
 #include <binder/Binder.h>
 #include <binder/IBinder.h>
@@ -30,22 +31,6 @@
 
 const String16 kServerName = String16("binderClearBuf");
 
-std::string hexString(const void* bytes, size_t len) {
-    if (bytes == nullptr) return "<null>";
-
-    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
-    char chars[] = "0123456789abcdef";
-    std::string result;
-    result.resize(len * 2);
-
-    for (size_t i = 0; i < len; i++) {
-        result[2 * i] = chars[bytes8[i] >> 4];
-        result[2 * i + 1] = chars[bytes8[i] & 0xf];
-    }
-
-    return result;
-}
-
 class FooBar : public BBinder {
  public:
     enum {
@@ -83,7 +68,7 @@
             lastReply = reply.data();
             lastReplySize = reply.dataSize();
         }
-        *outBuffer = hexString(lastReply, lastReplySize);
+        *outBuffer = android::base::HexString(lastReply, lastReplySize);
         return result;
     }
 };
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
new file mode 100644
index 0000000..3f72b8f
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+// Integration test for servicedispatcher + adb forward. Requires ADB.
+
+#include <stdlib.h>
+
+#include <vector>
+
+#include <android-base/parsebool.h>
+#include <android-base/result-gmock.h>
+#include <android-base/strings.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/RpcSession.h>
+
+#include "../UtilsHost.h"
+
+using ::android::setDefaultServiceManager;
+using ::android::base::EndsWith;
+using ::android::base::Join;
+using ::android::base::ParseBool;
+using ::android::base::ParseBoolResult;
+using ::android::base::Split;
+using ::android::base::StartsWith;
+using ::android::base::StringReplace;
+using ::android::base::Trim;
+using ::android::base::testing::Ok;
+using ::std::chrono_literals::operator""ms;
+using ::std::string_literals::operator""s;
+using ::testing::AllOf;
+using ::testing::Contains;
+using ::testing::ContainsRegex;
+using ::testing::ExplainMatchResult;
+using ::testing::InitGoogleMock;
+
+namespace android {
+
+namespace {
+
+constexpr const char* kServiceBinary = "/data/local/tmp/binderHostDeviceTest-service";
+constexpr const char* kServiceName = "binderHostDeviceTestService";
+constexpr const char* kDescriptor = "android.binderHostDeviceTestService";
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+    *result_listener << statusToString(arg);
+    return expected == arg;
+}
+
+void initHostRpcServiceManagerOnce() {
+    static std::once_flag gSmOnce;
+    std::call_once(gSmOnce, [] { setDefaultServiceManager(createRpcDelegateServiceManager()); });
+}
+
+// Test for host service manager.
+class HostDeviceTest : public ::testing::Test {
+public:
+    void SetUp() override {
+        auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
+        ASSERT_THAT(debuggableResult, Ok());
+        ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
+        auto debuggableBool = ParseBool(Trim(debuggableResult->stdout));
+        ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdout);
+        if (debuggableBool == ParseBoolResult::kFalse) {
+            GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdout);
+        }
+
+        auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
+        ASSERT_THAT(lsResult, Ok());
+        if (lsResult->exitCode != 0) {
+            GTEST_SKIP() << "b/182914638: until feature is fully enabled, skip test on devices "
+                            "without servicedispatcher";
+        }
+
+        initHostRpcServiceManagerOnce();
+        ASSERT_NE(nullptr, defaultServiceManager()) << "No defaultServiceManager() over RPC";
+
+        auto service = execute({"adb", "shell", kServiceBinary, kServiceName, kDescriptor},
+                               &CommandResult::stdoutEndsWithNewLine);
+        ASSERT_THAT(service, Ok());
+        ASSERT_EQ(std::nullopt, service->exitCode) << *service;
+        mService = std::move(*service);
+    }
+    void TearDown() override { mService.reset(); }
+
+    [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
+        auto rpcSession = RpcSession::make();
+        if (status_t status = rpcSession->setupInetClient("127.0.0.1", hostPort); status != OK) {
+            ADD_FAILURE() << "Failed to setupInetClient on " << hostPort << ": "
+                          << statusToString(status);
+            return nullptr;
+        }
+        return rpcSession->getRootObject();
+    }
+
+private:
+    std::optional<CommandResult> mService;
+};
+
+TEST_F(HostDeviceTest, List) {
+    auto sm = defaultServiceManager();
+
+    auto services = sm->listServices();
+    ASSERT_THAT(services, Contains(String16(kServiceName)));
+}
+
+TEST_F(HostDeviceTest, CheckService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->checkService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, GetService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->getService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, WaitForService) {
+    auto sm = defaultServiceManager();
+
+    auto rpcBinder = sm->waitForService(String16(kServiceName));
+    ASSERT_NE(nullptr, rpcBinder);
+
+    EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+    EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+}
+
+TEST_F(HostDeviceTest, TenClients) {
+    auto sm = defaultServiceManager();
+
+    auto threadFn = [&] {
+        auto rpcBinder = sm->checkService(String16(kServiceName));
+        ASSERT_NE(nullptr, rpcBinder);
+
+        EXPECT_THAT(rpcBinder->pingBinder(), StatusEq(OK));
+        EXPECT_EQ(String16(kDescriptor), rpcBinder->getInterfaceDescriptor());
+    };
+
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < 10; ++i) threads.emplace_back(threadFn);
+    for (auto& thread : threads) thread.join();
+}
+
+} // namespace
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.xml b/libs/binder/tests/binderHostDeviceTest.xml
new file mode 100644
index 0000000..250ed3a
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs binderHostDeviceTest.">
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push-file" key="binderHostDeviceTest-service"
+                value="/data/local/tmp/binderHostDeviceTest-service"/>
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.binary.ExecutableHostTest">
+        <option name="binary" value="binderHostDeviceTest"/>
+    </test>
+</configuration>
diff --git a/libs/binder/tests/binderHostDeviceTestService.cpp b/libs/binder/tests/binderHostDeviceTestService.cpp
new file mode 100644
index 0000000..6ddd2e7
--- /dev/null
+++ b/libs/binder/tests/binderHostDeviceTestService.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+#include <sysexits.h>
+
+#include <android-base/logging.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+namespace {
+class Service : public android::BBinder {
+public:
+    Service(std::string_view descriptor) : mDescriptor(descriptor.data(), descriptor.size()) {}
+    const android::String16& getInterfaceDescriptor() const override { return mDescriptor; }
+
+private:
+    android::String16 mDescriptor;
+};
+} // namespace
+
+int main(int argc, char** argv) {
+    if (argc != 3) {
+        std::cerr << "usage: " << argv[0] << " <service-name> <interface-descriptor>" << std::endl;
+        return EX_USAGE;
+    }
+    auto name = argv[1];
+    auto descriptor = argv[2];
+
+    auto sm = android::defaultServiceManager();
+    CHECK(sm != nullptr);
+    auto service = android::sp<Service>::make(descriptor);
+    auto status = sm->addService(android::String16(name), service);
+    CHECK_EQ(android::OK, status) << android::statusToString(status);
+    std::cout << "running..." << std::endl;
+    android::ProcessState::self()->startThreadPool();
+    android::IPCThreadState::self()->joinThreadPool();
+    LOG(ERROR) << "joinThreadPool exits";
+    return EX_SOFTWARE;
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 4c3225f..eea7d8c 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1192,8 +1192,8 @@
         if (rpcServer == nullptr) return {};
         rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
         unsigned int port;
-        if (!rpcServer->setupInetServer(0, &port)) {
-            ADD_FAILURE() << "setupInetServer failed";
+        if (status_t status = rpcServer->setupInetServer("127.0.0.1", 0, &port); status != OK) {
+            ADD_FAILURE() << "setupInetServer failed" << statusToString(status);
             return {};
         }
         return {rpcServer->releaseServer(), port};
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index a457e67..e430c28 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -18,21 +18,33 @@
 #include <android-base/logging.h>
 #include <benchmark/benchmark.h>
 #include <binder/Binder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
 
 #include <thread>
 
+#include <signal.h>
+#include <sys/prctl.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 using android::BBinder;
+using android::defaultServiceManager;
 using android::IBinder;
 using android::interface_cast;
+using android::IPCThreadState;
+using android::IServiceManager;
 using android::OK;
+using android::ProcessState;
 using android::RpcServer;
 using android::RpcSession;
 using android::sp;
+using android::status_t;
+using android::statusToString;
+using android::String16;
 using android::binder::Status;
 
 class MyBinderRpcBenchmark : public BnBinderRpcBenchmark {
@@ -40,34 +52,60 @@
         *out = str;
         return Status::ok();
     }
-    Status repeatBinder(const sp<IBinder>& str, sp<IBinder>* out) override {
-        *out = str;
+    Status repeatBinder(const sp<IBinder>& binder, sp<IBinder>* out) override {
+        *out = binder;
+        return Status::ok();
+    }
+    Status repeatBytes(const std::vector<uint8_t>& bytes, std::vector<uint8_t>* out) override {
+        *out = bytes;
         return Status::ok();
     }
 };
 
-static sp<RpcSession> gSession = RpcSession::make();
+enum Transport {
+    KERNEL,
+    RPC,
+};
 
-void BM_getRootObject(benchmark::State& state) {
-    while (state.KeepRunning()) {
-        CHECK(gSession->getRootObject() != nullptr);
+static const std::initializer_list<int64_t> kTransportList = {
+#ifdef __BIONIC__
+        Transport::KERNEL,
+#endif
+        Transport::RPC};
+
+static sp<RpcSession> gSession = RpcSession::make();
+#ifdef __BIONIC__
+static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
+static sp<IBinder> gKernelBinder;
+#endif
+
+static sp<IBinder> getBinderForOptions(benchmark::State& state) {
+    Transport transport = static_cast<Transport>(state.range(0));
+    switch (transport) {
+#ifdef __BIONIC__
+        case KERNEL:
+            return gKernelBinder;
+#endif
+        case RPC:
+            return gSession->getRootObject();
+        default:
+            LOG(FATAL) << "Unknown transport value: " << transport;
+            return nullptr;
     }
 }
-BENCHMARK(BM_getRootObject);
 
 void BM_pingTransaction(benchmark::State& state) {
-    sp<IBinder> binder = gSession->getRootObject();
-    CHECK(binder != nullptr);
+    sp<IBinder> binder = getBinderForOptions(state);
 
     while (state.KeepRunning()) {
         CHECK_EQ(OK, binder->pingBinder());
     }
 }
-BENCHMARK(BM_pingTransaction);
+BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
 
-void BM_repeatString(benchmark::State& state) {
-    sp<IBinder> binder = gSession->getRootObject();
-    CHECK(binder != nullptr);
+void BM_repeatTwoPageString(benchmark::State& state) {
+    sp<IBinder> binder = getBinderForOptions(state);
+
     sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
     CHECK(iface != nullptr);
 
@@ -92,10 +130,30 @@
         CHECK(ret.isOk()) << ret;
     }
 }
-BENCHMARK(BM_repeatString);
+BENCHMARK(BM_repeatTwoPageString)->ArgsProduct({kTransportList});
+
+void BM_throughputForTransportAndBytes(benchmark::State& state) {
+    sp<IBinder> binder = getBinderForOptions(state);
+    sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
+    CHECK(iface != nullptr);
+
+    std::vector<uint8_t> bytes = std::vector<uint8_t>(state.range(1));
+    for (size_t i = 0; i < bytes.size(); i++) {
+        bytes[i] = i % 256;
+    }
+
+    while (state.KeepRunning()) {
+        std::vector<uint8_t> out;
+        Status ret = iface->repeatBytes(bytes, &out);
+        CHECK(ret.isOk()) << ret;
+    }
+}
+BENCHMARK(BM_throughputForTransportAndBytes)
+        ->ArgsProduct({kTransportList,
+                       {64, 1024, 2048, 4096, 8182, 16364, 32728, 65535, 65536, 65537}});
 
 void BM_repeatBinder(benchmark::State& state) {
-    sp<IBinder> binder = gSession->getRootObject();
+    sp<IBinder> binder = getBinderForOptions(state);
     CHECK(binder != nullptr);
     sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
     CHECK(iface != nullptr);
@@ -109,7 +167,7 @@
         CHECK(ret.isOk()) << ret;
     }
 }
-BENCHMARK(BM_repeatBinder);
+BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
 
 int main(int argc, char** argv) {
     ::benchmark::Initialize(&argc, argv);
@@ -118,19 +176,44 @@
     std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
     (void)unlink(addr.c_str());
 
-    std::thread([addr]() {
+    std::cerr << "Tests suffixes:" << std::endl;
+    std::cerr << "\t.../" << Transport::KERNEL << " is KERNEL" << std::endl;
+    std::cerr << "\t.../" << Transport::RPC << " is RPC" << std::endl;
+
+    if (0 == fork()) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
         sp<RpcServer> server = RpcServer::make();
         server->setRootObject(sp<MyBinderRpcBenchmark>::make());
         server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-        CHECK(server->setupUnixDomainServer(addr.c_str()));
+        CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
         server->join();
-    }).detach();
+        exit(1);
+    }
 
+#ifdef __BIONIC__
+    if (0 == fork()) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+        CHECK_EQ(OK,
+                 defaultServiceManager()->addService(kKernelBinderInstance,
+                                                     sp<MyBinderRpcBenchmark>::make()));
+        IPCThreadState::self()->joinThreadPool();
+        exit(1);
+    }
+
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+
+    gKernelBinder = defaultServiceManager()->waitForService(kKernelBinderInstance);
+    CHECK_NE(nullptr, gKernelBinder.get());
+#endif
+
+    status_t status;
     for (size_t tries = 0; tries < 5; tries++) {
         usleep(10000);
-        if (gSession->setupUnixDomainClient(addr.c_str())) goto success;
+        status = gSession->setupUnixDomainClient(addr.c_str());
+        if (status == OK) goto success;
     }
-    LOG(FATAL) << "Could not connect.";
+    LOG(FATAL) << "Could not connect: " << statusToString(status).c_str();
 success:
 
     ::benchmark::RunSpecifiedBenchmarks();
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index e452678..15ccae9 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -29,6 +29,8 @@
 #include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
 #include <gtest/gtest.h>
 
 #include <chrono>
@@ -40,6 +42,7 @@
 #include <sys/prctl.h>
 #include <unistd.h>
 
+#include "../RpcSocketAddress.h" // for testing preconnected clients
 #include "../RpcState.h"   // for debugging
 #include "../vm_sockets.h" // for VMADDR_*
 
@@ -47,6 +50,25 @@
 
 namespace android {
 
+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 };
+
+static inline std::vector<RpcSecurity> RpcSecurityValues() {
+    return {RpcSecurity::RAW};
+}
+
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity) {
+    switch (rpcSecurity) {
+        case RpcSecurity::RAW:
+            return RpcTransportCtxFactoryRaw::make();
+        default:
+            LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
+    }
+}
+
 TEST(BinderRpcParcel, EntireParcelFormatted) {
     Parcel p;
     p.writeInt32(3);
@@ -54,19 +76,39 @@
     EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
 }
 
-TEST(BinderRpc, SetExternalServer) {
+class BinderRpcSimple : public ::testing::TestWithParam<RpcSecurity> {
+public:
+    static std::string PrintTestParam(const ::testing::TestParamInfo<ParamType>& info) {
+        return newFactory(info.param)->toCString();
+    }
+};
+
+TEST_P(BinderRpcSimple, SetExternalServerTest) {
     base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
     int sinkFd = sink.get();
-    auto server = RpcServer::make();
+    auto server = RpcServer::make(newFactory(GetParam()));
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     ASSERT_FALSE(server->hasServer());
-    ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
+    ASSERT_EQ(OK, server->setupExternalServer(std::move(sink)));
     ASSERT_TRUE(server->hasServer());
     base::unique_fd retrieved = server->releaseServer();
     ASSERT_FALSE(server->hasServer());
     ASSERT_EQ(sinkFd, retrieved.get());
 }
 
+TEST(BinderRpc, CannotUseNextWireVersion) {
+    auto session = RpcSession::make();
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 1));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 2));
+    EXPECT_FALSE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_NEXT + 15));
+}
+
+TEST(BinderRpc, CanUseExperimentalWireVersion) {
+    auto session = RpcSession::make();
+    EXPECT_TRUE(session->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL));
+}
+
 using android::binder::Status;
 
 #define EXPECT_OK(status)                 \
@@ -127,11 +169,6 @@
         out->clear();
         for (auto session : spServer->listSessions()) {
             size_t count = session->state()->countBinders();
-            if (count != 1) {
-                // this is called when there is only one binder held remaining,
-                // so to aid debugging
-                session->state()->dump();
-            }
             out->push_back(count);
         }
         return Status::ok();
@@ -360,7 +397,11 @@
                 EXPECT_EQ(remoteCount, 1);
             }
 
-            EXPECT_OK(rootIface->scheduleShutdown());
+            // even though it is on another thread, shutdown races with
+            // the transaction reply being written
+            if (auto status = rootIface->scheduleShutdown(); !status.isOk()) {
+                EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+            }
         }
 
         rootIface = nullptr;
@@ -369,12 +410,15 @@
 };
 
 enum class SocketType {
+    PRECONNECTED,
     UNIX,
     VSOCK,
     INET,
 };
-static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
-    switch (info.param) {
+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:
@@ -387,16 +431,41 @@
     }
 }
 
-class BinderRpc : public ::testing::TestWithParam<SocketType> {
+static base::unique_fd connectToUds(const char* addrStr) {
+    UnixSocketAddress addr(addrStr);
+    base::unique_fd serverFd(
+            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    int savedErrno = errno;
+    CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+
+    if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+        int savedErrno = errno;
+        LOG(FATAL) << "Could not connect to socket " << addrStr << ": " << strerror(savedErrno);
+    }
+    return serverFd;
+}
+
+class BinderRpc : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity>> {
 public:
+    struct Options {
+        size_t numThreads = 1;
+        size_t numSessions = 1;
+        size_t numIncomingConnections = 0;
+    };
+
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [type, security] = info.param;
+        return PrintToString(type) + "_" + newFactory(security)->toCString();
+    }
+
     // This creates a new process serving an interface on a certain number of
     // threads.
     ProcessSession createRpcTestSocketServerProcess(
-            size_t numThreads, size_t numSessions, size_t numReverseConnections,
-            const std::function<void(const sp<RpcServer>&)>& configure) {
-        CHECK_GE(numSessions, 1) << "Must have at least one session to a server";
+            const Options& options, const std::function<void(const sp<RpcServer>&)>& configure) {
+        CHECK_GE(options.numSessions, 1) << "Must have at least one session to a server";
 
-        SocketType socketType = GetParam();
+        SocketType socketType = std::get<0>(GetParam());
+        RpcSecurity rpcSecurity = std::get<1>(GetParam());
 
         unsigned int vsockPort = allocateVsockPort();
         std::string addr = allocateSocketAddress();
@@ -404,22 +473,24 @@
 
         auto ret = ProcessSession{
                 .host = Process([&](android::base::borrowed_fd writeEnd) {
-                    sp<RpcServer> server = RpcServer::make();
+                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
 
                     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-                    server->setMaxThreads(numThreads);
+                    server->setMaxThreads(options.numThreads);
 
                     unsigned int outPort = 0;
 
                     switch (socketType) {
+                        case SocketType::PRECONNECTED:
+                            [[fallthrough]];
                         case SocketType::UNIX:
-                            CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
+                            CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str())) << addr;
                             break;
                         case SocketType::VSOCK:
-                            CHECK(server->setupVsockServer(vsockPort));
+                            CHECK_EQ(OK, server->setupVsockServer(vsockPort));
                             break;
                         case SocketType::INET: {
-                            CHECK(server->setupInetServer(0, &outPort));
+                            CHECK_EQ(OK, server->setupInetServer(kLocalInetAddress, 0, &outPort));
                             CHECK_NE(0, outPort);
                             break;
                         }
@@ -445,36 +516,44 @@
             CHECK_NE(0, outPort);
         }
 
-        for (size_t i = 0; i < numSessions; i++) {
-            sp<RpcSession> session = RpcSession::make();
-            session->setMaxThreads(numReverseConnections);
+        status_t status;
+
+        for (size_t i = 0; i < options.numSessions; i++) {
+            sp<RpcSession> session = RpcSession::make(newFactory(rpcSecurity));
+            session->setMaxThreads(options.numIncomingConnections);
 
             switch (socketType) {
+                case SocketType::PRECONNECTED:
+                    status = session->setupPreconnectedClient({}, [=]() {
+                        return connectToUds(addr.c_str());
+                    });
+                    if (status == OK) goto success;
+                    break;
                 case SocketType::UNIX:
-                    if (session->setupUnixDomainClient(addr.c_str())) goto success;
+                    status = session->setupUnixDomainClient(addr.c_str());
+                    if (status == OK) goto success;
                     break;
                 case SocketType::VSOCK:
-                    if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+                    status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+                    if (status == OK) goto success;
                     break;
                 case SocketType::INET:
-                    if (session->setupInetClient("127.0.0.1", outPort)) goto success;
+                    status = session->setupInetClient("127.0.0.1", outPort);
+                    if (status == OK) goto success;
                     break;
                 default:
                     LOG_ALWAYS_FATAL("Unknown socket type");
             }
-            LOG_ALWAYS_FATAL("Could not connect");
+            LOG_ALWAYS_FATAL("Could not connect %s", statusToString(status).c_str());
         success:
             ret.sessions.push_back({session, session->getRootObject()});
         }
         return ret;
     }
 
-    BinderRpcTestProcessSession createRpcTestSocketServerProcess(size_t numThreads,
-                                                                 size_t numSessions = 1,
-                                                                 size_t numReverseConnections = 0) {
+    BinderRpcTestProcessSession createRpcTestSocketServerProcess(const Options& options) {
         BinderRpcTestProcessSession ret{
-                .proc = createRpcTestSocketServerProcess(numThreads, numSessions,
-                                                         numReverseConnections,
+                .proc = createRpcTestSocketServerProcess(options,
                                                          [&](const sp<RpcServer>& server) {
                                                              sp<MyBinderRpcTest> service =
                                                                      new MyBinderRpcTest;
@@ -491,19 +570,19 @@
 };
 
 TEST_P(BinderRpc, Ping) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     ASSERT_NE(proc.rootBinder, nullptr);
     EXPECT_EQ(OK, proc.rootBinder->pingBinder());
 }
 
 TEST_P(BinderRpc, GetInterfaceDescriptor) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     ASSERT_NE(proc.rootBinder, nullptr);
     EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
 }
 
 TEST_P(BinderRpc, MultipleSessions) {
-    auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 5 /*sessions*/);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 5});
     for (auto session : proc.proc.sessions) {
         ASSERT_NE(nullptr, session.root);
         EXPECT_EQ(OK, session.root->pingBinder());
@@ -511,14 +590,14 @@
 }
 
 TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     Parcel data;
     Parcel reply;
     EXPECT_EQ(BAD_TYPE, proc.rootBinder->transact(IBinder::PING_TRANSACTION, data, &reply, 0));
 }
 
 TEST_P(BinderRpc, AppendSeparateFormats) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     Parcel p1;
     p1.markForBinder(proc.rootBinder);
@@ -531,7 +610,7 @@
 }
 
 TEST_P(BinderRpc, UnknownTransaction) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     Parcel data;
     data.markForBinder(proc.rootBinder);
     Parcel reply;
@@ -539,19 +618,19 @@
 }
 
 TEST_P(BinderRpc, SendSomethingOneway) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     EXPECT_OK(proc.rootIface->sendString("asdf"));
 }
 
 TEST_P(BinderRpc, SendAndGetResultBack) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     std::string doubled;
     EXPECT_OK(proc.rootIface->doubleString("cool ", &doubled));
     EXPECT_EQ("cool cool ", doubled);
 }
 
 TEST_P(BinderRpc, SendAndGetResultBackBig) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     std::string single = std::string(1024, 'a');
     std::string doubled;
     EXPECT_OK(proc.rootIface->doubleString(single, &doubled));
@@ -559,7 +638,7 @@
 }
 
 TEST_P(BinderRpc, CallMeBack) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     int32_t pingResult;
     EXPECT_OK(proc.rootIface->pingMe(new MyBinderRpcSession("foo"), &pingResult));
@@ -569,7 +648,7 @@
 }
 
 TEST_P(BinderRpc, RepeatBinder) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> inBinder = new MyBinderRpcSession("foo");
     sp<IBinder> outBinder;
@@ -591,7 +670,7 @@
 }
 
 TEST_P(BinderRpc, RepeatTheirBinder) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinderRpcSession> session;
     EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
@@ -615,7 +694,7 @@
 }
 
 TEST_P(BinderRpc, RepeatBinderNull) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> outBinder;
     EXPECT_OK(proc.rootIface->repeatBinder(nullptr, &outBinder));
@@ -623,7 +702,7 @@
 }
 
 TEST_P(BinderRpc, HoldBinder) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     IBinder* ptr = nullptr;
     {
@@ -649,8 +728,8 @@
 // aren't supported.
 
 TEST_P(BinderRpc, CannotMixBindersBetweenUnrelatedSocketSessions) {
-    auto proc1 = createRpcTestSocketServerProcess(1);
-    auto proc2 = createRpcTestSocketServerProcess(1);
+    auto proc1 = createRpcTestSocketServerProcess({});
+    auto proc2 = createRpcTestSocketServerProcess({});
 
     sp<IBinder> outBinder;
     EXPECT_EQ(INVALID_OPERATION,
@@ -658,7 +737,7 @@
 }
 
 TEST_P(BinderRpc, CannotMixBindersBetweenTwoSessionsToTheSameServer) {
-    auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 2 /*sessions*/);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = 1, .numSessions = 2});
 
     sp<IBinder> outBinder;
     EXPECT_EQ(INVALID_OPERATION,
@@ -667,7 +746,7 @@
 }
 
 TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> someRealBinder = IInterface::asBinder(defaultServiceManager());
     sp<IBinder> outBinder;
@@ -676,7 +755,7 @@
 }
 
 TEST_P(BinderRpc, CannotSendSocketBinderOverRegularBinder) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     // for historical reasons, IServiceManager interface only returns the
     // exception code
@@ -687,7 +766,7 @@
 // END TESTS FOR LIMITATIONS OF SOCKET BINDER
 
 TEST_P(BinderRpc, RepeatRootObject) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> outBinder;
     EXPECT_OK(proc.rootIface->repeatBinder(proc.rootBinder, &outBinder));
@@ -695,7 +774,7 @@
 }
 
 TEST_P(BinderRpc, NestedTransactions) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     auto nastyNester = sp<MyBinderRpcTest>::make();
     EXPECT_OK(proc.rootIface->nestMe(nastyNester, 10));
@@ -706,7 +785,7 @@
 }
 
 TEST_P(BinderRpc, SameBinderEquality) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> a;
     EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
@@ -718,7 +797,7 @@
 }
 
 TEST_P(BinderRpc, SameBinderEqualityWeak) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinder> a;
     EXPECT_OK(proc.rootIface->alwaysGiveMeTheSameBinder(&a));
@@ -750,7 +829,7 @@
     } while (false)
 
 TEST_P(BinderRpc, SingleSession) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     sp<IBinderRpcSession> session;
     EXPECT_OK(proc.rootIface->openSession("aoeu", &session));
@@ -764,7 +843,7 @@
 }
 
 TEST_P(BinderRpc, ManySessions) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     std::vector<sp<IBinderRpcSession>> sessions;
 
@@ -800,7 +879,7 @@
 TEST_P(BinderRpc, ThreadPoolGreaterThanEqualRequested) {
     constexpr size_t kNumThreads = 10;
 
-    auto proc = createRpcTestSocketServerProcess(kNumThreads);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
 
     EXPECT_OK(proc.rootIface->lock());
 
@@ -834,7 +913,7 @@
     constexpr size_t kNumCalls = kNumThreads + 3;
     constexpr size_t kSleepMs = 500;
 
-    auto proc = createRpcTestSocketServerProcess(kNumThreads);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumThreads});
 
     size_t epochMsBefore = epochMillis();
 
@@ -858,7 +937,7 @@
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 100;
 
-    auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
 
     std::vector<std::thread> threads;
     for (size_t i = 0; i < kNumClientThreads; i++) {
@@ -879,7 +958,7 @@
     constexpr size_t kNumServerThreads = 10;
     constexpr size_t kNumCalls = 500;
 
-    auto proc = createRpcTestSocketServerProcess(kNumServerThreads);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
 
     std::vector<std::thread> threads;
     for (size_t i = 0; i < kNumClientThreads; i++) {
@@ -900,7 +979,7 @@
     constexpr size_t kReallyLongTimeMs = 100;
     constexpr size_t kSleepMs = kReallyLongTimeMs * 5;
 
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     size_t epochMsBefore = epochMillis();
 
@@ -916,7 +995,7 @@
     constexpr size_t kSleepMs = 50;
 
     // make sure calls to the same object happen on the same thread
-    auto proc = createRpcTestSocketServerProcess(1 + kNumExtraServerThreads);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = 1 + kNumExtraServerThreads});
 
     EXPECT_OK(proc.rootIface->lock());
 
@@ -946,7 +1025,7 @@
     constexpr size_t kNumClients = 2;
     constexpr size_t kTooLongMs = 1000;
 
-    auto proc = createRpcTestSocketServerProcess(kNumClients /*threads*/, 2 /*sessions*/);
+    auto proc = createRpcTestSocketServerProcess({.numThreads = kNumClients, .numSessions = 2});
 
     // Build up oneway calls on the second session to make sure it terminates
     // and shuts down. The first session should be unaffected (proc destructor
@@ -968,6 +1047,12 @@
     Status status = iface->sleepMsAsync(kTooLongMs);
     EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
 
+    // now that it has died, wait for the remote session to shutdown
+    std::vector<int32_t> remoteCounts;
+    do {
+        EXPECT_OK(proc.rootIface->countBinders(&remoteCounts));
+    } while (remoteCounts.size() == kNumClients);
+
     // the second session should be shutdown in the other process by the time we
     // are able to join above (it'll only be hung up once it finishes processing
     // any pending commands). We need to erase this session from the record
@@ -982,7 +1067,8 @@
     for (bool callIsOneway : {true, false}) {
         for (bool callbackIsOneway : {true, false}) {
             for (bool delayed : {true, false}) {
-                auto proc = createRpcTestSocketServerProcess(1, 1, 1);
+                auto proc = createRpcTestSocketServerProcess(
+                        {.numThreads = 1, .numSessions = 1, .numIncomingConnections = 1});
                 auto cb = sp<MyBinderRpcCallback>::make();
 
                 if (callIsOneway) {
@@ -1007,9 +1093,11 @@
 
                 // since we are severing the connection, we need to go ahead and
                 // tell the server to shutdown and exit so that waitpid won't hang
-                EXPECT_OK(proc.rootIface->scheduleShutdown());
+                if (auto status = proc.rootIface->scheduleShutdown(); !status.isOk()) {
+                    EXPECT_EQ(DEAD_OBJECT, status.transactionError()) << status;
+                }
 
-                // since this session has a reverse connection w/ a threadpool, we
+                // 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));
 
@@ -1020,7 +1108,7 @@
 }
 
 TEST_P(BinderRpc, OnewayCallbackWithNoThread) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
     auto cb = sp<MyBinderRpcCallback>::make();
 
     Status status = proc.rootIface->doCallback(cb, true /*oneway*/, false /*delayed*/, "anything");
@@ -1029,7 +1117,7 @@
 
 TEST_P(BinderRpc, Die) {
     for (bool doDeathCleanup : {true, false}) {
-        auto proc = createRpcTestSocketServerProcess(1);
+        auto proc = createRpcTestSocketServerProcess({});
 
         // make sure there is some state during crash
         // 1. we hold their binder
@@ -1047,7 +1135,7 @@
 }
 
 TEST_P(BinderRpc, UseKernelBinderCallingId) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     // we can't allocate IPCThreadState so actually the first time should
     // succeed :(
@@ -1060,7 +1148,7 @@
 }
 
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
     ASSERT_NE(binder, nullptr);
@@ -1069,7 +1157,7 @@
 }
 
 TEST_P(BinderRpc, WorksWithLibbinderNdkUserTransaction) {
-    auto proc = createRpcTestSocketServerProcess(1);
+    auto proc = createRpcTestSocketServerProcess({});
 
     ndk::SpAIBinder binder = ndk::SpAIBinder(AIBinder_fromPlatformBinder(proc.rootBinder));
     ASSERT_NE(binder, nullptr);
@@ -1097,28 +1185,34 @@
     ssize_t beforeFds = countFds();
     ASSERT_GE(beforeFds, 0);
     {
-        auto proc = createRpcTestSocketServerProcess(10);
+        auto proc = createRpcTestSocketServerProcess({.numThreads = 10});
         ASSERT_EQ(OK, proc.rootBinder->pingBinder());
     }
     ASSERT_EQ(beforeFds, countFds()) << (system("ls -l /proc/self/fd/"), "fd leak?");
 }
 
 static bool testSupportVsockLoopback() {
+    // We don't need to enable TLS to know if vsock is supported.
     unsigned int vsockPort = allocateVsockPort();
-    sp<RpcServer> server = RpcServer::make();
+    sp<RpcServer> server = RpcServer::make(RpcTransportCtxFactoryRaw::make());
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-    CHECK(server->setupVsockServer(vsockPort));
+    if (status_t status = server->setupVsockServer(vsockPort); status != OK) {
+        if (status == -EAFNOSUPPORT) {
+            return false;
+        }
+        LOG_ALWAYS_FATAL("Could not setup vsock server: %s", statusToString(status).c_str());
+    }
     server->start();
 
-    sp<RpcSession> session = RpcSession::make();
-    bool okay = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
-    CHECK(server->shutdown());
-    ALOGE("Detected vsock loopback supported: %d", okay);
-    return okay;
+    sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+    status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
+    while (!server->shutdown()) usleep(10000);
+    ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
+    return status == OK;
 }
 
 static std::vector<SocketType> testSocketTypes() {
-    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+    std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
 
     static bool hasVsockLoopback = testSupportVsockLoopback();
 
@@ -1129,10 +1223,13 @@
     return ret;
 }
 
-INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc, ::testing::ValuesIn(testSocketTypes()),
-                        PrintSocketType);
+INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
+                        ::testing::Combine(::testing::ValuesIn(testSocketTypes()),
+                                           ::testing::ValuesIn(RpcSecurityValues())),
+                        BinderRpc::PrintParamInfo);
 
-class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+class BinderRpcServerRootObject
+      : public ::testing::TestWithParam<std::tuple<bool, bool, RpcSecurity>> {};
 
 TEST_P(BinderRpcServerRootObject, WeakRootObject) {
     using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
@@ -1140,8 +1237,8 @@
         return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
     };
 
-    auto server = RpcServer::make();
-    auto [isStrong1, isStrong2] = GetParam();
+    auto [isStrong1, isStrong2, rpcSecurity] = GetParam();
+    auto server = RpcServer::make(newFactory(rpcSecurity));
     auto binder1 = sp<BBinder>::make();
     IBinder* binderRaw1 = binder1.get();
     setRootObject(isStrong1)(server.get(), binder1);
@@ -1158,7 +1255,8 @@
 }
 
 INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
-                        ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+                        ::testing::Combine(::testing::Bool(), ::testing::Bool(),
+                                           ::testing::ValuesIn(RpcSecurityValues())));
 
 class OneOffSignal {
 public:
@@ -1181,12 +1279,12 @@
     bool mValue = false;
 };
 
-TEST(BinderRpc, Shutdown) {
+TEST_P(BinderRpcSimple, Shutdown) {
     auto addr = allocateSocketAddress();
     unlink(addr.c_str());
-    auto server = RpcServer::make();
+    auto server = RpcServer::make(newFactory(GetParam()));
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-    ASSERT_TRUE(server->setupUnixDomainServer(addr.c_str()));
+    ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
     auto joinEnds = std::make_shared<OneOffSignal>();
 
     // If things are broken and the thread never stops, don't block other tests. Because the thread
@@ -1208,6 +1306,46 @@
             << "After server->shutdown() returns true, join() did not stop after 2s";
 }
 
+TEST(BinderRpc, Java) {
+#if !defined(__ANDROID__)
+    GTEST_SKIP() << "This test is only run on Android. Though it can technically run on host on"
+                    "createRpcDelegateServiceManager() with a device attached, such test belongs "
+                    "to binderHostDeviceTest. Hence, just disable this test on host.";
+#endif // !__ANDROID__
+    sp<IServiceManager> sm = defaultServiceManager();
+    ASSERT_NE(nullptr, sm);
+    // Any Java service with non-empty getInterfaceDescriptor() would do.
+    // Let's pick batteryproperties.
+    auto binder = sm->checkService(String16("batteryproperties"));
+    ASSERT_NE(nullptr, binder);
+    auto descriptor = binder->getInterfaceDescriptor();
+    ASSERT_GE(descriptor.size(), 0);
+    ASSERT_EQ(OK, binder->pingBinder());
+
+    auto rpcServer = RpcServer::make();
+    rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+    unsigned int port;
+    ASSERT_EQ(OK, rpcServer->setupInetServer(kLocalInetAddress, 0, &port));
+    auto socket = rpcServer->releaseServer();
+
+    auto keepAlive = sp<BBinder>::make();
+    ASSERT_EQ(OK, binder->setRpcClientDebug(std::move(socket), keepAlive));
+
+    auto rpcSession = RpcSession::make();
+    ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
+    auto rpcBinder = rpcSession->getRootObject();
+    ASSERT_NE(nullptr, rpcBinder);
+
+    ASSERT_EQ(OK, rpcBinder->pingBinder());
+
+    ASSERT_EQ(descriptor, rpcBinder->getInterfaceDescriptor())
+            << "getInterfaceDescriptor should not crash system_server";
+    ASSERT_EQ(OK, rpcBinder->pingBinder());
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
+                        BinderRpcSimple::PrintTestParam);
+
 } // namespace android
 
 int main(int argc, char** argv) {
diff --git a/libs/binder/tests/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
index 74b8eb8..acf3f8f 100644
--- a/libs/binder/tests/parcel_fuzzer/Android.bp
+++ b/libs/binder/tests/parcel_fuzzer/Android.bp
@@ -23,7 +23,6 @@
         "main.cpp",
         "random_fd.cpp",
         "random_parcel.cpp",
-        "util.cpp",
     ],
     static_libs: [
         "libbase",
diff --git a/libs/binder/tests/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
index 5f2c17c..9fe06dd 100644
--- a/libs/binder/tests/parcel_fuzzer/binder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/binder.cpp
@@ -18,11 +18,13 @@
 #include "binder.h"
 #include "util.h"
 
+#include <android-base/hex.h>
 #include <android/os/IServiceManager.h>
 #include <binder/ParcelableHolder.h>
 #include <binder/PersistableBundle.h>
 
 using ::android::status_t;
+using ::android::base::HexString;
 
 enum ByteEnum : int8_t {};
 enum IntEnum : int32_t {};
@@ -128,7 +130,7 @@
     [] (const ::android::Parcel& p, uint8_t len) {
         FUZZ_LOG() << "about to readInplace";
         const void* r = p.readInplace(len);
-        FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
+        FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << (r ? HexString(r, len) : "null");
     },
     PARCEL_READ_OPT_STATUS(int32_t, readInt32),
     PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
@@ -156,7 +158,7 @@
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outLen = 0;
         const char16_t* str = p.readString16Inplace(&outLen);
-        FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen)
+        FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outLen)
                    << " size: " << outLen;
     },
     PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
index 35b5ebc..ee9840f 100644
--- a/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
+++ b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
@@ -18,10 +18,12 @@
 #include "hwbinder.h"
 #include "util.h"
 
+#include <android-base/hex.h>
 #include <android-base/logging.h>
 #include <hwbinder/Parcel.h>
 
 using ::android::status_t;
+using ::android::base::HexString;
 
 // TODO: support scatter-gather types
 
@@ -70,13 +72,13 @@
         FUZZ_LOG() << "about to read";
         std::vector<uint8_t> data (length);
         status_t status = p.read(data.data(), length);
-        FUZZ_LOG() << "read status: " << status << " data: " << hexString(data.data(), data.size());
+        FUZZ_LOG() << "read status: " << status << " data: " << HexString(data.data(), data.size());
     },
     [] (const ::android::hardware::Parcel& p, uint8_t length) {
         FUZZ_LOG() << "about to read";
         std::vector<uint8_t> data (length);
         const void* inplace = p.readInplace(length);
-        FUZZ_LOG() << "read status: " << hexString(inplace, length);
+        FUZZ_LOG() << "read status: " << (inplace ? HexString(inplace, length) : "null");
     },
     PARCEL_READ_WITH_STATUS(int8_t, readInt8),
     PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
@@ -100,7 +102,7 @@
         FUZZ_LOG() << "about to readString16Inplace";
         size_t outSize = 0;
         const char16_t* str = p.readString16Inplace(&outSize);
-        FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outSize);
+        FUZZ_LOG() << "readString16Inplace: " << HexString(str, sizeof(char16_t) * outSize);
     },
     PARCEL_READ_OPT_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
     PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
index 2a79e85..f435dae 100644
--- a/libs/binder/tests/parcel_fuzzer/main.cpp
+++ b/libs/binder/tests/parcel_fuzzer/main.cpp
@@ -22,6 +22,7 @@
 
 #include <iostream>
 
+#include <android-base/hex.h>
 #include <android-base/logging.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_libbinder.h>
@@ -35,6 +36,7 @@
 
 using android::fillRandomParcel;
 using android::sp;
+using android::base::HexString;
 
 void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
     // TODO: functionality to create random parcels for libhwbinder parcels
@@ -78,8 +80,8 @@
     CHECK(reads.size() <= 255) << reads.size();
 
     FUZZ_LOG() << "backend: " << backend;
-    FUZZ_LOG() << "input: " << hexString(p.data(), p.dataSize());
-    FUZZ_LOG() << "instructions: " << hexString(instructions);
+    FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize());
+    FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size());
 
     for (size_t i = 0; i + 1 < instructions.size(); i += 2) {
         uint8_t a = instructions[i];
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 92fdc72..8bf04cc 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -19,6 +19,7 @@
 #include <android-base/logging.h>
 #include <binder/IServiceManager.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTransportRaw.h>
 #include <fuzzbinder/random_fd.h>
 #include <utils/String16.h>
 
@@ -35,8 +36,8 @@
 
 void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
     if (provider.ConsumeBool()) {
-        auto session = sp<RpcSession>::make();
-        CHECK(session->addNullDebuggingClient());
+        auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
+        CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
         fillRandomParcelData(p, std::move(provider));
         return;
diff --git a/libs/binder/tests/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
deleted file mode 100644
index 479f406..0000000
--- a/libs/binder/tests/parcel_fuzzer/util.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2019 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 FUZZ_LOG_TAG "util"
-#include "util.h"
-
-#include <android-base/logging.h>
-
-#include <iomanip>
-#include <sstream>
-
-std::string hexString(const void* bytes, size_t len) {
-    if (bytes == nullptr) return "<null>";
-
-    const uint8_t* bytes8 = static_cast<const uint8_t*>(bytes);
-    char chars[] = "0123456789abcdef";
-    std::string result;
-    result.resize(len * 2);
-
-    for (size_t i = 0; i < len; i++) {
-        result[2 * i] = chars[bytes8[i] >> 4];
-        result[2 * i + 1] = chars[bytes8[i] & 0xf];
-    }
-
-    return result;
-}
-std::string hexString(const std::vector<uint8_t>& bytes) {
-    return hexString(bytes.data(), bytes.size());
-}
diff --git a/libs/binder/tests/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
index 45e8c57..a5d0dae 100644
--- a/libs/binder/tests/parcel_fuzzer/util.h
+++ b/libs/binder/tests/parcel_fuzzer/util.h
@@ -49,6 +49,3 @@
     FuzzLog& log() { return *this; }
 };
 #endif
-
-std::string hexString(const void* bytes, size_t len);
-std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 9fc496f..230f5c7 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -60,7 +60,7 @@
     sp<RpcServer> server = RpcServer::make();
     server->setRootObject(sp<SomeBinder>::make());
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-    CHECK(server->setupUnixDomainServer(kSock.c_str()));
+    CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
 
     std::thread serverThread([=] { (void)server->join(); });
 
diff --git a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
index 626b758..4a0aeba 100644
--- a/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
@@ -62,20 +62,22 @@
              object = fdp->ConsumeIntegral<uint32_t>();
              cleanup_cookie = fdp->ConsumeIntegral<uint32_t>();
              IBinder::object_cleanup_func func = IBinder::object_cleanup_func();
-             ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
-                                                      : nullptr,
-                                   fdp->ConsumeBool() ? reinterpret_cast<void*>(&object) : nullptr,
-                                   fdp->ConsumeBool() ? reinterpret_cast<void*>(&cleanup_cookie)
-                                                      : nullptr,
-                                   func);
+             (void)ibinder->attachObject(fdp->ConsumeBool() ? reinterpret_cast<void*>(&objectID)
+                                                            : nullptr,
+                                         fdp->ConsumeBool() ? reinterpret_cast<void*>(&object)
+                                                            : nullptr,
+                                         fdp->ConsumeBool()
+                                                 ? reinterpret_cast<void*>(&cleanup_cookie)
+                                                 : nullptr,
+                                         func);
          },
          [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
              uint32_t id = fdp->ConsumeIntegral<uint32_t>();
-             ibinder->findObject(reinterpret_cast<void*>(&id));
+             (void)ibinder->findObject(reinterpret_cast<void*>(&id));
          },
          [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
              uint32_t id = fdp->ConsumeIntegral<uint32_t>();
-             ibinder->detachObject(reinterpret_cast<void*>(&id));
+             (void)ibinder->detachObject(reinterpret_cast<void*>(&id));
          },
          [](FuzzedDataProvider* fdp, IBinder* ibinder) -> void {
              uint32_t code = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
index b435dba..d086b49 100644
--- a/libs/binderdebug/BinderDebug.cpp
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <binder/Binder.h>
@@ -116,4 +117,60 @@
     return ret;
 }
 
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+                             int32_t handle, std::vector<pid_t>* pids) {
+    std::smatch match;
+    static const std::regex kNodeNumber("^\\s+ref \\d+:\\s+desc\\s+(\\d+)\\s+node\\s+(\\d+).*");
+    std::string contextStr = contextToString(context);
+    int32_t node;
+    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+        if (std::regex_search(line, match, kNodeNumber)) {
+            const std::string& descString = match.str(1);
+            int32_t desc;
+            if (!::android::base::ParseInt(descString.c_str(), &desc)) {
+                LOG(ERROR) << "Failed to parse desc int: " << descString;
+                return;
+            }
+            if (handle != desc) {
+                return;
+            }
+            const std::string& nodeString = match.str(2);
+            if (!::android::base::ParseInt(nodeString.c_str(), &node)) {
+                LOG(ERROR) << "Failed to parse node int: " << nodeString;
+                return;
+            }
+            return;
+        }
+        return;
+    });
+    if (ret != OK) {
+        return ret;
+    }
+    static const std::regex kClients("^\\s+node\\s+(\\d+).*proc\\s+([\\d+\\s*]*)");
+    ret = scanBinderContext(servicePid, contextStr, [&](const std::string& line) {
+        if (std::regex_search(line, match, kClients)) {
+            const std::string nodeString = match.str(1);
+            int32_t matchedNode;
+            if (!::android::base::ParseInt(nodeString.c_str(), &matchedNode)) {
+                LOG(ERROR) << "Failed to parse node int: " << nodeString;
+                return;
+            }
+            if (node != matchedNode) {
+                return;
+            }
+            const std::string clients = match.str(2);
+            for (const std::string& pidStr : base::Split(clients, " ")) {
+                int32_t pid;
+                if (!::android::base::ParseInt(pidStr, &pid)) {
+                    return;
+                }
+                pids->push_back(pid);
+            }
+            return;
+        }
+        return;
+    });
+    return ret;
+}
+
 } // namespace  android
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
index 14a0ef3..dfd5a7c 100644
--- a/libs/binderdebug/include/binderdebug/BinderDebug.h
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -32,6 +32,14 @@
     VNDBINDER,
 };
 
+/**
+ * pid is the pid of the service
+ */
 status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+/**
+ * pid is typically the pid of this process that is making the query
+ */
+status_t getBinderClientPids(BinderDebugContext context, pid_t pid, pid_t servicePid,
+                             int32_t handle, std::vector<pid_t>* pids);
 
 } // namespace  android
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 3030068..de5f1ed 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -643,6 +643,8 @@
       case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
       case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
           return 4;
+      case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
+          return 8;
       default:
           return 0;
   }
@@ -686,6 +688,10 @@
             "gralloc and AHardwareBuffer flags don't match");
     static_assert(AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE == (uint64_t)BufferUsage::GPU_MIPMAP_COMPLETE,
             "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_CAMERA_WRITE == (uint64_t)BufferUsage::CAMERA_OUTPUT,
+            "gralloc and AHardwareBuffer flags don't match");
+    static_assert(AHARDWAREBUFFER_USAGE_CAMERA_READ == (uint64_t)BufferUsage::CAMERA_INPUT,
+            "gralloc and AHardwareBuffer flags don't match");
     return usage;
 }
 
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 3392d7f..12f8691 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -81,6 +81,20 @@
     AHARDWAREBUFFER_FORMAT_YCbCr_422_I              = 0x14,
 };
 
+/**
+ * Buffer usage flags.
+ */
+enum {
+    /* for future proofing, keep these in sync with hardware/gralloc.h */
+
+    /* The buffer will be written by the HW camera pipeline. */
+    AHARDWAREBUFFER_USAGE_CAMERA_WRITE              = 2UL << 16,
+    /* The buffer will be read by the HW camera pipeline. */
+    AHARDWAREBUFFER_USAGE_CAMERA_READ               = 4UL << 16,
+    /* Mask for the camera access values. */
+    AHARDWAREBUFFER_USAGE_CAMERA_MASK               = 6UL << 16,
+};
+
 __END_DECLS
 
 #endif /* ANDROID_VNDK_NATIVEWINDOW_AHARDWAREBUFFER_H */
diff --git a/services/gpuservice/bpfprogs/gpu_mem.c b/services/gpuservice/bpfprogs/gpu_mem.c
index c75213b..16e1e8a 100644
--- a/services/gpuservice/bpfprogs/gpu_mem.c
+++ b/services/gpuservice/bpfprogs/gpu_mem.c
@@ -72,4 +72,4 @@
     return 0;
 }
 
-char _license[] SEC("license") = "Apache 2.0";
+LICENSE("Apache 2.0");
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index dadbd0e..9846640 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -90,4 +90,7 @@
     export_header_lib_headers: [
         "libinputreader_headers",
     ],
+    static_libs: [
+        "libc++fs"
+    ],
 }
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index a1514af..20a843f 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -34,20 +34,20 @@
 #define LOG_TAG "EventHub"
 
 // #define LOG_NDEBUG 0
-
-#include "EventHub.h"
-
 #include <android-base/stringprintf.h>
 #include <cutils/properties.h>
+#include <input/KeyCharacterMap.h>
+#include <input/KeyLayoutMap.h>
+#include <input/VirtualKeyMap.h>
 #include <openssl/sha.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/Timers.h>
 #include <utils/threads.h>
 
-#include <input/KeyCharacterMap.h>
-#include <input/KeyLayoutMap.h>
-#include <input/VirtualKeyMap.h>
+#include <filesystem>
+
+#include "EventHub.h"
 
 /* this macro is used to tell if "bit" is set in "array"
  * it selects a byte from the array, and does a boolean AND
@@ -69,9 +69,9 @@
 
 static constexpr bool DEBUG = false;
 
-static const char* DEVICE_PATH = "/dev/input";
+static const char* DEVICE_INPUT_PATH = "/dev/input";
 // v4l2 devices go directly into /dev
-static const char* VIDEO_DEVICE_PATH = "/dev";
+static const char* DEVICE_PATH = "/dev";
 
 static inline const char* toString(bool value) {
     return value ? "true" : "false";
@@ -94,8 +94,8 @@
 /**
  * Return true if name matches "v4l-touch*"
  */
-static bool isV4lTouchNode(const char* name) {
-    return strstr(name, "v4l-touch") == name;
+static bool isV4lTouchNode(std::string name) {
+    return name.find("v4l-touch") != std::string::npos;
 }
 
 /**
@@ -298,15 +298,23 @@
     LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
 
     mINotifyFd = inotify_init();
-    mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
-    LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
-                        strerror(errno));
-    if (isV4lScanningEnabled()) {
-        mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
-        LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
-                            VIDEO_DEVICE_PATH, strerror(errno));
+
+    std::error_code errorCode;
+    bool isDeviceInotifyAdded = false;
+    if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+        addDeviceInputInotify();
     } else {
-        mVideoWd = -1;
+        addDeviceInotify();
+        isDeviceInotifyAdded = true;
+        if (errorCode) {
+            ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+                  errorCode.message().c_str());
+        }
+    }
+
+    if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
+        addDeviceInotify();
+    } else {
         ALOGI("Video device scanning disabled");
     }
 
@@ -352,6 +360,23 @@
     ::close(mWakeWritePipeFd);
 }
 
+/**
+ * On devices that don't have any input devices (like some development boards), the /dev/input
+ * directory will be absent. However, the user may still plug in an input device at a later time.
+ * Add watch for contents of /dev/input only when /dev/input appears.
+ */
+void EventHub::addDeviceInputInotify() {
+    mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);
+    LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",
+                        DEVICE_INPUT_PATH, strerror(errno));
+}
+
+void EventHub::addDeviceInotify() {
+    mDeviceWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+    LOG_ALWAYS_FATAL_IF(mDeviceWd < 0, "Could not register INotify for %s: %s",
+                        DEVICE_PATH, strerror(errno));
+}
+
 InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
@@ -810,7 +835,7 @@
     return index >= 0 ? mDevices.valueAt(index) : NULL;
 }
 
-EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const {
+EventHub::Device* EventHub::getDeviceByPathLocked(const std::string& devicePath) const {
     for (size_t i = 0; i < mDevices.size(); i++) {
         Device* device = mDevices.valueAt(i);
         if (device->path == devicePath) {
@@ -1109,14 +1134,24 @@
 }
 
 void EventHub::scanDevicesLocked() {
-    status_t result = scanDirLocked(DEVICE_PATH);
-    if (result < 0) {
-        ALOGE("scan dir failed for %s", DEVICE_PATH);
+    status_t result;
+    std::error_code errorCode;
+
+    if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+        result = scanDirLocked(DEVICE_INPUT_PATH);
+        if (result < 0) {
+            ALOGE("scan dir failed for %s", DEVICE_INPUT_PATH);
+        }
+    } else {
+        if (errorCode) {
+            ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+                  errorCode.message().c_str());
+        }
     }
     if (isV4lScanningEnabled()) {
-        result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+        result = scanVideoDirLocked(DEVICE_PATH);
         if (result != OK) {
-            ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+            ALOGE("scan video dir failed for %s", DEVICE_PATH);
         }
     }
     if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
@@ -1215,14 +1250,14 @@
     }
 }
 
-status_t EventHub::openDeviceLocked(const char* devicePath) {
+status_t EventHub::openDeviceLocked(const std::string& devicePath) {
     char buffer[80];
 
-    ALOGV("Opening device: %s", devicePath);
+    ALOGV("Opening device: %s", devicePath.c_str());
 
-    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);
+    int fd = open(devicePath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
     if (fd < 0) {
-        ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
+        ALOGE("could not open %s, %s\n", devicePath.c_str(), strerror(errno));
         return -1;
     }
 
@@ -1230,7 +1265,7 @@
 
     // Get device name.
     if (ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
-        ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
+        ALOGE("Could not get device name for %s: %s", devicePath.c_str(), strerror(errno));
     } else {
         buffer[sizeof(buffer) - 1] = '\0';
         identifier.name = buffer;
@@ -1240,7 +1275,7 @@
     for (size_t i = 0; i < mExcludedDevices.size(); i++) {
         const std::string& item = mExcludedDevices[i];
         if (identifier.name == item) {
-            ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
+            ALOGI("ignoring event id %s driver %s\n", devicePath.c_str(), item.c_str());
             close(fd);
             return -1;
         }
@@ -1249,7 +1284,7 @@
     // Get device driver version.
     int driverVersion;
     if (ioctl(fd, EVIOCGVERSION, &driverVersion)) {
-        ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
+        ALOGE("could not get driver version for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
         return -1;
     }
@@ -1257,7 +1292,7 @@
     // Get device identifier.
     struct input_id inputId;
     if (ioctl(fd, EVIOCGID, &inputId)) {
-        ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
+        ALOGE("could not get device input id for %s, %s\n", devicePath.c_str(), strerror(errno));
         close(fd);
         return -1;
     }
@@ -1289,7 +1324,7 @@
     int32_t deviceId = mNextDeviceId++;
     Device* device = new Device(fd, deviceId, devicePath, identifier);
 
-    ALOGV("add device %d: %s\n", deviceId, devicePath);
+    ALOGV("add device %d: %s\n", deviceId, devicePath.c_str());
     ALOGV("  bus:        %04x\n"
           "  vendor      %04x\n"
           "  product     %04x\n"
@@ -1446,7 +1481,7 @@
 
     // If the device isn't recognized as something we handle, don't monitor it.
     if (device->classes == 0) {
-        ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath,
+        ALOGV("Dropping device: id=%d, path='%s', name='%s'", deviceId, devicePath.c_str(),
               device->identifier.name.c_str());
         delete device;
         return -1;
@@ -1492,7 +1527,7 @@
 
     ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
           "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
-          deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
+          deviceId, fd, devicePath.c_str(), device->identifier.name.c_str(), device->classes,
           device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
           device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));
 
@@ -1724,13 +1759,13 @@
     return NAME_NOT_FOUND;
 }
 
-void EventHub::closeDeviceByPathLocked(const char* devicePath) {
+void EventHub::closeDeviceByPathLocked(const std::string& devicePath) {
     Device* device = getDeviceByPathLocked(devicePath);
     if (device) {
         closeDeviceLocked(device);
         return;
     }
-    ALOGV("Remove device: %s not found, device may already have been removed.", devicePath);
+    ALOGV("Remove device: %s not found, device may already have been removed.", devicePath.c_str());
 }
 
 /**
@@ -1834,23 +1869,25 @@
     while (res >= (int)sizeof(*event)) {
         event = (struct inotify_event*)(event_buf + event_pos);
         if (event->len) {
-            if (event->wd == mInputWd) {
-                std::string filename = StringPrintf("%s/%s", DEVICE_PATH, event->name);
+            if (event->wd == mDeviceInputWd) {
+                std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name;
                 if (event->mask & IN_CREATE) {
-                    openDeviceLocked(filename.c_str());
+                    openDeviceLocked(filename);
                 } else {
                     ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
-                    closeDeviceByPathLocked(filename.c_str());
+                    closeDeviceByPathLocked(filename);
                 }
-            } else if (event->wd == mVideoWd) {
+            } else if (event->wd == mDeviceWd) {
                 if (isV4lTouchNode(event->name)) {
-                    std::string filename = StringPrintf("%s/%s", VIDEO_DEVICE_PATH, event->name);
+                    std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
                     if (event->mask & IN_CREATE) {
                         openVideoDeviceLocked(filename);
                     } else {
                         ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
                         closeVideoDeviceByPathLocked(filename);
                     }
+                } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE ) {
+                    addDeviceInputInotify();
                 }
             } else {
                 LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);
@@ -1863,24 +1900,10 @@
     return 0;
 }
 
-status_t EventHub::scanDirLocked(const char* dirname) {
-    char devname[PATH_MAX];
-    char* filename;
-    DIR* dir;
-    struct dirent* de;
-    dir = opendir(dirname);
-    if (dir == nullptr) return -1;
-    strcpy(devname, dirname);
-    filename = devname + strlen(devname);
-    *filename++ = '/';
-    while ((de = readdir(dir))) {
-        if (de->d_name[0] == '.' &&
-            (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0')))
-            continue;
-        strcpy(filename, de->d_name);
-        openDeviceLocked(devname);
+status_t EventHub::scanDirLocked(const std::string& dirname) {
+    for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
+        openDeviceLocked(entry.path());
     }
-    closedir(dir);
     return 0;
 }
 
@@ -1888,22 +1911,12 @@
  * Look for all dirname/v4l-touch* devices, and open them.
  */
 status_t EventHub::scanVideoDirLocked(const std::string& dirname) {
-    DIR* dir;
-    struct dirent* de;
-    dir = opendir(dirname.c_str());
-    if (!dir) {
-        ALOGE("Could not open video directory %s", dirname.c_str());
-        return BAD_VALUE;
-    }
-
-    while ((de = readdir(dir))) {
-        const char* name = de->d_name;
-        if (isV4lTouchNode(name)) {
-            ALOGI("Found touch video device %s", name);
-            openVideoDeviceLocked(dirname + "/" + name);
+    for (const auto& entry : std::filesystem::directory_iterator(dirname)) {
+        if (isV4lTouchNode(entry.path())) {
+            ALOGI("Found touch video device %s", entry.path().c_str());
+            openVideoDeviceLocked(entry.path());
         }
     }
-    closedir(dir);
     return OK;
 }
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index f5451d7..55f658e 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -373,13 +373,13 @@
         }
     };
 
-    status_t openDeviceLocked(const char* devicePath);
+    status_t openDeviceLocked(const std::string& devicePath);
     void openVideoDeviceLocked(const std::string& devicePath);
     void createVirtualKeyboardLocked();
     void addDeviceLocked(Device* device);
     void assignDescriptorLocked(InputDeviceIdentifier& identifier);
 
-    void closeDeviceByPathLocked(const char* devicePath);
+    void closeDeviceByPathLocked(const std::string& devicePath);
     void closeVideoDeviceByPathLocked(const std::string& devicePath);
     void closeDeviceLocked(Device* device);
     void closeAllDevicesLocked();
@@ -396,14 +396,14 @@
     status_t unregisterDeviceFromEpollLocked(Device* device);
     void unregisterVideoDeviceFromEpollLocked(const TouchVideoDevice& videoDevice);
 
-    status_t scanDirLocked(const char* dirname);
+    status_t scanDirLocked(const std::string& dirname);
     status_t scanVideoDirLocked(const std::string& dirname);
     void scanDevicesLocked();
     status_t readNotifyLocked();
 
     Device* getDeviceByDescriptorLocked(const std::string& descriptor) const;
     Device* getDeviceLocked(int32_t deviceId) const;
-    Device* getDeviceByPathLocked(const char* devicePath) const;
+    Device* getDeviceByPathLocked(const std::string& devicePath) const;
     /**
      * Look through all available fd's (both for input devices and for video devices),
      * and return the device pointer.
@@ -426,6 +426,9 @@
     status_t mapLed(Device* device, int32_t led, int32_t* outScanCode) const;
     void setLedStateLocked(Device* device, int32_t led, bool on);
 
+    void addDeviceInputInotify();
+    void addDeviceInotify();
+
     // Protect all internal state.
     mutable Mutex mLock;
 
@@ -465,8 +468,8 @@
     int mWakeReadPipeFd;
     int mWakeWritePipeFd;
 
-    int mInputWd;
-    int mVideoWd;
+    int mDeviceInputWd;
+    int mDeviceWd = -1;
 
     // Maximum number of signalled FDs to handle at a time.
     static const int EPOLL_MAX_EVENTS = 16;
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 86ed60d..24a27cf 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -46,5 +46,8 @@
         "InputReader_test.cpp",
         "UinputDevice.cpp",
     ],
+    static_libs: [
+        "libc++fs"
+    ],
     require_root: true,
 }
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 6b3bf8d..4e84e52 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -144,6 +144,7 @@
         "DisplayHardware/ComposerHal.cpp",
         "DisplayHardware/DisplayIdentification.cpp",
         "DisplayHardware/FramebufferSurface.cpp",
+        "DisplayHardware/Hash.cpp",
         "DisplayHardware/HWC2.cpp",
         "DisplayHardware/HWComposer.cpp",
         "DisplayHardware/PowerAdvisor.cpp",
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
index 4dfc743..20f3fd2 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -29,6 +29,7 @@
 #include <log/log.h>
 
 #include "DisplayIdentification.h"
+#include "Hash.h"
 
 namespace android {
 namespace {
@@ -281,8 +282,9 @@
     }
 
     // Hash model string instead of using product code or (integer) serial number, since the latter
-    // have been observed to change on some displays with multiple inputs.
-    const auto modelHash = static_cast<uint32_t>(std::hash<std::string_view>()(modelString));
+    // have been observed to change on some displays with multiple inputs. Use a stable hash instead
+    // of std::hash which is only required to be same within a single execution of a program.
+    const uint32_t modelHash = static_cast<uint32_t>(cityHash64Len0To16(modelString));
 
     // Parse extension blocks.
     std::optional<Cea861ExtensionBlock> cea861Block;
diff --git a/services/surfaceflinger/DisplayHardware/Hash.cpp b/services/surfaceflinger/DisplayHardware/Hash.cpp
new file mode 100644
index 0000000..6056c8d
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/Hash.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplayIdentification"
+
+#include <cstring>
+#include <type_traits>
+
+#include <log/log.h>
+
+#include "Hash.h"
+
+namespace android {
+namespace {
+
+template <class T>
+inline T load(const void* p) {
+    static_assert(std::is_integral<T>::value, "T must be integral");
+
+    T r;
+    std::memcpy(&r, p, sizeof(r));
+    return r;
+}
+
+uint64_t rotateByAtLeast1(uint64_t val, uint8_t shift) {
+    return (val >> shift) | (val << (64 - shift));
+}
+
+uint64_t shiftMix(uint64_t val) {
+    return val ^ (val >> 47);
+}
+
+uint64_t hash64Len16(uint64_t u, uint64_t v) {
+    constexpr uint64_t kMul = 0x9ddfea08eb382d69;
+    uint64_t a = (u ^ v) * kMul;
+    a ^= (a >> 47);
+    uint64_t b = (v ^ a) * kMul;
+    b ^= (b >> 47);
+    b *= kMul;
+    return b;
+}
+
+uint64_t hash64Len0To16(const char* s, uint64_t len) {
+    constexpr uint64_t k2 = 0x9ae16a3b2f90404f;
+    constexpr uint64_t k3 = 0xc949d7c7509e6557;
+
+    if (len > 8) {
+        const uint64_t a = load<uint64_t>(s);
+        const uint64_t b = load<uint64_t>(s + len - 8);
+        return hash64Len16(a, rotateByAtLeast1(b + len, static_cast<uint8_t>(len))) ^ b;
+    }
+    if (len >= 4) {
+        const uint32_t a = load<uint32_t>(s);
+        const uint32_t b = load<uint32_t>(s + len - 4);
+        return hash64Len16(len + (a << 3), b);
+    }
+    if (len > 0) {
+        const unsigned char a = static_cast<unsigned char>(s[0]);
+        const unsigned char b = static_cast<unsigned char>(s[len >> 1]);
+        const unsigned char c = static_cast<unsigned char>(s[len - 1]);
+        const uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
+        const uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
+        return shiftMix(y * k2 ^ z * k3) * k2;
+    }
+    return k2;
+}
+
+} // namespace
+
+uint64_t cityHash64Len0To16(std::string_view sv) {
+    auto len = sv.length();
+    if (len > 16) {
+        ALOGE("%s called with length %zu. Only hashing the first 16 chars", __FUNCTION__, len);
+        len = 16;
+    }
+    return hash64Len0To16(sv.data(), len);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/Hash.h b/services/surfaceflinger/DisplayHardware/Hash.h
new file mode 100644
index 0000000..a7b6c71
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/Hash.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <string_view>
+
+namespace android {
+
+// CityHash64 implementation that only hashes at most the first 16 characters of the given string.
+uint64_t cityHash64Len0To16(std::string_view sv);
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 2a0e913..300ef26 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -21,6 +21,7 @@
 #include <gtest/gtest.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/Hash.h"
 
 namespace android {
 namespace {
@@ -128,7 +129,7 @@
 }
 
 uint32_t hash(const char* str) {
-    return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+    return static_cast<uint32_t>(cityHash64Len0To16(str));
 }
 
 } // namespace
@@ -303,9 +304,9 @@
     ASSERT_TRUE(tertiaryInfo);
 
     // Display IDs should be unique.
-    EXPECT_NE(primaryInfo->id, secondaryInfo->id);
-    EXPECT_NE(primaryInfo->id, tertiaryInfo->id);
-    EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
+    EXPECT_EQ(21571479025788672, primaryInfo->id.value);
+    EXPECT_EQ(9834267132873217, secondaryInfo->id.value);
+    EXPECT_EQ(21441883803501570, tertiaryInfo->id.value);
 }
 
 TEST(DisplayIdentificationTest, deviceProductInfo) {
diff --git a/vulkan/README.md b/vulkan/README.md
index 185aa39..144805c 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -14,7 +14,7 @@
 
 ## Code Generation
 
-We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
+We generate several parts of the loader and tools directly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
 
 ### Run The Code Generator