Merge "servicedispatcher: exit when adb debugging is turned off."
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
index 0c78c5a..8262bc2 100644
--- a/cmds/cmd/fuzzer/Android.bp
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -14,6 +14,15 @@
  * 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: [
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 87a10d3..2127f57 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,6 +189,10 @@
         "libutils",
     ],
 
+    static_libs: [
+        "libbase",
+    ],
+
     header_libs: [
         "libbinder_headers",
         "libandroid_runtime_vm_headers",
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/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..e38ac63
--- /dev/null
+++ b/libs/binder/FdTrigger.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 = 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 & event ? OK : DEAD_OBJECT;
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
new file mode 100644
index 0000000..984e685
--- /dev/null
+++ b/libs/binder/FdTrigger.h
@@ -0,0 +1,56 @@
+/*
+ * 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/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();
+
+    /**
+     * Whether this has been triggered.
+     */
+    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);
+
+private:
+    base::unique_fd mWrite;
+    base::unique_fd mRead;
+};
+} // namespace android
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 62ea187..a20445b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -26,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"
@@ -37,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;
         }
 
@@ -80,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));
@@ -93,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) {
@@ -152,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->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));
@@ -220,6 +229,7 @@
     LOG_RPC_DETAIL("Finished waiting on shutdown.");
 
     mShutdownTrigger = nullptr;
+    mCtx = nullptr;
     return true;
 }
 
@@ -245,14 +255,29 @@
     // 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));
-    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
+    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 incoming = false;
@@ -272,8 +297,8 @@
                     .version = protocolVersion,
             };
 
-            status = server->mShutdownTrigger->interruptableWriteFully(clientFd.get(), &response,
-                                                                       sizeof(response));
+            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
@@ -342,7 +367,7 @@
         }
 
         if (incoming) {
-            LOG_ALWAYS_FATAL_IF(!session->addOutgoingConnection(std::move(clientFd), true),
+            LOG_ALWAYS_FATAL_IF(OK != session->addOutgoingConnection(std::move(client), true),
                                 "server state must already be initialized");
             return;
         }
@@ -351,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;
@@ -359,21 +384,22 @@
     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;
     }
 
     // Right now, we create all threads at once, making accept4 slow. To avoid hanging the client,
@@ -383,16 +409,16 @@
     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::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
@@ -425,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 254b99c..4c47005 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -30,13 +30,16 @@
 #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();
@@ -46,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>();
@@ -59,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) {
@@ -102,34 +109,63 @@
     return mProtocolVersion;
 }
 
-bool RpcSession::setupUnixDomainClient(const char* path) {
+status_t RpcSession::setupUnixDomainClient(const char* path) {
     return setupSocketClient(UnixSocketAddress(path));
 }
 
-bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
+status_t RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
     return setupSocketClient(VsockSocketAddress(cid, port));
 }
 
-bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
+status_t RpcSession::setupInetClient(const char* addr, unsigned int port) {
     auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
-    if (aiStart == nullptr) return false;
+    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 (setupSocketClient(socketAddress)) return true;
+        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 false;
+    return NAME_NOT_FOUND;
 }
 
-bool RpcSession::addNullDebuggingClient() {
+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) {
-        ALOGE("Could not connect to /dev/null: %s", strerror(errno));
-        return false;
+        int savedErrno = errno;
+        ALOGE("Could not connect to /dev/null: %s", strerror(savedErrno));
+        return -savedErrno;
     }
 
-    return addOutgoingConnection(std::move(serverFd), false);
+    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() {
@@ -188,83 +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::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 = 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 & event ? OK : DEAD_OBJECT;
-    }
-}
-
-status_t RpcSession::FdTrigger::interruptableWriteFully(base::borrowed_fd fd, const void* data,
-                                                        size_t size) {
-    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 = triggerablePoll(fd, POLLOUT)) == OK) {
-        ssize_t writeSize = TEMP_FAILURE_RETRY(send(fd.get(), buffer, end - buffer, MSG_NOSIGNAL));
-        if (writeSize == 0) return DEAD_OBJECT;
-
-        if (writeSize < 0) {
-            return -errno;
-        }
-        buffer += writeSize;
-        if (buffer == end) return OK;
-    }
-    return status;
-}
-
-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 = triggerablePoll(fd, POLLIN)) == 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);
@@ -312,10 +271,11 @@
     }
 }
 
-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;
 
