Merge "libbinder: split out PackageManagerNative aidl"
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index be2c702..8f1c01a 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -52,7 +52,7 @@
 }
 
 struct SecurityContext_Delete {
-    void operator()(security_context_t p) const {
+    void operator()(char* p) const {
         freecon(p);
     }
 };
@@ -108,7 +108,7 @@
         }
         if (is_selinux_enabled() && seLinuxContext.size() > 0) {
             String8 seLinuxContext8(seLinuxContext);
-            security_context_t tmp = nullptr;
+            char* tmp = nullptr;
             getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
             if (checkWrite) {
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 1db2867..75caac1 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1236,22 +1236,29 @@
         std::string path(title);
         path.append(" - ").append(String8(service).c_str());
         size_t bytes_written = 0;
-        status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
-        if (status == OK) {
-            dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
-            std::chrono::duration<double> elapsed_seconds;
-            if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
-                service == String16("meminfo")) {
-                // Use a longer timeout for meminfo, since 30s is not always enough.
-                status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
-                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
-            } else {
-                status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
-                                           /* as_proto = */ false, elapsed_seconds, bytes_written);
+        if (PropertiesHelper::IsDryRun()) {
+             dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+             dumpsys.writeDumpFooter(STDOUT_FILENO, service, std::chrono::milliseconds(1));
+        } else {
+            status_t status = dumpsys.startDumpThread(Dumpsys::TYPE_DUMP, service, args);
+            if (status == OK) {
+                dumpsys.writeDumpHeader(STDOUT_FILENO, service, priority);
+                std::chrono::duration<double> elapsed_seconds;
+                if (priority == IServiceManager::DUMP_FLAG_PRIORITY_HIGH &&
+                    service == String16("meminfo")) {
+                    // Use a longer timeout for meminfo, since 30s is not always enough.
+                    status = dumpsys.writeDump(STDOUT_FILENO, service, 60s,
+                                               /* as_proto = */ false, elapsed_seconds,
+                                                bytes_written);
+                } else {
+                    status = dumpsys.writeDump(STDOUT_FILENO, service, service_timeout,
+                                               /* as_proto = */ false, elapsed_seconds,
+                                                bytes_written);
+                }
+                dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
+                bool dump_complete = (status == OK);
+                dumpsys.stopDumpThread(dump_complete);
             }
-            dumpsys.writeDumpFooter(STDOUT_FILENO, service, elapsed_seconds);
-            bool dump_complete = (status == OK);
-            dumpsys.stopDumpThread(dump_complete);
         }
 
         auto elapsed_duration = std::chrono::duration_cast<std::chrono::milliseconds>(
@@ -1831,8 +1838,10 @@
     }
 
     /* Run some operations that require root. */
-    ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
-    ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+    if (!PropertiesHelper::IsDryRun()) {
+        ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
+        ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
+    }
 
     ds.AddDir(RECOVERY_DIR, true);
     ds.AddDir(RECOVERY_DATA_DIR, true);
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index fa63db5..677d6c7 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -60,6 +60,7 @@
     MOCK_METHOD1(isDeclared, bool(const String16&));
     MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
     MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&));
+    MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 0c3fb96..863490d 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -82,6 +82,7 @@
                 continue;
             }
             out->write(buffer, n);
+            continue;
         }
         if (pfd[0].revents & POLLHUP) {
             break;
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 6f08f74..cba7c4b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -22,9 +22,10 @@
 #include <thread>
 #include <vector>
 
-#include <gtest/gtest.h>
-#include <gmock/gmock.h>
+#include <android-base/parseint.h>
 #include <android/hardware/tests/inheritance/1.0/IChild.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
 #include <hidl/HidlTransportSupport.h>
 #include <vintf/parse_xml.h>
 
@@ -77,6 +78,13 @@
             content += "\n";
             content += option.c_str();
         }
+        if (options.size() > 0) {
+            uint64_t len;
+            if (android::base::ParseUint(options[0], &len)) {
+                content += "\n";
+                content += std::string(len, 'X');
+            }
+        }
         ssize_t written = write(fd, content.c_str(), content.size());
         if (written != (ssize_t)content.size()) {
             LOG(WARNING) << "SERVER(Child) debug writes " << written << " bytes < "
@@ -189,6 +197,16 @@
     EXPECT_THAT(err.str(), HasSubstr("does not exist"));
 }
 
+TEST_F(DebugTest, DebugLarge) {
+    EXPECT_EQ(0u, callMain(lshal, {
+        "lshal", "debug", "android.hardware.tests.inheritance@1.0::IChild/default", "10000"
+    }));
+    EXPECT_THAT(out.str(),
+                StrEq("android.hardware.tests.inheritance@1.0::IChild\n10000\n" +
+                      std::string(10000, 'X')));
+    EXPECT_THAT(err.str(), IsEmpty());
+}
+
 TEST_F(DebugTest, DebugParent) {
     EXPECT_EQ(0u, callMain(lshal, {
         "lshal", "debug", "android.hardware.tests.inheritance@1.0::IParent", "calling parent"
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index 90db509..4e44ac7 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -121,6 +121,35 @@
     return updatableViaApex;
 }
 
+static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) {
+    AidlName aname;
+    if (!AidlName::fill(name, &aname)) return std::nullopt;
+
+    std::optional<std::string> ip;
+    std::optional<uint64_t> port;
+    forEachManifest([&](const ManifestWithDescription& mwd) {
+        mwd.manifest->forEachInstance([&](const auto& manifestInstance) {
+            if (manifestInstance.format() != vintf::HalFormat::AIDL) return true;
+            if (manifestInstance.package() != aname.package) return true;
+            if (manifestInstance.interface() != aname.iface) return true;
+            if (manifestInstance.instance() != aname.instance) return true;
+            ip = manifestInstance.ip();
+            port = manifestInstance.port();
+            return false; // break (libvintf uses opposite convention)
+        });
+        return false; // continue
+    });
+
+    if (ip.has_value() && port.has_value()) {
+        ConnectionInfo info;
+        info.ipAddress = *ip;
+        info.port = *port;
+        return std::make_optional<ConnectionInfo>(info);
+    } else {
+        return std::nullopt;
+    }
+}
+
 static std::vector<std::string> getVintfInstances(const std::string& interface) {
     size_t lastDot = interface.rfind('.');
     if (lastDot == std::string::npos) {
@@ -437,6 +466,22 @@
     return Status::ok();
 }
 
+Status ServiceManager::getConnectionInfo(const std::string& name,
+                                         std::optional<ConnectionInfo>* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    if (!mAccess->canFind(ctx, name)) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    *outReturn = std::nullopt;
+
+#ifndef VENDORSERVICEMANAGER
+    *outReturn = getVintfConnectionInfo(name);
+#endif
+    return Status::ok();
+}
+
 void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
                                     ServiceCallbackMap::iterator* it,
                                     bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 4f23c21..5e40319 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -24,6 +24,7 @@
 
 namespace android {
 
+using os::ConnectionInfo;
 using os::IClientCallback;
 using os::IServiceCallback;
 using os::ServiceDebugInfo;
@@ -48,6 +49,8 @@
     binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
     binder::Status updatableViaApex(const std::string& name,
                                     std::optional<std::string>* outReturn) override;
+    binder::Status getConnectionInfo(const std::string& name,
+                                     std::optional<ConnectionInfo>* outReturn) override;
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                           const sp<IClientCallback>& cb) override;
     binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
new file mode 100644
index 0000000..235990a
--- /dev/null
+++ b/data/etc/Android.bp
@@ -0,0 +1,233 @@
+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_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+prebuilt_defaults {
+    name: "frameworks_native_data_etc_defaults",
+    relative_install_path: "permissions",
+    soc_specific: true,
+}
+
+// Modules use the 'prebuilt.xml' suffix to prevent conflicting
+// overridden paths, so that this Android.bp can exist alongside
+// devices that use PRODUCT_COPY_FILES for these files.
+//
+// This override prevention is also possible using a soong_namespace,
+// but that requires every dependent module (e.g. an APEX that includes
+// one of these files) to also reference this namespace, and so on
+// for all dependent modules. It is simpler to just use new path names.
+
+prebuilt_etc {
+    name: "android.hardware.audio.low_latency.prebuilt.xml",
+    src: "android.hardware.audio.low_latency.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.biometrics.face.prebuilt.xml",
+    src: "android.hardware.biometrics.face.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.bluetooth_le.prebuilt.xml",
+    src: "android.hardware.bluetooth_le.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.bluetooth.prebuilt.xml",
+    src: "android.hardware.bluetooth.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.camera.concurrent.prebuilt.xml",
+    src: "android.hardware.camera.concurrent.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.camera.flash-autofocus.prebuilt.xml",
+    src: "android.hardware.camera.flash-autofocus.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.camera.front.prebuilt.xml",
+    src: "android.hardware.camera.front.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.camera.full.prebuilt.xml",
+    src: "android.hardware.camera.full.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.camera.raw.prebuilt.xml",
+    src: "android.hardware.camera.raw.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.ethernet.prebuilt.xml",
+    src: "android.hardware.ethernet.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.faketouch.prebuilt.xml",
+    src: "android.hardware.faketouch.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.location.gps.prebuilt.xml",
+    src: "android.hardware.location.gps.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.reboot_escrow.prebuilt.xml",
+    src: "android.hardware.reboot_escrow.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.ambient_temperature.prebuilt.xml",
+    src: "android.hardware.sensor.ambient_temperature.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.barometer.prebuilt.xml",
+    src: "android.hardware.sensor.barometer.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.gyroscope.prebuilt.xml",
+    src: "android.hardware.sensor.gyroscope.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.hinge_angle.prebuilt.xml",
+    src: "android.hardware.sensor.hinge_angle.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.light.prebuilt.xml",
+    src: "android.hardware.sensor.light.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.proximity.prebuilt.xml",
+    src: "android.hardware.sensor.proximity.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.sensor.relative_humidity.prebuilt.xml",
+    src: "android.hardware.sensor.relative_humidity.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.telephony.gsm.prebuilt.xml",
+    src: "android.hardware.telephony.gsm.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.telephony.ims.prebuilt.xml",
+    src: "android.hardware.telephony.ims.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.usb.accessory.prebuilt.xml",
+    src: "android.hardware.usb.accessory.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.usb.host.prebuilt.xml",
+    src: "android.hardware.usb.host.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.vulkan.level-0.prebuilt.xml",
+    src: "android.hardware.vulkan.level-0.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.vulkan.version-1_0_3.prebuilt.xml",
+    src: "android.hardware.vulkan.version-1_0_3.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.hardware.wifi.prebuilt.xml",
+    src: "android.hardware.wifi.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.device_id_attestation.prebuilt.xml",
+    src: "android.software.device_id_attestation.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.ipsec_tunnels.prebuilt.xml",
+    src: "android.software.ipsec_tunnels.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.opengles.deqp.level-2021-03-01.prebuilt.xml",
+    src: "android.software.opengles.deqp.level-2021-03-01.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.sip.voip.prebuilt.xml",
+    src: "android.software.sip.voip.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.verified_boot.prebuilt.xml",
+    src: "android.software.verified_boot.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "android.software.vulkan.deqp.level-2021-03-01.prebuilt.xml",
+    src: "android.software.vulkan.deqp.level-2021-03-01.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "aosp_excluded_hardware.prebuilt.xml",
+    src: "aosp_excluded_hardware.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
+    name: "handheld_core_hardware.prebuilt.xml",
+    src: "handheld_core_hardware.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
diff --git a/data/etc/apex/Android.bp b/data/etc/apex/Android.bp
new file mode 100644
index 0000000..8c4929c
--- /dev/null
+++ b/data/etc/apex/Android.bp
@@ -0,0 +1,34 @@
+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_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+apex_key {
+    name: "com.android.hardware.core_permissions.key",
+    public_key: "com.android.hardware.core_permissions.avbpubkey",
+    private_key: "com.android.hardware.core_permissions.pem",
+}
+
+android_app_certificate {
+    name: "com.android.hardware.core_permissions.certificate",
+    certificate: "com.android.hardware.core_permissions",
+}
+
+apex {
+    name: "com.android.hardware.core_permissions",
+    manifest: "apex_manifest.json",
+    key: "com.android.hardware.core_permissions.key",
+    certificate: ":com.android.hardware.core_permissions.certificate",
+    file_contexts: "file_contexts",
+    updatable: false,
+    // Install the apex in /vendor/apex
+    soc_specific: true,
+    prebuilts: [
+        "handheld_core_hardware.prebuilt.xml",
+        "aosp_excluded_hardware.prebuilt.xml",
+    ],
+}
diff --git a/data/etc/apex/apex_manifest.json b/data/etc/apex/apex_manifest.json
new file mode 100644
index 0000000..5bbf229
--- /dev/null
+++ b/data/etc/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.hardware.core_permissions",
+  "version": 1
+}
diff --git a/data/etc/apex/com.android.hardware.core_permissions.avbpubkey b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
new file mode 100644
index 0000000..b9164fb
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.avbpubkey
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pem b/data/etc/apex/com.android.hardware.core_permissions.pem
new file mode 100644
index 0000000..7e2826d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKgIBAAKCAgEAuJjZgFCp6uX+xgKET1FsXYqEPGfYEWUWJ4VSP+Y5fgth/Om3
+XCRBhKSD4CPyL/E9ohh7eSLRqIzw/idUazgCqk+yYLiVkYZiuY02jcui1/Vze9er
+Nwi0ZSwA+zcvKCEOwZ3PBT6W1kehiQ5PU0IS+78po8LoUrvycmvbXJTHlVt1x2bo
+y2DQmxRjIH9xfACwFwh/JnKyr1O2NGjFbk+z3CYx9l7c0Ew9U/kGL3teSbMEi1le
+2PApAHYUA+kXiwjF07aRUN+zzSdZsI7goQXEsmqGXNy7Fzdp/UDocayBmCdI3a35
+igcPRUryBIf1YdSS+E9DwoXRR7pwzs4ajvVTrzuv7UohTnhPwj95TD0E3Z64r7S7
+AT4jtm9gbkAsKNkKOqioGTEIdmvj2prOA4wOUmVBGwOjGcjsyEPJaa56s0WEXUop
++OD2ZMV3StAIwQ5c/gpFzxWl+qATv3MH9MgwAIjT1TDyXv0R+q9JbFbgTtO748RS
+MZUb1i2odggNQCWRtv8fqJ7c51H7pUpHXCXElXHysFq2oBOY4J1jXr1craxsPn1P
+RcImVwAYTV80jOfmYtWhdJhDavDeD4uinLw+4HeZnFNwZXqCJl0LtLxMDRxoDCr7
+YgT2znh9BM6XXg8jekfkDYb5wyloU1eOZJMxF04pGecDB9n1w/OFBA4v0WECAwEA
+AQKCAgEArjhsRsNaqvzo6L7lWurxCJO73Drx3PD36NLWXsKNjl113LpEOO1q/KI8
+aKXkZMUdM0hB+IEZOSfUJzq9XPge49iV9N0hJJidwpv5WfhQN9xLYx2YVTec8kOG
+pZJeqlQQ1kF3am6484HlfjIIQf8BZaH0zb8df0AtQTp0bTtp5pfMYCbLHW/BUiv6
+pmhBlhQcHZECWCo2ZGzwcSRU+Zi1mthdnTXI17qswv0rjlK0GYCgkFgHwV1ghTPs
+DgjHFIxyES+klJyc2MoDxzQB41dLXkxVhX06Al5lZQUGnIqAQTcKeVZCRrgE/JQQ
+OKCMwglbsIk23XdonnbjEvvIaxY1JHjcnPBpOC4+O11fE0DiHXK3GBj5KlfVvB5D
+oMWko3R/Ky/T/KJhHYXbC1H71oYueCaY57kHFKk2k3qRJG4DU4MY20cfUZ0vp14H
+KJ++gDy0pxxjl4ZUiryBCti5k5GPU8Mm46MLJ/YPdX6Dj1nMtOgGpZkGQYIKPhEI
+qZjZBRyZlHeTJsTMc8Eh3/Krimmra5ID95HfJnTTHHshbRcLwL6/zMTU5fkwarsC
+f4HQ0602/9HqyI8Ty1S9Z4oByjwfW2uDcosnuOPfk/8XwfLWxrf2+TsAd3cXhOKw
+rwUfELzcgYNueLGTJOCsEJfo8NIIEGJCNSgMnWXmIAUIAlrMP8ECggEBAOt9X4Lb
+fkrQLjcQ+K1oOI0Q+43htNRYXiG2IDhmDlA+UnqPP+9j2cVyuo4QYhKTFXRbbezR
+blUHAowd4hKHtODaHMuq90KbeByVNB8idcIb+ELAOK4Ff+qd9ijrBIOuZZQB+KOo
+SlxVjy1LM0QGtUTJRHx4dkCmp+hMqrIc4LQOWd4hV5h85Oj8kp1L1eMvxEStUtwP
+tYR80OoOdDxgXcBHLdPs4rc0WunRabGE+cnCMrTy31D95OWg6aw/+XKSTUS5Hfdy
+4jDIwP8DR6JU71qNgen+fwrHFeDienM40sSpi85/WQndQW5TwOMbDlEfmgn6D4+s
+rVWqFk1XElfwwSkCggEBAMisvdv5fH4UeH+tz5cF5f3ZNY+NX8uj85wCsJAPaAVx
+i3t8BqEKUPA6FPt9SDMWg4QtgSSl0NmhH2F9CcAZUCiTZUrtgqyIo80ALONW1FR9
+ofElvZEeV2IzKn3Ci4HA2pKRtMcjjVLwxzdoHakbPS9CbdCGKYE3W75Huw410IW6
+gV4zQ2mWHT+FxXaatl6Arj0x7DHLeSrMV33uxcYWoclmrAK24uhq2gwhtC8U0SvY
+rtJ7+KpCRd5v3Cyzo2AEbZKyJYVKbMDu9RHDZwkZw6wVqaOKBPJVyC++yidksexX
+ZT0WGX0f23t+2jbbsNY6H27pJm9ApLuAYwiMGv9n/XkCggEADLlAcNyVLUukQ5tq
+JExuScjyHo9kati/dUjW4tU4zsMfR7n3tWKKwK1bQRPHiMNjtF7ASLxkHrn7PEDd
+Fy0367I9Pg/lvjaSPdEd+NSu0icaudiS92wapj2UsE9Kdib1HBMjMQyFwAlrbAIV
+KgbGwomxZpxHn2Shy95glrESvwfLeUIJ7pZI9AG5lkAjtVu+WguXX4aFwzvPOeZA
+B4cZaasu4bV55nYwt1N2R34s1ObmQHqi8EhXlsSj+4eVXchj3mO2J8mQSRx/uQef
+VjkKmbTtoQv8J0PsfbMe9JzMXo3enPCqiernfyONV3f9xQpVE1bsglHNJ8TB4bnj
+pta+SQKCAQEArDqNrFkAftkk3jgXnX9jeC3O6UilugoZj4FDdjCyz1E3LCEzM02+
+T58Z2QoaSDZ/Y5cGaqShjdbaLvp4vtU61chDPD6CU3/mTZBj9i3UiDtXHLeObhlD
+WDWft1WcFB2nufmx1OPvbArYf/Ys1rFZHtF9nGU5A/y2EaZQpY6MS+nZFDcdGWbL
+7XPrGLMJ6Cu63yyUkdwXPyMnyB6AwVU1P7yNzrqWHnFueNEIawwLxfzvdhkOP1on
+yxPoPLlkc4j5XdjlmPNaSXANB1TUfpwNMwlYkdJoEnCLImc16v9iMPyFGBt6fsgz
+wFcMA98jc4lo5vDVmtA5Ue+Lj49nsGLYyQKCAQEAoB21vLDm7sLcZhzHFnh7h3L0
+wLMFMyQ0QDMWOqrlABcME21CWhibu8XwouF+hHLKX9GjaBB3ujkyeun1x8MpGQwT
+1SrMVN4osHpFrCh85uK5mabsqC8YjICIncU1U1ykxDV9v7TXuXgMtUIMKPFcUQLv
+ckf/PNE1Fvt5ESn2GIxk+ibM0L2kzHgDFgwiPx+k8GmJt5VZSXwehPmH6jgyCBIv
+kPHos1Q/z2LtfdUZcGhwX88mBNBpk3UXjiU8qO+ddoXCRgbThFDqYvOcdacbKGc0
+upFMhNsTWocn7CW0rbzusTsTt6bSWCGas8f9G9CMNN6rp8SW7Qc04m6sXVjPbw==
+-----END RSA PRIVATE KEY-----
diff --git a/data/etc/apex/com.android.hardware.core_permissions.pk8 b/data/etc/apex/com.android.hardware.core_permissions.pk8
new file mode 100644
index 0000000..4497844
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.pk8
Binary files differ
diff --git a/data/etc/apex/com.android.hardware.core_permissions.x509.pem b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
new file mode 100644
index 0000000..57a311d
--- /dev/null
+++ b/data/etc/apex/com.android.hardware.core_permissions.x509.pem
@@ -0,0 +1,34 @@
+-----BEGIN CERTIFICATE-----
+MIIF7zCCA9cCFD7UZbcK7ZVyJegJvOs8e5T/n0DLMA0GCSqGSIb3DQEBCwUAMIGy
+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91
+bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwHQW5kcm9pZDEi
+MCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTEuMCwGA1UEAwwlY29t
+LmFuZHJvaWQuaGFyZHdhcmUuY29yZV9wZXJtaXNzaW9uczAgFw0yMTA4MjYyMDM2
+NTBaGA80NzU5MDcyMzIwMzY1MFowgbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRy
+b2lkMRAwDgYDVQQLDAdBbmRyb2lkMSIwIAYJKoZIhvcNAQkBFhNhbmRyb2lkQGFu
+ZHJvaWQuY29tMS4wLAYDVQQDDCVjb20uYW5kcm9pZC5oYXJkd2FyZS5jb3JlX3Bl
+cm1pc3Npb25zMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1ZGPs2s2
+R9/+jd3dHLH0nt4Z5WWduQ4Wqy6H9oojktTCv0IJekfiC6L0VHOvW9DKtSEGWTJg
+sJdoEpd2KDhNxAdjbE6k50AfKD0CAE0MAX2MyJIpUz7b6p6p7kxB7xpJohSGDOSZ
+otuMJ16W99PElwOtQr99Wztf+WehmEkKYDUVA0V3+UP3s0quAo3ZrFYgZxXy51YF
+/rcM+HFNrpBRNZRhm3n/2uM4vqt+HTjUFvPuxFIq44DH64ofD7OYBOTbq7rU3lFr
+jEP4IlVH1mjyirh0pWIzXtqhcj2yfV8HjqnwHz+DhIA7kI1hZNOTotTiYKZszboy
+mvo8YA+fuSDCohFxVJVHZGFu+FA+m353ZPLTDTee+d3F9JGbLxa3NoPAgDIyU/tR
+KD7+fKxfr32coZzf3bDi9T4CHBoHKoikRWqOAhkZ/xGvjX12bI6eS1QP9THGu3d6
+o+ZzSZDPR9GSu8ggFtkRGgaIIbgV3y4XUKqLK3+pyg14tHwqvSYMItZ7oOYKMT47
+R9qb8MlvAWS2ooZlJwSkGSM3y0pTwy3rKXug+Cpvx7zjc3Nm/srzdPAmrEvBTZZN
+k0J1oYKqiNHV1N3PIlMRE2d4g7MVF4GEwrAgL126JZOOmzefkP59eAPNrH6Coyka
+3pAVnifemHYZlhWpbKO6pnuxEwvBGXvJlgkCAwEAATANBgkqhkiG9w0BAQsFAAOC
+AgEAfc6TD6fURc9sKHn5TSi30rIlarR6h1TbxFL4PQroEXWafkNmOMujdyV6YZlZ
+j/lzU4ko+Pn3y1aU4r88PkrjkR2Ttf01H3wj8IkTVyl3kN3o/Ud2jJygL3SbjMS1
+CAxiotvPA3lst3KN3nnyFLe02EB4OIi8fS14/kUVFVz+djpGDhi/lJUzcTCzO1NR
+yoC3RuAHBrly1+0QYcXiRTtvgnXrUqsZery8pysR7OK8fWkJzQ6I6OipElrcRzfK
+qoRq/u7nn9FJxXauVjM5HNCPq1VsB8+/FQqP2CgvxNPtkxy8AkXS3hKMBC0Id0Mo
+sDsAr88QDnCb5DqrWSMDKTKA0k+2a6QwS72ANkK5Uq2Hf/xUVjn+yHLSFuo4pCYe
+TX4ZCjK8My+XPWEiHBV/AELAWA9SxxZFhHmyuPj3MwN5uJcPNPsQepnhpeGv0Dlp
+J7UfzkdAZvOyQ+9CAQfu8+e2MilLHC3uqfnGLpHGkcHoN93rmH1x14JdapKKk3XL
+4Wo0RzEjGQekjMF0topQSqDTukOMdtZ1T0WTVOstYLlNqlhn0ZVbwVANGklN/fDW
+d6OpayLPuuaLBAM6Ivnv7n4XA49ojd9Gw305Ha/ATEoH9KwImFjvUa4d9SkR0haP
+hAiGhpaWViEe2zXOpzLhePgqc2gJ/IO7vIgrVks0iVeBoWE=
+-----END CERTIFICATE-----
diff --git a/data/etc/apex/file_contexts b/data/etc/apex/file_contexts
new file mode 100644
index 0000000..6524a5e
--- /dev/null
+++ b/data/etc/apex/file_contexts
@@ -0,0 +1,2 @@
+(/.*)?		u:object_r:vendor_file:s0
+/etc(/.*)?	u:object_r:vendor_configs_file:s0
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 3694388..8e0ac17 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -117,7 +117,6 @@
         "ParcelFileDescriptor.cpp",
         "PersistableBundle.cpp",
         "ProcessState.cpp",
-        "RpcAddress.cpp",
         "RpcSession.cpp",
         "RpcServer.cpp",
         "RpcState.cpp",
@@ -254,12 +253,16 @@
     export_header_lib_headers: [
         "libbinder_headers",
     ],
+    export_shared_lib_headers: [
+        "libssl",
+    ],
     export_include_dirs: ["include_tls"],
     static_libs: [
         "libbase",
     ],
     srcs: [
         "RpcTransportTls.cpp",
+        "RpcTlsUtils.cpp",
     ],
 }
 
@@ -281,6 +284,7 @@
 filegroup {
     name: "libbinder_aidl",
     srcs: [
+        "aidl/android/os/ConnectionInfo.aidl",
         "aidl/android/os/IClientCallback.aidl",
         "aidl/android/os/IServiceCallback.aidl",
         "aidl/android/os/IServiceManager.aidl",
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 1100d72..06542f0 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -48,10 +48,6 @@
 // Another arbitrary value a binder count needs to drop below before another callback will be called
 uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
 
-// Once the limit has been exceeded, keep calling the limit callback for every this many new proxies
-// created over the limit.
-constexpr uint32_t REPEAT_LIMIT_CALLBACK_INTERVAL = 1000;
-
 enum {
     LIMIT_REACHED_MASK = 0x80000000,        // A flag denoting that the limit has been reached
     COUNTING_VALUE_MASK = 0x7FFFFFFF,       // A mask of the remaining bits for the count value
@@ -129,7 +125,7 @@
             uint32_t lastLimitCallbackAt = sLastLimitCallbackMap[trackedUid];
 
             if (trackedValue > lastLimitCallbackAt &&
-                (trackedValue - lastLimitCallbackAt > REPEAT_LIMIT_CALLBACK_INTERVAL)) {
+                (trackedValue - lastLimitCallbackAt > sBinderProxyCountHighWatermark)) {
                 ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
                       "held)",
                       getuid(), trackedUid, trackedValue);
@@ -156,7 +152,7 @@
     return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
 }
 
-sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, const RpcAddress& address) {
+sp<BpBinder> BpBinder::create(const sp<RpcSession>& session, uint64_t address) {
     LOG_ALWAYS_FATAL_IF(session == nullptr, "BpBinder::create null session");
 
     // These are not currently tracked, since there is no UID or other
@@ -193,7 +189,7 @@
     return std::holds_alternative<RpcHandle>(mHandle);
 }
 
-const RpcAddress& BpBinder::rpcAddress() const {
+uint64_t BpBinder::rpcAddress() const {
     return std::get<RpcHandle>(mHandle).address;
 }
 
@@ -510,7 +506,7 @@
 {
     ALOGV("onLastStrongRef BpBinder %p handle %d\n", this, binderHandle());
     if (CC_UNLIKELY(isRpcBinder())) {
-        (void)rpcSession()->sendDecStrong(rpcAddress());
+        (void)rpcSession()->sendDecStrong(this);
         return;
     }
     IF_ALOGV() {
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index b197a6a..5e22593 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -17,11 +17,13 @@
 #define LOG_TAG "FdTrigger"
 #include <log/log.h>
 
+#include "FdTrigger.h"
+
 #include <poll.h>
 
 #include <android-base/macros.h>
 
-#include "FdTrigger.h"
+#include "RpcState.h"
 namespace android {
 
 std::unique_ptr<FdTrigger> FdTrigger::make() {
@@ -42,36 +44,53 @@
 }
 
 status_t FdTrigger::triggerablePoll(base::borrowed_fd fd, int16_t event) {
-    while (true) {
-        pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
-                     {.fd = mRead.get(), .events = 0, .revents = 0}};
-        int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
-        if (ret < 0) {
-            return -errno;
-        }
-        if (ret == 0) {
-            continue;
-        }
-        if (pfd[1].revents & POLLHUP) {
-            return -ECANCELED;
-        }
-        return pfd[0].revents & event ? OK : DEAD_OBJECT;
-    }
-}
-
-android::base::Result<bool> FdTrigger::isTriggeredPolled() {
-    pollfd pfd{.fd = mRead.get(), .events = 0, .revents = 0};
-    int ret = TEMP_FAILURE_RETRY(poll(&pfd, 1, 0));
+    LOG_ALWAYS_FATAL_IF(event == 0, "triggerablePoll %d with event 0 is not allowed", fd.get());
+    pollfd pfd[]{{.fd = fd.get(), .events = static_cast<int16_t>(event), .revents = 0},
+                 {.fd = mRead.get(), .events = 0, .revents = 0}};
+    int ret = TEMP_FAILURE_RETRY(poll(pfd, arraysize(pfd), -1));
     if (ret < 0) {
-        return android::base::ErrnoError() << "FdTrigger::isTriggeredPolled: Error in poll()";
+        return -errno;
     }
-    if (ret == 0) {
-        return false;
+    LOG_ALWAYS_FATAL_IF(ret == 0, "poll(%d) returns 0 with infinite timeout", fd.get());
+
+    // At least one FD has events. Check them.
+
+    // Detect explicit trigger(): DEAD_OBJECT
+    if (pfd[1].revents & POLLHUP) {
+        return DEAD_OBJECT;
     }
-    if (pfd.revents & POLLHUP) {
-        return true;
+    // See unknown flags in trigger FD's revents (POLLERR / POLLNVAL).
+    // Treat this error condition as UNKNOWN_ERROR.
+    if (pfd[1].revents != 0) {
+        ALOGE("Unknown revents on trigger FD %d: revents = %d", pfd[1].fd, pfd[1].revents);
+        return UNKNOWN_ERROR;
     }
-    return android::base::Error() << "FdTrigger::isTriggeredPolled: poll() returns " << pfd.revents;
+
+    // pfd[1].revents is 0, hence pfd[0].revents must be set, and only possible values are
+    // a subset of event | POLLHUP | POLLERR | POLLNVAL.
+
+    // POLLNVAL: invalid FD number, e.g. not opened.
+    if (pfd[0].revents & POLLNVAL) {
+        return BAD_VALUE;
+    }
+
+    // Error condition. It wouldn't be possible to do I/O on |fd| afterwards.
+    // Note: If this is the write end of a pipe then POLLHUP may also be set simultaneously. We
+    //   still want DEAD_OBJECT in this case.
+    if (pfd[0].revents & POLLERR) {
+        LOG_RPC_DETAIL("poll() incoming FD %d results in revents = %d", pfd[0].fd, pfd[0].revents);
+        return DEAD_OBJECT;
+    }
+
+    // Success condition; event flag(s) set. Even though POLLHUP may also be set,
+    // treat it as a success condition to ensure data is drained.
+    if (pfd[0].revents & event) {
+        return OK;
+    }
+
+    // POLLHUP: Peer closed connection. Treat as DEAD_OBJECT.
+    // This is a very common case, so don't log.
+    return DEAD_OBJECT;
 }
 
 } // namespace android
diff --git a/libs/binder/FdTrigger.h b/libs/binder/FdTrigger.h
index a428417..a545d6c 100644
--- a/libs/binder/FdTrigger.h
+++ b/libs/binder/FdTrigger.h
@@ -35,9 +35,13 @@
     void trigger();
 
     /**
-     * Check whether this has been triggered by checking the write end.
+     * Check whether this has been triggered by checking the write end. Note:
+     * this has no internal locking, and it is inherently racey, but this is
+     * okay, because if we accidentally return false when a trigger has already
+     * happened, we can imagine that instead, the scheduler actually executed
+     * the code which is polling isTriggered earlier.
      */
-    bool isTriggered();
+    [[nodiscard]] bool isTriggered();
 
     /**
      * Poll for a read event.
@@ -48,17 +52,7 @@
      *   true - time to read!
      *   false - trigger happened
      */
-    status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
-
-    /**
-     * Check whether this has been triggered by poll()ing the read end.
-     *
-     * Return:
-     *   true - triggered
-     *   false - not triggered
-     *   error - error when polling
-     */
-    android::base::Result<bool> isTriggeredPolled();
+    [[nodiscard]] status_t triggerablePoll(base::borrowed_fd fd, int16_t event);
 
 private:
     base::unique_fd mWrite;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index fa9f3a9..9e04ffe 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1426,6 +1426,25 @@
     return ret;
 }
 
+#ifndef __ANDROID_VNDK__
+status_t IPCThreadState::getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
+                                              uint32_t *async_received)
+{
+    int ret = 0;
+    binder_frozen_status_info info;
+    info.pid = pid;
+
+#if defined(__ANDROID__)
+    if (ioctl(self()->mProcess->mDriverFD, BINDER_GET_FROZEN_INFO, &info) < 0)
+        ret = -errno;
+#endif
+    *sync_received = info.sync_recv;
+    *async_received = info.async_recv;
+
+    return ret;
+}
+#endif
+
 status_t IPCThreadState::freeze(pid_t pid, bool enable, uint32_t timeout_ms) {
     struct binder_freeze_info info;
     int ret = 0;
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 6e318ea..aff9e0d 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -78,6 +78,7 @@
     bool isDeclared(const String16& name) override;
     Vector<String16> getDeclaredInstances(const String16& interface) override;
     std::optional<String16> updatableViaApex(const String16& name) override;
+    std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
 
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
@@ -426,6 +427,21 @@
     return declared ? std::optional<String16>(String16(declared.value().c_str())) : std::nullopt;
 }
 
+std::optional<IServiceManager::ConnectionInfo> ServiceManagerShim::getConnectionInfo(
+        const String16& name) {
+    std::optional<os::ConnectionInfo> connectionInfo;
+    if (Status status =
+                mTheRealServiceManager->getConnectionInfo(String8(name).c_str(), &connectionInfo);
+        !status.isOk()) {
+        ALOGW("Failed to get ConnectionInfo for %s: %s", String8(name).c_str(),
+              status.toString8().c_str());
+    }
+    return connectionInfo.has_value()
+            ? std::make_optional<IServiceManager::ConnectionInfo>(
+                      {connectionInfo->ipAddress, static_cast<unsigned int>(connectionInfo->port)})
+            : std::nullopt;
+}
+
 #ifndef __ANDROID__
 // ServiceManagerShim for host. Implements the old libbinder android::IServiceManager API.
 // The internal implementation of the AIDL interface android::os::IServiceManager calls into
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b545484..6ce0922 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -205,11 +205,11 @@
         if (binder) {
             status_t status = writeInt32(1); // non-null
             if (status != OK) return status;
-            RpcAddress address = RpcAddress::zero();
+            uint64_t address;
             // TODO(b/167966510): need to undo this if the Parcel is not sent
             status = mSession->state()->onBinderLeaving(mSession, binder, &address);
             if (status != OK) return status;
-            status = address.writeToParcel(this);
+            status = writeUint64(address);
             if (status != OK) return status;
         } else {
             status_t status = writeInt32(0); // null
@@ -233,11 +233,11 @@
                 ALOGE("null proxy");
             } else {
                 if (proxy->isRpcBinder()) {
-                    ALOGE("Sending a socket binder over RPC is prohibited");
+                    ALOGE("Sending a socket binder over kernel binder is prohibited");
                     return INVALID_OPERATION;
                 }
             }
-            const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
+            const int32_t handle = proxy ? proxy->getPrivateAccessor().binderHandle() : 0;
             obj.hdr.type = BINDER_TYPE_HANDLE;
             obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
             obj.handle = handle;
@@ -279,18 +279,21 @@
     if (isForRpc()) {
         LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");
 
-        int32_t isNull;
-        status_t status = readInt32(&isNull);
+        int32_t isPresent;
+        status_t status = readInt32(&isPresent);
         if (status != OK) return status;
 
         sp<IBinder> binder;
 
-        if (isNull & 1) {
-            auto addr = RpcAddress::zero();
-            if (status_t status = addr.readFromParcel(*this); status != OK) return status;
+        if (isPresent & 1) {
+            uint64_t addr;
+            if (status_t status = readUint64(&addr); status != OK) return status;
             if (status_t status = mSession->state()->onBinderEntering(mSession, addr, &binder);
                 status != OK)
                 return status;
+            if (status_t status = mSession->state()->flushExcessBinderRefs(mSession, addr, binder);
+                status != OK)
+                return status;
         }
 
         return finishUnflattenBinder(binder, out);
@@ -572,7 +575,7 @@
     LOG_ALWAYS_FATAL_IF(mData != nullptr, "format must be set before data is written");
 
     if (binder && binder->remoteBinder() && binder->remoteBinder()->isRpcBinder()) {
-        markForRpc(binder->remoteBinder()->getPrivateAccessorForId().rpcSession());
+        markForRpc(binder->remoteBinder()->getPrivateAccessor().rpcSession());
     }
 }
 
diff --git a/libs/binder/ParcelValTypes.h b/libs/binder/ParcelValTypes.h
index 666d22a..80736c8 100644
--- a/libs/binder/ParcelValTypes.h
+++ b/libs/binder/ParcelValTypes.h
@@ -27,18 +27,32 @@
     VAL_PARCELABLE = 4,
     VAL_SHORT = 5,
     VAL_LONG = 6,
+    VAL_FLOAT = 7,
     VAL_DOUBLE = 8,
     VAL_BOOLEAN = 9,
+    VAL_CHARSEQUENCE = 10,
+    VAL_LIST = 11,
+    VAL_SPARSEARRAY = 12,
     VAL_BYTEARRAY = 13,
     VAL_STRINGARRAY = 14,
     VAL_IBINDER = 15,
+    VAL_PARCELABLEARRAY = 16,
+    VAL_OBJECTARRAY = 17,
     VAL_INTARRAY = 18,
     VAL_LONGARRAY = 19,
     VAL_BYTE = 20,
     VAL_SERIALIZABLE = 21,
+    VAL_SPARSEBOOLEANARRAY = 22,
     VAL_BOOLEANARRAY = 23,
+    VAL_CHARSEQUENCEARRAY = 24,
     VAL_PERSISTABLEBUNDLE = 25,
+    VAL_SIZE = 26,
+    VAL_SIZEF = 27,
     VAL_DOUBLEARRAY = 28,
+    VAL_CHAR = 29,
+    VAL_SHORTARRAY = 30,
+    VAL_CHARARRAY = 31,
+    VAL_FLOATARRAY = 32,
 };
 
 } // namespace binder
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 15b8604..4fe4fe6 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -212,7 +212,7 @@
     binder_node_info_for_ref info;
     memset(&info, 0, sizeof(binder_node_info_for_ref));
 
-    info.handle = binder->getPrivateAccessorForId().binderHandle();
+    info.handle = binder->getPrivateAccessor().binderHandle();
 
     status_t result = ioctl(mDriverFD, BINDER_GET_NODE_INFO_FOR_REF, &info);
 
@@ -301,7 +301,7 @@
                    return nullptr;
             }
 
-            sp<BpBinder> b = BpBinder::create(handle);
+            sp<BpBinder> b = BpBinder::PrivateAccessor::create(handle);
             e->binder = b.get();
             if (b) e->refs = b->getWeakRefs();
             result = b;
diff --git a/libs/binder/RpcAddress.cpp b/libs/binder/RpcAddress.cpp
deleted file mode 100644
index ffc94b9..0000000
--- a/libs/binder/RpcAddress.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <binder/RpcAddress.h>
-
-#include <android-base/hex.h>
-#include <binder/Parcel.h>
-
-#include "Debug.h"
-#include "RpcState.h"
-#include "RpcWireFormat.h"
-
-namespace android {
-
-RpcAddress RpcAddress::zero() {
-    return RpcAddress();
-}
-
-bool RpcAddress::isZero() const {
-    RpcWireAddress ZERO{.options = 0};
-    return memcmp(mRawAddr.get(), &ZERO, sizeof(RpcWireAddress)) == 0;
-}
-
-static void ReadRandomBytes(uint8_t* buf, size_t len) {
-    int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
-    if (fd == -1) {
-        ALOGE("%s: cannot read /dev/urandom", __func__);
-        return;
-    }
-
-    size_t n;
-    while ((n = TEMP_FAILURE_RETRY(read(fd, buf, len))) > 0) {
-        len -= n;
-        buf += n;
-    }
-    if (len > 0) {
-        ALOGW("%s: there are %d bytes skipped", __func__, (int)len);
-    }
-    close(fd);
-}
-
-RpcAddress RpcAddress::random(bool forServer) {
-    // The remainder of this header acts as reserved space for different kinds
-    // of binder objects.
-    uint64_t options = RPC_WIRE_ADDRESS_OPTION_CREATED;
-
-    // servers and clients allocate addresses independently, so this bit can
-    // tell you where an address originates
-    if (forServer) options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
-
-    RpcAddress ret;
-    RpcWireAddress* raw = ret.mRawAddr.get();
-
-    raw->options = options;
-    ReadRandomBytes(raw->address, sizeof(raw->address));
-
-    LOG_RPC_DETAIL("Creating new address: %s", ret.toString().c_str());
-    return ret;
-}
-
-bool RpcAddress::isForServer() const {
-    return mRawAddr.get()->options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
-}
-
-bool RpcAddress::isRecognizedType() const {
-    uint64_t allKnownOptions = RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
-    return (mRawAddr.get()->options & ~allKnownOptions) == 0;
-}
-
-RpcAddress RpcAddress::fromRawEmbedded(const RpcWireAddress* raw) {
-    RpcAddress addr;
-    memcpy(addr.mRawAddr.get(), raw, sizeof(RpcWireAddress));
-    return addr;
-}
-
-const RpcWireAddress& RpcAddress::viewRawEmbedded() const {
-    return *mRawAddr.get();
-}
-
-bool RpcAddress::operator<(const RpcAddress& rhs) const {
-    return std::memcmp(mRawAddr.get(), rhs.mRawAddr.get(), sizeof(RpcWireAddress)) < 0;
-}
-
-std::string RpcAddress::toString() const {
-    return base::HexString(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-status_t RpcAddress::writeToParcel(Parcel* parcel) const {
-    return parcel->write(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-status_t RpcAddress::readFromParcel(const Parcel& parcel) {
-    return parcel.read(mRawAddr.get(), sizeof(RpcWireAddress));
-}
-
-RpcAddress::~RpcAddress() {}
-RpcAddress::RpcAddress() : mRawAddr(std::make_shared<RpcWireAddress>()) {}
-
-} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index ad9ba96..44b588b 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "RpcServer"
 
+#include <inttypes.h>
 #include <poll.h>
 #include <sys/socket.h>
 #include <sys/un.h>
@@ -23,6 +24,8 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/hex.h>
 #include <android-base/scopeguard.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
@@ -36,6 +39,8 @@
 
 namespace android {
 
+constexpr size_t kSessionIdBytes = 32;
+
 using base::ScopeGuard;
 using base::unique_fd;
 
@@ -139,20 +144,11 @@
     return ret;
 }
 
-std::string RpcServer::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
     std::lock_guard<std::mutex> _l(mLock);
     return mCtx->getCertificate(format);
 }
 
-status_t RpcServer::addTrustedPeerCertificate(CertificateFormat format, std::string_view cert) {
-    std::lock_guard<std::mutex> _l(mLock);
-    // Ensure that join thread is not running or shutdown trigger is not set up. In either case,
-    // it means there are child threads running. It is invalid to add trusted peer certificates
-    // after join thread and/or child threads are running to avoid race condition.
-    if (mJoinThreadRunning || mShutdownTrigger != nullptr) return INVALID_OPERATION;
-    return mCtx->addTrustedPeerCertificate(format, cert);
-}
-
 static void joinRpcServer(sp<RpcServer>&& thiz) {
     thiz->join();
 }
@@ -212,8 +208,11 @@
     }
 
     mShutdownTrigger->trigger();
+
     for (auto& [id, session] : mSessions) {
         (void)id;
+        // server lock is a more general lock
+        std::lock_guard<std::mutex> _lSession(session->mMutex);
         session->mShutdownTrigger->trigger();
     }
 
@@ -282,7 +281,7 @@
     RpcConnectionHeader header;
     if (status == OK) {
         status = client->interruptableReadFully(server->mShutdownTrigger.get(), &header,
-                                                sizeof(header));
+                                                sizeof(header), {});
         if (status != OK) {
             ALOGE("Failed to read ID for client connecting to RPC server: %s",
                   statusToString(status).c_str());
@@ -290,17 +289,35 @@
         }
     }
 
+    std::vector<uint8_t> sessionId;
+    if (status == OK) {
+        if (header.sessionIdSize > 0) {
+            if (header.sessionIdSize == kSessionIdBytes) {
+                sessionId.resize(header.sessionIdSize);
+                status = client->interruptableReadFully(server->mShutdownTrigger.get(),
+                                                        sessionId.data(), sessionId.size(), {});
+                if (status != OK) {
+                    ALOGE("Failed to read session ID for client connecting to RPC server: %s",
+                          statusToString(status).c_str());
+                    // still need to cleanup before we can return
+                }
+            } else {
+                ALOGE("Malformed session ID. Expecting session ID of size %zu but got %" PRIu16,
+                      kSessionIdBytes, header.sessionIdSize);
+                status = BAD_VALUE;
+            }
+        }
+    }
+
     bool incoming = false;
     uint32_t protocolVersion = 0;
-    RpcAddress sessionId = RpcAddress::zero();
     bool requestingNewSession = false;
 
     if (status == OK) {
         incoming = header.options & RPC_CONNECTION_OPTION_INCOMING;
         protocolVersion = std::min(header.version,
                                    server->mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION));
-        sessionId = RpcAddress::fromRawEmbedded(&header.sessionId);
-        requestingNewSession = sessionId.isZero();
+        requestingNewSession = sessionId.empty();
 
         if (requestingNewSession) {
             RpcNewSessionResponse response{
@@ -308,7 +325,7 @@
             };
 
             status = client->interruptableWriteFully(server->mShutdownTrigger.get(), &response,
-                                                     sizeof(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,15 +359,25 @@
                 return;
             }
 
+            // Uniquely identify session at the application layer. Even if a
+            // client/server use the same certificates, if they create multiple
+            // sessions, we still want to distinguish between them.
+            sessionId.resize(kSessionIdBytes);
             size_t tries = 0;
             do {
                 // don't block if there is some entropy issue
                 if (tries++ > 5) {
-                    ALOGE("Cannot find new address: %s", sessionId.toString().c_str());
+                    ALOGE("Cannot find new address: %s",
+                          base::HexString(sessionId.data(), sessionId.size()).c_str());
                     return;
                 }
 
-                sessionId = RpcAddress::random(true /*forServer*/);
+                base::unique_fd fd(TEMP_FAILURE_RETRY(
+                        open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW)));
+                if (!base::ReadFully(fd, sessionId.data(), sessionId.size())) {
+                    ALOGE("Could not read from /dev/urandom to create session ID");
+                    return;
+                }
             } while (server->mSessions.end() != server->mSessions.find(sessionId));
 
             session = RpcSession::make();
@@ -370,7 +397,7 @@
             auto it = server->mSessions.find(sessionId);
             if (it == server->mSessions.end()) {
                 ALOGE("Cannot add thread, no record of session with ID %s",
-                      sessionId.toString().c_str());
+                      base::HexString(sessionId.data(), sessionId.size()).c_str());
                 return;
             }
             session = it->second;
@@ -432,16 +459,17 @@
 }
 
 void RpcServer::onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) {
-    auto id = session->mId;
-    LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
-    LOG_RPC_DETAIL("Dropping session with address %s", id->toString().c_str());
+    const std::vector<uint8_t>& id = session->mId;
+    LOG_ALWAYS_FATAL_IF(id.empty(), "Server sessions must be initialized with ID");
+    LOG_RPC_DETAIL("Dropping session with address %s",
+                   base::HexString(id.data(), id.size()).c_str());
 
     std::lock_guard<std::mutex> _l(mLock);
-    auto it = mSessions.find(*id);
+    auto it = mSessions.find(id);
     LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %s",
-                        id->toString().c_str());
+                        base::HexString(id.data(), id.size()).c_str());
     LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %s",
-                        id->toString().c_str());
+                        base::HexString(id.data(), id.size()).c_str());
     (void)mSessions.erase(it);
 }
 
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index c57b749..65f6bc6 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -26,8 +26,10 @@
 
 #include <string_view>
 
