Merge "Extend dumpstate.dry_run restrictions"
diff --git a/cmds/cmd/fuzzer/Android.bp b/cmds/cmd/fuzzer/Android.bp
index 8262bc2..a65f6de 100644
--- a/cmds/cmd/fuzzer/Android.bp
+++ b/cmds/cmd/fuzzer/Android.bp
@@ -30,12 +30,12 @@
     ],
     static_libs: [
         "libcmd",
-        "libutils",
         "liblog",
         "libselinux",
     ],
     shared_libs: [
         "libbinder",
+        "libutils",
     ],
     fuzz_config: {
         cc: [
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 99e0f4c..b2da6d5 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -24,7 +24,7 @@
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
-        "android.hardware.vibrator-V1-ndk_platform",
+        "android.hardware.vibrator-V1-ndk",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index a176df9..d55a927 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -307,6 +307,8 @@
         }
     }
 
+    out << "is_dexopt_blocked:" << android::installd::is_dexopt_blocked() << endl;
+
     out << endl;
     out.flush();
 
@@ -2399,7 +2401,8 @@
         const std::optional<std::string>& seInfo, bool downgrade, int32_t targetSdkVersion,
         const std::optional<std::string>& profileName,
         const std::optional<std::string>& dexMetadataPath,
-        const std::optional<std::string>& compilationReason) {
+        const std::optional<std::string>& compilationReason,
+        bool* aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_UUID(uuid);
     CHECK_ARGUMENT_PATH(apkPath);
@@ -2427,12 +2430,20 @@
     const char* dm_path = getCStr(dexMetadataPath);
     const char* compilation_reason = getCStr(compilationReason);
     std::string error_msg;
+    bool completed = false; // not necessary but for compiler
     int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded,
             oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info,
-            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg);
+            downgrade, targetSdkVersion, profile_name, dm_path, compilation_reason, &error_msg,
+            &completed);
+    *aidl_return = completed;
     return res ? error(res, error_msg) : ok();
 }
 
+binder::Status InstalldNativeService::controlDexOptBlocking(bool block) {
+    android::installd::control_dexopt_blocking(block);
+    return ok();
+}
+
 binder::Status InstalldNativeService::compileLayouts(const std::string& apkPath,
                                                      const std::string& packageName,
                                                      const std ::string& outDexFile, int uid,
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index 3127be6..480e41b 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -114,7 +114,10 @@
             const std::optional<std::string>& seInfo, bool downgrade,
             int32_t targetSdkVersion, const std::optional<std::string>& profileName,
             const std::optional<std::string>& dexMetadataPath,
-            const std::optional<std::string>& compilationReason);
+            const std::optional<std::string>& compilationReason,
+            bool* aidl_return);
+
+    binder::Status controlDexOptBlocking(bool block);
 
     binder::Status compileLayouts(const std::string& apkPath, const std::string& packageName,
                                   const std::string& outDexFile, int uid, bool* _aidl_return);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 816e508..b5d95c3 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -57,7 +57,8 @@
             @utf8InCpp String packageName, int appId,
             @utf8InCpp String seInfo, int targetSdkVersion, @utf8InCpp String fromCodePath);
 
-    void dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
+    // Returns false if it is cancelled. Returns true if it is completed or have other errors.
+    boolean dexopt(@utf8InCpp String apkPath, int uid, @nullable @utf8InCpp String packageName,
             @utf8InCpp String instructionSet, int dexoptNeeded,
             @nullable @utf8InCpp String outputPath, int dexFlags,
             @utf8InCpp String compilerFilter, @nullable @utf8InCpp String uuid,
@@ -66,6 +67,9 @@
             @nullable @utf8InCpp String profileName,
             @nullable @utf8InCpp String dexMetadataPath,
             @nullable @utf8InCpp String compilationReason);
+    // Blocks (when block is true) or unblock (when block is false) dexopt.
+    // Blocking also invloves cancelling the currently running dexopt.
+    void controlDexOptBlocking(boolean block);
     boolean compileLayouts(@utf8InCpp String apkPath, @utf8InCpp String packageName,
             @utf8InCpp String outDexFile, int uid);
 
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 210f977..7bb9bef 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -15,8 +15,8 @@
  */
 #define LOG_TAG "installd"
 
-#include <array>
 #include <fcntl.h>
+#include <signal.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/capability.h>
@@ -28,10 +28,14 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <array>
 #include <iomanip>
+#include <mutex>
+#include <unordered_set>
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/no_destructor.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
@@ -47,6 +51,7 @@
 #include <selinux/android.h>
 #include <server_configurable_flags/get_flags.h>
 #include <system/thread_defs.h>
+#include <utils/Mutex.h>
 
 #include "dexopt.h"
 #include "dexopt_return_codes.h"
@@ -69,6 +74,76 @@
 using android::base::WriteFully;
 using android::base::unique_fd;
 
+namespace {
+
+class DexOptStatus {
+ public:
+    // Check if dexopt is cancelled and fork if it is not cancelled.
+    // cancelled is set to true if cancelled. Otherwise it will be set to false.
+    // If it is not cancelled, it will return the return value of fork() call.
+    // If cancelled, fork will not happen and it will return -1.
+    pid_t check_cancellation_and_fork(/* out */ bool *cancelled) {
+        std::lock_guard<std::mutex> lock(dexopt_lock_);
+        if (dexopt_blocked_) {
+            *cancelled = true;
+            return -1;
+        }
+        pid_t pid = fork();
+        *cancelled = false;
+        if (pid > 0) { // parent
+            dexopt_pids_.insert(pid);
+        }
+        return pid;
+    }
+
+    // Returns true if pid was killed (is in killed list). It could have finished if killing
+    // happened after the process is finished.
+    bool check_if_killed_and_remove_dexopt_pid(pid_t pid) {
+        std::lock_guard<std::mutex> lock(dexopt_lock_);
+        dexopt_pids_.erase(pid);
+        if (dexopt_killed_pids_.erase(pid) == 1) {
+            return true;
+        }
+        return false;
+    }
+
+    // Tells whether dexopt is blocked or not.
+    bool is_dexopt_blocked() {
+        std::lock_guard<std::mutex> lock(dexopt_lock_);
+        return dexopt_blocked_;
+    }
+
+    // Enable or disable dexopt blocking.
+    void control_dexopt_blocking(bool block) {
+        std::lock_guard<std::mutex> lock(dexopt_lock_);
+        dexopt_blocked_ = block;
+        if (!block) {
+            return;
+        }
+        // Blocked, also kill currently running tasks
+        for (auto pid : dexopt_pids_) {
+            LOG(INFO) << "control_dexopt_blocking kill pid:" << pid;
+            kill(pid, SIGKILL);
+            dexopt_killed_pids_.insert(pid);
+        }
+        dexopt_pids_.clear();
+    }
+
+ private:
+    std::mutex dexopt_lock_;
+    // when true, dexopt is blocked and will not run.
+    bool dexopt_blocked_ GUARDED_BY(dexopt_lock_) = false;
+    // PIDs of child process while runinng dexopt.
+    // If the child process is finished, it should be removed.
+    std::unordered_set<pid_t> dexopt_pids_ GUARDED_BY(dexopt_lock_);
+    // PIDs of child processes killed by cancellation.
+    std::unordered_set<pid_t> dexopt_killed_pids_ GUARDED_BY(dexopt_lock_);
+};
+
+android::base::NoDestructor<DexOptStatus> dexopt_status_;
+
+} // namespace
+
 namespace android {
 namespace installd {
 
@@ -1525,23 +1600,46 @@
     return ss.str();
 }
 
+void control_dexopt_blocking(bool block) {
+    dexopt_status_->control_dexopt_blocking(block);
+}
+
+bool is_dexopt_blocked() {
+    return dexopt_status_->is_dexopt_blocked();
+}
+
+enum SecondaryDexOptProcessResult {
+    kSecondaryDexOptProcessOk = 0,
+    kSecondaryDexOptProcessCancelled = 1,
+    kSecondaryDexOptProcessError = 2
+};
+
 // Processes the dex_path as a secondary dex files and return true if the path dex file should
-// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
-// successfully.
-// When returning true, the output parameters will be:
+// be compiled.
+// Returns: kSecondaryDexOptProcessError for errors (logged).
+//          kSecondaryDexOptProcessOk if the secondary dex path was process successfully.
+//          kSecondaryDexOptProcessCancelled if the processing was cancelled.
+//
+// When returning kSecondaryDexOptProcessOk, the output parameters will be:
 //   - is_public_out: whether or not the oat file should not be made public
 //   - dexopt_needed_out: valid OatFileAsssitant::DexOptNeeded
 //   - oat_dir_out: the oat dir path where the oat file should be stored
-static bool process_secondary_dex_dexopt(const std::string& dex_path, const char* pkgname,
-        int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
-        const char* compiler_filter, bool* is_public_out, int* dexopt_needed_out,
-        std::string* oat_dir_out, bool downgrade, const char* class_loader_context,
-        const std::vector<std::string>& context_dex_paths, /* out */ std::string* error_msg) {
+static SecondaryDexOptProcessResult process_secondary_dex_dexopt(const std::string& dex_path,
+        const char* pkgname, int dexopt_flags, const char* volume_uuid, int uid,
+        const char* instruction_set, const char* compiler_filter, bool* is_public_out,
+        int* dexopt_needed_out, std::string* oat_dir_out, bool downgrade,
+        const char* class_loader_context, const std::vector<std::string>& context_dex_paths,
+        /* out */ std::string* error_msg) {
     LOG(DEBUG) << "Processing secondary dex path " << dex_path;
+
+    if (dexopt_status_->is_dexopt_blocked()) {
+        return kSecondaryDexOptProcessCancelled;
+    }
+
     int storage_flag;
     if (!validate_dexopt_storage_flags(dexopt_flags, &storage_flag, error_msg)) {
         LOG(ERROR) << *error_msg;
-        return false;
+        return kSecondaryDexOptProcessError;
     }
     // Compute the oat dir as it's not easy to extract it from the child computation.
     char oat_path[PKG_PATH_MAX];
@@ -1550,11 +1648,15 @@
     if (!create_secondary_dex_oat_layout(
             dex_path, instruction_set, oat_dir, oat_isa_dir, oat_path, error_msg)) {
         LOG(ERROR) << "Could not create secondary odex layout: " << *error_msg;
-        return false;
+        return kSecondaryDexOptProcessError;
     }
     oat_dir_out->assign(oat_dir);
 
-    pid_t pid = fork();
+    bool cancelled = false;
+    pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+    if (cancelled) {
+        return kSecondaryDexOptProcessCancelled;
+    }
     if (pid == 0) {
         // child -- drop privileges before continuing.
         drop_capabilities(uid);
@@ -1623,12 +1725,17 @@
 
     /* parent */
     int result = wait_child(pid);
+    cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
     if (!WIFEXITED(result)) {
+        if ((WTERMSIG(result) == SIGKILL) && cancelled) {
+            LOG(INFO) << "dexoptanalyzer cancelled for path:" << dex_path;
+            return kSecondaryDexOptProcessCancelled;
+        }
         *error_msg = StringPrintf("dexoptanalyzer failed for path %s: 0x%04x",
                                   dex_path.c_str(),
                                   result);
         LOG(ERROR) << *error_msg;
-        return false;
+        return kSecondaryDexOptProcessError;
     }
     result = WEXITSTATUS(result);
     // Check that we successfully executed dexoptanalyzer.
@@ -1656,7 +1763,7 @@
     // It is ok to check this flag outside in the parent process.
     *is_public_out = ((dexopt_flags & DEXOPT_PUBLIC) != 0) && is_file_public(dex_path);
 
-    return success;
+    return success ? kSecondaryDexOptProcessOk : kSecondaryDexOptProcessError;
 }
 
 static std::string format_dexopt_error(int status, const char* dex_path) {
@@ -1670,17 +1777,29 @@
   return StringPrintf("Dex2oat invocation for %s failed with 0x%04x", dex_path, status);
 }
 
+
 int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade, int target_sdk_version, const char* profile_name,
-        const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg) {
+        const char* dex_metadata_path, const char* compilation_reason, std::string* error_msg,
+        /* out */ bool* completed) {
     CHECK(pkgname != nullptr);
     CHECK(pkgname[0] != 0);
     CHECK(error_msg != nullptr);
     CHECK_EQ(dexopt_flags & ~DEXOPT_MASK, 0)
         << "dexopt flags contains unknown fields: " << dexopt_flags;
 
+    bool local_completed; // local placeholder for nullptr case
+    if (completed == nullptr) {
+        completed = &local_completed;
+    }
+    *completed = true;
+    if (dexopt_status_->is_dexopt_blocked()) {
+        *completed = false;
+        return 0;
+    }
+
     if (!validate_dex_path_size(dex_path)) {
         *error_msg = StringPrintf("Failed to validate %s", dex_path);
         return -1;
@@ -1712,14 +1831,19 @@
             *error_msg = "Failed acquiring context dex paths";
             return -1;  // We had an error, logged in the process method.
         }
-
-        if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
-                instruction_set, compiler_filter, &is_public, &dexopt_needed, &oat_dir_str,
-                downgrade, class_loader_context, context_dex_paths, error_msg)) {
+        SecondaryDexOptProcessResult sec_dex_result = process_secondary_dex_dexopt(dex_path,
+                pkgname, dexopt_flags, volume_uuid, uid,instruction_set, compiler_filter,
+                &is_public, &dexopt_needed, &oat_dir_str, downgrade, class_loader_context,
+                context_dex_paths, error_msg);
+        if (sec_dex_result == kSecondaryDexOptProcessOk) {
             oat_dir = oat_dir_str.c_str();
             if (dexopt_needed == NO_DEXOPT_NEEDED) {
                 return 0;  // Nothing to do, report success.
             }
+        } else if (sec_dex_result == kSecondaryDexOptProcessCancelled) {
+            // cancelled, not an error.
+            *completed = false;
+            return 0;
         } else {
             if (error_msg->empty()) {  // TODO: Make this a CHECK.
                 *error_msg = "Failed processing secondary.";
@@ -1849,7 +1973,11 @@
                       use_jitzygote_image,
                       compilation_reason);
 
-    pid_t pid = fork();
+    bool cancelled = false;
+    pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled);
+    if (cancelled) {
+        return 0;
+    }
     if (pid == 0) {
         // Need to set schedpolicy before dropping privileges
         // for cgroup migration. See details at b/175178520.
@@ -1867,9 +1995,16 @@
         runner.Exec(DexoptReturnCodes::kDex2oatExec);
     } else {
         int res = wait_child(pid);
+        bool cancelled = dexopt_status_->check_if_killed_and_remove_dexopt_pid(pid);
         if (res == 0) {
             LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' (success) ---";
         } else {
+            if ((WTERMSIG(res) == SIGKILL) && cancelled) {
+                LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- cancelled";
+                // cancelled, not an error
+                *completed = false;
+                return 0;
+            }
             LOG(VERBOSE) << "DexInv: --- END '" << dex_path << "' --- status=0x"
                          << std::hex << std::setw(4) << res << ", process failed";
             *error_msg = format_dexopt_error(res, dex_path);
@@ -1877,12 +2012,14 @@
         }
     }
 
+    // TODO(b/156537504) Implement SWAP of completed files
     // We've been successful, don't delete output.
     out_oat.DisableCleanup();
     out_vdex.DisableCleanup();
     out_image.DisableCleanup();
     reference_profile.DisableCleanup();
 
+    *completed = true;
     return 0;
 }
 
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 5a637b1..12579b0 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -121,11 +121,18 @@
         const std::string& pkgname, int uid, const std::optional<std::string>& volume_uuid,
         int storage_flag, std::vector<uint8_t>* out_secondary_dex_hash);
 