@@ -439,48 +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 /*incoming*/)) return false;
+    if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
+        return status;
 
     {
         ExclusiveConnection connection;
-        status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
-                                                    ConnectionUse::CLIENT, &connection);
-        if (status != OK) return false;
+        if (status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
+                                                        ConnectionUse::CLIENT, &connection);
+            status != OK)
+            return status;
 
         uint32_t version;
-        status = state()->readNewSessionResponse(connection.get(),
-                                                 sp<RpcSession>::fromExisting(this), &version);
-        if (!setProtocolVersion(version)) return false;
+        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 /*incoming*/)) return false;
+        return status;
     }
 
     // TODO(b/189955605): we should add additional sessions dynamically
@@ -489,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 /*incoming*/)) 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 incoming) {
+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()))) {
@@ -515,41 +488,87 @@
                 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{
-                .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
-                .options = 0,
-        };
-        memcpy(&header.sessionId, &id.viewRawEmbedded(), sizeof(RpcWireAddress));
-
-        if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
-
-        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 (incoming) {
-            return addIncomingConnection(std::move(serverFd));
-        } 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::addIncomingConnection(unique_fd fd) {
+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);
@@ -558,13 +577,13 @@
     bool ownershipTransferred = false;
     thread = std::thread([&]() {
         std::unique_lock<std::mutex> threadLock(mutex);
-        unique_fd movedFd = std::move(fd);
+        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(movedFd));
+        auto setupResult = session->preJoinSetup(std::move(movedRpcTransport));
 
         ownershipTransferred = true;
         threadLock.unlock();
@@ -575,23 +594,25 @@
     });
     joinCv.wait(lock, [&] { return ownershipTransferred; });
     LOG_ALWAYS_FATAL_IF(!ownershipTransferred);
-    return true;
+    return OK;
 }
 
-bool RpcSession::addOutgoingConnection(unique_fd fd, bool init) {
+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);
     }
@@ -606,7 +627,7 @@
         connection->exclusiveTid = std::nullopt;
     }
 
-    return status == OK;
+    return status;
 }
 
 bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
@@ -626,9 +647,16 @@
     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
@@ -638,7 +666,7 @@
     }
 
     sp<RpcConnection> session = sp<RpcConnection>::make();
-    session->fd = std::move(fd);
+    session->rpcTransport = std::move(rpcTransport);
     session->exclusiveTid = gettid();
 
     mIncomingConnections.push_back(session);
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index f3406bb..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>
@@ -272,8 +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());
+    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);
@@ -281,11 +282,12 @@
         return BAD_VALUE;
     }
 
-    if (status_t status = session->mShutdownTrigger->interruptableWriteFully(connection->fd.get(),
-                                                                             data, size);
+    if (status_t status =
+                connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
+                                                                  data, size);
         status != OK) {
-        LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on fd %d, error: %s", what, size,
-                       connection->fd.get(), statusToString(status).c_str());
+        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 status;
     }
@@ -303,15 +305,16 @@
     }
 
     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;
 }
 
@@ -489,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,
@@ -584,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));
@@ -597,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/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/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 1c2f9b4..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();
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/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 40ff78c..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();
 
@@ -161,14 +170,15 @@
 
 private:
     friend sp<RpcServer>;
-    RpcServer();
+    explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
 
     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;
@@ -181,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 1f7c029..761c50d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -18,6 +18,8 @@
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
 #include <binder/RpcAddress.h>
+#include <binder/RpcSession.h>
+#include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
@@ -36,6 +38,8 @@
 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;
@@ -48,7 +52,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).
@@ -74,17 +79,30 @@
      * 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!
@@ -93,7 +111,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
@@ -142,49 +160,7 @@
     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.
-         *
-         * event - for pollfd
-         *
-         * Return:
-         *   true - time to read!
-         *   false - trigger happened
-         */
-        status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
-
-        /**
-         * Read (or write), but allow to be interrupted by this trigger.
-         *
-         * Return:
-         *   true - succeeded in completely processing 'size'
-         *   false - interrupted (failure or trigger)
-         */
-        status_t interruptableReadFully(base::borrowed_fd fd, void* data, size_t size);
-        status_t interruptableWriteFully(base::borrowed_fd fd, const 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:
@@ -204,7 +180,7 @@
     };
 
     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.