+#include <android-base/hex.h>
 #include <android-base/macros.h>
 #include <android_runtime/vm.h>
+#include <binder/BpBinder.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcTransportRaw.h>
@@ -64,23 +66,12 @@
 
 sp<RpcSession> RpcSession::make() {
     // Default is without TLS.
-    return make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+    return make(RpcTransportCtxFactoryRaw::make());
 }
 
-sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
-                                std::optional<CertificateFormat> serverCertificateFormat,
-                                std::optional<std::string> serverCertificate) {
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
     auto ctx = rpcTransportCtxFactory->newClientCtx();
     if (ctx == nullptr) return nullptr;
-    LOG_ALWAYS_FATAL_IF(serverCertificateFormat.has_value() != serverCertificate.has_value());
-    if (serverCertificateFormat.has_value() && serverCertificate.has_value()) {
-        status_t status =
-                ctx->addTrustedPeerCertificate(*serverCertificateFormat, *serverCertificate);
-        if (status != OK) {
-            ALOGE("Cannot add trusted server certificate: %s", statusToString(status).c_str());
-            return nullptr;
-        }
-    }
     return sp<RpcSession>::make(std::move(ctx));
 }
 
@@ -143,7 +134,7 @@
 }
 
 status_t RpcSession::setupPreconnectedClient(unique_fd fd, std::function<unique_fd()>&& request) {
-    return setupClient([&](const RpcAddress& sessionId, bool incoming) -> status_t {
+    return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) -> status_t {
         // std::move'd from fd becomes -1 (!ok())
         if (!fd.ok()) {
             fd = request();
@@ -201,7 +192,7 @@
 
     if (wait) {
         LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
-        mShutdownListener->waitForShutdown(_l);
+        mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
 
         LOG_ALWAYS_FATAL_IF(!mThreads.empty(), "Shutdown failed");
     }
@@ -225,12 +216,18 @@
                              sp<RpcSession>::fromExisting(this), reply, flags);
 }
 
-status_t RpcSession::sendDecStrong(const RpcAddress& address) {
+status_t RpcSession::sendDecStrong(const BpBinder* binder) {
+    // target is 0 because this is used to free BpBinder objects
+    return sendDecStrongToTarget(binder->getPrivateAccessor().rpcAddress(), 0 /*target*/);
+}
+
+status_t RpcSession::sendDecStrongToTarget(uint64_t address, size_t target) {
     ExclusiveConnection connection;
     status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
                                                 ConnectionUse::CLIENT_REFCOUNT, &connection);
     if (status != OK) return status;
-    return state()->sendDecStrong(connection.get(), sp<RpcSession>::fromExisting(this), address);
+    return state()->sendDecStrongToTarget(connection.get(), sp<RpcSession>::fromExisting(this),
+                                          address, target);
 }
 
 status_t RpcSession::readId() {
@@ -244,29 +241,30 @@
                                                 ConnectionUse::CLIENT, &connection);
     if (status != OK) return status;
 
-    mId = RpcAddress::zero();
-    status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this),
-                                   &mId.value());
+    status = state()->getSessionId(connection.get(), sp<RpcSession>::fromExisting(this), &mId);
     if (status != OK) return status;
 
-    LOG_RPC_DETAIL("RpcSession %p has id %s", this, mId->toString().c_str());
+    LOG_RPC_DETAIL("RpcSession %p has id %s", this,
+                   base::HexString(mId.data(), mId.size()).c_str());
     return OK;
 }
 
 void RpcSession::WaitForShutdownListener::onSessionAllIncomingThreadsEnded(
         const sp<RpcSession>& session) {
     (void)session;
-    mShutdown = true;
 }
 
 void RpcSession::WaitForShutdownListener::onSessionIncomingThreadEnded() {
     mCv.notify_all();
 }
 
-void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock) {
-    while (!mShutdown) {
+void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
+                                                          const sp<RpcSession>& session) {
+    while (session->mIncomingConnections.size() > 0) {
         if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
-            ALOGE("Waiting for RpcSession to shut down (1s w/o progress).");
+            ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
+                  "still.",
+                  session->mIncomingConnections.size());
         }
     }
 }
@@ -408,8 +406,8 @@
     return server;
 }
 