+// completed pass false if it is canceled. Otherwise it will be true even if there is other
+// error.
 int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
         int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
         const char* volume_uuid, const char* class_loader_context, const char* se_info,
         bool downgrade, int target_sdk_version, const char* profile_name,
-        const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg);
+        const char* dexMetadataPath, const char* compilation_reason, std::string* error_msg,
+        /* out */ bool* completed = nullptr);
+
+bool is_dexopt_blocked();
+
+void control_dexopt_blocking(bool block);
 
 bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir,
         const char *apk_path, const char *instruction_set);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 7e7e513..ea26955 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -232,6 +232,7 @@
 
     virtual void TearDown() {
         if (!kDebug) {
+            service_->controlDexOptBlocking(false);
             service_->destroyAppData(
                 volume_uuid_, package_name_, kTestUserId, kAppDataFlags, ce_data_inode_);
             run_cmd("rm -rf " + app_apk_dir_);
@@ -347,7 +348,7 @@
     void CompileSecondaryDex(const std::string& path, int32_t dex_storage_flag,
             bool should_binder_call_succeed, bool should_dex_be_compiled = true,
             /*out */ binder::Status* binder_result = nullptr, int32_t uid = -1,
-            const char* class_loader_context = nullptr) {
+            const char* class_loader_context = nullptr, bool expect_completed = true) {
         if (uid == -1) {
             uid = kTestAppUid;
         }
@@ -364,6 +365,7 @@
         std::optional<std::string> dm_path;
         std::optional<std::string> compilation_reason;
 
+        bool completed = false;
         binder::Status result = service_->dexopt(path,
                                                  uid,
                                                  package_name_,
@@ -379,8 +381,10 @@
                                                  target_sdk_version,
                                                  profile_name,
                                                  dm_path,
-                                                 compilation_reason);
+                                                 compilation_reason,
+                                                 &completed);
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+        ASSERT_EQ(expect_completed, completed);
         int expected_access = should_dex_be_compiled ? 0 : -1;
         std::string odex = GetSecondaryDexArtifact(path, "odex");
         std::string vdex = GetSecondaryDexArtifact(path, "vdex");
@@ -431,6 +435,11 @@
         ASSERT_EQ(mode, st.st_mode);
     }
 
+    void AssertNoFile(const std::string& file) {
+        struct stat st;
+        ASSERT_EQ(-1, stat(file.c_str(), &st));
+    }
+
     void CompilePrimaryDexOk(std::string compiler_filter,
                              int32_t dex_flags,
                              const char* oat_dir,
@@ -447,6 +456,7 @@
                           dm_path,
                           downgrade,
                           true,
+                          true,
                           binder_result);
     }
 
@@ -466,6 +476,27 @@
                           dm_path,
                           downgrade,
                           false,
+                          true,
+                          binder_result);
+    }
+
+    void CompilePrimaryDexCancelled(std::string compiler_filter,
+                               int32_t dex_flags,
+                               const char* oat_dir,
+                               int32_t uid,
+                               int32_t dexopt_needed,
+                               binder::Status* binder_result = nullptr,
+                               const char* dm_path = nullptr,
+                               bool downgrade = false) {
+        CompilePrimaryDex(compiler_filter,
+                          dex_flags,
+                          oat_dir,
+                          uid,
+                          dexopt_needed,
+                          dm_path,
+                          downgrade,
+                          true, // should_binder_call_succeed
+                          false, // expect_completed
                           binder_result);
     }
 
@@ -477,6 +508,7 @@
                            const char* dm_path,
                            bool downgrade,
                            bool should_binder_call_succeed,
+                           bool expect_completed,
                            /*out */ binder::Status* binder_result) {
         std::optional<std::string> out_path = oat_dir ? std::make_optional<std::string>(oat_dir) : std::nullopt;
         std::string class_loader_context = "PCL[]";
@@ -491,6 +523,7 @@
                 dm_path_opt, &prof_result));
         ASSERT_TRUE(prof_result);
 
+        bool completed = false;
         binder::Status result = service_->dexopt(apk_path_,
                                                  uid,
                                                  package_name_,
@@ -506,8 +539,10 @@
                                                  target_sdk_version,
                                                  profile_name,
                                                  dm_path_opt,
-                                                 compilation_reason);
+                                                 compilation_reason,
+                                                 &completed);
         ASSERT_EQ(should_binder_call_succeed, result.isOk()) << result.toString8().c_str();
+        ASSERT_EQ(expect_completed, completed);
 
         if (!should_binder_call_succeed) {
             if (binder_result != nullptr) {
@@ -525,11 +560,20 @@
 
         bool is_public = (dex_flags & DEXOPT_PUBLIC) != 0;
         mode_t mode = S_IFREG | (is_public ? 0644 : 0640);
-        CheckFileAccess(odex, kSystemUid, uid, mode);
-        CheckFileAccess(vdex, kSystemUid, uid, mode);
+        if (expect_completed) {
+            CheckFileAccess(odex, kSystemUid, uid, mode);
+            CheckFileAccess(vdex, kSystemUid, uid, mode);
+        } else {
+            AssertNoFile(odex);
+            AssertNoFile(vdex);
+        }
 
         if (compiler_filter == "speed-profile") {
-            CheckFileAccess(art, kSystemUid, uid, mode);
+            if (expect_completed) {
+                CheckFileAccess(art, kSystemUid, uid, mode);
+            } else {
+                AssertNoFile(art);
+            }
         }
         if (binder_result != nullptr) {
             *binder_result = result;
@@ -750,6 +794,28 @@
                         empty_dm_file_.c_str());
 }
 
+TEST_F(DexoptTest, DexoptBlockPrimary) {
+    LOG(INFO) << "DexoptPrimaryPublic";
+    service_->controlDexOptBlocking(true);
+    CompilePrimaryDexCancelled("verify",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+    service_->controlDexOptBlocking(false);
+}
+
+TEST_F(DexoptTest, DexoptUnblockPrimary) {
+    LOG(INFO) << "DexoptPrimaryPublic";
+    service_->controlDexOptBlocking(true);
+    service_->controlDexOptBlocking(false);
+    CompilePrimaryDexOk("verify",
+                        DEXOPT_BOOTCOMPLETE | DEXOPT_PUBLIC,
+                        app_oat_dir_.c_str(),
+                        kTestAppGid,
+                        DEX2OAT_FROM_SCRATCH, nullptr, nullptr);
+}
+
 TEST_F(DexoptTest, DeleteDexoptArtifactsData) {
     LOG(INFO) << "DeleteDexoptArtifactsData";
     TestDeleteOdex(/*in_dalvik_cache=*/ false);
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 7422d09..9bca1f3 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -120,7 +120,6 @@
         "ParcelFileDescriptor.cpp",
         "PersistableBundle.cpp",
         "ProcessState.cpp",
-        "RpcAddress.cpp",
         "RpcSession.cpp",
         "RpcServer.cpp",
         "RpcState.cpp",
@@ -263,6 +262,7 @@
     ],
     srcs: [
         "RpcTransportTls.cpp",
+        "RpcCertificateUtils.cpp",
     ],
 }
 
@@ -271,6 +271,15 @@
     defaults: ["libbinder_tls_defaults"],
 }
 
+// For testing
+cc_library_static {
+    name: "libbinder_tls_static",
+    defaults: ["libbinder_tls_defaults"],
+    visibility: [
+        ":__subpackages__",
+    ],
+}
+
 // AIDL interface between libbinder and framework.jar
 filegroup {
     name: "libbinder_aidl",
@@ -289,6 +298,9 @@
         "aidl/android/content/pm/IPackageChangeObserver.aidl",
         "aidl/android/content/pm/IPackageManagerNative.aidl",
         "aidl/android/content/pm/PackageChangeEvent.aidl",
+        "aidl/android/content/pm/IStagedApexObserver.aidl",
+        "aidl/android/content/pm/ApexStagedEvent.aidl",
+        "aidl/android/content/pm/StagedApexInfo.aidl",
     ],
     path: "aidl",
 }
@@ -317,6 +329,7 @@
         "libbinder_ndk",
         "libutils",
     ],
+    export_include_dirs: ["include_rpc_unstable"],
 
     // enumerate stable entry points, for apex use
     stubs: {
@@ -326,14 +339,15 @@
     // This library is intentionally limited to these targets, and it will be removed later.
     // Do not expand the visibility.
     visibility: [
-        "//packages/modules/Virtualization/authfs:__subpackages__",
-        "//packages/modules/Virtualization/compos:__subpackages__",
-        "//packages/modules/Virtualization/microdroid",
-        "//packages/modules/Virtualization/microdroid_manager",
-        "//packages/modules/Virtualization/virtualizationservice",
+        "//packages/modules/Virtualization:__subpackages__",
     ],
 }
 
+filegroup {
+    name: "libbinder_rpc_unstable_header",
+    srcs: ["include_rpc_unstable/binder_rpc_unstable.hpp"],
+}
+
 // libbinder historically contained additional interfaces that provided specific
 // functionality in the platform but have nothing to do with binder itself. These
 // are moved out of libbinder in order to avoid the overhead of their vtables.
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 55566e2..687ee25 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -36,7 +36,8 @@
 // ---------------------------------------------------------------------------
 
 Mutex BpBinder::sTrackingLock;
-std::unordered_map<int32_t,uint32_t> BpBinder::sTrackingMap;
+std::unordered_map<int32_t, uint32_t> BpBinder::sTrackingMap;
+std::unordered_map<int32_t, uint32_t> BpBinder::sLastLimitCallbackMap;
 int BpBinder::sNumTrackedUids = 0;
 std::atomic_bool BpBinder::sCountByUidEnabled(false);
 binder_proxy_limit_callback BpBinder::sLimitCallback;
@@ -47,6 +48,10 @@
 // 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
@@ -120,12 +125,24 @@
             if (sBinderProxyThrottleCreate) {
                 return nullptr;
             }