@@ -230,21 +206,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 addIncomingConnection(base::unique_fd fd);
-    [[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,
@@ -275,6 +260,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).
     //
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/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/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/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index 5ad390e..b5c06e9 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -224,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());
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/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 0bff2a7..9811cdf 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -36,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;
@@ -50,6 +51,7 @@
 
 namespace {
 
+const char* kLocalInetAddress = "127.0.0.1";
 using ServiceRetriever = decltype(&android::IServiceManager::checkService);
 using android::debug::IAdbManager;
 
@@ -90,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();
@@ -203,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;
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
index 5dd9212..3f72b8f 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -101,8 +101,9 @@
 
     [[nodiscard]] static sp<IBinder> get(unsigned int hostPort) {
         auto rpcSession = RpcSession::make();
-        if (!rpcSession->setupInetClient("127.0.0.1", hostPort)) {
-            ADD_FAILURE() << "Failed to setupInetClient on " << hostPort;
+        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();
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 5f4a7b5..0c452ff 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -42,6 +42,8 @@
 using android::RpcServer;
 using android::RpcSession;
 using android::sp;
+using android::status_t;
+using android::statusToString;
 using android::String16;
 using android::binder::Status;
 
@@ -50,8 +52,12 @@
         *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();
     }
 };
@@ -61,12 +67,11 @@
     RPC,
 };
 
-static void EachTransport(benchmark::internal::Benchmark* b) {
+static const std::initializer_list<int64_t> kTransportList = {
 #ifdef __BIONIC__
-    b->Args({Transport::KERNEL});
+        Transport::KERNEL,
 #endif
-    b->Args({Transport::RPC});
-}
+        Transport::RPC};
 
 static sp<RpcSession> gSession = RpcSession::make();
 #ifdef __BIONIC__
@@ -96,9 +101,9 @@
         CHECK_EQ(OK, binder->pingBinder());
     }
 }
-BENCHMARK(BM_pingTransaction)->Apply(EachTransport);
+BENCHMARK(BM_pingTransaction)->ArgsProduct({kTransportList});
 
-void BM_repeatString(benchmark::State& state) {
+void BM_repeatTwoPageString(benchmark::State& state) {
     sp<IBinder> binder = getBinderForOptions(state);
 
     sp<IBinderRpcBenchmark> iface = interface_cast<IBinderRpcBenchmark>(binder);
@@ -125,7 +130,27 @@
         CHECK(ret.isOk()) << ret;
     }
 }
-BENCHMARK(BM_repeatString)->Apply(EachTransport);
+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();
@@ -142,7 +167,7 @@
         CHECK(ret.isOk()) << ret;
     }
 }
-BENCHMARK(BM_repeatBinder)->Apply(EachTransport);
+BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
 
 int main(int argc, char** argv) {
     ::benchmark::Initialize(&argc, argv);
@@ -152,15 +177,15 @@
     (void)unlink(addr.c_str());
 
     std::cerr << "Tests suffixes:" << std::endl;
-    std::cerr << "\t\\" << Transport::KERNEL << " is KERNEL" << std::endl;
-    std::cerr << "\t\\" << Transport::RPC << " is RPC" << 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();
         exit(1);
     }
@@ -182,11 +207,13 @@
     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 d5786bc..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_*
 
@@ -49,6 +52,22 @@
 
 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;
@@ -57,13 +76,20 @@
     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());
@@ -384,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:
@@ -402,7 +431,21 @@
     }
 }
 
-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;
@@ -410,13 +453,19 @@
         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(
             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();
@@ -424,7 +473,7 @@
 
         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(options.numThreads);
@@ -432,14 +481,16 @@
                     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;
                         }
@@ -465,24 +516,35 @@
             CHECK_NE(0, outPort);
         }
 
+        status_t status;
+
         for (size_t i = 0; i < options.numSessions; i++) {
-            sp<RpcSession> session = RpcSession::make();
+            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()});
         }
@@ -1130,21 +1192,27 @@
 }
 
 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);
+    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: %d", okay);
-    return okay;
+    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();
 
@@ -1155,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>)>;
@@ -1166,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);
@@ -1184,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:
@@ -1207,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
@@ -1253,14 +1325,14 @@
     auto rpcServer = RpcServer::make();
     rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     unsigned int port;
-    ASSERT_TRUE(rpcServer->setupInetServer(0, &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_TRUE(rpcSession->setupInetClient("127.0.0.1", port));
+    ASSERT_EQ(OK, rpcSession->setupInetClient("127.0.0.1", port));
     auto rpcBinder = rpcSession->getRootObject();
     ASSERT_NE(nullptr, rpcBinder);
 
@@ -1271,6 +1343,9 @@
     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(); });