-status_t RpcSession::setupClient(
-        const std::function<status_t(const RpcAddress& sessionId, bool incoming)>& connectAndInit) {
+status_t RpcSession::setupClient(const std::function<status_t(const std::vector<uint8_t>& sessionId,
+                                                              bool incoming)>& connectAndInit) {
     {
         std::lock_guard<std::mutex> _l(mMutex);
         LOG_ALWAYS_FATAL_IF(mOutgoingConnections.size() != 0,
@@ -418,8 +416,7 @@
     }
     if (auto status = initShutdownTrigger(); status != OK) return status;
 
-    if (status_t status = connectAndInit(RpcAddress::zero(), false /*incoming*/); status != OK)
-        return status;
+    if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
 
     {
         ExclusiveConnection connection;
@@ -460,26 +457,25 @@
 
     // 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;
+        if (status_t status = connectAndInit(mId, false /*incoming*/); status != OK) return status;
     }
 
     for (size_t i = 0; i < mMaxThreads; i++) {
-        if (status_t status = connectAndInit(mId.value(), true /*incoming*/); status != OK)
-            return status;
+        if (status_t status = connectAndInit(mId, true /*incoming*/); status != OK) return status;
     }
 
     return OK;
 }
 
 status_t RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
-    return setupClient([&](const RpcAddress& sessionId, bool incoming) {
+    return setupClient([&](const std::vector<uint8_t>& sessionId, bool incoming) {
         return setupOneSocketConnection(addr, sessionId, incoming);
     });
 }
 
 status_t RpcSession::setupOneSocketConnection(const RpcSocketAddress& addr,
-                                              const RpcAddress& sessionId, bool incoming) {
+                                              const std::vector<uint8_t>& sessionId,
+                                              bool incoming) {
     for (size_t tries = 0; tries < 5; tries++) {
         if (tries > 0) usleep(10000);
 
@@ -537,7 +533,7 @@
     return UNKNOWN_ERROR;
 }
 
-status_t RpcSession::initAndAddConnection(unique_fd fd, const RpcAddress& sessionId,
+status_t RpcSession::initAndAddConnection(unique_fd fd, const std::vector<uint8_t>& sessionId,
                                           bool incoming) {
     LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr);
     auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
@@ -548,22 +544,41 @@
 
     LOG_RPC_DETAIL("Socket at client with RpcTransport %p", server.get());
 
+    if (sessionId.size() > std::numeric_limits<uint16_t>::max()) {
+        ALOGE("Session ID too big %zu", sessionId.size());
+        return BAD_VALUE;
+    }
+
     RpcConnectionHeader header{
             .version = mProtocolVersion.value_or(RPC_WIRE_PROTOCOL_VERSION),
             .options = 0,
+            .sessionIdSize = static_cast<uint16_t>(sessionId.size()),
     };
-    memcpy(&header.sessionId, &sessionId.viewRawEmbedded(), sizeof(RpcWireAddress));
 
-    if (incoming) header.options |= RPC_CONNECTION_OPTION_INCOMING;
+    if (incoming) {
+        header.options |= RPC_CONNECTION_OPTION_INCOMING;
+    }
 
     auto sendHeaderStatus =
-            server->interruptableWriteFully(mShutdownTrigger.get(), &header, sizeof(header));
+            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;
     }
 
+    if (sessionId.size() > 0) {
+        auto sendSessionIdStatus =
+                server->interruptableWriteFully(mShutdownTrigger.get(), sessionId.data(),
+                                                sessionId.size(), {});
+        if (sendSessionIdStatus != OK) {
+            ALOGE("Could not write session ID ('%s') to socket: %s",
+                  base::HexString(sessionId.data(), sessionId.size()).c_str(),
+                  statusToString(sendSessionIdStatus).c_str());
+            return sendSessionIdStatus;
+        }
+    }
+
     LOG_RPC_DETAIL("Socket at client: header sent");
 
     if (incoming) {
@@ -636,7 +651,7 @@
 }
 
 bool RpcSession::setForServer(const wp<RpcServer>& server, const wp<EventListener>& eventListener,
-                              const RpcAddress& sessionId) {
+                              const std::vector<uint8_t>& sessionId) {
     LOG_ALWAYS_FATAL_IF(mForServer != nullptr);
     LOG_ALWAYS_FATAL_IF(server == nullptr);
     LOG_ALWAYS_FATAL_IF(mEventListener != nullptr);
@@ -697,7 +712,7 @@
     return false;
 }
 
-std::string RpcSession::getCertificate(CertificateFormat format) {
+std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
     return mCtx->getCertificate(format);
 }
 
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b58f1b3..ef62f20 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -52,11 +52,11 @@
 RpcState::~RpcState() {}
 
 status_t RpcState::onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
-                                   RpcAddress* outAddress) {
+                                   uint64_t* outAddress) {
     bool isRemote = binder->remoteBinder();
     bool isRpc = isRemote && binder->remoteBinder()->isRpcBinder();
 
-    if (isRpc && binder->remoteBinder()->getPrivateAccessorForId().rpcSession() != session) {
+    if (isRpc && binder->remoteBinder()->getPrivateAccessor().rpcSession() != session) {
         // We need to be able to send instructions over the socket for how to
         // connect to a different server, and we also need to let the host
         // process know that this is happening.
@@ -84,12 +84,10 @@
     for (auto& [addr, node] : mNodeForAddress) {
         if (binder == node.binder) {
             if (isRpc) {
-                const RpcAddress& actualAddr =
-                        binder->remoteBinder()->getPrivateAccessorForId().rpcAddress();
-                // TODO(b/182939933): this is only checking integrity of data structure
-                // a different data structure doesn't need this
-                LOG_ALWAYS_FATAL_IF(addr < actualAddr, "Address mismatch");
-                LOG_ALWAYS_FATAL_IF(actualAddr < addr, "Address mismatch");
+                // check integrity of data structure
+                uint64_t actualAddr = binder->remoteBinder()->getPrivateAccessor().rpcAddress();
+                LOG_ALWAYS_FATAL_IF(addr != actualAddr, "Address mismatch %" PRIu64 " vs %" PRIu64,
+                                    addr, actualAddr);
             }
             node.timesSent++;
             node.sentRef = binder; // might already be set
@@ -101,8 +99,29 @@
 
     bool forServer = session->server() != nullptr;
 
-    for (size_t tries = 0; tries < 5; tries++) {
-        auto&& [it, inserted] = mNodeForAddress.insert({RpcAddress::random(forServer),
+    // arbitrary limit for maximum number of nodes in a process (otherwise we
+    // might run out of addresses)
+    if (mNodeForAddress.size() > 100000) {
+        return NO_MEMORY;
+    }
+
+    while (true) {
+        RpcWireAddress address{
+                .options = RPC_WIRE_ADDRESS_OPTION_CREATED,
+                .address = mNextId,
+        };
+        if (forServer) {
+            address.options |= RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+        }
+
+        // avoid ubsan abort
+        if (mNextId >= std::numeric_limits<uint32_t>::max()) {
+            mNextId = 0;
+        } else {
+            mNextId++;
+        }
+
+        auto&& [it, inserted] = mNodeForAddress.insert({RpcWireAddress::toRaw(address),
                                                         BinderNode{
                                                                 .binder = binder,
                                                                 .timesSent = 1,
@@ -112,18 +131,10 @@
             *outAddress = it->first;
             return OK;
         }
-
-        // well, we don't have visibility into the header here, but still
-        static_assert(sizeof(RpcWireAddress) == 40, "this log needs updating");
-        ALOGW("2**256 is 1e77. If you see this log, you probably have some entropy issue, or maybe "
-              "you witness something incredible!");
     }
-
-    ALOGE("Unable to create an address in order to send out %p", binder.get());
-    return WOULD_BLOCK;
 }
 
-status_t RpcState::onBinderEntering(const sp<RpcSession>& session, const RpcAddress& address,
+status_t RpcState::onBinderEntering(const sp<RpcSession>& session, uint64_t address,
                                     sp<IBinder>* out) {
     // ensure that: if we want to use addresses for something else in the future (for
     //   instance, allowing transitive binder sends), that we don't accidentally
@@ -133,12 +144,15 @@
     //   if we communicate with a binder, it could always be proxying
     //   information. However, we want to make sure that isn't done on accident
     //   by a client.
-    if (!address.isRecognizedType()) {
-        ALOGE("Address is of an unknown type, rejecting: %s", address.toString().c_str());
+    RpcWireAddress addr = RpcWireAddress::fromRaw(address);
+    constexpr uint32_t kKnownOptions =
+            RPC_WIRE_ADDRESS_OPTION_CREATED | RPC_WIRE_ADDRESS_OPTION_FOR_SERVER;
+    if (addr.options & ~kKnownOptions) {
+        ALOGE("Address is of an unknown type, rejecting: %" PRIu64, address);
         return BAD_VALUE;
     }
 
-    std::unique_lock<std::mutex> _l(mNodeMutex);
+    std::lock_guard<std::mutex> _l(mNodeMutex);
     if (mTerminated) return DEAD_OBJECT;
 
     if (auto it = mNodeForAddress.find(address); it != mNodeForAddress.end()) {
@@ -146,22 +160,14 @@
 
         // implicitly have strong RPC refcount, since we received this binder
         it->second.timesRecd++;
-
-        _l.unlock();
-
-        // We have timesRecd RPC refcounts, but we only need to hold on to one
-        // when we keep the object. All additional dec strongs are sent
-        // immediately, we wait to send the last one in BpBinder::onLastDecStrong.
-        (void)session->sendDecStrong(address);
-
         return OK;
     }
 
     // we don't know about this binder, so the other side of the connection
     // should have created it.
-    if (address.isForServer() == !!session->server()) {
-        ALOGE("Server received unrecognized address which we should own the creation of %s.",
-              address.toString().c_str());
+    if ((addr.options & RPC_WIRE_ADDRESS_OPTION_FOR_SERVER) == !!session->server()) {
+        ALOGE("Server received unrecognized address which we should own the creation of %" PRIu64,
+              address);
         return BAD_VALUE;
     }
 
@@ -170,11 +176,44 @@
 
     // Currently, all binders are assumed to be part of the same session (no
     // device global binders in the RPC world).
-    it->second.binder = *out = BpBinder::create(session, it->first);
+    it->second.binder = *out = BpBinder::PrivateAccessor::create(session, it->first);
     it->second.timesRecd = 1;
     return OK;
 }
 
+status_t RpcState::flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+                                         const sp<IBinder>& binder) {
+    // We can flush all references when the binder is destroyed. No need to send
+    // extra reference counting packets now.
+    if (binder->remoteBinder()) return OK;
+
+    std::unique_lock<std::mutex> _l(mNodeMutex);
+    if (mTerminated) return DEAD_OBJECT;
+
+    auto it = mNodeForAddress.find(address);
+
+    LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Can't be deleted while we hold sp<>");
+    LOG_ALWAYS_FATAL_IF(it->second.binder != binder,
+                        "Caller of flushExcessBinderRefs using inconsistent arguments");
+
+    LOG_ALWAYS_FATAL_IF(it->second.timesSent <= 0, "Local binder must have been sent %p",
+                        binder.get());
+
+    // For a local binder, we only need to know that we sent it. Now that we
+    // have an sp<> for this call, we don't need anything more. If the other
+    // process is done with this binder, it needs to know we received the
+    // refcount associated with this call, so we can acknowledge that we
+    // received it. Once (or if) it has no other refcounts, it would reply with
+    // its own decStrong so that it could be removed from this session.
+    if (it->second.timesRecd != 0) {
+        _l.unlock();
+
+        return session->sendDecStrongToTarget(address, 0);
+    }
+
+    return OK;
+}
+
 size_t RpcState::countBinders() {
     std::lock_guard<std::mutex> _l(mNodeMutex);
     return mNodeForAddress.size();
@@ -241,9 +280,8 @@
             desc = "(null)";
         }
 
-        ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a:%s type:%s",
-              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address.toString().c_str(),
-              desc);
+        ALOGE("- BINDER NODE: %p times sent:%zu times recd: %zu a: %" PRIu64 " type: %s",
+              node.binder.unsafe_get(), node.timesSent, node.timesRecd, address, desc);
     }
     ALOGE("END DUMP OF RpcState");
 }
@@ -272,7 +310,7 @@
 
 status_t RpcState::rpcSend(const sp<RpcSession::RpcConnection>& connection,
                            const sp<RpcSession>& session, const char* what, const void* data,
-                           size_t size) {
+                           size_t size, const std::function<status_t()>& altPoll) {
     LOG_RPC_DETAIL("Sending %s on RpcTransport %p: %s", what, connection->rpcTransport.get(),
                    android::base::HexString(data, size).c_str());
 
@@ -284,7 +322,7 @@
 
     if (status_t status =
                 connection->rpcTransport->interruptableWriteFully(session->mShutdownTrigger.get(),
-                                                                  data, size);
+                                                                  data, size, altPoll);
         status != OK) {
         LOG_RPC_DETAIL("Failed to write %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
                        connection->rpcTransport.get(), statusToString(status).c_str());
@@ -306,10 +344,11 @@
 
     if (status_t status =
                 connection->rpcTransport->interruptableReadFully(session->mShutdownTrigger.get(),
-                                                                 data, size);
+                                                                 data, size, {});
         status != OK) {
         LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
                        connection->rpcTransport.get(), statusToString(status).c_str());
+        (void)session->shutdownAndWait(false);
         return status;
     }
 
@@ -360,8 +399,8 @@
     data.markForRpc(session);
     Parcel reply;
 
-    status_t status = transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_ROOT,
-                                      data, session, &reply, 0);
+    status_t status =
+            transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_ROOT, data, session, &reply, 0);
     if (status != OK) {
         ALOGE("Error getting root object: %s", statusToString(status).c_str());
         return nullptr;
@@ -376,9 +415,8 @@
     data.markForRpc(session);
     Parcel reply;
 
-    status_t status =
-            transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS,
-                            data, session, &reply, 0);
+    status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
+                                      session, &reply, 0);
     if (status != OK) {
         ALOGE("Error getting max threads: %s", statusToString(status).c_str());
         return status;
@@ -397,55 +435,58 @@
 }
 
 status_t RpcState::getSessionId(const sp<RpcSession::RpcConnection>& connection,
-                                const sp<RpcSession>& session, RpcAddress* sessionIdOut) {
+                                const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut) {
     Parcel data;
     data.markForRpc(session);
     Parcel reply;
 
-    status_t status =
-            transactAddress(connection, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_SESSION_ID,
-                            data, session, &reply, 0);
+    status_t status = transactAddress(connection, 0, RPC_SPECIAL_TRANSACT_GET_SESSION_ID, data,
+                                      session, &reply, 0);
     if (status != OK) {
         ALOGE("Error getting session ID: %s", statusToString(status).c_str());
         return status;
     }
 
-    return sessionIdOut->readFromParcel(reply);
+    return reply.readByteVector(sessionIdOut);
 }
 
 status_t RpcState::transact(const sp<RpcSession::RpcConnection>& connection,
                             const sp<IBinder>& binder, uint32_t code, const Parcel& data,
                             const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
     if (!data.isForRpc()) {
-        ALOGE("Refusing to send RPC with parcel not crafted for RPC");
+        ALOGE("Refusing to send RPC with parcel not crafted for RPC call on binder %p code "
+              "%" PRIu32,
+              binder.get(), code);
         return BAD_TYPE;
     }
 
     if (data.objectsCount() != 0) {
-        ALOGE("Parcel at %p has attached objects but is being used in an RPC call", &data);
+        ALOGE("Parcel at %p has attached objects but is being used in an RPC call on binder %p "
+              "code %" PRIu32,
+              &data, binder.get(), code);
         return BAD_TYPE;
     }
 
-    RpcAddress address = RpcAddress::zero();
+    uint64_t address;
     if (status_t status = onBinderLeaving(session, binder, &address); status != OK) return status;
 
     return transactAddress(connection, address, code, data, session, reply, flags);
 }
 
 status_t RpcState::transactAddress(const sp<RpcSession::RpcConnection>& connection,
-                                   const RpcAddress& address, uint32_t code, const Parcel& data,
+                                   uint64_t address, uint32_t code, const Parcel& data,
                                    const sp<RpcSession>& session, Parcel* reply, uint32_t flags) {
     LOG_ALWAYS_FATAL_IF(!data.isForRpc());
     LOG_ALWAYS_FATAL_IF(data.objectsCount() != 0);
 
     uint64_t asyncNumber = 0;
 
-    if (!address.isZero()) {
+    if (address != 0) {
         std::unique_lock<std::mutex> _l(mNodeMutex);
         if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
         auto it = mNodeForAddress.find(address);
-        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending transact on unknown address %s",
-                            address.toString().c_str());
+        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
+                            "Sending transact on unknown address %" PRIu64, address);
 
         if (flags & IBinder::FLAG_ONEWAY) {
             asyncNumber = it->second.asyncNumber;
@@ -466,8 +507,9 @@
             .command = RPC_COMMAND_TRANSACT,
             .bodySize = static_cast<uint32_t>(sizeof(RpcWireTransaction) + data.dataSize()),
     };
+
     RpcWireTransaction transaction{
-            .address = address.viewRawEmbedded(),
+            .address = RpcWireAddress::fromRaw(address),
             .code = code,
             .flags = flags,
             .asyncNumber = asyncNumber,
@@ -484,21 +526,44 @@
     memcpy(transactionData.data() + sizeof(RpcWireHeader) + sizeof(RpcWireTransaction), data.data(),
            data.dataSize());
 
+    constexpr size_t kWaitMaxUs = 1000000;
+    constexpr size_t kWaitLogUs = 10000;
+    size_t waitUs = 0;
+
+    // Oneway calls have no sync point, so if many are sent before, whether this
+    // is a twoway or oneway transaction, they may have filled up the socket.
+    // So, make sure we drain them before polling.
+    std::function<status_t()> drainRefs = [&] {
+        if (waitUs > kWaitLogUs) {
+            ALOGE("Cannot send command, trying to process pending refcounts. Waiting %zuus. Too "
+                  "many oneway calls?",
+                  waitUs);
+        }
+
+        if (waitUs > 0) {
+            usleep(waitUs);
+            waitUs = std::min(kWaitMaxUs, waitUs * 2);
+        } else {
+            waitUs = 1;
+        }
+
+        return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+    };
+
     if (status_t status = rpcSend(connection, session, "transaction", transactionData.data(),
-                                  transactionData.size());
-        status != OK)
+                                  transactionData.size(), drainRefs);
+        status != OK) {
         // TODO(b/167966510): need to undo onBinderLeaving - we know the
         // refcount isn't successfully transferred.
         return status;
+    }
 
     if (flags & IBinder::FLAG_ONEWAY) {
         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,
-        // so process those.
-        return drainCommands(connection, session, CommandType::CONTROL_ONLY);
+        return OK;
     }
 
     LOG_ALWAYS_FATAL_IF(reply == nullptr, "Reply parcel must be used for synchronous transaction.");
@@ -519,8 +584,8 @@
                                 const sp<RpcSession>& session, Parcel* reply) {
     RpcWireHeader command;
     while (true) {
-        if (status_t status =
-                    rpcRec(connection, session, "command header", &command, sizeof(command));
+        if (status_t status = rpcRec(connection, session, "command header (for reply)", &command,
+                                     sizeof(command));
             status != OK)
             return status;
 
@@ -556,34 +621,43 @@
     return OK;
 }
 
-status_t RpcState::sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
-                                 const sp<RpcSession>& session, const RpcAddress& addr) {
+status_t RpcState::sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+                                         const sp<RpcSession>& session, uint64_t addr,
+                                         size_t target) {
+    RpcDecStrong body = {
+            .address = RpcWireAddress::fromRaw(addr),
+    };
+
     {
         std::lock_guard<std::mutex> _l(mNodeMutex);
         if (mTerminated) return DEAD_OBJECT; // avoid fatal only, otherwise races
         auto it = mNodeForAddress.find(addr);
-        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(), "Sending dec strong on unknown address %s",
-                            addr.toString().c_str());
-        LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %s",
-                            addr.toString().c_str());
+        LOG_ALWAYS_FATAL_IF(it == mNodeForAddress.end(),
+                            "Sending dec strong on unknown address %" PRIu64, addr);
 
-        it->second.timesRecd--;
+        LOG_ALWAYS_FATAL_IF(it->second.timesRecd < target, "Can't dec count of %zu to %zu.",
+                            it->second.timesRecd, target);
+
+        // typically this happens when multiple threads send dec refs at the
+        // same time - the transactions will get combined automatically
+        if (it->second.timesRecd == target) return OK;
+
+        body.amount = it->second.timesRecd - target;
+        it->second.timesRecd = target;
+
         LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
                             "Bad state. RpcState shouldn't own received binder");
     }
 
     RpcWireHeader cmd = {
             .command = RPC_COMMAND_DEC_STRONG,
-            .bodySize = sizeof(RpcWireAddress),
+            .bodySize = sizeof(RpcDecStrong),
     };
     if (status_t status = rpcSend(connection, session, "dec ref header", &cmd, sizeof(cmd));
         status != OK)
         return status;
-    if (status_t status = rpcSend(connection, session, "dec ref body", &addr.viewRawEmbedded(),
-                                  sizeof(RpcWireAddress));
-        status != OK)
-        return status;
-    return OK;
+
+    return rpcSend(connection, session, "dec ref body", &body, sizeof(body));
 }
 
 status_t RpcState::getAndExecuteCommand(const sp<RpcSession::RpcConnection>& connection,
@@ -591,7 +665,8 @@
     LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
 
     RpcWireHeader command;
-    if (status_t status = rpcRec(connection, session, "command header", &command, sizeof(command));
+    if (status_t status = rpcRec(connection, session, "command header (for server)", &command,
+                                 sizeof(command));
         status != OK)
         return status;
 
@@ -674,7 +749,7 @@
     // for 'recursive' calls to this, we have already read and processed the
     // binder from the transaction data and taken reference counts into account,
     // so it is cached here.
-    sp<IBinder> targetRef;
+    sp<IBinder> target;
 processTransactInternalTailCall:
 
     if (transactionData.size() < sizeof(RpcWireTransaction)) {
@@ -685,18 +760,13 @@
     }
     RpcWireTransaction* transaction = reinterpret_cast<RpcWireTransaction*>(transactionData.data());
 
-    // TODO(b/182939933): heap allocation just for lookup in mNodeForAddress,
-    // maybe add an RpcAddress 'view' if the type remains 'heavy'
-    auto addr = RpcAddress::fromRawEmbedded(&transaction->address);
+    uint64_t addr = RpcWireAddress::toRaw(transaction->address);
     bool oneway = transaction->flags & IBinder::FLAG_ONEWAY;
 
     status_t replyStatus = OK;
-    sp<IBinder> target;
-    if (!addr.isZero()) {
-        if (!targetRef) {
+    if (addr != 0) {
+        if (!target) {
             replyStatus = onBinderEntering(session, addr, &target);
-        } else {
-            target = targetRef;
         }
 
         if (replyStatus != OK) {
@@ -708,21 +778,21 @@
             // (any binder which is being transacted on should be holding a
             // strong ref count), so in either case, terminating the
             // session.
-            ALOGE("While transacting, binder has been deleted at address %s. Terminating!",
-                  addr.toString().c_str());
+            ALOGE("While transacting, binder has been deleted at address %" PRIu64 ". Terminating!",
+                  addr);
             (void)session->shutdownAndWait(false);
             replyStatus = BAD_VALUE;
         } else if (target->localBinder() == nullptr) {
-            ALOGE("Unknown binder address or non-local binder, not address %s. Terminating!",
-                  addr.toString().c_str());
+            ALOGE("Unknown binder address or non-local binder, not address %" PRIu64
+                  ". Terminating!",
+                  addr);
             (void)session->shutdownAndWait(false);
             replyStatus = BAD_VALUE;
         } else if (oneway) {
             std::unique_lock<std::mutex> _l(mNodeMutex);
             auto it = mNodeForAddress.find(addr);
             if (it->second.binder.promote() != target) {
-                ALOGE("Binder became invalid during transaction. Bad client? %s",
-                      addr.toString().c_str());
+                ALOGE("Binder became invalid during transaction. Bad client? %" PRIu64, addr);
                 replyStatus = BAD_VALUE;
             } else if (transaction->asyncNumber != it->second.asyncNumber) {
                 // we need to process some other asynchronous transaction
@@ -734,8 +804,8 @@
                 });
 
                 size_t numPending = it->second.asyncTodo.size();
-                LOG_RPC_DETAIL("Enqueuing %" PRId64 " on %s (%zu pending)",
-                               transaction->asyncNumber, addr.toString().c_str(), numPending);
+                LOG_RPC_DETAIL("Enqueuing %" PRIu64 " on %" PRIu64 " (%zu pending)",
+                               transaction->asyncNumber, addr, numPending);
 
                 constexpr size_t kArbitraryOnewayCallTerminateLevel = 10000;
                 constexpr size_t kArbitraryOnewayCallWarnLevel = 1000;
@@ -792,7 +862,7 @@
                     // for client connections, this should always report the value
                     // originally returned from the server, so this is asserting
                     // that it exists
-                    replyStatus = session->mId.value().writeToParcel(&reply);
+                    replyStatus = reply.writeByteVector(session->mId);
                     break;
                 }
                 default: {
@@ -820,8 +890,8 @@
             ALOGW("Oneway call failed with error: %d", replyStatus);
         }
 
-        LOG_RPC_DETAIL("Processed async transaction %" PRId64 " on %s", transaction->asyncNumber,
-                       addr.toString().c_str());
+        LOG_RPC_DETAIL("Processed async transaction %" PRIu64 " on %" PRIu64,
+                       transaction->asyncNumber, addr);
 
         // Check to see if there is another asynchronous transaction to process.
         // This behavior differs from binder behavior, since in the binder
@@ -847,8 +917,8 @@
 
             if (it->second.asyncTodo.size() == 0) return OK;
             if (it->second.asyncTodo.top().asyncNumber == it->second.asyncNumber) {
-                LOG_RPC_DETAIL("Found next async transaction %" PRId64 " on %s",
-                               it->second.asyncNumber, addr.toString().c_str());
+                LOG_RPC_DETAIL("Found next async transaction %" PRIu64 " on %" PRIu64,
+                               it->second.asyncNumber, addr);
 
                 // justification for const_cast (consider avoiding priority_queue):
                 // - AsyncTodo operator< doesn't depend on 'data' or 'ref' objects
@@ -857,15 +927,29 @@
 
                 // reset up arguments
                 transactionData = std::move(todo.data);
-                targetRef = std::move(todo.ref);
+                LOG_ALWAYS_FATAL_IF(target != todo.ref,
+                                    "async list should be associated with a binder");
 
                 it->second.asyncTodo.pop();
                 goto processTransactInternalTailCall;
             }
         }
+
+        // done processing all the async commands on this binder that we can, so
+        // write decstrongs on the binder
+        if (addr != 0 && replyStatus == OK) {
+            return flushExcessBinderRefs(session, addr, target);
+        }
+
         return OK;
     }
 
+    // Binder refs are flushed for oneway calls only after all calls which are
+    // built up are executed. Otherwise, they fill up the binder buffer.
+    if (addr != 0 && replyStatus == OK) {
+        replyStatus = flushExcessBinderRefs(session, addr, target);
+    }
+
     LOG_ALWAYS_FATAL_IF(std::numeric_limits<int32_t>::max() - sizeof(RpcWireHeader) -
                                         sizeof(RpcWireReply) <
                                 reply.dataSize(),
@@ -904,41 +988,45 @@
         status != OK)
         return status;
 
-    if (command.bodySize < sizeof(RpcWireAddress)) {
-        ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
-              sizeof(RpcWireAddress), command.bodySize);
+    if (command.bodySize != sizeof(RpcDecStrong)) {
+        ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcDecStrong. Terminating!",
+              sizeof(RpcDecStrong), command.bodySize);
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
-    RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
+    RpcDecStrong* body = reinterpret_cast<RpcDecStrong*>(commandData.data());
 
-    // TODO(b/182939933): heap allocation just for lookup
-    auto addr = RpcAddress::fromRawEmbedded(address);
+    uint64_t addr = RpcWireAddress::toRaw(body->address);
     std::unique_lock<std::mutex> _l(mNodeMutex);
     auto it = mNodeForAddress.find(addr);
     if (it == mNodeForAddress.end()) {
-        ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
+        ALOGE("Unknown binder address %" PRIu64 " for dec strong.", addr);
         return OK;
     }
 
     sp<IBinder> target = it->second.binder.promote();
     if (target == nullptr) {
-        ALOGE("While requesting dec strong, binder has been deleted at address %s. Terminating!",
-              addr.toString().c_str());
+        ALOGE("While requesting dec strong, binder has been deleted at address %" PRIu64
+              ". Terminating!",
+              addr);
         _l.unlock();
         (void)session->shutdownAndWait(false);
         return BAD_VALUE;
     }
 
-    if (it->second.timesSent == 0) {
-        ALOGE("No record of sending binder, but requested decStrong: %s", addr.toString().c_str());
+    if (it->second.timesSent < body->amount) {
+        ALOGE("Record of sending binder %zu times, but requested decStrong for %" PRIu64 " of %u",
+              it->second.timesSent, addr, body->amount);
         return OK;
     }
 
-    LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %s",
-                        addr.toString().c_str());
+    LOG_ALWAYS_FATAL_IF(it->second.sentRef == nullptr, "Inconsistent state, lost ref for %" PRIu64,
+                        addr);
 
-    it->second.timesSent--;
+    LOG_RPC_DETAIL("Processing dec strong of %" PRIu64 " by %u from %zu", addr, body->amount,
+                   it->second.timesSent);
+
+    it->second.timesSent -= body->amount;
     sp<IBinder> tempHold = tryEraseNode(it);
     _l.unlock();
     tempHold = nullptr; // destructor may make binder calls on this session
@@ -946,7 +1034,7 @@
     return OK;
 }
 
-sp<IBinder> RpcState::tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it) {
+sp<IBinder> RpcState::tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it) {
     sp<IBinder> ref;
 
     if (it->second.timesSent == 0) {
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 1446eec..50de22b 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -73,17 +73,38 @@
     status_t getMaxThreads(const sp<RpcSession::RpcConnection>& connection,
                            const sp<RpcSession>& session, size_t* maxThreadsOut);
     status_t getSessionId(const sp<RpcSession::RpcConnection>& connection,
-                          const sp<RpcSession>& session, RpcAddress* sessionIdOut);
+                          const sp<RpcSession>& session, std::vector<uint8_t>* sessionIdOut);
 
     [[nodiscard]] status_t transact(const sp<RpcSession::RpcConnection>& connection,
                                     const sp<IBinder>& address, uint32_t code, const Parcel& data,
                                     const sp<RpcSession>& session, Parcel* reply, uint32_t flags);
     [[nodiscard]] status_t transactAddress(const sp<RpcSession::RpcConnection>& connection,
-                                           const RpcAddress& address, uint32_t code,
-                                           const Parcel& data, const sp<RpcSession>& session,
-                                           Parcel* reply, uint32_t flags);
-    [[nodiscard]] status_t sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
-                                         const sp<RpcSession>& session, const RpcAddress& address);
+                                           uint64_t address, uint32_t code, const Parcel& data,
+                                           const sp<RpcSession>& session, Parcel* reply,
+                                           uint32_t flags);
+
+    /**
+     * The ownership model here carries an implicit strong refcount whenever a
+     * binder is sent across processes. Since we have a local strong count in
+     * sp<> over these objects, we only ever need to keep one of these. So,
+     * typically we tell the remote process that we drop all the implicit dec
+     * strongs, and we hold onto the last one. 'target' here is the target
+     * timesRecd (the number of remaining reference counts) we wish to keep.
+     * Typically this should be '0' or '1'. The target is used instead of an
+     * explicit decrement count in order to allow multiple threads to lower the
+     * number of counts simultaneously. Since we only lower the count to 0 when
+     * a binder is deleted, targets of '1' should only be sent when the caller
+     * owns a local strong reference to the binder. Larger targets may be used
+     * for testing, and to make the function generic, but generally this should
+     * be avoided because it would be hard to guarantee another thread doesn't
+     * lower the number of held refcounts to '1'. Note also, these refcounts
+     * must be sent actively. If they are sent when binders are deleted, this
+     * can cause leaks, since even remote binders carry an implicit strong ref
+     * when they are sent to another process.
+     */
+    [[nodiscard]] status_t sendDecStrongToTarget(const sp<RpcSession::RpcConnection>& connection,
+                                                 const sp<RpcSession>& session, uint64_t address,
+                                                 size_t target);
 
     enum class CommandType {
         ANY,
@@ -99,15 +120,22 @@
      * ownership to the outgoing binder.
      */
     [[nodiscard]] status_t onBinderLeaving(const sp<RpcSession>& session, const sp<IBinder>& binder,
-                                           RpcAddress* outAddress);
+                                           uint64_t* outAddress);
 
     /**
      * Called by Parcel for incoming binders. This either returns the refcount
      * to the process, if this process already has one, or it takes ownership of
      * that refcount
      */
-    [[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session,
-                                            const RpcAddress& address, sp<IBinder>* out);
+    [[nodiscard]] status_t onBinderEntering(const sp<RpcSession>& session, uint64_t address,
+                                            sp<IBinder>* out);
+    /**
+     * Called on incoming binders to update refcounting information. This should
+     * only be called when it is done as part of making progress on a
+     * transaction.
+     */
+    [[nodiscard]] status_t flushExcessBinderRefs(const sp<RpcSession>& session, uint64_t address,
+                                                 const sp<IBinder>& binder);
 
     size_t countBinders();
     void dump();
@@ -149,7 +177,8 @@
 
     [[nodiscard]] status_t rpcSend(const sp<RpcSession::RpcConnection>& connection,
                                    const sp<RpcSession>& session, const char* what,
-                                   const void* data, size_t size);
+                                   const void* data, size_t size,
+                                   const std::function<status_t()>& altPoll = nullptr);
     [[nodiscard]] status_t rpcRec(const sp<RpcSession::RpcConnection>& connection,
                                   const sp<RpcSession>& session, const char* what, void* data,
                                   size_t size);
@@ -221,15 +250,16 @@
     // happens, and there is a strong reference to the binder kept by
     // binderNode, this returns that strong reference, so that it can be
     // dropped after any locks are removed.
-    sp<IBinder> tryEraseNode(std::map<RpcAddress, BinderNode>::iterator& it);
+    sp<IBinder> tryEraseNode(std::map<uint64_t, BinderNode>::iterator& it);
     // true - success
     // false - session shutdown, halt
     [[nodiscard]] bool nodeProgressAsyncNumber(BinderNode* node);
 
     std::mutex mNodeMutex;
     bool mTerminated = false;
+    uint32_t mNextId = 0;
     // binders known by both sides of a session
-    std::map<RpcAddress, BinderNode> mNodeForAddress;
+    std::map<uint64_t, BinderNode> mNodeForAddress;
 };
 
 } // namespace android
diff --git a/libs/binder/RpcTlsUtils.cpp b/libs/binder/RpcTlsUtils.cpp
new file mode 100644
index 0000000..f3ca02a
--- /dev/null
+++ b/libs/binder/RpcTlsUtils.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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 "RpcTlsUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+static_assert(sizeof(unsigned char) == sizeof(uint8_t));
+
+template <typename PemReadBioFn,
+          typename T = std::remove_pointer_t<std::invoke_result_t<
+                  PemReadBioFn, BIO*, std::nullptr_t, std::nullptr_t, std::nullptr_t>>>
+bssl::UniquePtr<T> fromPem(const std::vector<uint8_t>& data, PemReadBioFn fn) {
+    if (data.size() > std::numeric_limits<int>::max()) return nullptr;
+    bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data.data(), static_cast<int>(data.size())));
+    return bssl::UniquePtr<T>(fn(bio.get(), nullptr, nullptr, nullptr));
+}
+
+template <typename D2iFn,
+          typename T = std::remove_pointer_t<
+                  std::invoke_result_t<D2iFn, std::nullptr_t, const unsigned char**, long>>>
+bssl::UniquePtr<T> fromDer(const std::vector<uint8_t>& data, D2iFn fn) {
+    if (data.size() > std::numeric_limits<long>::max()) return nullptr;
+    const unsigned char* dataPtr = data.data();
+    auto expectedEnd = dataPtr + data.size();
+    bssl::UniquePtr<T> ret(fn(nullptr, &dataPtr, static_cast<long>(data.size())));
+    if (dataPtr != expectedEnd) {
+        ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - dataPtr);
+        return nullptr;
+    }
+    return ret;
+}
+
+template <typename T, typename WriteBioFn = int (*)(BIO*, T*)>
+std::vector<uint8_t> serialize(T* object, WriteBioFn writeBio) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    TEST_AND_RETURN({}, writeBio(bio.get(), object));
+    const uint8_t* data;
+    size_t len;
+    TEST_AND_RETURN({}, BIO_mem_contents(bio.get(), &data, &len));
+    return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
+                                             RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return fromPem(data, PEM_read_bio_X509);
+        case RpcCertificateFormat::DER:
+            return fromDer(data, d2i_X509);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return serialize(x509, PEM_write_bio_X509);
+        case RpcCertificateFormat::DER:
+            return serialize(x509, i2d_X509_bio);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+                                                           RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return fromPem(data, PEM_read_bio_PrivateKey);
+        case RpcKeyFormat::DER:
+            return fromDer(data, d2i_AutoPrivateKey);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return serialize(pkey, [](BIO* bio, EVP_PKEY* pkey) {
+                return PEM_write_bio_PrivateKey(bio, pkey, nullptr /* enc */, nullptr /* kstr */,
+                                                0 /* klen */, nullptr, nullptr);
+            });
+        case RpcKeyFormat::DER:
+            return serialize(pkey, i2d_PrivateKey_bio);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+} // namespace android
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index 930df12..7669518 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -35,20 +35,6 @@
 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) {
@@ -57,52 +43,72 @@
         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;
+    template <typename Buffer, typename SendOrReceive>
+    status_t interruptableReadOrWrite(FdTrigger* fdTrigger, Buffer buffer, size_t size,
+                                      SendOrReceive sendOrReceiveFun, const char* funName,
+                                      int16_t event, const std::function<status_t()>& altPoll) {
+        const Buffer 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();
+        // Since we didn't poll, we need to manually check to see if it was triggered. Otherwise, we
+        // may never know we should be shutting down.
+        if (fdTrigger->isTriggered()) {
+            return DEAD_OBJECT;
+        }
+
+        bool havePolled = false;
+        while (true) {
+            ssize_t processSize = TEMP_FAILURE_RETRY(
+                    sendOrReceiveFun(mSocket.get(), buffer, end - buffer, MSG_NOSIGNAL));
+
+            if (processSize < 0) {
+                int savedErrno = errno;
+
+                // Still return the error on later passes, since it would expose
+                // a problem with polling
+                if (havePolled ||
+                    (!havePolled && savedErrno != EAGAIN && savedErrno != EWOULDBLOCK)) {
+                    LOG_RPC_DETAIL("RpcTransport %s(): %s", funName, strerror(savedErrno));
+                    return -savedErrno;
+                }
+            } else if (processSize == 0) {
+                return DEAD_OBJECT;
+            } else {
+                buffer += processSize;
+                if (buffer == end) {
+                    return OK;
+                }
             }
 
-            if (*writeSize == 0) return DEAD_OBJECT;
-
-            buffer += *writeSize;
-            if (buffer == end) return OK;
+            if (altPoll) {
+                if (status_t status = altPoll(); status != OK) return status;
+                if (fdTrigger->isTriggered()) {
+                    return DEAD_OBJECT;
+                }
+            } else {
+                if (status_t status = fdTrigger->triggerablePoll(mSocket.get(), event);
+                    status != OK)
+                    return status;
+                if (!havePolled) havePolled = true;
+            }
         }
-        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;
+    status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+                                     const std::function<status_t()>& altPoll) override {
+        return interruptableReadOrWrite(fdTrigger, reinterpret_cast<const uint8_t*>(data), size,
+                                        send, "send", POLLOUT, altPoll);
+    }
 
-        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;
+    status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+                                    const std::function<status_t()>& altPoll) override {
+        return interruptableReadOrWrite(fdTrigger, reinterpret_cast<uint8_t*>(data), size, recv,
+                                        "recv", POLLIN, altPoll);
     }
 
 private:
-    android::base::unique_fd mSocket;
+    base::unique_fd mSocket;
 };
 
 // RpcTransportCtx with TLS disabled.
@@ -111,8 +117,7 @@
     std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
         return std::make_unique<RpcTransportRaw>(std::move(fd));
     }
-    std::string getCertificate(CertificateFormat) const override { return {}; }
-    status_t addTrustedPeerCertificate(CertificateFormat, std::string_view) override { return OK; }
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
 };
 
 } // namespace
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index e6cb04e..7f810b1 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -22,10 +22,12 @@
 #include <openssl/bn.h>
 #include <openssl/ssl.h>
 
+#include <binder/RpcTlsUtils.h>
 #include <binder/RpcTransportTls.h>
 
 #include "FdTrigger.h"
 #include "RpcState.h"
+#include "Utils.h"
 
 #define SHOULD_LOG_TLS_DETAIL false
 
@@ -35,14 +37,6 @@
 #define LOG_TLS_DETAIL(...) ALOGV(__VA_ARGS__) // for type checking
 #endif
 
-#define TEST_AND_RETURN(value, expr)            \
-    do {                                        \
-        if (!(expr)) {                          \
-            ALOGE("Failed to call: %s", #expr); \
-            return value;                       \
-        }                                       \
-    } while (0)
-
 using android::base::ErrnoError;
 using android::base::Error;
 using android::base::Result;
@@ -50,8 +44,6 @@
 namespace android {
 namespace {
 
-constexpr const int kCertValidDays = 30;
-
 // Implement BIO for socket that ignores SIGPIPE.
 int socketNew(BIO* bio) {
     BIO_set_data(bio, reinterpret_cast<void*>(-1));
@@ -106,49 +98,6 @@
     return ret;
 }
 
-bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
-    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
-    if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
-        ALOGE("Failed to generate key pair.");
-        return nullptr;
-    }
-    bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
-    // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
-    // the refcount of the ec_key, so it is okay to release it at the end of this function.
-    if (evp_pkey == nullptr || !EVP_PKEY_set1_EC_KEY(evp_pkey.get(), ec_key.get())) {
-        ALOGE("Failed to assign key pair.");
-        return nullptr;
-    }
-    return evp_pkey;
-}
-
-bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* evp_pkey, const int valid_days) {
-    bssl::UniquePtr<X509> x509(X509_new());
-    bssl::UniquePtr<BIGNUM> serial(BN_new());
-    bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
-    TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
-    TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
-    TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
-    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
-    TEST_AND_RETURN(nullptr,
-                    X509_gmtime_adj(X509_getm_notAfter(x509.get()), 60 * 60 * 24 * valid_days));
-
-    X509_NAME* subject = X509_get_subject_name(x509.get());
-    TEST_AND_RETURN(nullptr,
-                    X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
-                                               reinterpret_cast<const uint8_t*>("Android"), -1, -1,
-                                               0));
-    TEST_AND_RETURN(nullptr,
-                    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
-                                               reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
-                                               -1, 0));
-    TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
-
-    TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), evp_pkey));
-    TEST_AND_RETURN(nullptr, X509_sign(x509.get(), evp_pkey, EVP_sha256()));
-    return x509;
-}
-
 [[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) {
     switch (type) {
         case SSL_CB_HANDSHAKE_START:
@@ -220,12 +169,13 @@
     // If |sslError| is WANT_READ / WANT_WRITE, poll for POLLIN / POLLOUT respectively. Otherwise
     // return error. Also return error if |fdTrigger| is triggered before or during poll().
     status_t pollForSslError(android::base::borrowed_fd fd, int sslError, FdTrigger* fdTrigger,
-                             const char* fnString, int additionalEvent = 0) {
+                             const char* fnString, int additionalEvent,
+                             const std::function<status_t()>& altPoll) {
         switch (sslError) {
             case SSL_ERROR_WANT_READ:
-                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString);
+                return handlePoll(POLLIN | additionalEvent, fd, fdTrigger, fnString, altPoll);
             case SSL_ERROR_WANT_WRITE:
-                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString);
+                return handlePoll(POLLOUT | additionalEvent, fd, fdTrigger, fnString, altPoll);
             case SSL_ERROR_SYSCALL: {
                 auto queue = toString();
                 LOG_TLS_DETAIL("%s(): %s. Treating as DEAD_OBJECT. Error queue: %s", fnString,
@@ -245,11 +195,17 @@
     bool mHandled = false;
 
     status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
-                        const char* fnString) {
-        status_t ret = fdTrigger->triggerablePoll(fd, event);
-        if (ret != OK && ret != DEAD_OBJECT && ret != -ECANCELED) {
-            ALOGE("triggerablePoll error while poll()-ing after %s(): %s", fnString,
-                  statusToString(ret).c_str());
+                        const char* fnString, const std::function<status_t()>& altPoll) {
+        status_t ret;
+        if (altPoll) {
+            ret = altPoll();
+            if (fdTrigger->isTriggered()) ret = DEAD_OBJECT;
+        } else {
+            ret = fdTrigger->triggerablePoll(fd, event);
+        }
+
+        if (ret != OK && ret != DEAD_OBJECT) {
+            ALOGE("poll error while after %s(): %s", fnString, statusToString(ret).c_str());
         }
         clear();
         return ret;
@@ -319,14 +275,14 @@
     RpcTransportTls(android::base::unique_fd socket, Ssl ssl)
           : mSocket(std::move(socket)), mSsl(std::move(ssl)) {}
     Result<size_t> peek(void* buf, size_t size) override;
-    status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size) override;
-    status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) override;
+    status_t interruptableWriteFully(FdTrigger* fdTrigger, const void* data, size_t size,
+                                     const std::function<status_t()>& altPoll) override;
+    status_t interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+                                    const std::function<status_t()>& altPoll) override;
 
 private:
     android::base::unique_fd mSocket;
     Ssl mSsl;
-
-    static status_t isTriggered(FdTrigger* fdTrigger);
 };
 
 // Error code is errno.
@@ -347,17 +303,9 @@
     return ret;
 }
 
-status_t RpcTransportTls::isTriggered(FdTrigger* fdTrigger) {
-    auto ret = fdTrigger->isTriggeredPolled();
-    if (!ret.ok()) {
-        ALOGE("%s: %s", __PRETTY_FUNCTION__, ret.error().message().c_str());
-        return ret.error().code() == 0 ? UNKNOWN_ERROR : -ret.error().code();
-    }
-    return OK;
-}
-
 status_t RpcTransportTls::interruptableWriteFully(FdTrigger* fdTrigger, const void* data,
-                                                  size_t size) {
+                                                  size_t size,
+                                                  const std::function<status_t()>& altPoll) {
     auto buffer = reinterpret_cast<const uint8_t*>(data);
     const uint8_t* end = buffer + size;
 
@@ -365,7 +313,7 @@
 
     // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
     // once. The trigger is also checked via triggerablePoll() after every SSL_write().
-    if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+    if (fdTrigger->isTriggered()) return DEAD_OBJECT;
 
     while (buffer < end) {
         size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
@@ -379,8 +327,8 @@
         int sslError = mSsl.getError(writeSize);
         // TODO(b/195788248): BIO should contain the FdTrigger, and send(2) / recv(2) should be
         //   triggerablePoll()-ed. Then additionalEvent is no longer necessary.
-        status_t pollStatus =
-                errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_write", POLLIN);
+        status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+                                                         "SSL_write", POLLIN, altPoll);
         if (pollStatus != OK) return pollStatus;
         // Do not advance buffer. Try SSL_write() again.
     }
@@ -388,7 +336,8 @@
     return OK;
 }
 
-status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size) {
+status_t RpcTransportTls::interruptableReadFully(FdTrigger* fdTrigger, void* data, size_t size,
+                                                 const std::function<status_t()>& altPoll) {
     auto buffer = reinterpret_cast<uint8_t*>(data);
     uint8_t* end = buffer + size;
 
@@ -396,7 +345,7 @@
 
     // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
     // once. The trigger is also checked via triggerablePoll() after every SSL_write().
-    if (status_t status = isTriggered(fdTrigger); status != OK) return status;
+    if (fdTrigger->isTriggered()) return DEAD_OBJECT;
 
     while (buffer < end) {
         size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
@@ -412,8 +361,8 @@
             return DEAD_OBJECT;
         }
         int sslError = mSsl.getError(readSize);
-        status_t pollStatus =
-                errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger, "SSL_read");
+        status_t pollStatus = errorQueue.pollForSslError(mSocket.get(), sslError, fdTrigger,
+                                                         "SSL_read", 0, altPoll);
         if (pollStatus != OK) return pollStatus;
         // Do not advance buffer. Try SSL_read() again.
     }
@@ -444,7 +393,7 @@
         }
         int sslError = ssl->getError(ret);
         status_t pollStatus =
-                errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake");
+                errorQueue.pollForSslError(fd, sslError, fdTrigger, "SSL_do_handshake", 0, {});
         if (pollStatus != OK) return false;
     }
 }
@@ -453,45 +402,63 @@
 public:
     template <typename Impl,
               typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
-    static std::unique_ptr<RpcTransportCtxTls> create();
+    static std::unique_ptr<RpcTransportCtxTls> create(
+            std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth);
     std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
                                                FdTrigger* fdTrigger) const override;
-    std::string getCertificate(CertificateFormat) const override;
-    status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert) override;
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
 
 protected:
+    static ssl_verify_result_t sslCustomVerify(SSL* ssl, uint8_t* outAlert);
     virtual void preHandshake(Ssl* ssl) const = 0;
     bssl::UniquePtr<SSL_CTX> mCtx;
+    std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
 };
 
-std::string RpcTransportCtxTls::getCertificate(CertificateFormat) const {
-    // TODO(b/195166979): return certificate here
-    return {};
+std::vector<uint8_t> RpcTransportCtxTls::getCertificate(RpcCertificateFormat format) const {
+    X509* x509 = SSL_CTX_get0_certificate(mCtx.get()); // does not own
+    return serializeCertificate(x509, format);
 }
 
-status_t RpcTransportCtxTls::addTrustedPeerCertificate(CertificateFormat, std::string_view) {
-    // TODO(b/195166979): set certificate here
-    return OK;
+// Verify by comparing the leaf of peer certificate with every certificate in
+// mTrustedPeerCertificates. Does not support certificate chains.
+ssl_verify_result_t RpcTransportCtxTls::sslCustomVerify(SSL* ssl, uint8_t* outAlert) {
+    LOG_ALWAYS_FATAL_IF(outAlert == nullptr);
+    const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+
+    auto ctx = SSL_get_SSL_CTX(ssl); // Does not set error queue
+    LOG_ALWAYS_FATAL_IF(ctx == nullptr);
+    // void* -> RpcTransportCtxTls*
+    auto rpcTransportCtxTls = reinterpret_cast<RpcTransportCtxTls*>(SSL_CTX_get_app_data(ctx));
+    LOG_ALWAYS_FATAL_IF(rpcTransportCtxTls == nullptr);
+
+    status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(ssl, outAlert);
+    if (verifyStatus == OK) {
+        return ssl_verify_ok;
+    }
+    LOG_TLS_DETAIL("%s: Failed to verify client: status = %s, alert = %s", logPrefix,
+                   statusToString(verifyStatus).c_str(), SSL_alert_desc_string_long(*outAlert));
+    return ssl_verify_invalid;
 }
 
 // Common implementation for creating server and client contexts. The child class, |Impl|, is
 // provided as a template argument so that this function can initialize an |Impl| object.
 template <typename Impl, typename>
-std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create() {
+std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create(
+        std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth) {
     bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
     TEST_AND_RETURN(nullptr, ctx != nullptr);
 
-    auto evp_pkey = makeKeyPairForSelfSignedCert();
-    TEST_AND_RETURN(nullptr, evp_pkey != nullptr);
-    auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays);
-    TEST_AND_RETURN(nullptr, cert != nullptr);
-    TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
-    TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
+    if (status_t authStatus = auth->configure(ctx.get()); authStatus != OK) {
+        ALOGE("%s: Failed to configure auth info: %s", __PRETTY_FUNCTION__,
+              statusToString(authStatus).c_str());
+        return nullptr;
+    };
 
-    // TODO(b/195166979): peer should send certificate in a different channel, and this class
-    //  should verify it here.
-    SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
-                              [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
+    // Enable two-way authentication by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT on server.
+    // Client ignores SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
+    SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
+                              sslCustomVerify);
 
     // Require at least TLS 1.3
     TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
@@ -501,7 +468,10 @@
     }
 
     auto ret = std::make_unique<Impl>();
+    // RpcTransportCtxTls* -> void*
+    TEST_AND_RETURN(nullptr, SSL_CTX_set_app_data(ctx.get(), reinterpret_cast<void*>(ret.get())));
     ret->mCtx = std::move(ctx);
+    ret->mCertVerifier = std::move(verifier);
     return ret;
 }
 
@@ -533,19 +503,31 @@
 } // namespace
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
-    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>();
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier,
+                                                                         mAuth.get());
 }
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
-    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>();
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier,
+                                                                         mAuth.get());
 }
 
 const char* RpcTransportCtxFactoryTls::toCString() const {
     return "tls";
 }
 
-std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make() {
-    return std::unique_ptr<RpcTransportCtxFactoryTls>(new RpcTransportCtxFactoryTls());
+std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make(
+        std::shared_ptr<RpcCertificateVerifier> verifier, std::unique_ptr<RpcAuth> auth) {
+    if (verifier == nullptr) {
+        ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+    if (auth == nullptr) {
+        ALOGE("%s: Must provide an auth provider", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+    return std::unique_ptr<RpcTransportCtxFactoryTls>(
+            new RpcTransportCtxFactoryTls(std::move(verifier), std::move(auth)));
 }
 
 } // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 067c4ad..171550e 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -20,18 +20,23 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic error "-Wpadded"
 
-enum : uint8_t {
-    RPC_CONNECTION_OPTION_INCOMING = 0x1, // default is outgoing
-};
+constexpr uint8_t RPC_CONNECTION_OPTION_INCOMING = 0x1; // default is outgoing
 
-constexpr uint64_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
-constexpr uint64_t RPC_WIRE_ADDRESS_OPTION_FOR_SERVER = 1 << 1;
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_CREATED = 1 << 0; // distinguish from '0' address
+constexpr uint32_t RPC_WIRE_ADDRESS_OPTION_FOR_SERVER = 1 << 1;
 
 struct RpcWireAddress {
-    uint64_t options;
-    uint8_t address[32];
+    uint32_t options;
+    uint32_t address;
+
+    static inline RpcWireAddress fromRaw(uint64_t raw) {
+        return *reinterpret_cast<RpcWireAddress*>(&raw);
+    }
+    static inline uint64_t toRaw(RpcWireAddress addr) {
+        return *reinterpret_cast<uint64_t*>(&addr);
+    }
 };
-static_assert(sizeof(RpcWireAddress) == 40);
+static_assert(sizeof(RpcWireAddress) == sizeof(uint64_t));
 
 /**
  * This is sent to an RpcServer in order to request a new connection is created,
@@ -39,12 +44,13 @@
  */
 struct RpcConnectionHeader {
     uint32_t version; // maximum supported by caller
-    uint8_t reserver0[4];
-    RpcWireAddress sessionId;
     uint8_t options;
-    uint8_t reserved1[7];
+    uint8_t reservered[9];
+    // Follows is sessionIdSize bytes.
+    // if size is 0, this is requesting a new session.
+    uint16_t sessionIdSize;
 };
-static_assert(sizeof(RpcConnectionHeader) == 56);
+static_assert(sizeof(RpcConnectionHeader) == 16);
 
 /**
  * In response to an RpcConnectionHeader which corresponds to a new session,
@@ -79,7 +85,7 @@
      */
     RPC_COMMAND_REPLY,
     /**
-     * follows is RpcWireAddress
+     * follows is RpcDecStrong
      *
      * note - this in the protocol directly instead of as a 'special
      * transaction' in order to keep it as lightweight as possible (we don't
@@ -111,6 +117,13 @@
 };
 static_assert(sizeof(RpcWireHeader) == 16);
 
+struct RpcDecStrong {
+    RpcWireAddress address;
+    uint32_t amount;
+    uint32_t reserved;
+};
+static_assert(sizeof(RpcDecStrong) == 16);
+
 struct RpcWireTransaction {
     RpcWireAddress address;
     uint32_t code;
@@ -122,7 +135,7 @@
 
     uint8_t data[];
 };
-static_assert(sizeof(RpcWireTransaction) == 72);
+static_assert(sizeof(RpcWireTransaction) == 40);
 
 struct RpcWireReply {
     int32_t status; // transact return
diff --git a/libs/binder/ServiceManagerHost.cpp b/libs/binder/ServiceManagerHost.cpp
index 59334b7..27cc563 100644
--- a/libs/binder/ServiceManagerHost.cpp
+++ b/libs/binder/ServiceManagerHost.cpp
@@ -74,12 +74,12 @@
               result->toString().c_str());
         return std::nullopt;
     }
-    if (!result->stderr.empty()) {
+    if (!result->stderrStr.empty()) {
         LOG_HOST("`adb forward tcp:0 tcp:%d` writes to stderr: %s", devicePort,
-                 result->stderr.c_str());
+                 result->stderrStr.c_str());
     }
 
-    unsigned int hostPort = parsePortNumber(result->stdout, "host port");
+    unsigned int hostPort = parsePortNumber(result->stdoutStr, "host port");
     if (hostPort == 0) return std::nullopt;
 
     return AdbForwarder(hostPort);
@@ -105,9 +105,9 @@
               result->toString().c_str());
         return;
     }
-    if (!result->stderr.empty()) {
+    if (!result->stderrStr.empty()) {
         LOG_HOST("`adb forward --remove tcp:%d` writes to stderr: %s", *mPort,
-                 result->stderr.c_str());
+                 result->stderrStr.c_str());
     }
 
     LOG_HOST("Successfully run `adb forward --remove tcp:%d`", *mPort);
@@ -139,8 +139,8 @@
         ALOGE("Command exits with: %s", result->toString().c_str());
         return nullptr;
     }
-    if (!result->stderr.empty()) {
-        LOG_HOST("servicedispatcher writes to stderr: %s", result->stderr.c_str());
+    if (!result->stderrStr.empty()) {
+        LOG_HOST("servicedispatcher writes to stderr: %s", result->stderrStr.c_str());
     }
 
     if (!result->stdoutEndsWithNewLine()) {
@@ -148,7 +148,7 @@
         return nullptr;
     }
 
-    unsigned int devicePort = parsePortNumber(result->stdout, "device port");
+    unsigned int devicePort = parsePortNumber(result->stdoutStr, "device port");
     if (devicePort == 0) return nullptr;
 
     auto forwardResult = AdbForwarder::forward(devicePort);
diff --git a/libs/binder/Utils.h b/libs/binder/Utils.h
index 1e383da..ff2fad8 100644
--- a/libs/binder/Utils.h
+++ b/libs/binder/Utils.h
@@ -19,6 +19,15 @@
 
 #include <android-base/result.h>
 #include <android-base/unique_fd.h>
+#include <log/log.h>
+
+#define TEST_AND_RETURN(value, expr)            \
+    do {                                        \
+        if (!(expr)) {                          \
+            ALOGE("Failed to call: %s", #expr); \
+            return value;                       \
+        }                                       \
+    } while (0)
 
 namespace android {
 
diff --git a/libs/binder/UtilsHost.cpp b/libs/binder/UtilsHost.cpp
index d121ce2..52b8f69 100644
--- a/libs/binder/UtilsHost.cpp
+++ b/libs/binder/UtilsHost.cpp
@@ -63,7 +63,7 @@
     if (res.exitCode) os << "code=" << *res.exitCode;
     if (res.signal) os << "signal=" << *res.signal;
     if (res.pid) os << ", pid=" << *res.pid;
-    return os << ", stdout=" << res.stdout << ", stderr=" << res.stderr;
+    return os << ", stdout=" << res.stdoutStr << ", stderr=" << res.stderrStr;
 }
 
 std::string CommandResult::toString() const {
@@ -142,9 +142,9 @@
         int pollRet = poll(fds, nfds, 1000 /* ms timeout */);
         if (pollRet == -1) return android::base::ErrnoError() << "poll()";
 
-        if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdout))
+        if (!handlePoll(&ret.outPipe, outPollFd, &ret.stdoutStr))
             return android::base::ErrnoError() << "read(stdout)";
-        if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderr))
+        if (!handlePoll(&ret.errPipe, errPollFd, &ret.stderrStr))
             return android::base::ErrnoError() << "read(stderr)";
 
         if (end && end(ret)) return ret;
diff --git a/libs/binder/UtilsHost.h b/libs/binder/UtilsHost.h
index 0f29f60..98ac4e0 100644
--- a/libs/binder/UtilsHost.h
+++ b/libs/binder/UtilsHost.h
@@ -43,8 +43,8 @@
     std::optional<int32_t> exitCode;
     std::optional<int32_t> signal;
     std::optional<pid_t> pid;
-    std::string stdout;
-    std::string stderr;
+    std::string stdoutStr;
+    std::string stderrStr;
 
     android::base::unique_fd outPipe;
     android::base::unique_fd errPipe;
@@ -55,15 +55,15 @@
         std::swap(exitCode, other.exitCode);
         std::swap(signal, other.signal);
         std::swap(pid, other.pid);
-        std::swap(stdout, other.stdout);
-        std::swap(stderr, other.stderr);
+        std::swap(stdoutStr, other.stdoutStr);
+        std::swap(stderrStr, other.stderrStr);
         return *this;
     }
     ~CommandResult();
     [[nodiscard]] std::string toString() const;
 
     [[nodiscard]] bool stdoutEndsWithNewLine() const {
-        return !stdout.empty() && stdout.back() == '\n';
+        return !stdoutStr.empty() && stdoutStr.back() == '\n';
     }
 
 private:
diff --git a/libs/binder/aidl/android/os/ConnectionInfo.aidl b/libs/binder/aidl/android/os/ConnectionInfo.aidl
new file mode 100644
index 0000000..160c9ea
--- /dev/null
+++ b/libs/binder/aidl/android/os/ConnectionInfo.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * Remote connection info associated with a declared service
+ * @hide
+ */
+parcelable ConnectionInfo {
+    /**
+     * IP address that the service is listening on.
+     */
+    @utf8InCpp String ipAddress;
+    /**
+     * Port number that the service is listening on. Actual value is an unsigned integer.
+     */
+    int port;
+}
+
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index 75c4092..5880c0a 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -19,6 +19,7 @@
 import android.os.IClientCallback;
 import android.os.IServiceCallback;
 import android.os.ServiceDebugInfo;
+import android.os.ConnectionInfo;
 
 /**
  * Basic interface for finding and publishing system services.
@@ -113,6 +114,11 @@
     @nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
 
     /**
+     * If connection info is available for the given instance, returns the ConnectionInfo
+     */
+    @nullable ConnectionInfo getConnectionInfo(@utf8InCpp String name);
+
+    /**
      * Request a callback when the number of clients of the service changes.
      * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
      */
diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h
index 9dea3b4..793795e 100644
--- a/libs/binder/binder_module.h
+++ b/libs/binder/binder_module.h
@@ -74,6 +74,8 @@
     //
     // Indicates whether the process has received any sync calls since last
     // freeze (cleared at freeze/unfreeze)
+    // bit 0: received sync transaction after being frozen
+    // bit 1: new pending sync transaction during freezing
     //
     __u32 sync_recv;
     //
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index b58cb7e..c0454b6 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -17,7 +17,6 @@
 #pragma once
 
 #include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
 #include <utils/KeyedVector.h>
 #include <utils/Mutex.h>
 #include <utils/threads.h>