+            trackedValue = trackedValue & COUNTING_VALUE_MASK;
+            uint32_t lastLimitCallbackAt = sLastLimitCallbackMap[trackedUid];
+
+            if (trackedValue > lastLimitCallbackAt &&
+                (trackedValue - lastLimitCallbackAt > REPEAT_LIMIT_CALLBACK_INTERVAL)) {
+                ALOGE("Still too many binder proxy objects sent to uid %d from uid %d (%d proxies "
+                      "held)",
+                      getuid(), trackedUid, trackedValue);
+                if (sLimitCallback) sLimitCallback(trackedUid);
+                sLastLimitCallbackMap[trackedUid] = trackedValue;
+            }
         } else {
             if ((trackedValue & COUNTING_VALUE_MASK) >= sBinderProxyCountHighWatermark) {
                 ALOGE("Too many binder proxy objects sent to uid %d from uid %d (%d proxies held)",
                       getuid(), trackedUid, trackedValue);
                 sTrackingMap[trackedUid] |= LIMIT_REACHED_MASK;
                 if (sLimitCallback) sLimitCallback(trackedUid);
+                sLastLimitCallbackMap[trackedUid] = trackedValue & COUNTING_VALUE_MASK;
                 if (sBinderProxyThrottleCreate) {
                     ALOGI("Throttling binder proxy creates from uid %d in uid %d until binder proxy"
                           " count drops below %d",
@@ -139,7 +156,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
@@ -176,7 +193,7 @@
     return std::holds_alternative<RpcHandle>(mHandle);
 }
 
-const RpcAddress& BpBinder::rpcAddress() const {
+uint64_t BpBinder::rpcAddress() const {
     return std::get<RpcHandle>(mHandle).address;
 }
 
@@ -465,8 +482,9 @@
                 ((trackedValue & COUNTING_VALUE_MASK) <= sBinderProxyCountLowWatermark)
                 )) {
                 ALOGI("Limit reached bit reset for uid %d (fewer than %d proxies from uid %d held)",
-                                   getuid(), mTrackedUid, sBinderProxyCountLowWatermark);
+                      getuid(), sBinderProxyCountLowWatermark, mTrackedUid);
                 sTrackingMap[mTrackedUid] &= ~LIMIT_REACHED_MASK;
+                sLastLimitCallbackMap.erase(mTrackedUid);
             }
             if (--sTrackingMap[mTrackedUid] == 0) {
                 sTrackingMap.erase(mTrackedUid);
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/Parcel.cpp b/libs/binder/Parcel.cpp
index 956524a..9147e23 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -104,7 +104,7 @@
     switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
-                LOG_REFS("Parcel %p acquiring reference on local %p", who, obj.cookie);
+                LOG_REFS("Parcel %p acquiring reference on local %llu", who, obj.cookie);
                 reinterpret_cast<IBinder*>(obj.cookie)->incStrong(who);
             }
             return;
@@ -137,7 +137,7 @@
     switch (obj.hdr.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
-                LOG_REFS("Parcel %p releasing reference on local %p", who, obj.cookie);
+                LOG_REFS("Parcel %p releasing reference on local %llu", who, obj.cookie);
                 reinterpret_cast<IBinder*>(obj.cookie)->decStrong(who);
             }
             return;
@@ -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
@@ -279,15 +279,15 @@
     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;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index caa00a5..15b8604 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -18,6 +18,7 @@
 
 #include <binder/ProcessState.h>
 
+#include <android-base/result.h>
 #include <binder/BpBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
@@ -384,74 +385,78 @@
     return mDriverName;
 }
 
-static int open_driver(const char *driver)
-{
+static base::Result<int> open_driver(const char* driver) {
     int fd = open(driver, O_RDWR | O_CLOEXEC);
-    if (fd >= 0) {
-        int vers = 0;
-        status_t result = ioctl(fd, BINDER_VERSION, &vers);
-        if (result == -1) {
-            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
-            close(fd);
-            fd = -1;
-        }
-        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
-          ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
-                vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
-            close(fd);
-            fd = -1;
-        }
-        size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
-        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
-        if (result == -1) {
-            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
-        }
-        uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
-        result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
-        if (result == -1) {
-            ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
-        }
-    } else {
-        ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
+    if (fd < 0) {
+        return base::ErrnoError() << "Opening '" << driver << "' failed";
+    }
+    int vers = 0;
+    status_t result = ioctl(fd, BINDER_VERSION, &vers);
+    if (result == -1) {
+        close(fd);
+        return base::ErrnoError() << "Binder ioctl to obtain version failed";
+    }
+    if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
+        close(fd);
+        return base::Error() << "Binder driver protocol(" << vers
+                             << ") does not match user space protocol("
+                             << BINDER_CURRENT_PROTOCOL_VERSION
+                             << ")! ioctl() return value: " << result;
+    }
+    size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
+    result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
+    if (result == -1) {
+        ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
+    }
+    uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
+    result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
+    if (result == -1) {
+        ALOGV("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
     }
     return fd;
 }
 
-ProcessState::ProcessState(const char *driver)
-    : mDriverName(String8(driver))
-    , mDriverFD(open_driver(driver))
-    , mVMStart(MAP_FAILED)
-    , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
-    , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
-    , mExecutingThreadsCount(0)
-    , mWaitingForThreads(0)
-    , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
-    , mStarvationStartTimeMs(0)
-    , mThreadPoolStarted(false)
-    , mThreadPoolSeq(1)
-    , mCallRestriction(CallRestriction::NONE)
-{
-
+ProcessState::ProcessState(const char* driver)
+      : mDriverName(String8(driver)),
+        mDriverFD(-1),
+        mVMStart(MAP_FAILED),
+        mThreadCountLock(PTHREAD_MUTEX_INITIALIZER),
+        mThreadCountDecrement(PTHREAD_COND_INITIALIZER),
+        mExecutingThreadsCount(0),
+        mWaitingForThreads(0),
+        mMaxThreads(DEFAULT_MAX_BINDER_THREADS),
+        mStarvationStartTimeMs(0),
+        mThreadPoolStarted(false),
+        mThreadPoolSeq(1),
+        mCallRestriction(CallRestriction::NONE) {
 // TODO(b/166468760): enforce in build system
 #if defined(__ANDROID_APEX__)
     LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
 #endif
 
-    if (mDriverFD >= 0) {
+    base::Result<int> opened = open_driver(driver);
+
+    if (opened.ok()) {
         // mmap the binder, providing a chunk of virtual address space to receive transactions.
-        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
+        mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE,
+                        opened.value(), 0);
         if (mVMStart == MAP_FAILED) {
+            close(opened.value());
             // *sigh*
-            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
-            close(mDriverFD);
-            mDriverFD = -1;
+            opened = base::Error()
+                    << "Using " << driver << " failed: unable to mmap transaction memory.";
             mDriverName.clear();
         }
     }
 
 #ifdef __ANDROID__
-    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened.  Terminating.", driver);
+    LOG_ALWAYS_FATAL_IF(!opened.ok(), "Binder driver '%s' could not be opened. Terminating: %s",
+                        driver, opened.error().message().c_str());
 #endif
+
+    if (opened.ok()) {
+        mDriverFD = opened.value();
+    }
 }
 
 ProcessState::~ProcessState()
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/RpcCertificateUtils.cpp b/libs/binder/RpcCertificateUtils.cpp
new file mode 100644
index 0000000..d91736c
--- /dev/null
+++ b/libs/binder/RpcCertificateUtils.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 "RpcCertificateUtils"
+#include <log/log.h>
+
+#include <binder/RpcCertificateUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+bssl::UniquePtr<X509> fromPem(const std::vector<uint8_t>& cert) {
+    if (cert.size() > std::numeric_limits<int>::max()) return nullptr;
+    bssl::UniquePtr<BIO> certBio(BIO_new_mem_buf(cert.data(), static_cast<int>(cert.size())));
+    return bssl::UniquePtr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
+}
+
+bssl::UniquePtr<X509> fromDer(const std::vector<uint8_t>& cert) {
+    if (cert.size() > std::numeric_limits<long>::max()) return nullptr;
+    const unsigned char* data = cert.data();
+    auto expectedEnd = data + cert.size();
+    bssl::UniquePtr<X509> ret(d2i_X509(nullptr, &data, static_cast<long>(cert.size())));
+    if (data != expectedEnd) {
+        ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - data);
+        return nullptr;
+    }
+    return ret;
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+                                             RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return fromPem(cert);
+        case RpcCertificateFormat::DER:
+            return fromDer(cert);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+    bssl::UniquePtr<BIO> certBio(BIO_new(BIO_s_mem()));
+    switch (format) {
+        case RpcCertificateFormat::PEM: {
+            TEST_AND_RETURN({}, PEM_write_bio_X509(certBio.get(), x509));
+        } break;
+        case RpcCertificateFormat::DER: {
+            TEST_AND_RETURN({}, i2d_X509_bio(certBio.get(), x509));
+        } break;
+        default: {
+            LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+        }
+    }
+    const uint8_t* data;
+    size_t len;
+    TEST_AND_RETURN({}, BIO_mem_contents(certBio.get(), &data, &len));
+    return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace android
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index a20445b..5733993 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -23,6 +23,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>
@@ -39,8 +41,7 @@
 using base::ScopeGuard;
 using base::unique_fd;
 
-RpcServer::RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
-      : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {}
+RpcServer::RpcServer(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {}
 RpcServer::~RpcServer() {
     (void)shutdown();
 }
@@ -49,7 +50,9 @@
     // Default is without TLS.
     if (rpcTransportCtxFactory == nullptr)
         rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
-    return sp<RpcServer>::make(std::move(rpcTransportCtxFactory));
+    auto ctx = rpcTransportCtxFactory->newServerCtx();
+    if (ctx == nullptr) return nullptr;
+    return sp<RpcServer>::make(std::move(ctx));
 }
 
 void RpcServer::iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction() {
@@ -138,6 +141,11 @@
     return ret;
 }
 
+std::vector<uint8_t> RpcServer::getCertificate(RpcCertificateFormat format) {
+    std::lock_guard<std::mutex> _l(mLock);
+    return mCtx->getCertificate(format);
+}
+
 static void joinRpcServer(sp<RpcServer>&& thiz) {
     thiz->join();
 }
@@ -159,10 +167,6 @@
         mJoinThreadRunning = true;
         mShutdownTrigger = FdTrigger::make();
         LOG_ALWAYS_FATAL_IF(mShutdownTrigger == nullptr, "Cannot create join signaler");
-
-        mCtx = mRpcTransportCtxFactory->newServerCtx();
-        LOG_ALWAYS_FATAL_IF(mCtx == nullptr, "Unable to create RpcTransportCtx with %s sockets",
-                            mRpcTransportCtxFactory->toCString());
     }
 
     status_t status;
@@ -229,7 +233,6 @@
     LOG_RPC_DETAIL("Finished waiting on shutdown.");
 
     mShutdownTrigger = nullptr;
-    mCtx = nullptr;
     return true;
 }
 
@@ -280,17 +283,29 @@
         }
     }
 
+    std::vector<uint8_t> sessionId;
+    if (status == OK) {
+        if (header.sessionIdSize > 0) {
+            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
+            }
+        }
+    }
+
     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{
@@ -332,15 +347,26 @@
                 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.
+            constexpr size_t kSessionIdSize = 32;
+            sessionId.resize(kSessionIdSize);
             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();
@@ -360,7 +386,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;
@@ -422,16 +448,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 4c47005..9395b50 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -26,6 +26,7 @@
 
 #include <string_view>
 
+#include <android-base/hex.h>
 #include <android-base/macros.h>
 #include <android_runtime/vm.h>
 #include <binder/Parcel.h>
@@ -49,8 +50,7 @@
 
 using base::unique_fd;
 
-RpcSession::RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory)
-      : mRpcTransportCtxFactory(std::move(rpcTransportCtxFactory)) {
+RpcSession::RpcSession(std::unique_ptr<RpcTransportCtx> ctx) : mCtx(std::move(ctx)) {
     LOG_RPC_DETAIL("RpcSession created %p", this);
 
     mState = std::make_unique<RpcState>();
@@ -63,11 +63,15 @@
                         "Should not be able to destroy a session with servers in use.");
 }
 
-sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+sp<RpcSession> RpcSession::make() {
     // Default is without TLS.
-    if (rpcTransportCtxFactory == nullptr)
-        rpcTransportCtxFactory = RpcTransportCtxFactoryRaw::make();
-    return sp<RpcSession>::make(std::move(rpcTransportCtxFactory));
+    return make(RpcTransportCtxFactoryRaw::make());
+}
+
+sp<RpcSession> RpcSession::make(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory) {
+    auto ctx = rpcTransportCtxFactory->newClientCtx();
+    if (ctx == nullptr) return nullptr;
+    return sp<RpcSession>::make(std::move(ctx));
 }
 
 void RpcSession::setMaxThreads(size_t threads) {
@@ -129,7 +133,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();
@@ -155,12 +159,7 @@
         return -savedErrno;
     }
 
-    auto ctx = mRpcTransportCtxFactory->newClientCtx();
-    if (ctx == nullptr) {
-        ALOGE("Unable to create RpcTransportCtx for null debugging client");
-        return NO_MEMORY;
-    }
-    auto server = ctx->newTransport(std::move(serverFd), mShutdownTrigger.get());
+    auto server = mCtx->newTransport(std::move(serverFd), mShutdownTrigger.get());
     if (server == nullptr) {
         ALOGE("Unable to set up RpcTransport");
         return UNKNOWN_ERROR;
@@ -216,7 +215,7 @@
                              sp<RpcSession>::fromExisting(this), reply, flags);
 }
 
-status_t RpcSession::sendDecStrong(const RpcAddress& address) {
+status_t RpcSession::sendDecStrong(uint64_t address) {
     ExclusiveConnection connection;
     status_t status = ExclusiveConnection::find(sp<RpcSession>::fromExisting(this),
                                                 ConnectionUse::CLIENT_REFCOUNT, &connection);
@@ -235,12 +234,11 @@
                                                 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;
 }
 
@@ -399,8 +397,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,
@@ -409,8 +407,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;
@@ -451,26 +448,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);
 
@@ -484,37 +480,39 @@
         }
 
         if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
-            if (errno == ECONNRESET) {
+            int connErrno = errno;
+            if (connErrno == EAGAIN || connErrno == EINPROGRESS) {
+                // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
+                // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
+                status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
+                if (pollStatus != OK) {
+                    ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
+                          statusToString(pollStatus).c_str());
+                    return pollStatus;
+                }
+                // Set connErrno to the errno that connect() would have set if the fd were blocking.
+                socklen_t connErrnoLen = sizeof(connErrno);
+                int ret =
+                        getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &connErrno, &connErrnoLen);
+                if (ret == -1) {
+                    int savedErrno = errno;
+                    ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s. "
+                          "(Original error from connect() is: %s)",
+                          strerror(savedErrno), strerror(connErrno));
+                    return -savedErrno;
+                }
+                // Retrieved the real connErrno as if connect() was called with a blocking socket
+                // fd. Continue checking connErrno.
+            }
+            if (connErrno == ECONNRESET) {
                 ALOGW("Connection reset on %s", addr.toString().c_str());
                 continue;
             }