@@ -40,9 +39,6 @@
 class BpBinder : public IBinder
 {
 public:
-    static sp<BpBinder> create(int32_t handle);
-    static sp<BpBinder> create(const sp<RpcSession>& session, const RpcAddress& address);
-
     /**
      * Return value:
      * true - this is associated with a socket RpcSession
@@ -117,42 +113,49 @@
         KeyedVector<const void*, entry_t> mObjects;
     };
 
-    class PrivateAccessorForId {
+    class PrivateAccessor {
     private:
         friend class BpBinder;
         friend class ::android::Parcel;
         friend class ::android::ProcessState;
+        friend class ::android::RpcSession;
         friend class ::android::RpcState;
-        explicit PrivateAccessorForId(const BpBinder* binder) : mBinder(binder) {}
+        explicit PrivateAccessor(const BpBinder* binder) : mBinder(binder) {}
+
+        static sp<BpBinder> create(int32_t handle) { return BpBinder::create(handle); }
+        static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address) {
+            return BpBinder::create(session, address);
+        }
 
         // valid if !isRpcBinder
         int32_t binderHandle() const { return mBinder->binderHandle(); }
 
         // valid if isRpcBinder
-        const RpcAddress& rpcAddress() const { return mBinder->rpcAddress(); }
+        uint64_t rpcAddress() const { return mBinder->rpcAddress(); }
         const sp<RpcSession>& rpcSession() const { return mBinder->rpcSession(); }
 
         const BpBinder* mBinder;
     };
-    const PrivateAccessorForId getPrivateAccessorForId() const {
-        return PrivateAccessorForId(this);
-    }
+    const PrivateAccessor getPrivateAccessor() const { return PrivateAccessor(this); }
 
 private:
-    friend PrivateAccessorForId;
+    friend PrivateAccessor;
     friend class sp<BpBinder>;
 
+    static sp<BpBinder> create(int32_t handle);
+    static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
+
     struct BinderHandle {
         int32_t handle;
     };
     struct RpcHandle {
         sp<RpcSession> session;
-        RpcAddress address;
+        uint64_t address;
     };
     using Handle = std::variant<BinderHandle, RpcHandle>;
 
     int32_t binderHandle() const;
-    const RpcAddress& rpcAddress() const;
+    uint64_t rpcAddress() const;
     const sp<RpcSession>& rpcSession() const;
 
     explicit BpBinder(Handle&& handle);
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 20a9f36..065e6e3 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -53,6 +53,13 @@
     // Provide information about the state of a frozen process
     static  status_t            getProcessFreezeInfo(pid_t pid, bool *sync_received,
                                                     bool *async_received);
+
+    // TODO: Remove the above legacy duplicated function in next version
+#ifndef __ANDROID_VNDK__
+    static  status_t            getProcessFreezeInfo(pid_t pid, uint32_t *sync_received,
+                                                    uint32_t *async_received);
+#endif
+
             sp<ProcessState>    process();
             
             status_t            clearLastError();
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index d152005..a48075d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -15,11 +15,9 @@
  */
 
 #pragma once
-
 #include <binder/IInterface.h>
 #include <utils/Vector.h>
 #include <utils/String16.h>
-
 #include <optional>
 
 namespace android {
@@ -107,6 +105,16 @@
      * this can be updated.
      */
     virtual std::optional<String16> updatableViaApex(const String16& name) = 0;
+
+    /**
+     * If this instance has declared remote connection information, returns
+     * the ConnectionInfo.
+     */
+    struct ConnectionInfo {
+        std::string ipAddress;
+        unsigned int port;
+    };
+    virtual std::optional<ConnectionInfo> getConnectionInfo(const String16& name) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
diff --git a/libs/binder/include/binder/RpcAddress.h b/libs/binder/include/binder/RpcAddress.h
deleted file mode 100644
index e428908..0000000
--- a/libs/binder/include/binder/RpcAddress.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#pragma once
-
-#include <memory>
-
-#include <utils/Errors.h>
-
-// WARNING: This is a feature which is still in development, and it is subject
-// to radical change. Any production use of this may subject your code to any
-// number of problems.
-
-namespace android {
-
-class Parcel;
-struct RpcWireAddress;
-
-/**
- * This class represents an identifier across an RPC boundary.
- */
-class RpcAddress {
-public:
-    /**
-     * The zero address is used for special RPC transactions, but it might also
-     * be used in conjunction with readFromParcel.
-     */
-    static RpcAddress zero();
-
-    bool isZero() const;
-
-    /**
-     * Create a new random address.
-     */
-    static RpcAddress random(bool forServer);
-
-    /**
-     * Whether this address was created with 'bool forServer' true
-     */
-    bool isForServer() const;
-
-    /**
-     * Whether this address is one that could be created with this version of
-     * libbinder.
-     */
-    bool isRecognizedType() const;
-
-    /**
-     * Creates a new address as a copy of an embedded object.
-     */
-    static RpcAddress fromRawEmbedded(const RpcWireAddress* raw);
-    const RpcWireAddress& viewRawEmbedded() const;
-
-    bool operator<(const RpcAddress& rhs) const;
-    std::string toString() const;
-
-    status_t writeToParcel(Parcel* parcel) const;
-    status_t readFromParcel(const Parcel& parcel);
-
-    ~RpcAddress();
-
-private:
-    RpcAddress();
-
-    std::shared_ptr<RpcWireAddress> mRawAddr;
-};
-
-} // namespace android
diff --git a/libs/binder/include/binder/RpcCertificateFormat.h b/libs/binder/include/binder/RpcCertificateFormat.h
new file mode 100644
index 0000000..bc9d814
--- /dev/null
+++ b/libs/binder/include/binder/RpcCertificateFormat.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.
+ */
+
+// Formats for serializing TLS certificate.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcCertificateFormat {
+    PEM,
+    DER,
+};
+
+static inline std::string PrintToString(RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return "PEM";
+        case RpcCertificateFormat::DER:
+            return "DER";
+        default:
+            return "<unknown>";
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcKeyFormat.h b/libs/binder/include/binder/RpcKeyFormat.h
new file mode 100644
index 0000000..5099c2e
--- /dev/null
+++ b/libs/binder/include/binder/RpcKeyFormat.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.
+ */
+
+// Formats for serializing TLS private keys.
+
+#pragma once
+
+#include <string>
+
+namespace android {
+
+enum class RpcKeyFormat {
+    PEM,
+    DER,
+};
+
+static inline std::string PrintToString(RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return "PEM";
+        case RpcKeyFormat::DER:
+            return "DER";
+        default:
+            return "<unknown>";
+    }
+}
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index d0e4e27..fb2cf23 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -17,7 +17,6 @@
 
 #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>
@@ -136,13 +135,7 @@
     /**
      * See RpcTransportCtx::getCertificate
      */
-    std::string getCertificate(CertificateFormat);
-
-    /**
-     * See RpcTransportCtx::addTrustedPeerCertificate.
-     * Thread-safe. This is only possible before the server is join()-ing.
-     */
-    status_t addTrustedPeerCertificate(CertificateFormat, std::string_view cert);
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat);
 
     /**
      * Runs join() in a background thread. Immediately returns.
@@ -201,7 +194,7 @@
     std::map<std::thread::id, std::thread> mConnectingThreads;
     sp<IBinder> mRootObject;
     wp<IBinder> mRootObjectWeak;
-    std::map<RpcAddress, sp<RpcSession>> mSessions;
+    std::map<std::vector<uint8_t>, sp<RpcSession>> mSessions;
     std::unique_ptr<FdTrigger> mShutdownTrigger;
     std::condition_variable mShutdownCv;
 };
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index d92af0a..12d448d 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -17,7 +17,6 @@
 
 #include <android-base/unique_fd.h>
 #include <binder/IBinder.h>
-#include <binder/RpcAddress.h>
 #include <binder/RpcTransport.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -54,12 +53,10 @@
     // Create an RpcSession with default configuration (raw sockets).
     static sp<RpcSession> make();
 
-    // Create an RpcSession with the given configuration. |serverCertificateFormat| and
+    // Create an RpcSession with the given configuration. |serverRpcCertificateFormat| and
     // |serverCertificate| must have values or be nullopt simultaneously. If they have values, set
     // server certificate.
-    static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory,
-                               std::optional<CertificateFormat> serverCertificateFormat,
-                               std::optional<std::string> serverCertificate);
+    static sp<RpcSession> make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
 
     /**
      * Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -134,7 +131,7 @@
     /**
      * See RpcTransportCtx::getCertificate
      */
-    std::string getCertificate(CertificateFormat);
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat);
 
     /**
      * Shuts down the service.
@@ -154,7 +151,13 @@
 
     [[nodiscard]] status_t transact(const sp<IBinder>& binder, uint32_t code, const Parcel& data,
                                     Parcel* reply, uint32_t flags);
-    [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
+
+    /**
+     * Generally, you should not call this, unless you are testing error
+     * conditions, as this is called automatically by BpBinders when they are
+     * deleted (this is also why a raw pointer is used here)
+     */
+    [[nodiscard]] status_t sendDecStrong(const BpBinder* binder);
 
     ~RpcSession();
 
@@ -173,6 +176,9 @@
     friend RpcState;
     explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
 
+    // for 'target', see RpcState::sendDecStrongToTarget
+    [[nodiscard]] status_t sendDecStrongToTarget(uint64_t address, size_t target);
+
     class EventListener : public virtual RefBase {
     public:
         virtual void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) = 0;
@@ -183,12 +189,12 @@
     public:
         void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
         void onSessionIncomingThreadEnded() override;
-        void waitForShutdown(std::unique_lock<std::mutex>& lock);
+        void waitForShutdown(std::unique_lock<std::mutex>& lock, const sp<RpcSession>& session);
 
     private:
         std::condition_variable mCv;
-        volatile bool mShutdown = false;
     };
+    friend WaitForShutdownListener;
 
     struct RpcConnection : public RefBase {
         std::unique_ptr<RpcTransport> rpcTransport;
@@ -222,19 +228,21 @@
     static void join(sp<RpcSession>&& session, PreJoinSetupResult&& result);
 
     [[nodiscard]] status_t setupClient(
-            const std::function<status_t(const RpcAddress& sessionId, bool incoming)>&
+            const std::function<status_t(const std::vector<uint8_t>& 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,
+                                                    const std::vector<uint8_t>& sessionId,
+                                                    bool incoming);
+    [[nodiscard]] status_t initAndAddConnection(base::unique_fd fd,
+                                                const std::vector<uint8_t>& 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);
+                                    const std::vector<uint8_t>& sessionId);
     sp<RpcConnection> assignIncomingConnectionToThisThread(
             std::unique_ptr<RpcTransport> rpcTransport);
     [[nodiscard]] bool removeIncomingConnection(const sp<RpcConnection>& connection);
@@ -291,7 +299,7 @@
     sp<WaitForShutdownListener> mShutdownListener; // used for client sessions
     wp<EventListener> mEventListener; // mForServer if server, mShutdownListener if client
 
-    std::optional<RpcAddress> mId;
+    std::vector<uint8_t> mId;
 
     std::unique_ptr<FdTrigger> mShutdownTrigger;
 
diff --git a/libs/binder/include/binder/RpcTransport.h b/libs/binder/include/binder/RpcTransport.h
index 8d08b34..db8b5e9 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <functional>
 #include <memory>
 #include <string>
 
@@ -25,15 +26,12 @@
 #include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 
+#include <binder/RpcCertificateFormat.h>
+
 namespace android {
 
 class FdTrigger;
 
-enum class CertificateFormat {
-    PEM,
-    // TODO(b/195166979): support other formats, e.g. DER
-};
-
 // Represents a socket connection.
 // No thread-safety is guaranteed for these APIs.
 class RpcTransport {
@@ -41,18 +39,25 @@
     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;
+    [[nodiscard]] virtual android::base::Result<size_t> peek(void *buf, size_t size) = 0;
 
     /**
      * Read (or write), but allow to be interrupted by a trigger.
      *
+     * altPoll - function to be called instead of polling, when needing to wait
+     * to read/write data. If this returns an error, that error is returned from
+     * this function.
+     *
      * 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;
+    [[nodiscard]] virtual status_t interruptableWriteFully(
+            FdTrigger *fdTrigger, const void *buf, size_t size,
+            const std::function<status_t()> &altPoll) = 0;
+    [[nodiscard]] virtual status_t interruptableReadFully(
+            FdTrigger *fdTrigger, void *buf, size_t size,
+            const std::function<status_t()> &altPoll) = 0;
 
 protected:
     RpcTransport() = default;
@@ -76,19 +81,8 @@
     // Implementation details:
     // - For raw sockets, this always returns empty string.
     // - For TLS, this returns the certificate. See RpcTransportTls for details.
-    [[nodiscard]] virtual std::string getCertificate(CertificateFormat format) const = 0;
-
-    // Add a trusted peer certificate. Peers presenting this certificate are accepted.
-    //
-    // Caller must ensure that newTransport() are called after all trusted peer certificates
-    // are added. Otherwise, RpcTransport-s created before may not trust peer certificates
-    // added later.
-    //
-    // Implementation details:
-    // - For raw sockets, this always returns OK.
-    // - For TLS, this adds trusted peer certificate. See RpcTransportTls for details.
-    [[nodiscard]] virtual status_t addTrustedPeerCertificate(CertificateFormat format,
-                                                             std::string_view cert) = 0;
+    [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
+            RpcCertificateFormat format) const = 0;
 
 protected:
     RpcTransportCtx() = default;
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
new file mode 100644
index 0000000..4c2f296
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+// An interface with a function that configures the SSL_CTX object with authentication information,
+// including certificates and private keys.
+class RpcAuth {
+public:
+    virtual ~RpcAuth() = default;
+
+    // The keys and certificates to provide is up to the implementation. Multiple calls to
+    // |configure()| may configure |ctx| with the same keys / certificates, or generate a
+    // different key / certificate every time |configure()| is called.
+    //
+    // It is guaranteed that, when a context object (RpcTransportCtx) is created,
+    // libbinder_tls calls |configure()| on server RpcAuth exactly once.
+    //
+    // The implementation may use the following function to set the private
+    // keys and certificates:
+    // - SSL_CTX_use_PrivateKey
+    // - SSL_CTX_use_certificate
+    // - SSL_CTX_set*_chain
+    // - SSL_CTX_add0_chain_cert
+    virtual status_t configure(SSL_CTX* ctx) = 0;
+};
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcCertificateVerifier.h b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
new file mode 100644
index 0000000..800e375
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+// An interface with a function that verifies a peer certificate. It is a wrapper over the custom
+// verify function (see SSL_CTX_set_custom_verify).
+class RpcCertificateVerifier {
+public:
+    virtual ~RpcCertificateVerifier() = default;
+
+    // The implementation may use the following function to get
+    // the peer certificate and chain:
+    // - SSL_get_peer_certificate
+    // - SSL_get_peer_cert_chain
+    // - SSL_get_peer_full_cert_chain
+    //
+    // The implementation should return OK on success or error codes on error. For example:
+    // - PERMISSION_DENIED for rejected certificates
+    // - NO_INIT for not presenting a certificate when requested
+    // - UNKNOWN_ERROR for other errors
+    virtual status_t verify(const SSL* ssl, uint8_t* outAlert) = 0;
+};
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTlsUtils.h b/libs/binder/include_tls/binder/RpcTlsUtils.h
new file mode 100644
index 0000000..591926b
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcTlsUtils.h
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+// Utilities for serializing and deserializing X509 certificates.
+
+#pragma once
+
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcKeyFormat.h>
+
+namespace android {
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
+                                             RpcCertificateFormat format);
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+
+// Deserialize an un-encrypted private key.
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+                                                           RpcKeyFormat format);
+
+// Serialize a private key in un-encrypted form.
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format);
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
index 531aaa9..8a11125 100644
--- a/libs/binder/include_tls/binder/RpcTransportTls.h
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -18,6 +18,8 @@
 
 #pragma once
 
+#include <binder/RpcAuth.h>
+#include <binder/RpcCertificateVerifier.h>
 #include <binder/RpcTransport.h>
 
 namespace android {
@@ -25,14 +27,20 @@
 // RpcTransportCtxFactory with TLS enabled with self-signed certificate.
 class RpcTransportCtxFactoryTls : public RpcTransportCtxFactory {
 public:
-    static std::unique_ptr<RpcTransportCtxFactory> make();
+    static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>,
+                                                        std::unique_ptr<RpcAuth>);
 
     std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
     std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
     const char* toCString() const override;
 
 private:
-    RpcTransportCtxFactoryTls() = default;
+    RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier,
+                              std::unique_ptr<RpcAuth> auth)
+          : mCertVerifier(std::move(verifier)), mAuth(std::move(auth)){};
+
+    std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
+    std::unique_ptr<RpcAuth> mAuth;
 };
 
 } // namespace android
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 23db59e..83bf9be 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -373,6 +373,12 @@
     return clazz->getInterfaceDescriptorUtf8();
 }
 
+AIBinder_DeathRecipient::TransferDeathRecipient::~TransferDeathRecipient() {
+    if (mOnUnlinked != nullptr) {
+        mOnUnlinked(mCookie);
+    }
+}
+
 void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
     CHECK(who == mWho) << who.unsafe_get() << "(" << who.get_refs() << ") vs " << mWho.unsafe_get()
                        << " (" << mWho.get_refs() << ")";
@@ -394,7 +400,7 @@
 }
 
 AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
-    : mOnDied(onDied) {
+    : mOnDied(onDied), mOnUnlinked(nullptr) {
     CHECK(onDied != nullptr);
 }
 
@@ -412,10 +418,12 @@
     std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
 
     sp<TransferDeathRecipient> recipient =
-            new TransferDeathRecipient(binder, cookie, this, mOnDied);
+            new TransferDeathRecipient(binder, cookie, this, mOnDied, mOnUnlinked);
 
     status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
     if (status != STATUS_OK) {
+        // When we failed to link, the destructor of TransferDeathRecipient runs here, which
+        // ensures that mOnUnlinked is called before we return with an error from this method.
         return PruneStatusT(status);
     }
 
@@ -448,6 +456,10 @@
     return STATUS_NAME_NOT_FOUND;
 }
 
+void AIBinder_DeathRecipient::setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
+    mOnUnlinked = onUnlinked;
+}
+
 // start of C-API methods
 
 AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
@@ -689,6 +701,15 @@
     return ret;
 }
 
+void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
+                                           AIBinder_DeathRecipient_onBinderUnlinked onUnlinked) {
+    if (recipient == nullptr) {
+        return;
+    }
+
+    recipient->setOnUnlinked(onUnlinked);
+}
+
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
     if (recipient == nullptr) {
         return;
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 6509545..9fb5c1d 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -148,8 +148,14 @@
     struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
         TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
                                const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
-                               const AIBinder_DeathRecipient_onBinderDied onDied)
-            : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
+                               const AIBinder_DeathRecipient_onBinderDied onDied,
+                               const AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
+            : mWho(who),
+              mCookie(cookie),
+              mParentRecipient(parentRecipient),
+              mOnDied(onDied),
+              mOnUnlinked(onUnlinked) {}
+        ~TransferDeathRecipient();
 
         void binderDied(const ::android::wp<::android::IBinder>& who) override;
 
@@ -165,11 +171,13 @@
         // This is kept separately from AIBinder_DeathRecipient in case the death recipient is
         // deleted while the death notification is fired
         const AIBinder_DeathRecipient_onBinderDied mOnDied;
+        const AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
     };
 
     explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
     binder_status_t linkToDeath(const ::android::sp<::android::IBinder>&, void* cookie);
     binder_status_t unlinkToDeath(const ::android::sp<::android::IBinder>& binder, void* cookie);
+    void setOnUnlinked(AIBinder_DeathRecipient_onBinderUnlinked onUnlinked);
 
    private:
     // When the user of this API deletes a Bp object but not the death recipient, the
@@ -180,4 +188,5 @@
     std::mutex mDeathRecipientsMutex;
     std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
     AIBinder_DeathRecipient_onBinderDied mOnDied;
+    AIBinder_DeathRecipient_onBinderUnlinked mOnUnlinked;
 };
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index b881c2c..43533c5 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -319,9 +319,9 @@
 /**
  * Registers for notifications that the associated binder is dead. The same death recipient may be
  * associated with multiple different binders. If the binder is local, then no death recipient will
- * be given (since if the local process dies, then no recipient will exist to recieve a
+ * be given (since if the local process dies, then no recipient will exist to receive a
  * transaction). The cookie is passed to recipient in the case that this binder dies and can be
- * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
+ * null. The exact cookie must also be used to unlink this transaction (see AIBinder_unlinkToDeath).
  * This function may return a binder transaction failure. The cookie can be used both for
  * identification and holding user data.
  *
@@ -348,6 +348,10 @@
  * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
  * automatically unlinked.
  *
+ * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
+ * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
+ * AIBinder_DeathRecipient_setOnUnlinked.
+ *
  * Available since API level 29.
  *
  * \param binder the binder object to remove a previously linked death recipient from.
@@ -568,6 +572,22 @@
 typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie) __INTRODUCED_IN(29);
 
 /**
+ * This function is intended for cleaning up the data in the provided cookie, and it is executed
+ * when the DeathRecipient is unlinked. When the DeathRecipient is unlinked due to a death receipt,
+ * this method is called after the call to onBinderDied.
+ *
+ * This method is called once for each binder that is unlinked. Hence, if the same cookie is passed
+ * to multiple binders, then the caller is responsible for reference counting the cookie.
+ *
+ * See also AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ *
+ * Available since API level 33.
+ *
+ * \param cookie the cookie passed to AIBinder_linkToDeath.
+ */
+typedef void (*AIBinder_DeathRecipient_onBinderUnlinked)(void* cookie) __INTRODUCED_IN(33);
+
+/**
  * Creates a new binder death recipient. This can be attached to multiple different binder objects.
  *
  * Available since API level 29.
@@ -580,9 +600,47 @@
         AIBinder_DeathRecipient_onBinderDied onBinderDied) __INTRODUCED_IN(29);
 
 /**
+ * Set the callback to be called when this DeathRecipient is unlinked from a binder. The callback is
+ * called in the following situations:
+ *
+ *  1. If the binder died, shortly after the call to onBinderDied.
+ *  2. If the binder is explicitly unlinked with AIBinder_unlinkToDeath or
+ *     AIBinder_DeathRecipient_delete.
+ *  3. During or shortly after the AIBinder_linkToDeath call if it returns an error.
+ *
+ * It is guaranteed that the callback is called exactly once for each call to linkToDeath unless the
+ * process is aborted before the binder is unlinked.
+ *
+ * Be aware that when the binder is explicitly unlinked, it is not guaranteed that onUnlinked has
+ * been called before the call to AIBinder_unlinkToDeath or AIBinder_DeathRecipient_delete returns.
+ * For example, if the binder dies concurrently with a call to AIBinder_unlinkToDeath, the binder is
+ * not unlinked until after the death notification is delivered, even if AIBinder_unlinkToDeath
+ * returns before that happens.
+ *
+ * This method should be called before linking the DeathRecipient to a binder because the function
+ * pointer is cached. If you change it after linking to a binder, it is unspecified whether the old
+ * binder will call the old or new onUnlinked callback.
+ *
+ * The onUnlinked argument may be null. In this case, no notification is given when the binder is
+ * unlinked.
+ *
+ * Available since API level 33.
+ *
+ * \param recipient the DeathRecipient to set the onUnlinked callback for.
+ * \param onUnlinked the callback to call when a binder is unlinked from recipient.
+ */
+void AIBinder_DeathRecipient_setOnUnlinked(AIBinder_DeathRecipient* recipient,
+                                           AIBinder_DeathRecipient_onBinderUnlinked onUnlinked)
+        __INTRODUCED_IN(33);
+
+/**
  * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
  * calling this as these will all be automatically unlinked.
  *
+ * Be aware that it is not safe to immediately deallocate the cookie when this call returns. If you
+ * need to clean up the cookie, you should do so in the onUnlinked callback, which can be set using
+ * AIBinder_DeathRecipient_setOnUnlinked.
+ *
  * Available since API level 29.
  *
  * \param recipient the binder to delete (previously created with AIBinder_DeathRecipient_new).
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a2f5c93..8457581 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1167,6 +1167,8 @@
 /**
  * Marshals the raw bytes of the Parcel to a buffer.
  *
+ * Available since API level 33.
+ *
  * The parcel must not contain any binders or file descriptors.
  *
  * The data you retrieve here must not be placed in any kind of persistent storage. (on local disk,
@@ -1189,6 +1191,8 @@
 /**
  * Set the data in the parcel to the raw bytes from the buffer.
  *
+ * Available since API level 33.
+ *
  * \param parcel The parcel to set data.
  * \param buffer The data buffer to set.
  * \param len The size of the data to set.
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index ac892db..8605686 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -144,6 +144,7 @@
 LIBBINDER_NDK33 { # introduced=33
   global:
     AIBinder_Class_disableInterfaceTokenHeader;
+    AIBinder_DeathRecipient_setOnUnlinked;
     AParcel_marshal;
     AParcel_unmarshal;
 };
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index a8ae441..8ed91a5 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -20,6 +20,7 @@
 #include <android-base/logging.h>
 
 using ::android::status_t;
+using ::android::statusToString;
 using ::android::binder::Status;
 
 AStatus* AStatus_newOk() {
@@ -126,7 +127,7 @@
             return STATUS_UNKNOWN_ERROR;
 
         default:
-            LOG(WARNING) << __func__ << ": Unknown status_t (" << status
+            LOG(WARNING) << __func__ << ": Unknown status_t (" << statusToString(status)
                          << ") pruned into STATUS_UNKNOWN_ERROR";
             return STATUS_UNKNOWN_ERROR;
     }
diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
index b5c06e9..d1ff4de 100644
--- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp
@@ -375,9 +375,16 @@
             << "Service failed to shut down.";
 }
 
+struct DeathRecipientCookie {
+    std::function<void(void)>*onDeath, *onUnlink;
+};
 void LambdaOnDeath(void* cookie) {
-    auto onDeath = static_cast<std::function<void(void)>*>(cookie);
-    (*onDeath)();
+    auto funcs = static_cast<DeathRecipientCookie*>(cookie);
+    (*funcs->onDeath)();
+};
+void LambdaOnUnlink(void* cookie) {
+    auto funcs = static_cast<DeathRecipientCookie*>(cookie);
+    (*funcs->onUnlink)();
 };
 TEST(NdkBinder, DeathRecipient) {
     using namespace std::chrono_literals;
@@ -389,26 +396,46 @@
 
     std::mutex deathMutex;
     std::condition_variable deathCv;
-    bool deathRecieved = false;
+    bool deathReceived = false;
 
     std::function<void(void)> onDeath = [&] {
         std::cerr << "Binder died (as requested)." << std::endl;
-        deathRecieved = true;
+        deathReceived = true;
         deathCv.notify_one();
     };
 
-    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+    std::mutex unlinkMutex;
+    std::condition_variable unlinkCv;
+    bool unlinkReceived = false;
+    bool wasDeathReceivedFirst = false;
 
-    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&onDeath)));
+    std::function<void(void)> onUnlink = [&] {
+        std::cerr << "Binder unlinked (as requested)." << std::endl;
+        wasDeathReceivedFirst = deathReceived;
+        unlinkReceived = true;
+        unlinkCv.notify_one();
+    };
+
+    DeathRecipientCookie cookie = {&onDeath, &onUnlink};
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(LambdaOnDeath);
+    AIBinder_DeathRecipient_setOnUnlinked(recipient, LambdaOnUnlink);
+
+    EXPECT_EQ(STATUS_OK, AIBinder_linkToDeath(binder, recipient, static_cast<void*>(&cookie)));
 
     // the binder driver should return this if the service dies during the transaction
     EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
 
     foo = nullptr;
 
-    std::unique_lock<std::mutex> lock(deathMutex);
-    EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
-    EXPECT_TRUE(deathRecieved);
+    std::unique_lock<std::mutex> lockDeath(deathMutex);
+    EXPECT_TRUE(deathCv.wait_for(lockDeath, 1s, [&] { return deathReceived; }));
+    EXPECT_TRUE(deathReceived);
+
+    std::unique_lock<std::mutex> lockUnlink(unlinkMutex);
+    EXPECT_TRUE(deathCv.wait_for(lockUnlink, 1s, [&] { return unlinkReceived; }));
+    EXPECT_TRUE(unlinkReceived);
+    EXPECT_TRUE(wasDeathReceivedFirst);
 
     AIBinder_DeathRecipient_delete(recipient);
     AIBinder_decStrong(binder);
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index dd0c7b8..41ceee5 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -152,20 +152,46 @@
     /// available.
     fn get_extension(&mut self) -> Result<Option<SpIBinder>>;
 
+    /// Create a Parcel that can be used with `submit_transact`.
+    fn prepare_transact(&self) -> Result<Parcel>;
+
     /// Perform a generic operation with the object.
     ///
+    /// The provided [`Parcel`] must have been created by a call to
+    /// `prepare_transact` on the same binder.
+    ///
+    /// # Arguments
+    ///
+    /// * `code` - Transaction code for the operation.
+    /// * `data` - [`Parcel`] with input data.
+    /// * `flags` - Transaction flags, e.g. marking the transaction as
+    ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY)).
+    fn submit_transact(
+        &self,
+        code: TransactionCode,
+        data: Parcel,
+        flags: TransactionFlags,
+    ) -> Result<Parcel>;
+
+    /// Perform a generic operation with the object. This is a convenience
+    /// method that internally calls `prepare_transact` followed by
+    /// `submit_transact.
+    ///
     /// # Arguments
     /// * `code` - Transaction code for the operation
-    /// * `data` - [`Parcel`] with input data
-    /// * `reply` - Optional [`Parcel`] for reply data
     /// * `flags` - Transaction flags, e.g. marking the transaction as
     ///   asynchronous ([`FLAG_ONEWAY`](FLAG_ONEWAY))
+    /// * `input_callback` A callback for building the `Parcel`.
     fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
         &self,
         code: TransactionCode,
         flags: TransactionFlags,
         input_callback: F,
-    ) -> Result<Parcel>;
+    ) -> Result<Parcel> {
+        let mut parcel = self.prepare_transact()?;
+        input_callback(&mut parcel)?;
+        self.submit_transact(code, parcel, flags)
+    }
 }
 
 /// Interface of binder local or remote objects.
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index cb330a6..7e8e3a5 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -112,8 +112,7 @@
     FLAG_CLEAR_BUF, FLAG_ONEWAY, FLAG_PRIVATE_LOCAL, LAST_CALL_TRANSACTION,
 };
 pub use error::{status_t, ExceptionCode, Result, Status, StatusCode};
-pub use native::add_service;
-pub use native::Binder;
+pub use native::{add_service, force_lazy_services_persist, register_lazy_service, Binder};
 pub use parcel::Parcel;
 pub use proxy::{get_interface, get_service, wait_for_interface, wait_for_service};
 pub use proxy::{AssociateClass, DeathRecipient, Proxy, SpIBinder, WpIBinder};
@@ -129,7 +128,10 @@
 /// The public API usable outside AIDL-generated interface crates.
 pub mod public_api {
     pub use super::parcel::ParcelFileDescriptor;
-    pub use super::{add_service, get_interface, wait_for_interface};
+    pub use super::{
+        add_service, force_lazy_services_persist, get_interface, register_lazy_service,
+        wait_for_interface,
+    };
     pub use super::{
         BinderFeatures, DeathRecipient, ExceptionCode, IBinder, Interface, ProcessState, SpIBinder,
         Status, StatusCode, Strong, ThreadState, Weak, WpIBinder,
diff --git a/libs/binder/rust/src/native.rs b/libs/binder/rust/src/native.rs
index a0dfeec..a91092e 100644
--- a/libs/binder/rust/src/native.rs
+++ b/libs/binder/rust/src/native.rs
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-use crate::binder::{AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode};
+use crate::binder::{
+    AsNative, Interface, InterfaceClassMethods, Remotable, Stability, TransactionCode,
+};
 use crate::error::{status_result, status_t, Result, StatusCode};
 use crate::parcel::{Parcel, Serialize};
 use crate::proxy::SpIBinder;
@@ -321,7 +323,12 @@
     /// contains a `T` pointer in its user data. fd should be a non-owned file
     /// descriptor, and args must be an array of null-terminated string
     /// poiinters with length num_args.
-    unsafe extern "C" fn on_dump(binder: *mut sys::AIBinder, fd: i32, args: *mut *const c_char, num_args: u32) -> status_t {
+    unsafe extern "C" fn on_dump(
+        binder: *mut sys::AIBinder,
+        fd: i32,
+        args: *mut *const c_char,
+        num_args: u32,
+    ) -> status_t {
         if fd < 0 {
             return StatusCode::UNEXPECTED_NULL as status_t;
         }
@@ -434,6 +441,8 @@
 ///
 /// Registers the given binder object with the given identifier. If successful,
 /// this service can then be retrieved using that identifier.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
 pub fn add_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
     let instance = CString::new(identifier).unwrap();
     let status = unsafe {
@@ -447,6 +456,43 @@
     status_result(status)
 }
 
+/// Register a dynamic service via the LazyServiceRegistrar.
+///
+/// Registers the given binder object with the given identifier. If successful,
+/// this service can then be retrieved using that identifier. The service process
+/// will be shut down once all registered services are no longer in use.
+///
+/// If any service in the process is registered as lazy, all should be, otherwise
+/// the process may be shut down while a service is in use.
+///
+/// This function will panic if the identifier contains a 0 byte (NUL).
+pub fn register_lazy_service(identifier: &str, mut binder: SpIBinder) -> Result<()> {
+    let instance = CString::new(identifier).unwrap();
+    let status = unsafe {
+        // Safety: `AServiceManager_registerLazyService` expects valid `AIBinder` and C
+        // string pointers. Caller retains ownership of both
+        // pointers. `AServiceManager_registerLazyService` creates a new strong reference
+        // and copies the string, so both pointers need only be valid until the
+        // call returns.
+
+        sys::AServiceManager_registerLazyService(binder.as_native_mut(), instance.as_ptr())
+    };
+    status_result(status)
+}
+
+/// Prevent a process which registers lazy services from being shut down even when none
+/// of the services is in use.
+///
+/// If persist is true then shut down will be blocked until this function is called again with
+/// persist false. If this is to be the initial state, call this function before calling
+/// register_lazy_service.
+pub fn force_lazy_services_persist(persist: bool) {
+    unsafe {
+        // Safety: No borrowing or transfer of ownership occurs here.
+        sys::AServiceManager_forceLazyServicesPersist(persist)
+    }
+}
+
 /// Tests often create a base BBinder instance; so allowing the unit
 /// type to be remotable translates nicely to Binder::new(()).
 impl Remotable for () {
diff --git a/libs/binder/rust/src/parcel.rs b/libs/binder/rust/src/parcel.rs
index a0e991c..dad89ec 100644
--- a/libs/binder/rust/src/parcel.rs
+++ b/libs/binder/rust/src/parcel.rs
@@ -25,6 +25,7 @@
 use std::convert::TryInto;
 use std::mem::ManuallyDrop;
 use std::ptr;
+use std::fmt;
 
 mod file_descriptor;
 mod parcelable;
@@ -96,6 +97,13 @@
         let _ = ManuallyDrop::new(self);
         ptr
     }
+
+    pub(crate) fn is_owned(&self) -> bool {
+        match *self {
+            Self::Owned(_) => true,
+            Self::Borrowed(_) => false,
+        }
+    }
 }
 
 // Data serialization methods
@@ -412,6 +420,13 @@
     }
 }
 
+impl fmt::Debug for Parcel {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Parcel")
+            .finish()
+    }
+}
+
 #[cfg(test)]
 impl Parcel {
     /// Create a new parcel tied to a bogus binder. TESTING ONLY!
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 179b7c8..f71a686 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, RawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 
 /// Rust version of the Java class android.os.ParcelFileDescriptor
 #[derive(Debug)]
@@ -54,6 +54,12 @@
     }
 }
 
+impl IntoRawFd for ParcelFileDescriptor {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
 impl Serialize for ParcelFileDescriptor {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         let fd = self.0.as_raw_fd();
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index b03ed49..68fa34b 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -31,8 +31,10 @@
 use std::convert::TryInto;
 use std::ffi::{c_void, CString};
 use std::fmt;
+use std::mem;
 use std::os::unix::io::AsRawFd;
 use std::ptr;
+use std::sync::Arc;
 
 /// A strong reference to a Binder remote object.
 ///
@@ -233,13 +235,7 @@
 }
 
 impl<T: AsNative<sys::AIBinder>> IBinderInternal for T {
-    /// Perform a binder transaction
-    fn transact<F: FnOnce(&mut Parcel) -> Result<()>>(
-        &self,
-        code: TransactionCode,
-        flags: TransactionFlags,
-        input_callback: F,
-    ) -> Result<Parcel> {
+    fn prepare_transact(&self) -> Result<Parcel> {
         let mut input = ptr::null_mut();
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
@@ -252,15 +248,25 @@
             // pointer, or null.
             sys::AIBinder_prepareTransaction(self.as_native() as *mut sys::AIBinder, &mut input)
         };
+
         status_result(status)?;
-        let mut input = unsafe {
+
+        unsafe {
             // Safety: At this point, `input` is either a valid, owned `AParcel`
             // pointer, or null. `Parcel::owned` safely handles both cases,
             // taking ownership of the parcel.
-            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)?
-        };
-        input_callback(&mut input)?;
+            Parcel::owned(input).ok_or(StatusCode::UNEXPECTED_NULL)
+        }
+    }
+
+    fn submit_transact(
+        &self,
+        code: TransactionCode,
+        data: Parcel,
+        flags: TransactionFlags,
+    ) -> Result<Parcel> {
         let mut reply = ptr::null_mut();
+        assert!(data.is_owned());
         let status = unsafe {
             // Safety: `SpIBinder` guarantees that `self` always contains a
             // valid pointer to an `AIBinder`. Although `IBinder::transact` is
@@ -275,13 +281,13 @@
             // only providing `on_transact` with an immutable reference to
             // `self`.
             //
-            // This call takes ownership of the `input` parcel pointer, and
+            // This call takes ownership of the `data` parcel pointer, and
             // passes ownership of the `reply` out parameter to its caller. It
             // does not affect ownership of the `binder` parameter.
             sys::AIBinder_transact(
                 self.as_native() as *mut sys::AIBinder,
                 code,
-                &mut input.into_raw(),
+                &mut data.into_raw(),
                 &mut reply,
                 flags,
             )
@@ -378,13 +384,17 @@
             // Safety: `SpIBinder` guarantees that `self` always contains a
             // valid pointer to an `AIBinder`. `recipient` can always be
             // converted into a valid pointer to an
-            // `AIBinder_DeathRecipient`. Any value is safe to pass as the
-            // cookie, although we depend on this value being set by
-            // `get_cookie` when the death recipient callback is called.
+            // `AIBinder_DeathRecipient`.
+            //
+            // The cookie is also the correct pointer, and by calling new_cookie,
+            // we have created a new ref-count to the cookie, which linkToDeath
+            // takes ownership of. Once the DeathRecipient is unlinked for any
+            // reason (including if this call fails), the onUnlinked callback
+            // will consume that ref-count.
             sys::AIBinder_linkToDeath(
                 self.as_native_mut(),
                 recipient.as_native_mut(),
-                recipient.get_cookie(),
+                recipient.new_cookie(),
             )
         })
     }
@@ -552,10 +562,20 @@
 }
 
 /// Rust wrapper around DeathRecipient objects.
+///
+/// The cookie in this struct represents an Arc<F> for the owned callback.
+/// This struct owns a ref-count of it, and so does every binder that we
+/// have been linked with.
 #[repr(C)]
 pub struct DeathRecipient {
     recipient: *mut sys::AIBinder_DeathRecipient,
-    callback: Box<dyn Fn() + Send + 'static>,
+    cookie: *mut c_void,
+    vtable: &'static DeathRecipientVtable,
+}
+
+struct DeathRecipientVtable {
+    cookie_incr_refcount: unsafe extern "C" fn(*mut c_void),
+    cookie_decr_refcount: unsafe extern "C" fn(*mut c_void),
 }
 
 impl DeathRecipient {
@@ -563,9 +583,9 @@
     /// associated object dies.
     pub fn new<F>(callback: F) -> DeathRecipient
     where
-        F: Fn() + Send + 'static,
+        F: Fn() + Send + Sync + 'static,
     {
-        let callback = Box::new(callback);
+        let callback: *const F = Arc::into_raw(Arc::new(callback));
         let recipient = unsafe {
             // Safety: The function pointer is a valid death recipient callback.
             //
@@ -574,34 +594,85 @@
             // no longer needed.
             sys::AIBinder_DeathRecipient_new(Some(Self::binder_died::<F>))
         };
+        unsafe {
+            // Safety: The function pointer is a valid onUnlinked callback.
+            //
+            // All uses of linkToDeath in this file correctly increment the
+            // ref-count that this onUnlinked callback will decrement.
+            sys::AIBinder_DeathRecipient_setOnUnlinked(recipient, Some(Self::cookie_decr_refcount::<F>));
+        }
         DeathRecipient {
             recipient,
-            callback,
+            cookie: callback as *mut c_void,
+            vtable: &DeathRecipientVtable {
+                cookie_incr_refcount: Self::cookie_incr_refcount::<F>,
+                cookie_decr_refcount: Self::cookie_decr_refcount::<F>,
+            },
         }
     }
 
+    /// Increment the ref-count for the cookie and return it.
+    ///
+    /// # Safety
+    ///
+    /// The caller must handle the returned ref-count correctly.
+    unsafe fn new_cookie(&self) -> *mut c_void {
+        (self.vtable.cookie_incr_refcount)(self.cookie);
+
+        // Return a raw pointer with ownership of a ref-count
+        self.cookie
+    }
+
     /// Get the opaque cookie that identifies this death recipient.
     ///
     /// This cookie will be used to link and unlink this death recipient to a
     /// binder object and will be passed to the `binder_died` callback as an
     /// opaque userdata pointer.
     fn get_cookie(&self) -> *mut c_void {
-        &*self.callback as *const _ as *mut c_void
+        self.cookie
     }
 
     /// Callback invoked from C++ when the binder object dies.
     ///
     /// # Safety
     ///
-    /// The `cookie` parameter must have been created with the `get_cookie`
-    /// method of this object.
+    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// the caller must hold a ref-count to it.
     unsafe extern "C" fn binder_died<F>(cookie: *mut c_void)
     where
-        F: Fn() + Send + 'static,
+        F: Fn() + Send + Sync + 'static,
     {
-        let callback = (cookie as *mut F).as_ref().unwrap();
+        let callback = (cookie as *const F).as_ref().unwrap();
         callback();
     }
+
+    /// Callback that decrements the ref-count.
+    /// This is invoked from C++ when a binder is unlinked.
+    ///
+    /// # Safety
+    ///
+    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// the owner must give up a ref-count to it.
+    unsafe extern "C" fn cookie_decr_refcount<F>(cookie: *mut c_void)
+    where
+        F: Fn() + Send + Sync + 'static,
+    {
+        drop(Arc::from_raw(cookie as *const F));
+    }
+
+    /// Callback that increments the ref-count.
+    ///
+    /// # Safety
+    ///
+    /// The `cookie` parameter must be the cookie for an Arc<F> and
+    /// the owner must handle the created ref-count properly.
+    unsafe extern "C" fn cookie_incr_refcount<F>(cookie: *mut c_void)
+    where
+        F: Fn() + Send + Sync + 'static,
+    {
+        let arc = mem::ManuallyDrop::new(Arc::from_raw(cookie as *const F));
+        mem::forget(Arc::clone(&arc));
+    }
 }
 
 /// # Safety
@@ -627,6 +698,12 @@
             // `AIBinder_DeathRecipient_new` when `self` was created. This
             // delete method can only be called once when `self` is dropped.
             sys::AIBinder_DeathRecipient_delete(self.recipient);
+
+            // Safety: We own a ref-count to the cookie, and so does every
+            // linked binder. This call gives up our ref-count. The linked
+            // binders should already have given up their ref-count, or should
+            // do so shortly.
+            (self.vtable.cookie_decr_refcount)(self.cookie)
         }
     }
 }
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index da8907d..335e8d8 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -363,13 +363,58 @@
         );
     }
 
-    fn register_death_notification(binder: &mut SpIBinder) -> (Arc<AtomicBool>, DeathRecipient) {
+    struct Bools {
+        binder_died: Arc<AtomicBool>,
+        binder_dealloc: Arc<AtomicBool>,
+    }
+
+    impl Bools {
+        fn is_dead(&self) -> bool {
+            self.binder_died.load(Ordering::Relaxed)
+        }
+        fn assert_died(&self) {
+            assert!(
+                self.is_dead(),
+                "Did not receive death notification"
+            );
+        }
+        fn assert_dropped(&self) {
+            assert!(
+                self.binder_dealloc.load(Ordering::Relaxed),
+                "Did not dealloc death notification"
+            );
+        }
+        fn assert_not_dropped(&self) {
+            assert!(
+                !self.binder_dealloc.load(Ordering::Relaxed),
+                "Dealloc death notification too early"
+            );
+        }
+    }
+
+    fn register_death_notification(binder: &mut SpIBinder) -> (Bools, DeathRecipient) {
         let binder_died = Arc::new(AtomicBool::new(false));
+        let binder_dealloc = Arc::new(AtomicBool::new(false));
+
+        struct SetOnDrop {
+            binder_dealloc: Arc<AtomicBool>,
+        }
+        impl Drop for SetOnDrop {
+            fn drop(&mut self) {
+                self.binder_dealloc.store(true, Ordering::Relaxed);
+            }
+        }
 
         let mut death_recipient = {
             let flag = binder_died.clone();
+            let set_on_drop = SetOnDrop {
+                binder_dealloc: binder_dealloc.clone(),
+            };
             DeathRecipient::new(move || {
                 flag.store(true, Ordering::Relaxed);
+                // Force the closure to take ownership of set_on_drop. When the closure is
+                // dropped, the destructor of `set_on_drop` will run.
+                let _ = &set_on_drop;
             })
         };
 
@@ -377,7 +422,12 @@
             .link_to_death(&mut death_recipient)
             .expect("link_to_death failed");
 
-        (binder_died, death_recipient)
+        let bools = Bools {
+            binder_died,
+            binder_dealloc,
+        };
+
+        (bools, death_recipient)
     }
 
     /// Killing a remote service should unregister the service and trigger
@@ -390,7 +440,7 @@
         let service_process = ScopedServiceProcess::new(service_name);
         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
 
-        let (binder_died, _recipient) = register_death_notification(&mut remote);
+        let (bools, recipient) = register_death_notification(&mut remote);
 
         drop(service_process);
         remote
@@ -400,10 +450,12 @@
         // Pause to ensure any death notifications get delivered
         thread::sleep(Duration::from_secs(1));
 
-        assert!(
-            binder_died.load(Ordering::Relaxed),
-            "Did not receive death notification"
-        );
+        bools.assert_died();
+        bools.assert_not_dropped();
+
+        drop(recipient);
+
+        bools.assert_dropped();
     }
 
     /// Test unregistering death notifications.
@@ -415,7 +467,7 @@
         let service_process = ScopedServiceProcess::new(service_name);
         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
 
-        let (binder_died, mut recipient) = register_death_notification(&mut remote);
+        let (bools, mut recipient) = register_death_notification(&mut remote);
 
         remote
             .unlink_to_death(&mut recipient)
@@ -430,9 +482,13 @@
         thread::sleep(Duration::from_secs(1));
 
         assert!(
-            !binder_died.load(Ordering::Relaxed),
+            !bools.is_dead(),
             "Received unexpected death notification after unlinking",
         );
+
+        bools.assert_not_dropped();
+        drop(recipient);
+        bools.assert_dropped();
     }
 
     /// Dropping a remote handle should unregister any death notifications.
@@ -444,7 +500,7 @@
         let service_process = ScopedServiceProcess::new(service_name);
         let mut remote = binder::get_service(service_name).expect("Could not retrieve service");
 
-        let (binder_died, _recipient) = register_death_notification(&mut remote);
+        let (bools, recipient) = register_death_notification(&mut remote);
 
         // This should automatically unregister our death notification.
         drop(remote);
@@ -457,9 +513,13 @@
         // We dropped the remote handle, so we should not receive the death
         // notification when the remote process dies here.
         assert!(
-            !binder_died.load(Ordering::Relaxed),
+            !bools.is_dead(),
             "Received unexpected death notification after dropping remote handle"
         );
+
+        bools.assert_not_dropped();
+        drop(recipient);
+        bools.assert_dropped();
     }
 
     /// Test IBinder interface methods not exercised elsewhere.
@@ -637,4 +697,27 @@
         assert!(!(service1 > service1));
         assert_eq!(service1 < service2, !(service2 < service1));
     }
+
+    #[test]
+    fn binder_parcel_mixup() {
+        let service1 = BnTest::new_binder(
+            TestService::new("testing_service1"),
+            BinderFeatures::default(),
+        );
+        let service2 = BnTest::new_binder(
+            TestService::new("testing_service2"),
+            BinderFeatures::default(),
+        );
+
+        let service1 = service1.as_binder();
+        let service2 = service2.as_binder();
+
+        let parcel = service1.prepare_transact().unwrap();
+        let res = service2.submit_transact(super::TestTransactionCode::Test as binder::TransactionCode, parcel, 0);
+
+        match res {
+            Ok(_) => panic!("submit_transact should fail"),
+            Err(err) => assert_eq!(err, binder::StatusCode::BAD_VALUE),
+        }
+    }
 }
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 9811cdf..23e34aa 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -157,6 +157,11 @@
                                              std::optional<std::string>* _aidl_return) override {
         return mImpl->updatableViaApex(name, _aidl_return);
     }
+    android::binder::Status getConnectionInfo(
+            const std::string& name,
+            std::optional<android::os::ConnectionInfo>* _aidl_return) override {
+        return mImpl->getConnectionInfo(name, _aidl_return);
+    }
     android::binder::Status registerClientCallback(
             const std::string&, const android::sp<android::IBinder>&,
             const android::sp<android::os::IClientCallback>&) override {
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 13ea827..680f0ed 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -120,9 +120,12 @@
     host_supported: true,
     unstable: true,
     srcs: [
+        "BinderRpcTestClientInfo.aidl",
+        "BinderRpcTestServerInfo.aidl",
         "IBinderRpcCallback.aidl",
         "IBinderRpcSession.aidl",
         "IBinderRpcTest.aidl",
+        "ParcelableCertificateData.aidl",
     ],
     backend: {
         java: {
@@ -131,6 +134,37 @@
     },
 }
 
+cc_library_static {
+    name: "libbinder_tls_test_utils",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    defaults: [
+        "binder_test_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libbinder_tls_static",
+    ],
+    srcs: [
+        "RpcTlsTestUtils.cpp",
+    ],
+    export_include_dirs: [
+        "include_tls_test_utils",
+    ],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
 cc_test {
     name: "binderRpcTest",
     host_supported: true,
@@ -161,6 +195,7 @@
     ],
     static_libs: [
         "libbinder_tls_static",
+        "libbinder_tls_test_utils",
         "binderRpcTestIface-cpp",
         "binderRpcTestIface-ndk",
     ],
@@ -168,9 +203,43 @@
     require_root: true,
 }
 
+cc_test {
+    name: "RpcTlsUtilsTest",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        android: {
+            test_suites: ["vts"],
+        },
+    },
+    defaults: [
+        "binder_test_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+    srcs: [
+        "RpcTlsUtilsTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libbinder_tls_test_utils",
+        "libbinder_tls_static",
+    ],
+    test_suites: ["general-tests", "device-tests"],
+}
+
 cc_benchmark {
     name: "binderRpcBenchmark",
-    defaults: ["binder_test_defaults"],
+    defaults: [
+        "binder_test_defaults",
+        "libbinder_tls_shared_deps",
+    ],
     host_supported: true,
     target: {
         darwin: {
@@ -187,6 +256,10 @@
         "liblog",
         "libutils",
     ],
+    static_libs: [
+        "libbinder_tls_test_utils",
+        "libbinder_tls_static",
+    ],
 }
 
 cc_test {
diff --git a/libs/binder/tests/BinderRpcTestClientInfo.aidl b/libs/binder/tests/BinderRpcTestClientInfo.aidl
new file mode 100644
index 0000000..b4baebc
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestClientInfo.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+import ParcelableCertificateData;
+
+parcelable BinderRpcTestClientInfo {
+    ParcelableCertificateData[] certs;
+}
diff --git a/libs/binder/tests/BinderRpcTestServerInfo.aidl b/libs/binder/tests/BinderRpcTestServerInfo.aidl
new file mode 100644
index 0000000..00dc0bc
--- /dev/null
+++ b/libs/binder/tests/BinderRpcTestServerInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+import ParcelableCertificateData;
+
+parcelable BinderRpcTestServerInfo {
+    long port;
+    ParcelableCertificateData cert;
+}
diff --git a/libs/binder/tests/ParcelableCertificateData.aidl b/libs/binder/tests/ParcelableCertificateData.aidl
new file mode 100644
index 0000000..38c382e
--- /dev/null
+++ b/libs/binder/tests/ParcelableCertificateData.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+
+parcelable ParcelableCertificateData {
+    byte[] data;
+}
diff --git a/libs/binder/tests/RpcTlsTestUtils.cpp b/libs/binder/tests/RpcTlsTestUtils.cpp
new file mode 100644
index 0000000..6119313
--- /dev/null
+++ b/libs/binder/tests/RpcTlsTestUtils.cpp
@@ -0,0 +1,118 @@
+/*
+ * 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 "RpcTlsTestUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsTestUtils.h>
+
+#include <binder/RpcTlsUtils.h>
+
+#include "../Utils.h" // for TEST_AND_RETURN
+
+namespace android {
+
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
+    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
+        ALOGE("Failed to generate key pair.");
+        return nullptr;
+    }
+    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+    // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
+    // the refcount of the ec_key, so it is okay to release it at the end of this function.
+    if (pkey == nullptr || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) {
+        ALOGE("Failed to assign key pair.");
+        return nullptr;
+    }
+    return pkey;
+}
+
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pkey, const uint32_t validSeconds) {
+    bssl::UniquePtr<X509> x509(X509_new());
+    bssl::UniquePtr<BIGNUM> serial(BN_new());
+    bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
+    TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
+    TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
+    TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
+    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
+    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notAfter(x509.get()), validSeconds));
+
+    X509_NAME* subject = X509_get_subject_name(x509.get());
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("Android"), -1, -1,
+                                               0));
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
+                                               -1, 0));
+    TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
+
+    TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), pkey));
+    TEST_AND_RETURN(nullptr, X509_sign(x509.get(), pkey, EVP_sha256()));
+    return x509;
+}
+
+status_t RpcAuthSelfSigned::configure(SSL_CTX* ctx) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    TEST_AND_RETURN(UNKNOWN_ERROR, pkey != nullptr);
+    auto cert = makeSelfSignedCert(pkey.get(), mValidSeconds);
+    TEST_AND_RETURN(UNKNOWN_ERROR, cert != nullptr);
+    TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_PrivateKey(ctx, pkey.get()));
+    TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_certificate(ctx, cert.get()));
+    return OK;
+}
+
+status_t RpcAuthPreSigned::configure(SSL_CTX* ctx) {
+    if (!SSL_CTX_use_PrivateKey(ctx, mPkey.get())) {
+        return INVALID_OPERATION;
+    }
+    if (!SSL_CTX_use_certificate(ctx, mCert.get())) {
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+status_t RpcCertificateVerifierSimple::verify(const SSL* ssl, uint8_t* outAlert) {
+    const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+    bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+    LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+                        "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (const auto& trustedCert : mTrustedPeerCertificates) {
+        if (0 == X509_cmp(trustedCert.get(), peerCert.get())) {
+            return OK;
+        }
+    }
+    *outAlert = SSL_AD_CERTIFICATE_UNKNOWN;
+    return PERMISSION_DENIED;
+}
+
+status_t RpcCertificateVerifierSimple::addTrustedPeerCertificate(RpcCertificateFormat format,
+                                                                 const std::vector<uint8_t>& cert) {
+    bssl::UniquePtr<X509> x509 = deserializeCertificate(cert, format);
+    if (x509 == nullptr) {
+        ALOGE("Certificate is not in the proper format %s", PrintToString(format).c_str());
+        return BAD_VALUE;
+    }
+    std::lock_guard<std::mutex> lock(mMutex);
+    mTrustedPeerCertificates.push_back(std::move(x509));
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/RpcTlsUtilsTest.cpp b/libs/binder/tests/RpcTlsUtilsTest.cpp
new file mode 100644
index 0000000..530606c
--- /dev/null
+++ b/libs/binder/tests/RpcTlsUtilsTest.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+std::string toDebugString(EVP_PKEY* pkey) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    int res = EVP_PKEY_print_public(bio.get(), pkey, 2, nullptr);
+    std::string buf = "\nEVP_PKEY_print_public -> " + std::to_string(res) + "\n";
+    if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+    res = EVP_PKEY_print_private(bio.get(), pkey, 2, nullptr);
+    buf = "\nEVP_PKEY_print_private -> " + std::to_string(res);
+    if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+    const uint8_t* data;
+    size_t len;
+    if (!BIO_mem_contents(bio.get(), &data, &len)) return {};
+    return std::string(reinterpret_cast<const char*>(data), len);
+}
+
+class RpcTlsUtilsKeyTest : public testing::TestWithParam<RpcKeyFormat> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        return PrintToString(info.param);
+    }
+};
+
+TEST_P(RpcTlsUtilsKeyTest, Test) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), GetParam());
+    auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, GetParam());
+    ASSERT_NE(nullptr, deserializedPkey);
+    EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), deserializedPkey.get()))
+            << "expected: " << toDebugString(pkey.get())
+            << "\nactual: " << toDebugString(deserializedPkey.get());
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyTest,
+                        testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                        RpcTlsUtilsKeyTest::PrintParamInfo);
+
+class RpcTlsUtilsCertTest : public testing::TestWithParam<RpcCertificateFormat> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        return PrintToString(info.param);
+    }
+};
+
+TEST_P(RpcTlsUtilsCertTest, Test) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    // Make certificate from the original key in memory
+    auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+    ASSERT_NE(nullptr, cert);
+    auto certData = serializeCertificate(cert.get(), GetParam());
+    auto deserializedCert = deserializeCertificate(certData, GetParam());
+    ASSERT_NE(nullptr, deserializedCert);
+    EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsCertTest,
+                        testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+                        RpcTlsUtilsCertTest::PrintParamInfo);
+
+class RpcTlsUtilsKeyAndCertTest
+      : public testing::TestWithParam<std::tuple<RpcKeyFormat, RpcCertificateFormat>> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [keyFormat, certificateFormat] = info.param;
+        return "key_" + PrintToString(keyFormat) + "_cert_" + PrintToString(certificateFormat);
+    }
+};
+
+TEST_P(RpcTlsUtilsKeyAndCertTest, TestCertFromDeserializedKey) {
+    auto [keyFormat, certificateFormat] = GetParam();
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+    auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+    ASSERT_NE(nullptr, deserializedPkey);
+
+    // Make certificate from deserialized key loaded from bytes
+    auto cert = makeSelfSignedCert(deserializedPkey.get(), kCertValidSeconds);
+    ASSERT_NE(nullptr, cert);
+    auto certData = serializeCertificate(cert.get(), certificateFormat);
+    auto deserializedCert = deserializeCertificate(certData, certificateFormat);
+    ASSERT_NE(nullptr, deserializedCert);
+    EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyAndCertTest,
+                        testing::Combine(testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                                         testing::Values(RpcCertificateFormat::PEM,
+                                                         RpcCertificateFormat::DER)),
+                        RpcTlsUtilsKeyAndCertTest::PrintParamInfo);
+
+} // namespace android
diff --git a/libs/binder/tests/binderHostDeviceTest.cpp b/libs/binder/tests/binderHostDeviceTest.cpp
index 3f72b8f..eec3b44 100644
--- a/libs/binder/tests/binderHostDeviceTest.cpp
+++ b/libs/binder/tests/binderHostDeviceTest.cpp
@@ -75,10 +75,10 @@
         auto debuggableResult = execute(Split("adb shell getprop ro.debuggable", " "), nullptr);
         ASSERT_THAT(debuggableResult, Ok());
         ASSERT_EQ(0, debuggableResult->exitCode) << *debuggableResult;
-        auto debuggableBool = ParseBool(Trim(debuggableResult->stdout));
-        ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdout);
+        auto debuggableBool = ParseBool(Trim(debuggableResult->stdoutStr));
+        ASSERT_NE(ParseBoolResult::kError, debuggableBool) << Trim(debuggableResult->stdoutStr);
         if (debuggableBool == ParseBoolResult::kFalse) {
-            GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdout);
+            GTEST_SKIP() << "ro.debuggable=" << Trim(debuggableResult->stdoutStr);
         }
 
         auto lsResult = execute(Split("adb shell which servicedispatcher", " "), nullptr);
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index eea7d8c..639876f 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -465,31 +465,30 @@
 
 TEST_F(BinderLibTest, Freeze) {
     Parcel data, reply, replypid;
-    std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
+    std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze");
 
-    //Pass test on devices where the freezer is not supported
+    // Pass test on devices where the cgroup v2 freezer is not supported
     if (freezer_file.fail()) {
         GTEST_SKIP();
         return;
     }
 
-    std::string freezer_enabled;
-    std::getline(freezer_file, freezer_enabled);
-
-    //Pass test on devices where the freezer is disabled
-    if (freezer_enabled != "1") {
-        GTEST_SKIP();
-        return;
-    }
-
     EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
     int32_t pid = replypid.readInt32();
     for (int i = 0; i < 10; i++) {
         EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
     }
-    EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
-    EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, 1, 0));
-    EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 1, 1000));
+
+    // Pass test on devices where BINDER_FREEZE ioctl is not supported
+    int ret = IPCThreadState::self()->freeze(pid, false, 0);
+    if (ret != 0) {
+        GTEST_SKIP();
+        return;
+    }
+
+    EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
+    EXPECT_EQ(-EAGAIN, IPCThreadState::self()->freeze(pid, true, 0));
+    EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, true, 1000));
     EXPECT_EQ(FAILED_TRANSACTION, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
 
     bool sync_received, async_received;
@@ -500,6 +499,14 @@
     EXPECT_EQ(sync_received, 1);
     EXPECT_EQ(async_received, 0);
 
+    uint32_t sync_received2, async_received2;
+
+    EXPECT_EQ(NO_ERROR, IPCThreadState::self()->getProcessFreezeInfo(pid, &sync_received2,
+                &async_received2));
+
+    EXPECT_EQ(sync_received2, 1);
+    EXPECT_EQ(async_received2, 0);
+
     EXPECT_EQ(NO_ERROR, IPCThreadState::self()->freeze(pid, 0, 0));
     EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply));
 }
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index e430c28..f8718aa 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -21,8 +21,15 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
+#include <openssl/ssl.h>
 
 #include <thread>
 
@@ -39,8 +46,15 @@
 using android::IServiceManager;
 using android::OK;
 using android::ProcessState;
+using android::RpcAuthPreSigned;
+using android::RpcCertificateFormat;
+using android::RpcCertificateVerifier;
+using android::RpcCertificateVerifierNoOp;
 using android::RpcServer;
 using android::RpcSession;
+using android::RpcTransportCtxFactory;
+using android::RpcTransportCtxFactoryRaw;
+using android::RpcTransportCtxFactoryTls;
 using android::sp;
 using android::status_t;
 using android::statusToString;
@@ -65,15 +79,32 @@
 enum Transport {
     KERNEL,
     RPC,
+    RPC_TLS,
 };
 
 static const std::initializer_list<int64_t> kTransportList = {
 #ifdef __BIONIC__
         Transport::KERNEL,
 #endif
-        Transport::RPC};
+        Transport::RPC,
+        Transport::RPC_TLS,
+};
+
+std::unique_ptr<RpcTransportCtxFactory> makeFactoryTls() {
+    auto pkey = android::makeKeyPairForSelfSignedCert();
+    CHECK_NE(pkey.get(), nullptr);
+    auto cert = android::makeSelfSignedCert(pkey.get(), android::kCertValidSeconds);
+    CHECK_NE(cert.get(), nullptr);
+
+    auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(OK);
+    auto auth = std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
+    return RpcTransportCtxFactoryTls::make(verifier, std::move(auth));
+}
 
 static sp<RpcSession> gSession = RpcSession::make();
+// Certificate validation happens during handshake and does not affect the result of benchmarks.
+// Skip certificate validation to simplify the setup process.
+static sp<RpcSession> gSessionTls = RpcSession::make(makeFactoryTls());
 #ifdef __BIONIC__
 static const String16 kKernelBinderInstance = String16(u"binderRpcBenchmark-control");
 static sp<IBinder> gKernelBinder;
@@ -88,6 +119,8 @@
 #endif
         case RPC:
             return gSession->getRootObject();
+        case RPC_TLS:
+            return gSessionTls->getRootObject();
         default:
             LOG(FATAL) << "Unknown transport value: " << transport;
             return nullptr;
@@ -169,26 +202,35 @@
 }
 BENCHMARK(BM_repeatBinder)->ArgsProduct({kTransportList});
 
+void forkRpcServer(const char* addr, const sp<RpcServer>& server) {
+    if (0 == fork()) {
+        prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+        server->setRootObject(sp<MyBinderRpcBenchmark>::make());
+        server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+        CHECK_EQ(OK, server->setupUnixDomainServer(addr));
+        server->join();
+        exit(1);
+    }
+}
+
+void setupClient(const sp<RpcSession>& session, const char* addr) {
+    status_t status;
+    for (size_t tries = 0; tries < 5; tries++) {
+        usleep(10000);
+        status = session->setupUnixDomainClient(addr);
+        if (status == OK) break;
+    }
+    CHECK_EQ(status, OK) << "Could not connect: " << addr << ": " << statusToString(status).c_str();
+}
+
 int main(int argc, char** argv) {
     ::benchmark::Initialize(&argc, argv);
     if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
 
-    std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
-    (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;
-
-    if (0 == fork()) {
-        prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
-        sp<RpcServer> server = RpcServer::make();
-        server->setRootObject(sp<MyBinderRpcBenchmark>::make());
-        server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-        CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
-        server->join();
-        exit(1);
-    }
+    std::cerr << "\t.../" << Transport::RPC_TLS << " is RPC with TLS" << std::endl;
 
 #ifdef __BIONIC__
     if (0 == fork()) {
@@ -207,14 +249,17 @@
     CHECK_NE(nullptr, gKernelBinder.get());
 #endif
 
-    status_t status;
-    for (size_t tries = 0; tries < 5; tries++) {
-        usleep(10000);
-        status = gSession->setupUnixDomainClient(addr.c_str());
-        if (status == OK) goto success;
-    }
-    LOG(FATAL) << "Could not connect: " << statusToString(status).c_str();
-success:
+    std::string tmp = getenv("TMPDIR") ?: "/tmp";
+
+    std::string addr = tmp + "/binderRpcBenchmark";
+    (void)unlink(addr.c_str());
+    forkRpcServer(addr.c_str(), RpcServer::make(RpcTransportCtxFactoryRaw::make()));
+    setupClient(gSession, addr.c_str());
+
+    std::string tlsAddr = tmp + "/binderRpcTlsBenchmark";
+    (void)unlink(tlsAddr.c_str());
+    forkRpcServer(tlsAddr.c_str(), RpcServer::make(makeFactoryTls()));
+    setupClient(gSessionTls, tlsAddr.c_str());
 
     ::benchmark::RunSpecifiedBenchmarks();
     return 0;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 7c405d3..a1058bc 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include <BinderRpcTestClientInfo.h>
+#include <BinderRpcTestServerInfo.h>
 #include <BnBinderRpcCallback.h>
 #include <BnBinderRpcSession.h>
 #include <BnBinderRpcTest.h>
@@ -29,6 +31,8 @@
 #include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTlsUtils.h>
 #include <binder/RpcTransport.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/RpcTransportTls.h>
@@ -40,14 +44,20 @@
 #include <thread>
 #include <type_traits>
 
+#include <poll.h>
 #include <sys/prctl.h>
 #include <unistd.h>
 
+#include "../FdTrigger.h"
 #include "../RpcSocketAddress.h" // for testing preconnected clients
-#include "../RpcState.h"   // for debugging
-#include "../vm_sockets.h" // for VMADDR_*
+#include "../RpcState.h"         // for debugging
+#include "../vm_sockets.h"       // for VMADDR_*
 
 using namespace std::chrono_literals;
+using namespace std::placeholders;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
 
 namespace android {
 
@@ -61,12 +71,21 @@
     return {RpcSecurity::RAW, RpcSecurity::TLS};
 }
 
-static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(RpcSecurity rpcSecurity) {
+static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
+        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+        std::unique_ptr<RpcAuth> auth = nullptr) {
     switch (rpcSecurity) {
         case RpcSecurity::RAW:
             return RpcTransportCtxFactoryRaw::make();
-        case RpcSecurity::TLS:
-            return RpcTransportCtxFactoryTls::make();
+        case RpcSecurity::TLS: {
+            if (verifier == nullptr) {
+                verifier = std::make_shared<RpcCertificateVerifierSimple>();
+            }
+            if (auth == nullptr) {
+                auth = std::make_unique<RpcAuthSelfSigned>();
+            }
+            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
+        }
         default:
             LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
     }
@@ -304,14 +323,17 @@
 class Process {
 public:
     Process(Process&&) = default;
-    Process(const std::function<void(android::base::borrowed_fd /* writeEnd */)>& f) {
-        android::base::unique_fd writeEnd;
-        CHECK(android::base::Pipe(&mReadEnd, &writeEnd)) << strerror(errno);
+    Process(const std::function<void(android::base::borrowed_fd /* writeEnd */,
+                                     android::base::borrowed_fd /* readEnd */)>& f) {
+        android::base::unique_fd childWriteEnd;
+        android::base::unique_fd childReadEnd;
+        CHECK(android::base::Pipe(&mReadEnd, &childWriteEnd)) << strerror(errno);
+        CHECK(android::base::Pipe(&childReadEnd, &mWriteEnd)) << strerror(errno);
         if (0 == (mPid = fork())) {
             // racey: assume parent doesn't crash before this is set
             prctl(PR_SET_PDEATHSIG, SIGHUP);
 
-            f(writeEnd);
+            f(childWriteEnd, childReadEnd);
 
             exit(0);
         }
@@ -322,16 +344,20 @@
         }
     }
     android::base::borrowed_fd readEnd() { return mReadEnd; }
+    android::base::borrowed_fd writeEnd() { return mWriteEnd; }
 
 private:
     pid_t mPid = 0;
     android::base::unique_fd mReadEnd;
+    android::base::unique_fd mWriteEnd;
 };
 
 static std::string allocateSocketAddress() {
     static size_t id = 0;
     std::string temp = getenv("TMPDIR") ?: "/tmp";
-    return temp + "/binderRpcTest_" + std::to_string(id++);
+    auto ret = temp + "/binderRpcTest_" + std::to_string(id++);
+    unlink(ret.c_str());
+    return ret;
 };
 
 static unsigned int allocateVsockPort() {
@@ -434,16 +460,17 @@
     }
 }
 