-            if (errno != EAGAIN && errno != EINPROGRESS) {
-                int savedErrno = errno;
+            // connErrno could be zero if getsockopt determines so. Hence zero-check again.
+            if (connErrno != 0) {
                 ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
-                      strerror(savedErrno));
-                return -savedErrno;
-            }
-            // For non-blocking sockets, connect() may return EAGAIN (for unix domain socket) or
-            // EINPROGRESS (for others). Call poll() and getsockopt() to get the error.
-            status_t pollStatus = mShutdownTrigger->triggerablePoll(serverFd, POLLOUT);
-            if (pollStatus != OK) {
-                ALOGE("Could not POLLOUT after connect() on non-blocking socket: %s",
-                      statusToString(pollStatus).c_str());
-                return pollStatus;
-            }
-            int soError;
-            socklen_t soErrorLen = sizeof(soError);
-            int ret = getsockopt(serverFd.get(), SOL_SOCKET, SO_ERROR, &soError, &soErrorLen);
-            if (ret == -1) {
-                int savedErrno = errno;
-                ALOGE("Could not getsockopt() after connect() on non-blocking socket: %s",
-                      strerror(savedErrno));
-                return -savedErrno;
-            }
-            if (soError != 0) {
-                ALOGE("After connect(), getsockopt() returns error for socket at %s: %s",
-                      addr.toString().c_str(), strerror(soError));
-                return -soError;
+                      strerror(connErrno));
+                return -connErrno;
             }
         }
         LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
@@ -526,30 +524,31 @@
     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 ctx = mRpcTransportCtxFactory->newClientCtx();
-    if (ctx == nullptr) {
-        ALOGE("Unable to create client RpcTransportCtx with %s sockets",
-              mRpcTransportCtxFactory->toCString());
-        return NO_MEMORY;
-    }
-    auto server = ctx->newTransport(std::move(fd), mShutdownTrigger.get());
+    auto server = mCtx->newTransport(std::move(fd), mShutdownTrigger.get());
     if (server == nullptr) {
-        ALOGE("Unable to set up RpcTransport in %s context", mRpcTransportCtxFactory->toCString());
+        ALOGE("%s: Unable to set up RpcTransport", __PRETTY_FUNCTION__);
         return UNKNOWN_ERROR;
     }
 
     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));
@@ -559,6 +558,18 @@
         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) {
@@ -631,7 +642,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);
@@ -692,6 +703,10 @@
     return false;
 }
 
+std::vector<uint8_t> RpcSession::getCertificate(RpcCertificateFormat format) {
+    return mCtx->getCertificate(format);
+}
+
 status_t RpcSession::ExclusiveConnection::find(const sp<RpcSession>& session, ConnectionUse use,
                                                ExclusiveConnection* connection) {
     connection->mSession = session;
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index b58f1b3..59643ba 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -52,7 +52,7 @@
 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();
 
@@ -84,12 +84,11 @@
     for (auto& [addr, node] : mNodeForAddress) {
         if (binder == node.binder) {
             if (isRpc) {
-                const RpcAddress& actualAddr =
+                // check integrity of data structure
+                uint64_t 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");
+                LOG_ALWAYS_FATAL_IF(addr != actualAddr, "Address mismatch %" PRIu64 " vs %" PRIu64,
+                                    addr, actualAddr);
             }
             node.timesSent++;
             node.sentRef = binder; // might already be set
@@ -101,8 +100,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 +132,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,8 +145,11 @@
     //   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;
     }
 
@@ -159,9 +174,9 @@
 
     // 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;
     }
 
@@ -241,9 +256,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");
 }
@@ -360,8 +374,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 +390,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,20 +410,19 @@
 }
 
 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,
@@ -426,26 +438,26 @@
         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 +478,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,
@@ -557,15 +570,14 @@
 }
 
 status_t RpcState::sendDecStrong(const sp<RpcSession::RpcConnection>& connection,
-                                 const sp<RpcSession>& session, const RpcAddress& addr) {
+                                 const sp<RpcSession>& session, uint64_t 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);
+        LOG_ALWAYS_FATAL_IF(it->second.timesRecd <= 0, "Bad dec strong %" PRIu64, addr);
 
         it->second.timesRecd--;
         LOG_ALWAYS_FATAL_IF(nullptr != tryEraseNode(it),
@@ -579,8 +591,7 @@
     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));
+    if (status_t status = rpcSend(connection, session, "dec ref body", &addr, sizeof(addr));
         status != OK)
         return status;
     return OK;
@@ -685,14 +696,12 @@
     }
     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 (addr != 0) {
         if (!targetRef) {
             replyStatus = onBinderEntering(session, addr, &target);
         } else {
@@ -708,21 +717,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 +743,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 +801,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 +829,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 +856,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
@@ -904,7 +913,7 @@
         status != OK)
         return status;
 
-    if (command.bodySize < sizeof(RpcWireAddress)) {
+    if (command.bodySize != sizeof(RpcWireAddress)) {
         ALOGE("Expecting %zu but got %" PRId32 " bytes for RpcWireAddress. Terminating!",
               sizeof(RpcWireAddress), command.bodySize);
         (void)session->shutdownAndWait(false);
@@ -912,31 +921,32 @@
     }
     RpcWireAddress* address = reinterpret_cast<RpcWireAddress*>(commandData.data());
 
-    // TODO(b/182939933): heap allocation just for lookup
-    auto addr = RpcAddress::fromRawEmbedded(address);
+    uint64_t addr = RpcWireAddress::toRaw(*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());
+        ALOGE("No record of sending binder, but requested decStrong: %" PRIu64, addr);
         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--;
     sp<IBinder> tempHold = tryEraseNode(it);
@@ -946,7 +956,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..dcfb569 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -73,17 +73,17 @@
     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);
+                                           uint64_t 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);
+                                         const sp<RpcSession>& session, uint64_t address);
 
     enum class CommandType {
         ANY,
@@ -99,15 +99,15 @@
      * 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);
 
     size_t countBinders();
     void dump();
@@ -221,15 +221,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/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index d77fc52..c012df8 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -111,7 +111,9 @@
     std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd, FdTrigger*) const {
         return std::make_unique<RpcTransportRaw>(std::move(fd));
     }
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
 };
+
 } // namespace
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryRaw::newServerCtx() const {
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index a102913..d40cfc8 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/RpcCertificateUtils.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;
@@ -166,6 +160,34 @@
     }
 }
 
+// Helper class to ErrorQueue::toString
+class ErrorQueueString {
+public:
+    static std::string toString() {
+        ErrorQueueString thiz;
+        ERR_print_errors_cb(staticCallback, &thiz);
+        return thiz.mSs.str();
+    }
+
+private:
+    static int staticCallback(const char* str, size_t len, void* ctx) {
+        return reinterpret_cast<ErrorQueueString*>(ctx)->callback(str, len);
+    }
+    int callback(const char* str, size_t len) {
+        if (len == 0) return 1; // continue
+        // ERR_print_errors_cb place a new line at the end, but it doesn't say so in the API.
+        if (str[len - 1] == '\n') len -= 1;
+        if (!mIsFirst) {
+            mSs << '\n';
+        }
+        mSs << std::string_view(str, len);
+        mIsFirst = false;
+        return 1; // continue
+    }
+    std::stringstream mSs;
+    bool mIsFirst = true;
+};
+
 // Handles libssl's error queue.
 //
 // Call into any of its member functions to ensure the error queue is properly handled or cleared.
@@ -182,17 +204,10 @@
 
     // Stores the error queue in |ssl| into a string, then clears the error queue.
     std::string toString() {
-        std::stringstream ss;
-        ERR_print_errors_cb(
-                [](const char* str, size_t len, void* ctx) {
-                    auto ss = (std::stringstream*)ctx;
-                    (*ss) << std::string_view(str, len) << "\n";
-                    return 1; // continue
-                },
-                &ss);
+        auto ret = ErrorQueueString::toString();
         // Though ERR_print_errors_cb should have cleared it, it is okay to clear again.
         clear();
-        return ss.str();
+        return ret;
     }
 
     // |sslError| should be from Ssl::getError().
@@ -428,27 +443,73 @@
     }
 }
 
-class RpcTransportCtxTlsServer : public RpcTransportCtx {
+class RpcTransportCtxTls : public RpcTransportCtx {
 public:
-    static std::unique_ptr<RpcTransportCtxTlsServer> create();
-    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd acceptedFd,
+    template <typename Impl,
+              typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
+    static std::unique_ptr<RpcTransportCtxTls> create(
+            std::shared_ptr<RpcCertificateVerifier> verifier);
+    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
                                                FdTrigger* fdTrigger) const override;
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
 
-private:
+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::unique_ptr<RpcTransportCtxTlsServer> RpcTransportCtxTlsServer::create() {
+std::vector<uint8_t> RpcTransportCtxTls::getCertificate(RpcCertificateFormat format) const {
+    X509* x509 = SSL_CTX_get0_certificate(mCtx.get()); // does not own
+    return serializeCertificate(x509, format);
+}
+
+// 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";
+
+    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);
+
+    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(peerCert.get(), 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::shared_ptr<RpcCertificateVerifier> verifier) {
     bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
     TEST_AND_RETURN(nullptr, ctx != nullptr);
 
-    // Server use self-signing cert
     auto evp_pkey = makeKeyPairForSelfSignedCert();
     TEST_AND_RETURN(nullptr, evp_pkey != nullptr);
     auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays);
     TEST_AND_RETURN(nullptr, cert != nullptr);
     TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
     TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
+
+    // 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));
 
@@ -456,80 +517,61 @@
         SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
     }
 
-    auto rpcTransportTlsServerCtx = std::make_unique<RpcTransportCtxTlsServer>();
-    rpcTransportTlsServerCtx->mCtx = std::move(ctx);
-    return rpcTransportTlsServerCtx;
+    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;
 }
 
-std::unique_ptr<RpcTransport> RpcTransportCtxTlsServer::newTransport(
-        android::base::unique_fd acceptedFd, FdTrigger* fdTrigger) const {
+std::unique_ptr<RpcTransport> RpcTransportCtxTls::newTransport(android::base::unique_fd fd,
+                                                               FdTrigger* fdTrigger) const {
     bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
     TEST_AND_RETURN(nullptr, ssl != nullptr);
     Ssl wrapped(std::move(ssl));
 
-    wrapped.call(SSL_set_accept_state).errorQueue.clear();
-    TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, acceptedFd, fdTrigger));
-    return std::make_unique<RpcTransportTls>(std::move(acceptedFd), std::move(wrapped));
+    preHandshake(&wrapped);
+    TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, fd, fdTrigger));
+    return std::make_unique<RpcTransportTls>(std::move(fd), std::move(wrapped));
 }
 
-class RpcTransportCtxTlsClient : public RpcTransportCtx {
-public:
-    static std::unique_ptr<RpcTransportCtxTlsClient> create();
-    std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd connectedFd,
-                                               FdTrigger* fdTrigger) const override;
-
-private:
-    bssl::UniquePtr<SSL_CTX> mCtx;
+class RpcTransportCtxTlsServer : public RpcTransportCtxTls {
+protected:
+    void preHandshake(Ssl* ssl) const override {
+        ssl->call(SSL_set_accept_state).errorQueue.clear();
+    }
 };
 