-static base::unique_fd connectToUds(const char* addrStr) {
-    UnixSocketAddress addr(addrStr);
+static base::unique_fd connectTo(const RpcSocketAddress& addr) {
     base::unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
     int savedErrno = errno;
-    CHECK(serverFd.ok()) << "Could not create socket " << addrStr << ": " << strerror(savedErrno);
+    CHECK(serverFd.ok()) << "Could not create socket " << addr.toString() << ": "
+                         << 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);
+        LOG(FATAL) << "Could not connect to socket " << addr.toString() << ": "
+                   << strerror(savedErrno);
     }
     return serverFd;
 }
@@ -461,6 +488,37 @@
         return PrintToString(type) + "_" + newFactory(security)->toCString();
     }
 
+    static inline void writeString(android::base::borrowed_fd fd, std::string_view str) {
+        uint64_t length = str.length();
+        CHECK(android::base::WriteFully(fd, &length, sizeof(length)));
+        CHECK(android::base::WriteFully(fd, str.data(), str.length()));
+    }
+
+    static inline std::string readString(android::base::borrowed_fd fd) {
+        uint64_t length;
+        CHECK(android::base::ReadFully(fd, &length, sizeof(length)));
+        std::string ret(length, '\0');
+        CHECK(android::base::ReadFully(fd, ret.data(), length));
+        return ret;
+    }
+
+    static inline void writeToFd(android::base::borrowed_fd fd, const Parcelable& parcelable) {
+        Parcel parcel;
+        CHECK_EQ(OK, parcelable.writeToParcel(&parcel));
+        writeString(fd,
+                    std::string(reinterpret_cast<const char*>(parcel.data()), parcel.dataSize()));
+    }
+
+    template <typename T>
+    static inline T readFromFd(android::base::borrowed_fd fd) {
+        std::string data = readString(fd);
+        Parcel parcel;
+        CHECK_EQ(OK, parcel.setData(reinterpret_cast<const uint8_t*>(data.data()), data.size()));
+        T object;
+        CHECK_EQ(OK, object.readFromParcel(&parcel));
+        return object;
+    }
+
     // This creates a new process serving an interface on a certain number of
     // threads.
     ProcessSession createRpcTestSocketServerProcess(
@@ -472,11 +530,12 @@
 
         unsigned int vsockPort = allocateVsockPort();
         std::string addr = allocateSocketAddress();
-        unlink(addr.c_str());
 
         auto ret = ProcessSession{
-                .host = Process([&](android::base::borrowed_fd writeEnd) {
-                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity));
+                .host = Process([&](android::base::borrowed_fd writeEnd,
+                                    android::base::borrowed_fd readEnd) {
+                    auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+                    sp<RpcServer> server = RpcServer::make(newFactory(rpcSecurity, certVerifier));
 
                     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
                     server->setMaxThreads(options.numThreads);
@@ -501,7 +560,20 @@
                             LOG_ALWAYS_FATAL("Unknown socket type");
                     }
 
-                    CHECK(android::base::WriteFully(writeEnd, &outPort, sizeof(outPort)));
+                    BinderRpcTestServerInfo serverInfo;
+                    serverInfo.port = static_cast<int64_t>(outPort);
+                    serverInfo.cert.data = server->getCertificate(RpcCertificateFormat::PEM);
+                    writeToFd(writeEnd, serverInfo);
+                    auto clientInfo = readFromFd<BinderRpcTestClientInfo>(readEnd);
+
+                    if (rpcSecurity == RpcSecurity::TLS) {
+                        for (const auto& clientCert : clientInfo.certs) {
+                            CHECK_EQ(OK,
+                                     certVerifier
+                                             ->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+                                                                         clientCert.data));
+                        }
+                    }
 
                     configure(server);
 
@@ -512,44 +584,56 @@
                 }),
         };
 
-        // always read socket, so that we have waited for the server to start
-        unsigned int outPort = 0;
-        CHECK(android::base::ReadFully(ret.host.readEnd(), &outPort, sizeof(outPort)));
+        std::vector<sp<RpcSession>> sessions;
+        auto certVerifier = std::make_shared<RpcCertificateVerifierSimple>();
+        for (size_t i = 0; i < options.numSessions; i++) {
+            sessions.emplace_back(RpcSession::make(newFactory(rpcSecurity, certVerifier)));
+        }
+
+        auto serverInfo = readFromFd<BinderRpcTestServerInfo>(ret.host.readEnd());
+        BinderRpcTestClientInfo clientInfo;
+        for (const auto& session : sessions) {
+            auto& parcelableCert = clientInfo.certs.emplace_back();
+            parcelableCert.data = session->getCertificate(RpcCertificateFormat::PEM);
+        }
+        writeToFd(ret.host.writeEnd(), clientInfo);
+
+        CHECK_LE(serverInfo.port, std::numeric_limits<unsigned int>::max());
         if (socketType == SocketType::INET) {
-            CHECK_NE(0, outPort);
+            CHECK_NE(0, serverInfo.port);
+        }
+
+        if (rpcSecurity == RpcSecurity::TLS) {
+            const auto& serverCert = serverInfo.cert.data;
+            CHECK_EQ(OK,
+                     certVerifier->addTrustedPeerCertificate(RpcCertificateFormat::PEM,
+                                                             serverCert));
         }
 
         status_t status;
 
-        for (size_t i = 0; i < options.numSessions; i++) {
-            sp<RpcSession> session =
-                    RpcSession::make(newFactory(rpcSecurity), std::nullopt, std::nullopt);
+        for (const auto& session : sessions) {
             session->setMaxThreads(options.numIncomingConnections);
 
             switch (socketType) {
                 case SocketType::PRECONNECTED:
                     status = session->setupPreconnectedClient({}, [=]() {
-                        return connectToUds(addr.c_str());
+                        return connectTo(UnixSocketAddress(addr.c_str()));
                     });
-                    if (status == OK) goto success;
                     break;
                 case SocketType::UNIX:
                     status = session->setupUnixDomainClient(addr.c_str());
-                    if (status == OK) goto success;
                     break;
                 case SocketType::VSOCK:
                     status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
-                    if (status == OK) goto success;
                     break;
                 case SocketType::INET:
-                    status = session->setupInetClient("127.0.0.1", outPort);
-                    if (status == OK) goto success;
+                    status = session->setupInetClient("127.0.0.1", serverInfo.port);
                     break;
                 default:
                     LOG_ALWAYS_FATAL("Unknown socket type");
             }
-            LOG_ALWAYS_FATAL("Could not connect %s", statusToString(status).c_str());
-        success:
+            CHECK_EQ(status, OK) << "Could not connect: " << statusToString(status);
             ret.sessions.push_back({session, session->getRootObject()});
         }
         return ret;
@@ -957,10 +1041,18 @@
     for (auto& t : threads) t.join();
 }
 
+static void saturateThreadPool(size_t threadCount, const sp<IBinderRpcTest>& iface) {
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < threadCount; i++) {
+        threads.push_back(std::thread([&] { EXPECT_OK(iface->sleepMs(500)); }));
+    }
+    for (auto& t : threads) t.join();
+}
+
 TEST_P(BinderRpc, OnewayStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
-    constexpr size_t kNumCalls = 500;
+    constexpr size_t kNumCalls = 1000;
 
     auto proc = createRpcTestSocketServerProcess({.numThreads = kNumServerThreads});
 
@@ -970,13 +1062,12 @@
             for (size_t j = 0; j < kNumCalls; j++) {
                 EXPECT_OK(proc.rootIface->sendString("a"));
             }
-
-            // check threads are not stuck
-            EXPECT_OK(proc.rootIface->sleepMs(250));
         }));
     }
 
     for (auto& t : threads) t.join();
+
+    saturateThreadPool(kNumServerThreads, proc.rootIface);
 }
 
 TEST_P(BinderRpc, OnewayCallDoesNotWait) {
@@ -1003,26 +1094,23 @@
 
     EXPECT_OK(proc.rootIface->lock());
 
-    for (size_t i = 0; i < kNumSleeps; i++) {
-        // these should be processed serially
+    size_t epochMsBefore = epochMillis();
+
+    // all these *Async commands should be queued on the server sequentially,
+    // even though there are multiple threads.
+    for (size_t i = 0; i + 1 < kNumSleeps; i++) {
         proc.rootIface->sleepMsAsync(kSleepMs);
     }
-    // should also be processesed serially
     EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
 
-    size_t epochMsBefore = epochMillis();
+    // this can only return once the final async call has unlocked
     EXPECT_OK(proc.rootIface->lockUnlock());
+
     size_t epochMsAfter = epochMillis();
 
     EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 
-    // pending oneway transactions hold ref, make sure we read data on all
-    // sockets
-    std::vector<std::thread> threads;
-    for (size_t i = 0; i < 1 + kNumExtraServerThreads; i++) {
-        threads.push_back(std::thread([&] { EXPECT_OK(proc.rootIface->sleepMs(250)); }));
-    }
-    for (auto& t : threads) t.join();
+    saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
 }
 
 TEST_P(BinderRpc, OnewayCallExhaustion) {
@@ -1208,16 +1296,17 @@
     }
     server->start();
 
-    sp<RpcSession> session =
-            RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+    sp<RpcSession> session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
     status_t status = session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort);
     while (!server->shutdown()) usleep(10000);
     ALOGE("Detected vsock loopback supported: %s", statusToString(status).c_str());
     return status == OK;
 }
 
-static std::vector<SocketType> testSocketTypes() {
-    std::vector<SocketType> ret = {SocketType::PRECONNECTED, SocketType::UNIX, SocketType::INET};
+static std::vector<SocketType> testSocketTypes(bool hasPreconnected = true) {
+    std::vector<SocketType> ret = {SocketType::UNIX, SocketType::INET};
+
+    if (hasPreconnected) ret.push_back(SocketType::PRECONNECTED);
 
     static bool hasVsockLoopback = testSupportVsockLoopback();
 
@@ -1286,7 +1375,6 @@
 
 TEST_P(BinderRpcSimple, Shutdown) {
     auto addr = allocateSocketAddress();
-    unlink(addr.c_str());
     auto server = RpcServer::make(newFactory(GetParam()));
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     ASSERT_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
@@ -1351,6 +1439,479 @@
 INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
                         BinderRpcSimple::PrintTestParam);
 
+class RpcTransportTestUtils {
+public:
+    using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
+    using ConnectToServer = std::function<base::unique_fd()>;
+
+    // A server that handles client socket connections.
+    class Server {
+    public:
+        explicit Server() {}
+        Server(Server&&) = default;
+        ~Server() { shutdownAndWait(); }
+        [[nodiscard]] AssertionResult setUp(
+                const Param& param,
+                std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
+            auto [socketType, rpcSecurity, certificateFormat] = param;
+            auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
+            rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+            switch (socketType) {
+                case SocketType::PRECONNECTED: {
+                    return AssertionFailure() << "Not supported by this test";
+                } break;
+                case SocketType::UNIX: {
+                    auto addr = allocateSocketAddress();
+                    auto status = rpcServer->setupUnixDomainServer(addr.c_str());
+                    if (status != OK) {
+                        return AssertionFailure()
+                                << "setupUnixDomainServer: " << statusToString(status);
+                    }
+                    mConnectToServer = [addr] {
+                        return connectTo(UnixSocketAddress(addr.c_str()));
+                    };
+                } break;
+                case SocketType::VSOCK: {
+                    auto port = allocateVsockPort();
+                    auto status = rpcServer->setupVsockServer(port);
+                    if (status != OK) {
+                        return AssertionFailure() << "setupVsockServer: " << statusToString(status);
+                    }
+                    mConnectToServer = [port] {
+                        return connectTo(VsockSocketAddress(VMADDR_CID_LOCAL, port));
+                    };
+                } break;
+                case SocketType::INET: {
+                    unsigned int port;
+                    auto status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port);
+                    if (status != OK) {
+                        return AssertionFailure() << "setupInetServer: " << statusToString(status);
+                    }
+                    mConnectToServer = [port] {
+                        const char* addr = kLocalInetAddress;
+                        auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
+                        if (aiStart == nullptr) return base::unique_fd{};
+                        for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+                            auto fd = connectTo(
+                                    InetSocketAddress(ai->ai_addr, ai->ai_addrlen, addr, port));
+                            if (fd.ok()) return fd;
+                        }
+                        ALOGE("None of the socket address resolved for %s:%u can be connected",
+                              addr, port);
+                        return base::unique_fd{};
+                    };
+                }
+            }
+            mFd = rpcServer->releaseServer();
+            if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
+            mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
+            if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
+            mSetup = true;
+            return AssertionSuccess();
+        }
+        RpcTransportCtx* getCtx() const { return mCtx.get(); }
+        std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+            return mCertVerifier;
+        }
+        ConnectToServer getConnectToServerFn() { return mConnectToServer; }
+        void start() {
+            LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+            mThread = std::make_unique<std::thread>(&Server::run, this);
+        }
+        void run() {
+            LOG_ALWAYS_FATAL_IF(!mSetup, "Call Server::setup first!");
+
+            std::vector<std::thread> threads;
+            while (OK == mFdTrigger->triggerablePoll(mFd, POLLIN)) {
+                base::unique_fd acceptedFd(
+                        TEMP_FAILURE_RETRY(accept4(mFd.get(), nullptr, nullptr /*length*/,
+                                                   SOCK_CLOEXEC | SOCK_NONBLOCK)));
+                threads.emplace_back(&Server::handleOne, this, std::move(acceptedFd));
+            }
+
+            for (auto& thread : threads) thread.join();
+        }
+        void handleOne(android::base::unique_fd acceptedFd) {
+            ASSERT_TRUE(acceptedFd.ok());
+            auto serverTransport = mCtx->newTransport(std::move(acceptedFd), mFdTrigger.get());
+            if (serverTransport == nullptr) return; // handshake failed
+            ASSERT_TRUE(mPostConnect(serverTransport.get(), mFdTrigger.get()));
+        }
+        void shutdownAndWait() {
+            shutdown();
+            join();
+        }
+        void shutdown() { mFdTrigger->trigger(); }
+
+        void setPostConnect(
+                std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> fn) {
+            mPostConnect = std::move(fn);
+        }
+
+    private:
+        std::unique_ptr<std::thread> mThread;
+        ConnectToServer mConnectToServer;
+        std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+        base::unique_fd mFd;
+        std::unique_ptr<RpcTransportCtx> mCtx;
+        std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+                std::make_shared<RpcCertificateVerifierSimple>();
+        bool mSetup = false;
+        // The function invoked after connection and handshake. By default, it is
+        // |defaultPostConnect| that sends |kMessage| to the client.
+        std::function<AssertionResult(RpcTransport*, FdTrigger* fdTrigger)> mPostConnect =
+                Server::defaultPostConnect;
+
+        void join() {
+            if (mThread != nullptr) {
+                mThread->join();
+                mThread = nullptr;
+            }
+        }
+
+        static AssertionResult defaultPostConnect(RpcTransport* serverTransport,
+                                                  FdTrigger* fdTrigger) {
+            std::string message(kMessage);
+            auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
+                                                                   message.size(), {});
+            if (status != OK) return AssertionFailure() << statusToString(status);
+            return AssertionSuccess();
+        }
+    };
+
+    class Client {
+    public:
+        explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
+        Client(Client&&) = default;
+        [[nodiscard]] AssertionResult setUp(const Param& param) {
+            auto [socketType, rpcSecurity, certificateFormat] = param;
+            mFdTrigger = FdTrigger::make();
+            mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
+            if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
+            return AssertionSuccess();
+        }
+        RpcTransportCtx* getCtx() const { return mCtx.get(); }
+        std::shared_ptr<RpcCertificateVerifierSimple> getCertVerifier() const {
+            return mCertVerifier;
+        }
+        // connect() and do handshake
+        bool setUpTransport() {
+            mFd = mConnectToServer();
+            if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+            mClientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
+            return mClientTransport != nullptr;
+        }
+        AssertionResult readMessage(const std::string& expectedMessage = kMessage) {
+            LOG_ALWAYS_FATAL_IF(mClientTransport == nullptr, "setUpTransport not called or failed");
+            std::string readMessage(expectedMessage.size(), '\0');
+            status_t readStatus =
+                    mClientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
+                                                             readMessage.size(), {});
+            if (readStatus != OK) {
+                return AssertionFailure() << statusToString(readStatus);
+            }
+            if (readMessage != expectedMessage) {
+                return AssertionFailure()
+                        << "Expected " << expectedMessage << ", actual " << readMessage;
+            }
+            return AssertionSuccess();
+        }
+        void run(bool handshakeOk = true, bool readOk = true) {
+            if (!setUpTransport()) {
+                ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
+                return;
+            }
+            ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
+            ASSERT_EQ(readOk, readMessage());
+        }
+
+    private:
+        ConnectToServer mConnectToServer;
+        base::unique_fd mFd;
+        std::unique_ptr<FdTrigger> mFdTrigger = FdTrigger::make();
+        std::unique_ptr<RpcTransportCtx> mCtx;
+        std::shared_ptr<RpcCertificateVerifierSimple> mCertVerifier =
+                std::make_shared<RpcCertificateVerifierSimple>();
+        std::unique_ptr<RpcTransport> mClientTransport;
+    };
+
+    // Make A trust B.
+    template <typename A, typename B>
+    static status_t trust(RpcSecurity rpcSecurity,
+                          std::optional<RpcCertificateFormat> certificateFormat, const A& a,
+                          const B& b) {
+        if (rpcSecurity != RpcSecurity::TLS) return OK;
+        LOG_ALWAYS_FATAL_IF(!certificateFormat.has_value());
+        auto bCert = b->getCtx()->getCertificate(*certificateFormat);
+        return a->getCertVerifier()->addTrustedPeerCertificate(*certificateFormat, bCert);
+    }
+
+    static constexpr const char* kMessage = "hello";
+};
+
+class RpcTransportTest : public testing::TestWithParam<RpcTransportTestUtils::Param> {
+public:
+    using Server = RpcTransportTestUtils::Server;
+    using Client = RpcTransportTestUtils::Client;
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [socketType, rpcSecurity, certificateFormat] = info.param;
+        auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
+        if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+        return ret;
+    }
+    static std::vector<ParamType> getRpcTranportTestParams() {
+        std::vector<ParamType> ret;
+        for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+            for (auto rpcSecurity : RpcSecurityValues()) {
+                switch (rpcSecurity) {
+                    case RpcSecurity::RAW: {
+                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
+                    } break;
+                    case RpcSecurity::TLS: {
+                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
+                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
+                    } break;
+                }
+            }
+        }
+        return ret;
+    }
+    template <typename A, typename B>
+    status_t trust(const A& a, const B& b) {
+        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
+    }
+};
+
+TEST_P(RpcTransportTest, GoodCertificate) {
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
+
+    Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(GetParam()));
+
+    ASSERT_EQ(OK, trust(&client, server));
+    ASSERT_EQ(OK, trust(server, &client));
+
+    server->start();
+    client.run();
+}
+
+TEST_P(RpcTransportTest, MultipleClients) {
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
+
+    std::vector<Client> clients;
+    for (int i = 0; i < 2; i++) {
+        auto& client = clients.emplace_back(server->getConnectToServerFn());
+        ASSERT_TRUE(client.setUp(GetParam()));
+        ASSERT_EQ(OK, trust(&client, server));
+        ASSERT_EQ(OK, trust(server, &client));
+    }
+
+    server->start();
+    for (auto& client : clients) client.run();
+}
+
+TEST_P(RpcTransportTest, UntrustedServer) {
+    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+
+    auto untrustedServer = std::make_unique<Server>();
+    ASSERT_TRUE(untrustedServer->setUp(GetParam()));
+
+    Client client(untrustedServer->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(GetParam()));
+
+    ASSERT_EQ(OK, trust(untrustedServer, &client));
+
+    untrustedServer->start();
+
+    // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+    // the client can't verify the server's identity.
+    bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+    client.run(handshakeOk);
+}
+TEST_P(RpcTransportTest, MaliciousServer) {
+    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto validServer = std::make_unique<Server>();
+    ASSERT_TRUE(validServer->setUp(GetParam()));
+
+    auto maliciousServer = std::make_unique<Server>();
+    ASSERT_TRUE(maliciousServer->setUp(GetParam()));
+
+    Client client(maliciousServer->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(GetParam()));
+
+    ASSERT_EQ(OK, trust(&client, validServer));
+    ASSERT_EQ(OK, trust(validServer, &client));
+    ASSERT_EQ(OK, trust(maliciousServer, &client));
+
+    maliciousServer->start();
+
+    // For TLS, this should reject the certificate. For RAW sockets, it should pass because
+    // the client can't verify the server's identity.
+    bool handshakeOk = rpcSecurity != RpcSecurity::TLS;
+    client.run(handshakeOk);
+}
+
+TEST_P(RpcTransportTest, UntrustedClient) {
+    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
+
+    Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(GetParam()));
+
+    ASSERT_EQ(OK, trust(&client, server));
+
+    server->start();
+
+    // For TLS, Client should be able to verify server's identity, so client should see
+    // do_handshake() successfully executed. However, server shouldn't be able to verify client's
+    // identity and should drop the connection, so client shouldn't be able to read anything.
+    bool readOk = rpcSecurity != RpcSecurity::TLS;
+    client.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, MaliciousClient) {
+    auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
+
+    Client validClient(server->getConnectToServerFn());
+    ASSERT_TRUE(validClient.setUp(GetParam()));
+    Client maliciousClient(server->getConnectToServerFn());
+    ASSERT_TRUE(maliciousClient.setUp(GetParam()));
+
+    ASSERT_EQ(OK, trust(&validClient, server));
+    ASSERT_EQ(OK, trust(&maliciousClient, server));
+
+    server->start();
+
+    // See UntrustedClient.
+    bool readOk = rpcSecurity != RpcSecurity::TLS;
+    maliciousClient.run(true, readOk);
+}
+
+TEST_P(RpcTransportTest, Trigger) {
+    std::string msg2 = ", world!";
+    std::mutex writeMutex;
+    std::condition_variable writeCv;
+    bool shouldContinueWriting = false;
+    auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
+        std::string message(RpcTransportTestUtils::kMessage);
+        auto status = serverTransport->interruptableWriteFully(fdTrigger, message.data(),
+                                                               message.size(), {});
+        if (status != OK) return AssertionFailure() << statusToString(status);
+
+        {
+            std::unique_lock<std::mutex> lock(writeMutex);
+            if (!writeCv.wait_for(lock, 3s, [&] { return shouldContinueWriting; })) {
+                return AssertionFailure() << "write barrier not cleared in time!";
+            }
+        }
+
+        status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size(), {});
+        if (status != DEAD_OBJECT)
+            return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
+                                         "should return DEAD_OBJECT, but it is "
+                                      << statusToString(status);
+        return AssertionSuccess();
+    };
+
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
+
+    // Set up client
+    Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(GetParam()));
+
+    // Exchange keys
+    ASSERT_EQ(OK, trust(&client, server));
+    ASSERT_EQ(OK, trust(server, &client));
+
+    server->setPostConnect(serverPostConnect);
+
+    server->start();
+    // connect() to server and do handshake
+    ASSERT_TRUE(client.setUpTransport());
+    // read the first message. This ensures that server has finished handshake and start handling
+    // client fd. Server thread should pause at writeCv.wait_for().
+    ASSERT_TRUE(client.readMessage(RpcTransportTestUtils::kMessage));
+    // Trigger server shutdown after server starts handling client FD. This ensures that the second
+    // write is on an FdTrigger that has been shut down.
+    server->shutdown();
+    // Continues server thread to write the second message.
+    {
+        std::lock_guard<std::mutex> lock(writeMutex);
+        shouldContinueWriting = true;
+    }
+    writeCv.notify_all();
+    // After this line, server thread unblocks and attempts to write the second message, but
+    // shutdown is triggered, so write should failed with DEAD_OBJECT. See |serverPostConnect|.
+    // On the client side, second read fails with DEAD_OBJECT
+    ASSERT_FALSE(client.readMessage(msg2));
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
+                        ::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
+                        RpcTransportTest::PrintParamInfo);
+
+class RpcTransportTlsKeyTest
+      : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+public:
+    template <typename A, typename B>
+    status_t trust(const A& a, const B& b) {
+        auto [socketType, certificateFormat, keyFormat] = GetParam();
+        return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
+    }
+    static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [socketType, certificateFormat, keyFormat] = info.param;
+        auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+                "_key_" + PrintToString(keyFormat);
+        return ret;
+    };
+};
+
+TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
+    auto [socketType, certificateFormat, keyFormat] = GetParam();
+
+    std::vector<uint8_t> pkeyData, certData;
+    {
+        auto pkey = makeKeyPairForSelfSignedCert();
+        ASSERT_NE(nullptr, pkey);
+        auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+        ASSERT_NE(nullptr, cert);
+        pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+        certData = serializeCertificate(cert.get(), certificateFormat);
+    }
+
+    auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+    auto desCert = deserializeCertificate(certData, certificateFormat);
+    auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
+    auto utilsParam =
+            std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+
+    auto server = std::make_unique<RpcTransportTestUtils::Server>();
+    ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
+
+    RpcTransportTestUtils::Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(utilsParam));
+
+    ASSERT_EQ(OK, trust(&client, server));
+    ASSERT_EQ(OK, trust(server, &client));
+
+    server->start();
+    client.run();
+}
+
+INSTANTIATE_TEST_CASE_P(
+        BinderRpc, RpcTransportTlsKeyTest,
+        testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
+                         testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+        RpcTransportTlsKeyTest::PrintParamInfo);
+
 } // namespace android
 
 int main(int argc, char** argv) {
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
index 6c3b3d9..2398e1e 100644
--- a/libs/binder/tests/binderStabilityTest.cpp
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -197,6 +197,14 @@
     }
 }
 