-std::unique_ptr<RpcTransportCtxTlsClient> RpcTransportCtxTlsClient::create() {
-    bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
-    TEST_AND_RETURN(nullptr, ctx != nullptr);
-
-    // TODO(b/195166979): server should send certificate in a different channel, and client
-    //  should verify it here.
-    SSL_CTX_set_custom_verify(ctx.get(), SSL_VERIFY_PEER,
-                              [](SSL*, uint8_t*) -> ssl_verify_result_t { return ssl_verify_ok; });
-
-    // Require at least TLS 1.3
-    TEST_AND_RETURN(nullptr, SSL_CTX_set_min_proto_version(ctx.get(), TLS1_3_VERSION));
-
-    if constexpr (SHOULD_LOG_TLS_DETAIL) { // NOLINT
-        SSL_CTX_set_info_callback(ctx.get(), sslDebugLog);
+class RpcTransportCtxTlsClient : public RpcTransportCtxTls {
+protected:
+    void preHandshake(Ssl* ssl) const override {
+        ssl->call(SSL_set_connect_state).errorQueue.clear();
     }
-
-    auto rpcTransportTlsClientCtx = std::make_unique<RpcTransportCtxTlsClient>();
-    rpcTransportTlsClientCtx->mCtx = std::move(ctx);
-    return rpcTransportTlsClientCtx;
-}
-
-std::unique_ptr<RpcTransport> RpcTransportCtxTlsClient::newTransport(
-        android::base::unique_fd connectedFd, FdTrigger* fdTrigger) const {
-    bssl::UniquePtr<SSL> ssl(SSL_new(mCtx.get()));
-    TEST_AND_RETURN(nullptr, ssl != nullptr);
-    Ssl wrapped(std::move(ssl));
-
-    wrapped.call(SSL_set_connect_state).errorQueue.clear();
-    TEST_AND_RETURN(nullptr, setFdAndDoHandshake(&wrapped, connectedFd, fdTrigger));
-    return std::make_unique<RpcTransportTls>(std::move(connectedFd), std::move(wrapped));
-}
+};
 
 } // namespace
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
-    return android::RpcTransportCtxTlsServer::create();
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier);
 }
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
-    return android::RpcTransportCtxTlsClient::create();
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier);
 }
 
 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) {
+    if (verifier == nullptr) {
+        ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
+    return std::unique_ptr<RpcTransportCtxFactoryTls>(
+            new RpcTransportCtxFactoryTls(std::move(verifier)));
 }
 
 } // namespace android
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 0f8efd2..a87aa07 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -20,17 +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) == sizeof(uint64_t));
 
 /**
  * This is sent to an RpcServer in order to request a new connection is created,
@@ -38,11 +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) == 16);
 
 /**
  * In response to an RpcConnectionHeader which corresponds to a new session,
@@ -52,6 +60,7 @@
     uint32_t version; // maximum supported by callee <= maximum supported by caller
     uint8_t reserved[4];
 };
+static_assert(sizeof(RpcNewSessionResponse) == 8);
 
 #define RPC_CONNECTION_INIT_OKAY "cci"
 
@@ -64,6 +73,7 @@
     char msg[4];
     uint8_t reserved[4];
 };
+static_assert(sizeof(RpcOutgoingConnectionInit) == 8);
 
 enum : uint32_t {
     /**
@@ -105,6 +115,7 @@
 
     uint32_t reserved[2];
 };
+static_assert(sizeof(RpcWireHeader) == 16);
 
 struct RpcWireTransaction {
     RpcWireAddress address;
@@ -115,13 +126,15 @@
 
     uint32_t reserved[4];
 
-    uint8_t data[0];
+    uint8_t data[];
 };
+static_assert(sizeof(RpcWireTransaction) == 40);
 
 struct RpcWireReply {
     int32_t status; // transact return
-    uint8_t data[0];
+    uint8_t data[];
 };
+static_assert(sizeof(RpcWireReply) == 4);
 
 #pragma clang diagnostic pop
 
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 9c5ce67..ebb0d27 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -34,6 +34,9 @@
       "name": "binderStabilityTest"
     },
     {
+      "name": "binderRpcWireProtocolTest"
+    },
+    {
       "name": "binderUtilsHostTest"
     },
     {
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/rust/src/binder_rpc_unstable.hpp b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
similarity index 69%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
index 7932d0f..75f8753 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/aidl/android/content/pm/ApexStagedEvent.aidl
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.content.pm;
 
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+/**
+ * This event is designed for notification to native code listener about
+ * any changes to set of apex packages staged for installation on next boot.
+ *
+ * @hide
+ */
+parcelable ApexStagedEvent {
+  @utf8InCpp String[] stagedApexModuleNames;
 }
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index dc8d74c..c076be7 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -18,6 +18,8 @@
 package android.content.pm;
 
 import android.content.pm.IPackageChangeObserver;
+import android.content.pm.IStagedApexObserver;
+import android.content.pm.StagedApexInfo;
 
 /**
  * Parallel implementation of certain {@link PackageManager} APIs that need to
@@ -101,4 +103,24 @@
      * This does nothing if this observer was not already registered.
      */
     void unregisterPackageChangeObserver(in IPackageChangeObserver observer);
+
+    /** Register a observer for change in set of staged APEX ready for installation */
+    void registerStagedApexObserver(in IStagedApexObserver observer);
+
+    /**
+     * Unregister an existing staged apex observer.
+     * This does nothing if this observer was not already registered.
+     */
+    void unregisterStagedApexObserver(in IStagedApexObserver observer);
+
+    /**
+     * Get APEX module names of all APEX that are staged ready for installation
+     */
+    @utf8InCpp String[] getStagedApexModuleNames();
+
+    /**
+     * Get information of APEX which is staged ready for installation.
+     * Returns null if no such APEX is found.
+     */
+    StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
 }
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
similarity index 70%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
index 7932d0f..9906436 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/aidl/android/content/pm/IStagedApexObserver.aidl
@@ -14,13 +14,15 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.content.pm;
 
-extern "C" {
+import android.content.pm.ApexStagedEvent;
 
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+/**
+ * This is a non-blocking notification when set of staged apex has changed
+ *
+ * @hide
+ */
+oneway interface IStagedApexObserver {
+  void onApexStaged(in ApexStagedEvent event);
 }
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
similarity index 65%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
index 7932d0f..ece7989 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/aidl/android/content/pm/StagedApexInfo.aidl
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
-#pragma once
+package android.content.pm;
 
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+/**
+ * This object is designed for returning information regarding
+ * staged APEX that are ready to be installed on next reboot.
+ *
+ * @hide
+ */
+parcelable StagedApexInfo {
+  @utf8InCpp String moduleName;
+  @utf8InCpp String diskImagePath;
+  long versionCode;
+  @utf8InCpp String versionName;
 }
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 a6d35c7..9f2ce1e 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>
@@ -41,7 +40,7 @@
 {
 public:
     static sp<BpBinder> create(int32_t handle);
-    static sp<BpBinder> create(const sp<RpcSession>& session, const RpcAddress& address);
+    static sp<BpBinder> create(const sp<RpcSession>& session, uint64_t address);
 
     /**
      * Return value:
@@ -129,7 +128,7 @@
         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;
@@ -147,12 +146,12 @@
     };
     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);
@@ -194,6 +193,7 @@
     static uint32_t                             sBinderProxyCountHighWatermark;
     static uint32_t                             sBinderProxyCountLowWatermark;
     static bool                                 sBinderProxyThrottleCreate;
+    static std::unordered_map<int32_t,uint32_t> sLastLimitCallbackMap;
 };
 
 } // namespace android
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/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/rust/src/binder_rpc_unstable.hpp b/libs/binder/include/binder/RpcCertificateVerifier.h
similarity index 60%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/include/binder/RpcCertificateVerifier.h
index 7932d0f..97af31c 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/include/binder/RpcCertificateVerifier.h
@@ -16,11 +16,17 @@
 
 #pragma once
 
-extern "C" {
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
 
-struct AIBinder;
+namespace android {
 
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
+// 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;
+    virtual status_t verify(const X509* peerCert, uint8_t* outAlert) = 0;
+};
 
-}
+} // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index bf3e7e0..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>
@@ -134,6 +133,11 @@
     sp<IBinder> getRootObject();
 
     /**
+     * See RpcTransportCtx::getCertificate
+     */
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat);
+
+    /**
      * Runs join() in a background thread. Immediately returns.
      */
     void start();
@@ -170,7 +174,7 @@
 
 private:
     friend sp<RpcServer>;
-    explicit RpcServer(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+    explicit RpcServer(std::unique_ptr<RpcTransportCtx> ctx);
 
     void onSessionAllIncomingThreadsEnded(const sp<RpcSession>& session) override;
     void onSessionIncomingThreadEnded() override;
@@ -178,7 +182,7 @@
     static void establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd);
     status_t setupSocketServer(const RpcSocketAddress& address);
 
-    const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+    const std::unique_ptr<RpcTransportCtx> mCtx;
     bool mAgreedExperimental = false;
     size_t mMaxThreads = 1;
     std::optional<uint32_t> mProtocolVersion;
@@ -190,10 +194,9 @@
     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;
-    std::unique_ptr<RpcTransportCtx> mCtx;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 6e6eb74..71eb223 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>
@@ -51,8 +50,13 @@
  */
 class RpcSession final : public virtual RefBase {
 public:
-    static sp<RpcSession> make(
-            std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory = nullptr);
+    // Create an RpcSession with default configuration (raw sockets).
+    static sp<RpcSession> make();
+
+    // 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);
 
     /**
      * Set the maximum number of threads allowed to be made (for things like callbacks).
@@ -125,6 +129,11 @@
     status_t getRemoteMaxThreads(size_t* maxThreads);
 
     /**
+     * See RpcTransportCtx::getCertificate
+     */
+    std::vector<uint8_t> getCertificate(RpcCertificateFormat);
+
+    /**
      * Shuts down the service.
      *
      * For client sessions, wait can be true or false. For server sessions,
@@ -142,7 +151,7 @@
 
     [[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);
+    [[nodiscard]] status_t sendDecStrong(uint64_t address);
 
     ~RpcSession();
 
@@ -159,7 +168,7 @@
     friend sp<RpcSession>;
     friend RpcServer;
     friend RpcState;
-    explicit RpcSession(std::unique_ptr<RpcTransportCtxFactory> rpcTransportCtxFactory);
+    explicit RpcSession(std::unique_ptr<RpcTransportCtx> ctx);
 
     class EventListener : public virtual RefBase {
     public:
@@ -210,19 +219,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);
@@ -259,7 +270,7 @@
         bool mReentrant = false;
     };
 
-    const std::unique_ptr<RpcTransportCtxFactory> mRpcTransportCtxFactory;
+    const std::unique_ptr<RpcTransportCtx> mCtx;
 
     // On the other side of a session, for each of mOutgoingConnections here, there should
     // be one of mIncomingConnections on the other side (and vice versa).
@@ -279,7 +290,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 1b69519..1c0bb18 100644
--- a/libs/binder/include/binder/RpcTransport.h
+++ b/libs/binder/include/binder/RpcTransport.h
@@ -25,11 +25,14 @@
 #include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 
+#include <binder/RpcCertificateFormat.h>
+
 namespace android {
 
 class FdTrigger;
 
 // Represents a socket connection.
+// No thread-safety is guaranteed for these APIs.
 class RpcTransport {
 public:
     virtual ~RpcTransport() = default;
@@ -53,22 +56,32 @@
 };
 
 // Represents the context that generates the socket connection.
+// All APIs are thread-safe. See RpcTransportCtxRaw and RpcTransportCtxTls for details.
 class RpcTransportCtx {
 public:
     virtual ~RpcTransportCtx() = default;
 
     // Create a new RpcTransport object.
     //
-    // Implemenion details: for TLS, this function may incur I/O. |fdTrigger| may be used
+    // Implementation details: for TLS, this function may incur I/O. |fdTrigger| may be used
     // to interrupt I/O. This function blocks until handshake is finished.
     [[nodiscard]] virtual std::unique_ptr<RpcTransport> newTransport(
             android::base::unique_fd fd, FdTrigger *fdTrigger) const = 0;
 
+    // Return the preconfigured certificate of this context.
+    //
+    // Implementation details:
+    // - For raw sockets, this always returns empty string.
+    // - For TLS, this returns the certificate. See RpcTransportTls for details.
+    [[nodiscard]] virtual std::vector<uint8_t> getCertificate(
+            RpcCertificateFormat format) const = 0;
+
 protected:
     RpcTransportCtx() = default;
 };
 
 // A factory class that generates RpcTransportCtx.
+// All APIs are thread-safe.
 class RpcTransportCtxFactory {
 public:
     virtual ~RpcTransportCtxFactory() = default;
diff --git a/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
new file mode 100644
index 0000000..08f5eed
--- /dev/null
+++ b/libs/binder/include_rpc_unstable/binder_rpc_unstable.hpp
@@ -0,0 +1,44 @@
+/*
+ * 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
+
+extern "C" {
+
+struct AIBinder;
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server and joins before returning.
+bool RunRpcServer(AIBinder* service, unsigned int port);
+
+// Starts an RPC server on a given port and a given root IBinder object.
+// This function sets up the server, calls readyCallback with a given param, and
+// then joins before returning.
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+                          void* param);
+
+AIBinder* RpcClient(unsigned int cid, unsigned int port);
+
+// Connect to an RPC server with preconnected file descriptors.
+//
+// requestFd should connect to the server and return a valid file descriptor, or
+// -1 if connection fails.
+//
+// param will be passed to requestFd. Callers can use param to pass contexts to
+// the requestFd function.
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param);
+
+}
diff --git a/libs/binder/include_tls/binder/RpcCertificateUtils.h b/libs/binder/include_tls/binder/RpcCertificateUtils.h
new file mode 100644
index 0000000..8d07835
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcCertificateUtils.h
@@ -0,0 +1,34 @@
+/*
+ * 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>
+
+namespace android {
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+                                             RpcCertificateFormat format);
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+
+} // namespace android
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
index 531aaa9..f26a3e9 100644
--- a/libs/binder/include_tls/binder/RpcTransportTls.h
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <binder/RpcCertificateVerifier.h>
 #include <binder/RpcTransport.h>
 
 namespace android {
@@ -25,14 +26,17 @@
 // 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<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)
+          : mCertVerifier(std::move(verifier)){};
+
+    std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
 };
 
 } // namespace android
diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp
index bcb13ae..cad55fb 100644
--- a/libs/binder/libbinder_rpc_unstable.cpp
+++ b/libs/binder/libbinder_rpc_unstable.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <android/binder_libbinder.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
@@ -24,10 +25,12 @@
 using android::RpcSession;
 using android::status_t;
 using android::statusToString;
+using android::base::unique_fd;
 
 extern "C" {
 
-bool RunRpcServer(AIBinder* service, unsigned int port) {
+bool RunRpcServerCallback(AIBinder* service, unsigned int port, void (*readyCallback)(void* param),
+                          void* param) {
     auto server = RpcServer::make();
     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
     if (status_t status = server->setupVsockServer(port); status != OK) {
@@ -36,6 +39,8 @@
         return false;
     }
     server->setRootObject(AIBinder_toPlatformBinder(service));
+
+    if (readyCallback) readyCallback(param);
     server->join();
 
     // Shutdown any open sessions since server failed.
@@ -43,6 +48,10 @@
     return true;
 }
 
+bool RunRpcServer(AIBinder* service, unsigned int port) {
+    return RunRpcServerCallback(service, port, nullptr, nullptr);
+}
+
 AIBinder* RpcClient(unsigned int cid, unsigned int port) {
     auto session = RpcSession::make();
     if (status_t status = session->setupVsockClient(cid, port); status != OK) {
@@ -52,4 +61,14 @@
     }
     return AIBinder_fromPlatformBinder(session->getRootObject());
 }
+
+AIBinder* RpcPreconnectedClient(int (*requestFd)(void* param), void* param) {
+    auto session = RpcSession::make();
+    auto request = [=] { return unique_fd{requestFd(param)}; };
+    if (status_t status = session->setupPreconnectedClient(unique_fd{}, request); status != OK) {
+        LOG(ERROR) << "Failed to set up vsock client. error: " << statusToString(status).c_str();
+        return nullptr;
+    }
+    return AIBinder_fromPlatformBinder(session->getRootObject());
+}
 }
diff --git a/libs/binder/libbinder_rpc_unstable.map.txt b/libs/binder/libbinder_rpc_unstable.map.txt
index 3921a4d..e856569 100644
--- a/libs/binder/libbinder_rpc_unstable.map.txt
+++ b/libs/binder/libbinder_rpc_unstable.map.txt
@@ -1,7 +1,9 @@
 LIBBINDER_RPC_UNSTABLE_SHIM { # platform-only
   global:
     RunRpcServer;
+    RunRpcServerCallback;
     RpcClient;
+    RpcPreconnectedClient;
   local:
     *;
 };
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index b03e24c..9c04e58 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -117,6 +117,9 @@
             "30",
         ],
     },
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
     tidy: true,
     tidy_flags: [
         // Only check our headers
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index 11e9fc5..23db59e 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -172,7 +172,7 @@
 status_t ABBinder::onTransact(transaction_code_t code, const Parcel& data, Parcel* reply,
                               binder_flags_t flags) {
     if (isUserCommand(code)) {
-        if (!data.checkInterface(this)) {
+        if (getClass()->writeHeader && !data.checkInterface(this)) {
             return STATUS_BAD_TYPE;
         }
 
@@ -354,6 +354,12 @@
     clazz->onDump = onDump;
 }
 
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) {
+    CHECK(clazz != nullptr) << "disableInterfaceTokenHeader requires non-null clazz";
+
+    clazz->writeHeader = false;
+}
+
 void AIBinder_Class_setHandleShellCommand(AIBinder_Class* clazz,
                                           AIBinder_handleShellCommand handleShellCommand) {
     CHECK(clazz != nullptr) << "setHandleShellCommand requires non-null clazz";
@@ -606,7 +612,10 @@
     *in = new AParcel(binder);
     (*in)->get()->markForBinder(binder->getBinder());
 
-    status_t status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+    status_t status = android::OK;
+    if (clazz->writeHeader) {
+        status = (*in)->get()->writeInterfaceToken(clazz->getInterfaceDescriptor());
+    }
     binder_status_t ret = PruneStatusT(status);
 
     if (ret != STATUS_OK) {
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index f2c69b3..6509545 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -116,6 +116,9 @@
     const ::android::String16& getInterfaceDescriptor() const { return mWideInterfaceDescriptor; }
     const char* getInterfaceDescriptorUtf8() const { return mInterfaceDescriptor.c_str(); }
 
+    // whether a transaction header should be written
+    bool writeHeader = true;
+
     // required to be non-null, implemented for every class
     const AIBinder_Class_onCreate onCreate;
     const AIBinder_Class_onDestroy onDestroy;
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 78f2d3a..b881c2c 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -219,6 +219,21 @@
 void AIBinder_Class_setOnDump(AIBinder_Class* clazz, AIBinder_onDump onDump) __INTRODUCED_IN(29);
 
 /**
+ * This tells users of this class not to use a transaction header. By default, libbinder_ndk users
+ * read/write transaction headers implicitly (in the SDK, this must be manually written by
+ * android.os.Parcel#writeInterfaceToken, and it is read/checked with
+ * android.os.Parcel#enforceInterface). This method is provided in order to talk to legacy code
+ * which does not write an interface token. When this is disabled, type safety is reduced, so you
+ * must have a separate way of determining the binder you are talking to is the right type. Must
+ * be called before any instance of the class is created.
+ *
+ * Available since API level 33.
+ *
+ * \param clazz class to disable interface header on.
+ */
+void AIBinder_Class_disableInterfaceTokenHeader(AIBinder_Class* clazz) __INTRODUCED_IN(33);
+
+/**
  * Creates a new binder object of the appropriate class.
  *
  * Ownership of args is passed to this object. The lifecycle is implemented with AIBinder_incStrong
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 527b151..a2f5c93 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1163,6 +1163,41 @@
  * \return A parcel which is not related to any IBinder objects.
  */
 AParcel* AParcel_create() __INTRODUCED_IN(31);
+
+/**
+ * Marshals the raw bytes of the Parcel to a buffer.
+ *
+ * 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,
+ * across a network, etc). For that, you should use standard serialization or another kind of
+ * general serialization mechanism. The Parcel marshalled representation is highly optimized for
+ * local IPC, and as such does not attempt to maintain compatibility with data created in different
+ * versions of the platform.
+ *
+ * \param parcel The parcel of which to get the data.
+ * \param buffer The buffer to copy the raw bytes to.
+ * \param start The start position in the buffer to copy from.
+ * \param len The size of the data to copy, buffer size must be larger or equal to this.
+ *
+ * \return STATUS_OK on success, STATUS_INVALID_OPERATION if parcel contains binders or file
+ * descriptors. STATUS_BAD_VALUE if the buffer size is less than parcel size.
+ */
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len)
+        __INTRODUCED_IN(33);
+
+/**
+ * Set the data in the parcel to the raw bytes from the buffer.
+ *
+ * \param parcel The parcel to set data.
+ * \param buffer The data buffer to set.
+ * \param len The size of the data to set.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len)
+        __INTRODUCED_IN(33);
+
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 685ebb5..ac892db 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -141,6 +141,13 @@
     AParcel_reset;
 };
 
+LIBBINDER_NDK33 { # introduced=33
+  global:
+    AIBinder_Class_disableInterfaceTokenHeader;
+    AParcel_marshal;
+    AParcel_unmarshal;
+};
+
 LIBBINDER_NDK_PLATFORM {
   global:
     AParcel_getAllowFds;
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index b2f21c7..c320e8d 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -673,4 +673,32 @@
     return new AParcel(nullptr);
 }
 
+binder_status_t AParcel_marshal(const AParcel* parcel, uint8_t* buffer, size_t start, size_t len) {
+    if (parcel->get()->objectsCount()) {
+        return STATUS_INVALID_OPERATION;
+    }
+    int32_t dataSize = AParcel_getDataSize(parcel);
+    if (len > static_cast<size_t>(dataSize) || start > static_cast<size_t>(dataSize) - len) {
+        return STATUS_BAD_VALUE;
+    }
+    const uint8_t* internalBuffer = parcel->get()->data();
+    memcpy(buffer, internalBuffer + start, len);
+    return STATUS_OK;
+}
+
+binder_status_t AParcel_unmarshal(AParcel* parcel, const uint8_t* buffer, size_t len) {
+    status_t status = parcel->get()->setDataSize(len);
+    if (status != ::android::OK) {
+        return PruneStatusT(status);
+    }
+    parcel->get()->setDataPosition(0);
+
+    void* raw = parcel->get()->writeInplace(len);
+    if (raw == nullptr) {
+        return STATUS_NO_MEMORY;
+    }
+    memcpy(raw, buffer, len);
+    return STATUS_OK;
+}
+
 // @END
diff --git a/libs/binder/ndk/tests/Android.bp b/libs/binder/ndk/tests/Android.bp
index 488009f..8ee396e 100644
--- a/libs/binder/ndk/tests/Android.bp
+++ b/libs/binder/ndk/tests/Android.bp
@@ -71,7 +71,7 @@
     srcs: ["libbinder_ndk_unit_test.cpp"],
     static_libs: [
         "IBinderNdkUnitTest-cpp",
-        "IBinderNdkUnitTest-ndk_platform",
+        "IBinderNdkUnitTest-ndk",
     ],
     test_suites: [
         "general-tests",
@@ -88,8 +88,8 @@
     ],
     static_libs: [
         "IBinderVendorDoubleLoadTest-cpp",
-        "IBinderVendorDoubleLoadTest-ndk_platform",
-        "libbinder_aidl_test_stub-ndk_platform",
+        "IBinderVendorDoubleLoadTest-ndk",
+        "libbinder_aidl_test_stub-ndk",
     ],
     // critical that libbinder/libbinder_ndk are shared for VTS
     shared_libs: [
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 8d27eed..d9d7caf 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -109,7 +109,7 @@
 // TODO(b/184872979): remove once the Rust API is created.
 rust_bindgen {
     name: "libbinder_rpc_unstable_bindgen",
-    wrapper_src: "src/binder_rpc_unstable.hpp",
+    wrapper_src: ":libbinder_rpc_unstable_header",
     crate_name: "binder_rpc_unstable_bindgen",
     source_stem: "bindings",
     shared_libs: [
@@ -135,3 +135,23 @@
         "libbinder_ndk_sys",
     ],
 }
+
+rust_test {
+    name: "libbinder_ndk_bindgen_test",
+    srcs: [":libbinder_ndk_bindgen"],
+    crate_name: "binder_ndk_bindgen",
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    clippy_lints: "none",
+    lints: "none",
+}
+
+rust_test {
+    name: "libbinder_rpc_unstable_bindgen_test",
+    srcs: [":libbinder_rpc_unstable_bindgen"],
+    crate_name: "binder_rpc_unstable_bindgen",
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    clippy_lints: "none",
+    lints: "none",
+}
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..e7c3396 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;
         }
@@ -447,6 +454,41 @@
     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.
+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/proxy.rs b/libs/binder/rust/src/proxy.rs
index cdd7c08..b03ed49 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -38,7 +38,7 @@
 ///
 /// This struct encapsulates the generic C++ `sp<IBinder>` class. This wrapper
 /// is untyped; typed interface access is implemented by the AIDL compiler.
-pub struct SpIBinder(*mut sys::AIBinder);
+pub struct SpIBinder(ptr::NonNull<sys::AIBinder>);
 
 impl fmt::Debug for SpIBinder {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -74,7 +74,7 @@
     /// to an `AIBinder`, which will remain valid for the entire lifetime of the
     /// `SpIBinder` (we keep a strong reference, and only decrement on drop).
     pub(crate) unsafe fn from_raw(ptr: *mut sys::AIBinder) -> Option<Self> {
-        ptr.as_mut().map(|p| Self(p))
+        ptr::NonNull::new(ptr).map(Self)
     }
 
     /// Extract a raw `AIBinder` pointer from this wrapper.
@@ -88,7 +88,7 @@
     /// The SpIBinder object retains ownership of the AIBinder and the caller
     /// should not attempt to free the returned pointer.
     pub unsafe fn as_raw(&self) -> *mut sys::AIBinder {
-        self.0
+        self.0.as_ptr()
     }
 
     /// Return true if this binder object is hosted in a different process than
@@ -176,13 +176,13 @@
             // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
             // this pointer is always safe to pass to `AIBinder_lt` (null is
             // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(self.0, other.0)
+            sys::AIBinder_lt(self.0.as_ptr(), other.0.as_ptr())
         };
         let greater_than = unsafe {
             // Safety: SpIBinder always holds a valid `AIBinder` pointer, so
             // this pointer is always safe to pass to `AIBinder_lt` (null is
             // also safe to pass to this function, but we should never do that).
-            sys::AIBinder_lt(other.0, self.0)
+            sys::AIBinder_lt(other.0.as_ptr(), self.0.as_ptr())
         };
         if !less_than && !greater_than {
             Ordering::Equal
@@ -202,7 +202,7 @@
 
 impl PartialEq for SpIBinder {
     fn eq(&self, other: &Self) -> bool {
-        ptr::eq(self.0, other.0)
+        ptr::eq(self.0.as_ptr(), other.0.as_ptr())
     }
 }
 
@@ -214,7 +214,7 @@
             // Safety: Cloning a strong reference must increment the reference
             // count. We are guaranteed by the `SpIBinder` constructor
             // invariants that `self.0` is always a valid `AIBinder` pointer.
-            sys::AIBinder_incStrong(self.0);
+            sys::AIBinder_incStrong(self.0.as_ptr());
         }
         Self(self.0)
     }
@@ -443,7 +443,7 @@
 ///
 /// This struct encapsulates the generic C++ `wp<IBinder>` class. This wrapper
 /// is untyped; typed interface access is implemented by the AIDL compiler.
-pub struct WpIBinder(*mut sys::AIBinder_Weak);
+pub struct WpIBinder(ptr::NonNull<sys::AIBinder_Weak>);
 
 impl fmt::Debug for WpIBinder {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -470,8 +470,7 @@
             // valid pointer to an `AIBinder`.
             sys::AIBinder_Weak_new(binder.as_native_mut())
         };
-        assert!(!ptr.is_null());
-        Self(ptr)
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_new"))
     }
 
     /// Promote this weak reference to a strong reference to the binder object.
@@ -481,7 +480,7 @@
             // can pass this pointer to `AIBinder_Weak_promote`. Returns either
             // null or an AIBinder owned by the caller, both of which are valid
             // to pass to `SpIBinder::from_raw`.
-            let ptr = sys::AIBinder_Weak_promote(self.0);
+            let ptr = sys::AIBinder_Weak_promote(self.0.as_ptr());
             SpIBinder::from_raw(ptr)
         }
     }
@@ -496,13 +495,9 @@
             //
             // We get ownership of the returned pointer, so can construct a new
             // WpIBinder object from it.
-            sys::AIBinder_Weak_clone(self.0)
+            sys::AIBinder_Weak_clone(self.0.as_ptr())
         };
-        assert!(
-            !ptr.is_null(),
-            "Unexpected null pointer from AIBinder_Weak_clone"
-        );
-        Self(ptr)
+        Self(ptr::NonNull::new(ptr).expect("Unexpected null pointer from AIBinder_Weak_clone"))
     }
 }
 
@@ -513,14 +508,14 @@
             // so this pointer is always safe to pass to `AIBinder_Weak_lt`
             // (null is also safe to pass to this function, but we should never
             // do that).
-            sys::AIBinder_Weak_lt(self.0, other.0)
+            sys::AIBinder_Weak_lt(self.0.as_ptr(), other.0.as_ptr())
         };
         let greater_than = unsafe {
             // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer,
             // so this pointer is always safe to pass to `AIBinder_Weak_lt`
             // (null is also safe to pass to this function, but we should never
             // do that).
-            sys::AIBinder_Weak_lt(other.0, self.0)
+            sys::AIBinder_Weak_lt(other.0.as_ptr(), self.0.as_ptr())
         };
         if !less_than && !greater_than {
             Ordering::Equal
@@ -551,7 +546,7 @@
         unsafe {
             // Safety: WpIBinder always holds a valid `AIBinder_Weak` pointer, so we
             // know this pointer is safe to pass to `AIBinder_Weak_delete` here.
-            sys::AIBinder_Weak_delete(self.0);
+            sys::AIBinder_Weak_delete(self.0.as_ptr());
         }
     }
 }
@@ -716,10 +711,10 @@
 /// `AIBinder`, so we can trivially extract this pointer here.
 unsafe impl AsNative<sys::AIBinder> for SpIBinder {
     fn as_native(&self) -> *const sys::AIBinder {
-        self.0
+        self.0.as_ptr()
     }
 
     fn as_native_mut(&mut self) -> *mut sys::AIBinder {
-        self.0
+        self.0.as_ptr()
     }
 }
diff --git a/libs/binder/rust/tests/Android.bp b/libs/binder/rust/tests/Android.bp
index 607860f..ecc61f4 100644
--- a/libs/binder/rust/tests/Android.bp
+++ b/libs/binder/rust/tests/Android.bp
@@ -50,7 +50,7 @@
         "libbinder_ndk",
     ],
     static_libs: [
-        "IBinderRustNdkInteropTest-ndk_platform",
+        "IBinderRustNdkInteropTest-ndk",
         "libbinder_ndk_rust_interop",
     ],
     test_suites: ["general-tests"],
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 24afcf6..1968058 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: {
@@ -145,10 +148,12 @@
     defaults: [
         "binder_test_defaults",
         "libbinder_ndk_host_user",
+        "libbinder_tls_shared_deps",
     ],
 
     srcs: [
         "binderRpcTest.cpp",
+        "RpcCertificateVerifierSimple.cpp",
     ],
     shared_libs: [
         "libbinder",
@@ -159,8 +164,9 @@
         "liblog",
     ],
     static_libs: [
+        "libbinder_tls_static",
         "binderRpcTestIface-cpp",
-        "binderRpcTestIface-ndk_platform",
+        "binderRpcTestIface-ndk",
     ],
     test_suites: ["general-tests"],
     require_root: true,
@@ -188,6 +194,33 @@
 }
 
 cc_test {
+    name: "binderRpcWireProtocolTest",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        android: {
+            test_suites: ["vts"],
+        },
+    },
+    defaults: [
+        "binder_test_defaults",
+    ],
+    srcs: [
+        "binderRpcWireProtocolTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libutils",
+        "libcutils",
+        "liblog",
+    ],
+    test_suites: ["general-tests"],
+}
+
+cc_test {
     name: "binderThroughputTest",
     defaults: ["binder_test_defaults"],
     srcs: ["binderThroughputTest.cpp"],
@@ -296,7 +329,7 @@
     ],
     static_libs: [
         "binderStabilityTestIface-cpp",
-        "binderStabilityTestIface-ndk_platform",
+        "binderStabilityTestIface-ndk",
     ],
 
     test_suites: ["device-tests", "vts"],
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/BinderRpcTestClientInfo.aidl
similarity index 78%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/tests/BinderRpcTestClientInfo.aidl
index 7932d0f..b4baebc 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/BinderRpcTestClientInfo.aidl
@@ -14,13 +14,8 @@
  * limitations under the License.
  */
 
-#pragma once
+import ParcelableCertificateData;
 
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable BinderRpcTestClientInfo {
+    ParcelableCertificateData[] certs;
 }
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/BinderRpcTestServerInfo.aidl
similarity index 78%
copy from libs/binder/rust/src/binder_rpc_unstable.hpp
copy to libs/binder/tests/BinderRpcTestServerInfo.aidl
index 7932d0f..00dc0bc 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/BinderRpcTestServerInfo.aidl
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-#pragma once
+import ParcelableCertificateData;
 
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable BinderRpcTestServerInfo {
+    long port;
+    ParcelableCertificateData cert;
 }
diff --git a/libs/binder/rust/src/binder_rpc_unstable.hpp b/libs/binder/tests/ParcelableCertificateData.aidl
similarity index 78%
rename from libs/binder/rust/src/binder_rpc_unstable.hpp
rename to libs/binder/tests/ParcelableCertificateData.aidl
index 7932d0f..38c382e 100644
--- a/libs/binder/rust/src/binder_rpc_unstable.hpp
+++ b/libs/binder/tests/ParcelableCertificateData.aidl
@@ -14,13 +14,6 @@
  * limitations under the License.
  */
 
-#pragma once
-
-extern "C" {
-
-struct AIBinder;
-
-bool RunRpcServer(AIBinder* service, unsigned int port);
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-
+parcelable ParcelableCertificateData {
+    byte[] data;
 }
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.cpp b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
new file mode 100644
index 0000000..4694d1b
--- /dev/null
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "RpcCertificateVerifierSimple"
+#include <log/log.h>
+
+#include <binder/RpcCertificateUtils.h>
+
+#include "RpcCertificateVerifierSimple.h"
+
+namespace android {
+
+status_t RpcCertificateVerifierSimple::verify(const X509* peerCert, uint8_t* outAlert) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (const auto& trustedCert : mTrustedPeerCertificates) {
+        if (0 == X509_cmp(trustedCert.get(), peerCert)) {
+            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/RpcCertificateVerifierSimple.h b/libs/binder/tests/RpcCertificateVerifierSimple.h
new file mode 100644
index 0000000..1f2e531
--- /dev/null
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.h
@@ -0,0 +1,53 @@
+/*
+ * 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 <mutex>
+#include <string_view>
+#include <vector>
+
+#include <openssl/ssl.h>
+
+#include <binder/RpcCertificateFormat.h>
+#include <binder/RpcCertificateVerifier.h>
+
+namespace android {
+
+// 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 X509*, 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;
+};
+
+} // namespace android
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/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 15ccae9..a4e37ad 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>
@@ -31,6 +33,7 @@
 #include <binder/RpcSession.h>
 #include <binder/RpcTransport.h>
 #include <binder/RpcTransportRaw.h>
+#include <binder/RpcTransportTls.h>
 #include <gtest/gtest.h>
 
 #include <chrono>
@@ -39,14 +42,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 "RpcCertificateVerifierSimple.h"
 
 using namespace std::chrono_literals;
+using testing::AssertionFailure;
+using testing::AssertionResult;
+using testing::AssertionSuccess;
 
 namespace android {
 
@@ -54,16 +63,23 @@
               RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
 const char* kLocalInetAddress = "127.0.0.1";
 
-enum class RpcSecurity { RAW };
+enum class RpcSecurity { RAW, TLS };
 
 static inline std::vector<RpcSecurity> RpcSecurityValues() {
-    return {RpcSecurity::RAW};
+    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) {
     switch (rpcSecurity) {
         case RpcSecurity::RAW:
             return RpcTransportCtxFactoryRaw::make();
+        case RpcSecurity::TLS: {
+            if (verifier == nullptr) {
+                verifier = std::make_shared<RpcCertificateVerifierSimple>();
+            }
+            return RpcTransportCtxFactoryTls::make(std::move(verifier));
+        }
         default:
             LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
     }
@@ -301,14 +317,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);
         }
@@ -319,16 +338,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() {
@@ -431,16 +454,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;
 }
@@ -458,6 +482,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(
@@ -469,11 +524,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);
@@ -498,7 +554,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);
 
@@ -509,23 +578,41 @@
                 }),
         };
 
-        // 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));
+        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;
@@ -538,7 +625,7 @@
                     if (status == OK) goto success;
                     break;
                 case SocketType::INET:
-                    status = session->setupInetClient("127.0.0.1", outPort);
+                    status = session->setupInetClient("127.0.0.1", serverInfo.port);
                     if (status == OK) goto success;
                     break;
                 default:
@@ -1211,8 +1298,10 @@
     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();
 
@@ -1281,7 +1370,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()));
@@ -1346,6 +1434,314 @@
 INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
                         BinderRpcSimple::PrintTestParam);
 
+class RpcTransportTest
+      : public ::testing::TestWithParam<std::tuple<SocketType, RpcSecurity, RpcCertificateFormat>> {
+public:
+    using ConnectToServer = std::function<base::unique_fd()>;
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [socketType, rpcSecurity, certificateFormat] = info.param;
+        return PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString() + "_" +
+                PrintToString(certificateFormat);
+    }
+    void TearDown() override {
+        for (auto& server : mServers) server->shutdown();
+    }
+
+    // A server that handles client socket connections.
+    class Server {
+    public:
+        explicit Server() {}
+        Server(Server&&) = default;
+        ~Server() { shutdown(); }
+        [[nodiscard]] AssertionResult setUp() {
+            auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+            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)->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
+            std::string message(kMessage);
+            ASSERT_EQ(OK,
+                      serverTransport->interruptableWriteFully(mFdTrigger.get(), message.data(),
+                                                               message.size()));
+        }
+        void shutdown() {
+            mFdTrigger->trigger();
+            if (mThread != nullptr) {
+                mThread->join();
+                mThread = nullptr;
+            }
+        }
+
+    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;
+    };
+
+    class Client {
+    public:
+        explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
+        Client(Client&&) = default;
+        [[nodiscard]] AssertionResult setUp() {
+            auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+            mFd = mConnectToServer();
+            if (!mFd.ok()) return AssertionFailure() << "Cannot connect to server";
+            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;
+        }
+        void run(bool handshakeOk = true, bool readOk = true) {
+            auto clientTransport = mCtx->newTransport(std::move(mFd), mFdTrigger.get());
+            if (clientTransport == nullptr) {
+                ASSERT_FALSE(handshakeOk) << "newTransport returns nullptr, but it shouldn't";
+                return;
+            }
+            ASSERT_TRUE(handshakeOk) << "newTransport does not return nullptr, but it should";
+            std::string expectedMessage(kMessage);
+            std::string readMessage(expectedMessage.size(), '\0');
+            status_t readStatus =
+                    clientTransport->interruptableReadFully(mFdTrigger.get(), readMessage.data(),
+                                                            readMessage.size());
+            if (readOk) {
+                ASSERT_EQ(OK, readStatus);
+                ASSERT_EQ(readMessage, expectedMessage);
+            } else {
+                ASSERT_NE(OK, readStatus);
+            }
+        }
+
+    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>();
+    };
+
+    // Make A trust B.
+    template <typename A, typename B>
+    status_t trust(A* a, B* b) {
+        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        if (rpcSecurity != RpcSecurity::TLS) return OK;
+        auto bCert = b->getCtx()->getCertificate(certificateFormat);
+        return a->getCertVerifier()->addTrustedPeerCertificate(certificateFormat, bCert);
+    }
+
+    static constexpr const char* kMessage = "hello";
+    std::vector<std::unique_ptr<Server>> mServers;
+};
+
+TEST_P(RpcTransportTest, GoodCertificate) {
+    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(server->setUp());
+
+    Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp());
+
+    ASSERT_EQ(OK, trust(&client, server));
+    ASSERT_EQ(OK, trust(server, &client));
+
+    server->start();
+    client.run();
+}
+
+TEST_P(RpcTransportTest, MultipleClients) {
+    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(server->setUp());
+
+    std::vector<Client> clients;
+    for (int i = 0; i < 2; i++) {
+        auto& client = clients.emplace_back(server->getConnectToServerFn());
+        ASSERT_TRUE(client.setUp());
+        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 = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(untrustedServer->setUp());
+
+    Client client(untrustedServer->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp());
+
+    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 = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(validServer->setUp());
+
+    auto maliciousServer = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(maliciousServer->setUp());
+
+    Client client(maliciousServer->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp());
+
+    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 = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(server->setUp());
+
+    Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp());
+
+    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 = mServers.emplace_back(std::make_unique<Server>()).get();
+    ASSERT_TRUE(server->setUp());
+
+    Client validClient(server->getConnectToServerFn());
+    ASSERT_TRUE(validClient.setUp());
+    Client maliciousClient(server->getConnectToServerFn());
+    ASSERT_TRUE(maliciousClient.setUp());
+
+    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);
+}
+
+std::vector<RpcCertificateFormat> testRpcCertificateFormats() {
+    return {
+            RpcCertificateFormat::PEM,
+            RpcCertificateFormat::DER,
+    };
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, RpcTransportTest,
+                        ::testing::Combine(::testing::ValuesIn(testSocketTypes(false)),
+                                           ::testing::ValuesIn(RpcSecurityValues()),
+                                           ::testing::ValuesIn(testRpcCertificateFormats())),
+                        RpcTransportTest::PrintParamInfo);
+
 } // namespace android
 
 int main(int argc, char** argv) {
diff --git a/libs/binder/tests/binderRpcWireProtocolTest.cpp b/libs/binder/tests/binderRpcWireProtocolTest.cpp
new file mode 100644
index 0000000..a807afa
--- /dev/null
+++ b/libs/binder/tests/binderRpcWireProtocolTest.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 <android-base/hex.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <binder/Parcel.h>
+#include <binder/RpcSession.h>
+#include <binder/Status.h>
+#include <gtest/gtest.h>
+
+#include "../Debug.h"
+
+namespace android {
+
+static const int32_t kInt32Array[] = {-1, 0, 17};
+static const uint8_t kByteArray[] = {0, 17, 255};
+enum EnumInt8 : int8_t { Int8A, Int8B };
+enum EnumInt32 : int32_t { Int32A, Int32B };
+enum EnumInt64 : int64_t { Int64A, Int64B };
+struct AParcelable : Parcelable {
+    status_t writeToParcel(Parcel* parcel) const { return parcel->writeInt32(37); }
+    status_t readFromParcel(const Parcel*) { return OK; }
+};
+
+// clang-format off
+constexpr size_t kFillFunIndexLineBase = __LINE__ + 2;
+static const std::vector<std::function<void(Parcel* p)>> kFillFuns {
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInterfaceToken(String16(u"tok"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(-1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32(17)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint32(10003)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(-1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64(17)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64(10003)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(0.0f)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(0.1f)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloat(9.1f)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(0.0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(0.1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDouble(9.1)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("")); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("a")); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCString("baba")); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8(""))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8("a"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString8(String8("baba"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u""))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u"a"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16(String16(u"baba"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinder(nullptr)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Array(arraysize(kInt32Array), kInt32Array)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteArray(arraysize(kByteArray), kByteArray)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBool(true)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBool(false)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('a')); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('?')); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeChar('\0')); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(-128)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(0)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByte(127)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string(""))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string("a"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::string("abab"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::nullopt)); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>(""))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>("a"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8AsUtf16(std::optional<std::string>("abab"))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<int8_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<int8_t>>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<int8_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<int8_t>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<uint8_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::optional<std::vector<uint8_t>>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<uint8_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeByteVector(std::vector<uint8_t>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::optional<std::vector<int32_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::optional<std::vector<int32_t>>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::vector<int32_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt32Vector(std::vector<int32_t>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::optional<std::vector<int64_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::optional<std::vector<int64_t>>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::vector<int64_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeInt64Vector(std::vector<int64_t>({-1, 0, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::optional<std::vector<uint64_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::optional<std::vector<uint64_t>>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::vector<uint64_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUint64Vector(std::vector<uint64_t>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::optional<std::vector<float>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::optional<std::vector<float>>({0.0f, 0.1f, 9.1f}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::vector<float>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeFloatVector(std::vector<float>({0.0f, 0.1f, 9.1f}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::optional<std::vector<double>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::optional<std::vector<double>>({0.0, 0.1, 9.1}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::vector<double>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeDoubleVector(std::vector<double>({0.0, 0.1, 9.1}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::optional<std::vector<bool>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::optional<std::vector<bool>>({true, false}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::vector<bool>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeBoolVector(std::vector<bool>({true, false}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::optional<std::vector<char16_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::optional<std::vector<char16_t>>({'a', '\0', '?'}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::vector<char16_t>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeCharVector(std::vector<char16_t>({'a', '\0', '?'}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::optional<std::vector<std::optional<String16>>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::optional<std::vector<std::optional<String16>>>({std::nullopt, String16(), String16(u"a")}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::vector<std::optional<String16>>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeString16Vector(std::vector<std::optional<String16>>({std::nullopt, String16(), String16(u"a")}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::optional<std::vector<std::optional<std::string>>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::optional<std::vector<std::optional<std::string>>>({std::nullopt, std::string(), std::string("a")}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::vector<std::optional<std::string>>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeUtf8VectorAsUtf16Vector(std::vector<std::optional<std::string>>({std::nullopt, std::string(), std::string("a")}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::optional<std::vector<sp<IBinder>>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::optional<std::vector<sp<IBinder>>>({nullptr}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::vector<sp<IBinder>>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeStrongBinderVector(std::vector<sp<IBinder>>({nullptr}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt8>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt8>>({Int8A, Int8B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt8>({Int8A, Int8B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt32>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt32>>({Int32A, Int32B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt32>({Int32A, Int32B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt64>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::optional<std::vector<EnumInt64>>({Int64A, Int64B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeEnumVector(std::vector<EnumInt64>({Int64A, Int64B}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::optional<std::vector<std::optional<AParcelable>>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::optional<std::vector<std::optional<AParcelable>>>({AParcelable()}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelableVector(std::vector<AParcelable>({AParcelable()}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeNullableParcelable(std::optional<AParcelable>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeNullableParcelable(std::optional<AParcelable>(AParcelable()))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeParcelable(AParcelable())); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::vector<int32_t>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::vector<AParcelable>({}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>(std::nullopt))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeVectorSize(std::optional<std::vector<int32_t>>({0, 1, 17}))); },
+    [](Parcel* p) { ASSERT_EQ(OK, p->writeNoException()); },
+    [](Parcel* p) { ASSERT_EQ(OK, binder::Status::ok().writeToParcel(p)); },
+    [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromExceptionCode(7, ":D").writeToParcel(p)); },
+    [](Parcel* p) { ASSERT_EQ(OK, binder::Status::fromServiceSpecificError(8, ":/").writeToParcel(p)); },
+};
+// clang-format on
+
+static void setParcelForRpc(Parcel* p, uint32_t version) {
+    auto session = RpcSession::make();
+    CHECK(session->setProtocolVersion(version));
+    CHECK_EQ(OK, session->addNullDebuggingClient());
+    p->markForRpc(session);
+}
+
+static std::string buildRepr(uint32_t version) {
+    std::string result;
+    for (size_t i = 0; i < kFillFuns.size(); i++) {
+        if (i != 0) result += "|";
+        Parcel p;
+        setParcelForRpc(&p, version);
+        kFillFuns[i](&p);
+
+        result += base::HexString(p.data(), p.dataSize());
+    }
+    return result;
+}
+
+static void checkRepr(const std::string& repr, uint32_t version) {
+    const std::string actualRepr = buildRepr(version);
+
+    auto expected = base::Split(repr, "|");
+    ASSERT_EQ(expected.size(), kFillFuns.size());
+
+    auto actual = base::Split(actualRepr, "|");
+    ASSERT_EQ(actual.size(), kFillFuns.size());
+
+    for (size_t i = 0; i < kFillFuns.size(); i++) {
+        EXPECT_EQ(expected[i], actual[i])
+                << "Format mismatch, see " __FILE__ " line " << (kFillFunIndexLineBase + i);
+    }
+
+    // same check as in the loop, but the above error is more clear to debug,
+    // and this error is more clear to be able to update the source file here.
+    EXPECT_EQ(repr, actualRepr);
+}
+
+const std::string kCurrentRepr =
+        "0300000074006f006b000000|ffffffff|00000000|11000000|00000000|01000000|13270000|"
+        "ffffffffffffffff|0000000000000000|1100000000000000|0000000000000000|0100000000000000|"
+        "1327000000000000|00000000|cdcccc3d|9a991141|0000000000000000|9a9999999999b93f|"
+        "3333333333332240|00000000|61000000|6261626100000000|0000000000000000|0100000061000000|"
+        "040000006261626100000000|0000000000000000|0100000061000000|"
+        "04000000620061006200610000000000|0000000000000000|03000000ffffffff0000000011000000|"
+        "030000000011ff00|01000000|00000000|61000000|3f000000|00000000|80ffffff|00000000|7f000000|"
+        "0000000000000000|0100000061000000|04000000610062006100620000000000|ffffffff|"
+        "0000000000000000|0100000061000000|04000000610062006100620000000000|ffffffff|"
+        "03000000ff001100|00000000|03000000ff001100|ffffffff|0300000000011100|00000000|"
+        "0300000000011100|ffffffff|03000000ffffffff0000000011000000|00000000|"
+        "03000000ffffffff0000000011000000|ffffffff|"
+        "03000000ffffffffffffffff00000000000000001100000000000000|00000000|"
+        "03000000ffffffffffffffff00000000000000001100000000000000|ffffffff|"
+        "03000000000000000000000001000000000000001100000000000000|00000000|"
+        "03000000000000000000000001000000000000001100000000000000|ffffffff|"
+        "0300000000000000cdcccc3d9a991141|00000000|0300000000000000cdcccc3d9a991141|ffffffff|"
+        "0300000000000000000000009a9999999999b93f3333333333332240|00000000|"
+        "0300000000000000000000009a9999999999b93f3333333333332240|ffffffff|"
+        "020000000100000000000000|00000000|020000000100000000000000|ffffffff|"
+        "0300000061000000000000003f000000|00000000|0300000061000000000000003f000000|ffffffff|"
+        "03000000ffffffff00000000000000000100000061000000|00000000|"
+        "03000000ffffffff00000000000000000100000061000000|ffffffff|"
+        "03000000ffffffff00000000000000000100000061000000|00000000|"
+        "03000000ffffffff00000000000000000100000061000000|ffffffff|010000000000000000000000|"
+        "00000000|010000000000000000000000|ffffffff|0200000000010000|0200000000010000|ffffffff|"
+        "020000000000000001000000|020000000000000001000000|ffffffff|"
+        "0200000000000000000000000100000000000000|0200000000000000000000000100000000000000|"
+        "ffffffff|010000000100000025000000|010000000100000025000000|00000000|0100000025000000|"
+        "0100000025000000|03000000|00000000|ffffffff|03000000|00000000|00000000|"
+        "07000000020000003a0044000000000000000000|f8ffffff020000003a002f00000000000000000008000000";
+
+TEST(RpcWire, CurrentVersion) {
+    checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION);
+}
+
+static_assert(RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL,
+              "you better update this test!");
+
+TEST(RpcWire, ReleaseBranchHasFrozenRpcWireProtocol) {
+    if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+        EXPECT_FALSE(base::GetProperty("ro.build.version.codename", "") == "REL")
+                << "Binder RPC wire protocol must be frozen on a release branch!";
+    }
+}
+
+TEST(RpcWire, IfNotExperimentalCodeHasNoExperimentalFeatures) {
+    if (RPC_WIRE_PROTOCOL_VERSION == RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL) {
+        GTEST_SKIP() << "Version is experimental, so experimental features are okay.";
+    }
+
+    // if we set the wire protocol version to experimental, none of the code
+    // should introduce a difference (if this fails, it means we have features
+    // which are enabled under experimental mode, but we aren't actually using
+    // or testing them!)
+    checkRepr(kCurrentRepr, RPC_WIRE_PROTOCOL_VERSION_EXPERIMENTAL);
+}
+
+} // namespace android
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index 1c75306..9323bd5 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -22,18 +22,19 @@
         "libbase",
         "libcutils",
         "liblog",
-        "libutils",
     ],
 
     target: {
         android: {
             shared_libs: [
                 "libbinder",
+                "libutils",
             ],
         },
         host: {
             static_libs: [
                 "libbinder",
+                "libutils",
             ],
         },
     },
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index a0032ae..cda9e19 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -52,14 +52,14 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
     ],
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) {
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 07760ab..26c874e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -89,7 +89,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
@@ -106,7 +106,7 @@
 
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk",
         "android.hardware.graphics.mapper@4.0",
         "libgralloctypes",
     ],
diff --git a/services/memtrackproxy/Android.bp b/services/memtrackproxy/Android.bp
index 7d78f3b..3233cc9 100644
--- a/services/memtrackproxy/Android.bp
+++ b/services/memtrackproxy/Android.bp
@@ -32,7 +32,7 @@
         "libcutils",
         "libutils",
         "android.hardware.memtrack@1.0",
-        "android.hardware.memtrack-V1-ndk_platform",
+        "android.hardware.memtrack-V1-ndk",
     ],
     srcs: [
         "MemtrackProxy.cpp",
@@ -45,6 +45,6 @@
     ],
     export_shared_lib_headers: [
         "android.hardware.memtrack@1.0",
-        "android.hardware.memtrack-V1-ndk_platform",
+        "android.hardware.memtrack-V1-ndk",
     ],
 }
diff --git a/services/memtrackproxy/test/Android.bp b/services/memtrackproxy/test/Android.bp
index f943761..1dc21bf 100644
--- a/services/memtrackproxy/test/Android.bp
+++ b/services/memtrackproxy/test/Android.bp
@@ -29,7 +29,7 @@
     shared_libs: [
         "libbinder_ndk",
         "libmemtrackproxy",
-        "android.hardware.memtrack-V1-ndk_platform",
+        "android.hardware.memtrack-V1-ndk",
     ],
     test_suites: ["general-tests"],
     require_root: true,
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 15744a1..81e39c7 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -53,7 +53,7 @@
         "libtrace_proto",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-V2-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.composer@2.1",
         "libandroid",