+TEST(BinderStability, ConnectionInfoRequiresManifestEntries) {
+    sp<IServiceManager> sm = android::defaultServiceManager();
+    sp<IBinder> systemBinder = BadStableBinder::system();
+    EXPECT_EQ(OK, sm->addService(String16("no.connection.foo"), systemBinder));
+    std::optional<android::IServiceManager::ConnectionInfo> connectionInfo;
+    connectionInfo = sm->getConnectionInfo(String16("no.connection.foo"));
+    EXPECT_EQ(connectionInfo, std::nullopt);
+}
 TEST(BinderStability, CantCallVendorBinderInSystemContext) {
     sp<IBinder> serverBinder = android::defaultServiceManager()->getService(kSystemStabilityServer);
     auto server = interface_cast<IBinderStabilityTest>(serverBinder);
diff --git a/libs/binder/tests/binderUtilsHostTest.cpp b/libs/binder/tests/binderUtilsHostTest.cpp
index fb24836..4330e3e 100644
--- a/libs/binder/tests/binderUtilsHostTest.cpp
+++ b/libs/binder/tests/binderUtilsHostTest.cpp
@@ -34,7 +34,7 @@
     auto result = execute({"echo", "foo"}, nullptr);
     ASSERT_THAT(result, Ok());
     EXPECT_THAT(result->exitCode, Optional(EX_OK));
-    EXPECT_EQ(result->stdout, "foo\n");
+    EXPECT_EQ(result->stdoutStr, "foo\n");
 }
 
 TEST(UtilsHost, ExecuteLongRunning) {
@@ -44,7 +44,7 @@
         std::vector<std::string> args{"sh", "-c",
                                       "sleep 0.5 && echo -n f && sleep 0.5 && echo oo && sleep 1"};
         auto result = execute(std::move(args), [](const CommandResult& commandResult) {
-            return android::base::EndsWith(commandResult.stdout, "\n");
+            return android::base::EndsWith(commandResult.stdoutStr, "\n");
         });
         auto elapsed = std::chrono::system_clock::now() - now;
         auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
@@ -53,7 +53,7 @@
 
         ASSERT_THAT(result, Ok());
         EXPECT_EQ(std::nullopt, result->exitCode);
-        EXPECT_EQ(result->stdout, "foo\n");
+        EXPECT_EQ(result->stdoutStr, "foo\n");
     }
 
     // ~CommandResult() called, child process is killed.
@@ -70,7 +70,7 @@
         std::vector<std::string> args{"sh", "-c",
                                       "sleep 2 && echo -n f && sleep 2 && echo oo && sleep 2"};
         auto result = execute(std::move(args), [](const CommandResult& commandResult) {
-            return android::base::EndsWith(commandResult.stdout, "\n");
+            return android::base::EndsWith(commandResult.stdoutStr, "\n");
         });
         auto elapsed = std::chrono::system_clock::now() - now;
         auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(elapsed).count();
@@ -79,7 +79,7 @@
 
         ASSERT_THAT(result, Ok());
         EXPECT_EQ(std::nullopt, result->exitCode);
-        EXPECT_EQ(result->stdout, "foo\n");
+        EXPECT_EQ(result->stdoutStr, "foo\n");
     }
 
     // ~CommandResult() called, child process is killed.
diff --git a/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
new file mode 100644
index 0000000..094addd
--- /dev/null
+++ b/libs/binder/tests/include_tls_test_utils/binder/RpcTlsTestUtils.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <mutex>
+
+#include <binder/RpcAuth.h>
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
+#include <binder/RpcTransport.h>
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert();
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds);
+
+// An implementation of RpcAuth that generates a key pair and a self-signed
+// certificate every time configure() is called.
+class RpcAuthSelfSigned : public RpcAuth {
+public:
+    RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {}
+    status_t configure(SSL_CTX* ctx) override;
+
+private:
+    const uint32_t mValidSeconds;
+};
+
+class RpcAuthPreSigned : public RpcAuth {
+public:
+    RpcAuthPreSigned(bssl::UniquePtr<EVP_PKEY> pkey, bssl::UniquePtr<X509> cert)
+          : mPkey(std::move(pkey)), mCert(std::move(cert)) {}
+    status_t configure(SSL_CTX* ctx) override;
+
+private:
+    bssl::UniquePtr<EVP_PKEY> mPkey;
+    bssl::UniquePtr<X509> mCert;
+};
+
+// A simple certificate verifier for testing.
+// Keep a list of leaf certificates as trusted. No certificate chain support.
+//
+// All APIs are thread-safe. However, if verify() and addTrustedPeerCertificate() are called
+// simultaneously in different threads, it is not deterministic whether verify() will use the
+// certificate being added.
+class RpcCertificateVerifierSimple : public RpcCertificateVerifier {
+public:
+    status_t verify(const SSL*, uint8_t*) override;
+
+    // Add a trusted peer certificate. Peers presenting this certificate are accepted.
+    //
+    // Caller must ensure that RpcTransportCtx::newTransport() are called after all trusted peer
+    // certificates are added. Otherwise, RpcTransport-s created before may not trust peer
+    // certificates added later.
+    [[nodiscard]] status_t addTrustedPeerCertificate(RpcCertificateFormat format,
+                                                     const std::vector<uint8_t>& cert);
+
+private:
+    std::mutex mMutex; // for below
+    std::vector<bssl::UniquePtr<X509>> mTrustedPeerCertificates;
+};
+
+// A RpcCertificateVerifier that does not verify anything.
+class RpcCertificateVerifierNoOp : public RpcCertificateVerifier {
+public:
+    RpcCertificateVerifierNoOp(status_t status) : mStatus(status) {}
+    status_t verify(const SSL*, uint8_t*) override { return mStatus; }
+
+private:
+    status_t mStatus;
+};
+
+} // namespace android
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index 7fd9f6b..8bf04cc 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -36,8 +36,7 @@
 
 void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider) {
     if (provider.ConsumeBool()) {
-        auto session =
-                RpcSession::make(RpcTransportCtxFactoryRaw::make(), std::nullopt, std::nullopt);
+        auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make());
         CHECK_EQ(OK, session->addNullDebuggingClient());
         p->markForRpc(session);
         fillRandomParcelData(p, std::move(provider));
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index 9323bd5..c0f0a12 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,16 +14,24 @@
     fuzz_config: {
         cc: ["smoreland@google.com"],
     },
+    dictionary: "binder_rpc_fuzzer.dict",
 
     srcs: [
         "main.cpp",
     ],
+    // Not using libbinder_tls_shared_deps to use deterministic boringssl libraries.
     static_libs: [
         "libbase",
         "libcutils",
         "liblog",
+        "libbinder_tls_static",
+        "libbinder_tls_test_utils",
+        "libssl_fuzz_unsafe",
+        "libcrypto_fuzz_unsafe",
     ],
-
+    cflags: [
+        "-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE" // for RAND_reset_for_fuzzing
+    ],
     target: {
         android: {
             shared_libs: [
@@ -38,4 +46,8 @@
             ],
         },
     },
+    data: [
+        "server.crt",
+        "server.key",
+    ],
 }
diff --git a/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
new file mode 100644
index 0000000..b110a02
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
@@ -0,0 +1,2 @@
+# connection okay header
+"cci"
diff --git a/libs/binder/tests/rpc_fuzzer/create_certs.sh b/libs/binder/tests/rpc_fuzzer/create_certs.sh
new file mode 100755
index 0000000..4ae4cb1
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/create_certs.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# As explained in
+#  https://gist.github.com/darrenjs/4645f115d10aa4b5cebf57483ec82eca
+
+openssl genrsa -des3 -passout pass:xxxx -out server.pass.key 2048
+openssl rsa -passin pass:xxxx -in server.pass.key -out server.key
+rm -f server.pass.key
+
+openssl req \
+    -subj "/" \
+    -new -key server.key -out server.csr
+
+openssl x509 -req -sha256 -days 99999 -in server.csr -signkey server.key -out server.crt
+rm -f server.csr
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 230f5c7..518849a 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -13,13 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/unique_fd.h>
 #include <binder/Binder.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
-#include <binder/RpcSession.h>
+#include <binder/RpcTlsTestUtils.h>
+#include <binder/RpcTransport.h>
+#include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
 #include <fuzzer/FuzzedDataProvider.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
 
 #include <sys/resource.h>
 #include <sys/un.h>
@@ -51,13 +58,66 @@
     }
 };
 
+int passwordCallback(char* buf, int size, int /*rwflag*/, void* /*u*/) {
+    constexpr const char pass[] = "xxxx"; // See create_certs.sh
+    if (size <= 0) return 0;
+    int numCopy = std::min<int>(size, sizeof(pass));
+    (void)memcpy(buf, pass, numCopy);
+    return numCopy;
+}
+
+struct ServerAuth {
+    bssl::UniquePtr<EVP_PKEY> pkey;
+    bssl::UniquePtr<X509> cert;
+};
+
+// Use pre-configured keys because runtime generated keys / certificates are not
+// deterministic, and the algorithm is time consuming.
+ServerAuth readServerKeyAndCert() {
+    ServerAuth ret;
+
+    auto keyPath = android::base::GetExecutableDirectory() + "/data/server.key";
+    bssl::UniquePtr<BIO> keyBio(BIO_new_file(keyPath.c_str(), "r"));
+    ret.pkey.reset(PEM_read_bio_PrivateKey(keyBio.get(), nullptr, passwordCallback, nullptr));
+    CHECK_NE(ret.pkey.get(), nullptr);
+
+    auto certPath = android::base::GetExecutableDirectory() + "/data/server.crt";
+    bssl::UniquePtr<BIO> certBio(BIO_new_file(certPath.c_str(), "r"));
+    ret.cert.reset(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+    CHECK_NE(ret.cert.get(), nullptr);
+
+    return ret;
+}
+
+std::unique_ptr<RpcAuth> createServerRpcAuth() {
+    static auto sAuth = readServerKeyAndCert();
+
+    CHECK(EVP_PKEY_up_ref(sAuth.pkey.get()));
+    bssl::UniquePtr<EVP_PKEY> pkey(sAuth.pkey.get());
+    CHECK(X509_up_ref(sAuth.cert.get()));
+    bssl::UniquePtr<X509> cert(sAuth.cert.get());
+
+    return std::make_unique<RpcAuthPreSigned>(std::move(pkey), std::move(cert));
+}
+
+std::unique_ptr<RpcTransportCtxFactory> makeTransportCtxFactory(FuzzedDataProvider* provider) {
+    bool isTls = provider->ConsumeBool();
+    if (!isTls) {
+        return RpcTransportCtxFactoryRaw::make();
+    }
+    status_t verifyStatus = provider->ConsumeIntegral<status_t>();
+    auto verifier = std::make_shared<RpcCertificateVerifierNoOp>(verifyStatus);
+    return RpcTransportCtxFactoryTls::make(verifier, createServerRpcAuth());
+}
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     if (size > 50000) return 0;
     FuzzedDataProvider provider(data, size);
+    RAND_reset_for_fuzzing();
 
     unlink(kSock.c_str());
 
-    sp<RpcServer> server = RpcServer::make();
+    sp<RpcServer> server = RpcServer::make(makeTransportCtxFactory(&provider));
     server->setRootObject(sp<SomeBinder>::make());
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     CHECK_EQ(OK, server->setupUnixDomainServer(kSock.c_str()));
@@ -87,8 +147,7 @@
             size_t idx = provider.ConsumeIntegralInRange<size_t>(0, connections.size() - 1);
 
             if (provider.ConsumeBool()) {
-                std::vector<uint8_t> writeData = provider.ConsumeBytes<uint8_t>(
-                        provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+                std::string writeData = provider.ConsumeRandomLengthString();
                 ssize_t size = TEMP_FAILURE_RETRY(send(connections.at(idx).get(), writeData.data(),
                                                        writeData.size(), MSG_NOSIGNAL));
                 CHECK(errno == EPIPE || size == writeData.size())
@@ -101,7 +160,7 @@
 
     if (hangupBeforeShutdown) {
         connections.clear();
-        while (!server->listSessions().empty() && server->numUninitializedSessions()) {
+        while (!server->listSessions().empty() || server->numUninitializedSessions()) {
             // wait for all threads to finish processing existing information
             usleep(1);
         }
diff --git a/libs/binder/tests/rpc_fuzzer/server.crt b/libs/binder/tests/rpc_fuzzer/server.crt
new file mode 100644
index 0000000..9142474
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.crt
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICiTCCAXECFG1ggXE36l2WXeG6YTnaRVB7EmgQMA0GCSqGSIb3DQEBCwUAMAAw
+IBcNMjEwOTI5MDEzOTEzWhgPMjI5NTA3MTQwMTM5MTNaMAAwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDE3KnhPMwINpP5aIHIo/3GTlROZOK5AmkEsWmP
+w8smSWo2hJ7M0sOhruvOz82WORj48K8C0W72yFN+e9g32qoNMJFP/s6j1RWmaAKZ
+eSQUq6ixyaGhFLBOoukVykfTnY4qn4RbX5HzgpAPR1gv5ELvMXXPrxvtpIcVIrhm
+/dBQIa3iHZS6kypNbmRx/nhDVU8FK9s9WU5VLpbuNxv+m4X4Y1M/VZNatUMx5I0o
+ystV4JTqzjRZRPR4sxtMhu8/A11JsBVLeu8ZM/0IGCjmLOF4hy5a5YDv8MOJtdG2
+LI7ibZNtyrZiKwwhJc3tElzeIFit4T5Xjx69y/EMS4Hwhf3zAgMBAAEwDQYJKoZI
+hvcNAQELBQADggEBAD3gRbUybW7P2CihMyskTgS9HoIT9c02JWjtueWQIiQkyqTB
+6QdUQTHM5weil6TiW8NfpQQUIvrh66Pkph65shvFqxUsjdW25b4RbfUldFihfs1n
+kTa+e+hZONnVuzLvezIs2b8dygH9GA5y2OiLxwrMUcyaoCHGwKF7iOE0SJhfx0kY
+JDs4O+gAVjEsBSc24pm9aHBxgRCiEm1I4+RZf6PRBIz1ZadGBFsCZ+Gj6wyLP2Wq
+kjjMiV6o8pEjJjM+Oi4GfxvNewMCd2hMZYuJYpYC3cc7fPIpx8luidqKJdve8c6m
+KQ+dJ6ZQxEi0Zc9Jzre7NNoVcpIdc8SbkEM/DDo=
+-----END CERTIFICATE-----
diff --git a/libs/binder/tests/rpc_fuzzer/server.key b/libs/binder/tests/rpc_fuzzer/server.key
new file mode 100644
index 0000000..743470e
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAxNyp4TzMCDaT+WiByKP9xk5UTmTiuQJpBLFpj8PLJklqNoSe
+zNLDoa7rzs/NljkY+PCvAtFu9shTfnvYN9qqDTCRT/7Oo9UVpmgCmXkkFKuoscmh
+oRSwTqLpFcpH052OKp+EW1+R84KQD0dYL+RC7zF1z68b7aSHFSK4Zv3QUCGt4h2U
+upMqTW5kcf54Q1VPBSvbPVlOVS6W7jcb/puF+GNTP1WTWrVDMeSNKMrLVeCU6s40
+WUT0eLMbTIbvPwNdSbAVS3rvGTP9CBgo5izheIcuWuWA7/DDibXRtiyO4m2Tbcq2
+YisMISXN7RJc3iBYreE+V48evcvxDEuB8IX98wIDAQABAoIBACcI5jp+NqrOP6st
+uMZTFifzMi5VPMuYmcBPeXIDTc3qsr/ari5JAHeX2rQoakiGS9hYySsS4iDW+g9T
+eT0iA6QX5Ehrawf7YY6cgx9xcOEUZJ/ULlNlacw961/huzpPvHfhJ3qCycryMaSF
+7guZBFivgv/KZgxKGmrrdosdeufYXL3eHWZIrvcN4cDVgxslZg0o3Y5kCW3/KmDO
+QwvBlqgja93yImmkFA5BA/hQUsWuMBiR0xAd4b1NSBVCGTAYuCm6Up+6tIxeBSu5
+MVnNXbAIyVkbAS+gaR4uut6ObzFwUyGKDMaMpJ0LHLbusZy0svevu6Hjx+eH0ePC
+rj1xmDECgYEA4WR+1m3Tej0botG68+pZ8yLBgomSBAqpINCFkMEGQ2sQ1CqMMkHq
+8LAQNotU56W/0/H3eQemE3qBSKt1BUffpCvCHWkL9DRyDNhiq9U2PvV2Lx0Bv77e
+ET5MSDECUjlIsDqnv2qbq/m23BiP7AM8c9s6HjD0PqptyHjLlWHK86kCgYEA35hW
+AZEqMzsTNVQ8lXQtbqCyv8lls1SJbvIf3b5KItw9CwqpLr+UXssXh713j+yMW+WN
+3nv5+VaggkNBa9fHdqQEYT0L52OnLNjsfTlVhP5g2lOIa5VQYb/wqF1TaiZ27SGU
+lmLqiyArZgTnc3yo1wuIRPAbYbbm6CVnz7bm5jsCgYEAqfov7WZF5hnPjaq9YtWJ
+oGLFrLwy8flYMvcOw2vOXWmQ93Be6kfr9jfRAlFxZoEJeb0w9IVgKbBpb3Ree+0I
+K7cUXTmrWi9zE1zcjNnuXuyehElL2F8I+dgRjx/msDujJcQWXbT4UWmxDas4XrTS
+Ek1yNvKUP+4nfNgcMDvf4oECgYEAjgfYajpqEgzukKunqFAaI/HUWdt2zMlgW6dV
+8qdTtH0uEXt+KIHtn6FmmwURk8zxA9b3nWInUeljIBvUzMpOm+BoH9SFYUB+CxDo
+eEsZNdfYchcpyx0X6F/iYTCXMhCo7syr9DN1RVbz+mQXGdcP8ToUH6Zd3l4uozxP
+izRly80CgYEAqz7fCgQH74BwHoroSNdD3Cn6KNVx+oPuwRmzO4xMSOGyd/dNB2NA
+uzzuCTbrzC0jCXpqR0Bh9gYMjxyRZbifPX/YuFHyCIKK4+SQfeC4ZEwmSJVGWeh7
+3NksFJPCH4K3KbLNputByWJWOgKUdy70e/xOi83acBAVyRs+7H9LocE=
+-----END RSA PRIVATE KEY-----
diff --git a/libs/binder/tests/unit_fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
index b1263e8..8ea948c 100644
--- a/libs/binder/tests/unit_fuzzers/Android.bp
+++ b/libs/binder/tests/unit_fuzzers/Android.bp
@@ -30,16 +30,28 @@
         "-Wall",
         "-Werror",
     ],
-    shared_libs: [
-        "libbinder",
-        "libutils",
-        "libbase",
-    ],
     target: {
+        android: {
+            shared_libs: [
+                "libcutils",
+                "libutils",
+                "libbase",
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libcutils",
+                "liblog",
+                "libutils",
+                "libbase",
+                "libbinder",
+            ],
+        },
         darwin: {
             enabled: false,
-        }
-    }
+        },
+    },
 }
 
 cc_fuzz {
@@ -51,7 +63,6 @@
 cc_fuzz {
     name: "binder_bpBinderFuzz",
     defaults: ["binder_fuzz_defaults"],
-    host_supported: false,
     srcs: ["BpBinderFuzz.cpp"],
 }
 
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
index c50279b..20c5569 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
@@ -19,8 +19,15 @@
 #include <commonFuzzHelpers.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
+#include <android-base/logging.h>
 #include <binder/BpBinder.h>
 #include <binder/IServiceManager.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+
+#include <signal.h>
+#include <sys/prctl.h>
+#include <thread>
 
 namespace android {
 
@@ -28,13 +35,30 @@
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
     FuzzedDataProvider fdp(data, size);
 
-    // TODO: In the future it would be more effective to fork a new process and then pass a BBinder
-    // to your process. Right now this is not implemented because it would involved fuzzing IPC on a
-    // forked process, and libfuzzer will not be able to handle code coverage. This would lead to
-    // crashes that are not easy to diagnose.
-    int32_t handle = fdp.ConsumeIntegralInRange<int32_t>(0, 1024);
-    sp<BpBinder> bpbinder = BpBinder::create(handle);
-    if (bpbinder == nullptr) return 0;
+    std::string addr = std::string(getenv("TMPDIR") ?: "/tmp") + "/binderRpcBenchmark";
+    (void)unlink(addr.c_str());
+
+    sp<RpcServer> server = RpcServer::make();
+
+    // use RPC binder because fuzzer can't get coverage from another process.
+    auto thread = std::thread([&]() {
+        prctl(PR_SET_PDEATHSIG, SIGHUP); // racey, okay
+        server->setRootObject(sp<BBinder>::make());
+        server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+        CHECK_EQ(OK, server->setupUnixDomainServer(addr.c_str()));
+        server->join();
+    });
+
+    sp<RpcSession> session = RpcSession::make();
+    status_t status;
+    for (size_t tries = 0; tries < 5; tries++) {
+        usleep(10000);
+        status = session->setupUnixDomainClient(addr.c_str());
+        if (status == OK) break;
+    }
+    CHECK_EQ(status, OK) << "Unable to connect";
+
+    sp<BpBinder> bpBinder = session->getRootObject()->remoteBinder();
 
     // To prevent memory from running out from calling too many add item operations.
     const uint32_t MAX_RUNS = 2048;
@@ -43,12 +67,16 @@
 
     while (fdp.remaining_bytes() > 0 && count++ < MAX_RUNS) {
         if (fdp.ConsumeBool()) {
-            callArbitraryFunction(&fdp, gBPBinderOperations, bpbinder, s_recipient);
+            callArbitraryFunction(&fdp, gBPBinderOperations, bpBinder, s_recipient);
         } else {
-            callArbitraryFunction(&fdp, gIBinderOperations, bpbinder.get());
+            callArbitraryFunction(&fdp, gIBinderOperations, bpBinder.get());
         }
     }
 
+    CHECK(session->shutdownAndWait(true)) << "couldn't shutdown session";
+    CHECK(server->shutdown()) << "couldn't shutdown server";
+    thread.join();
+
     return 0;
 }
 } // namespace android
diff --git a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
index 6ca0e2f..741987f 100644
--- a/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
+++ b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
@@ -52,7 +52,7 @@
                     const sp<IBinder::DeathRecipient>& s_recipient) -> void {
                      // Clean up possible leftover memory.
                      wp<IBinder::DeathRecipient> outRecipient(nullptr);
-                     bpbinder->sendObituary();
+                     if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
                      bpbinder->unlinkToDeath(nullptr, reinterpret_cast<void*>(&kBpBinderCookie), 0,
                                              &outRecipient);
 
@@ -72,7 +72,9 @@
                  [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
                     const sp<IBinder::DeathRecipient>&) -> void { bpbinder->remoteBinder(); },
                  [](FuzzedDataProvider*, const sp<BpBinder>& bpbinder,
-                    const sp<IBinder::DeathRecipient>&) -> void { bpbinder->sendObituary(); },
+                    const sp<IBinder::DeathRecipient>&) -> void {
+                     if (!bpbinder->isRpcBinder()) bpbinder->sendObituary();
+                 },
                  [](FuzzedDataProvider* fdp, const sp<BpBinder>& bpbinder,
                     const sp<IBinder::DeathRecipient>&) -> void {
                      uint32_t uid = fdp->ConsumeIntegral<uint32_t>();
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 761e45c..9f0754b 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -78,4 +78,10 @@
     return std::nullopt;
 }
 
+std::optional<IServiceManager::ConnectionInfo> ServiceManager::getConnectionInfo(
+        const String16& name) {
+    (void)name;
+    return std::nullopt;
+}
+
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index e26c21b..b1496ba 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -51,6 +51,8 @@
 
     std::optional<String16> updatableViaApex(const String16& name) override;
 
+    std::optional<IServiceManager::ConnectionInfo> getConnectionInfo(const String16& name) override;
+
 private:
     std::map<String16, sp<IBinder>> mNameToService;
 };
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index df308d8..5fe5e71 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -645,7 +645,10 @@
                     slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
             return BAD_VALUE;
         } else if (!mSlots[slot].mBufferState.isDequeued()) {
-            BQ_LOGE("detachBuffer: slot %d is not owned by the producer "
+            // TODO(http://b/140581935): This message is BQ_LOGW because it
+            // often logs when no actionable errors are present. Return to
+            // using BQ_LOGE after ensuring this only logs during errors.
+            BQ_LOGW("detachBuffer: slot %d is not owned by the producer "
                     "(state = %s)", slot, mSlots[slot].mBufferState.string());
             return BAD_VALUE;
         } else if (!mSlots[slot].mRequestBufferCalled) {