Merge "Remove vr_hwc."
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8173c89..f7d1dde 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -55,9 +55,6 @@
           "include-filter": "*RelativeZTest.*"
         }
       ]
-    },
-    {
-      "name": "libsurfaceflinger_unittest"
     }
   ]
 }
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index d09d3e8..18c267d 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -47,6 +47,9 @@
         "libutils",
         "server_configurable_flags",
     ],
+    static_libs: [
+        "libasync_safe",
+    ],
     export_shared_lib_headers: [
         "libbinder",
     ],
@@ -251,6 +254,7 @@
     ],
 
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libotapreoptparameters",
     ],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0cf50a3..204953c 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -36,6 +36,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <async_safe/log.h>
 #include <cutils/fs.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
@@ -727,7 +728,8 @@
 
         if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) {
             if (errno != EWOULDBLOCK) {
-                PLOG(WARNING) << "Error locking profile " << package_name;
+                async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error locking profile %s: %d",
+                        package_name.c_str(), errno);
             }
             // This implies that the app owning this profile is running
             // (and has acquired the lock).
@@ -735,13 +737,15 @@
             // The app never acquires the lock for the reference profiles of primary apks.
             // Only dex2oat from installd will do that. Since installd is single threaded
             // we should not see this case. Nevertheless be prepared for it.
-            PLOG(WARNING) << "Failed to flock " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Failed to flock %s: %d",
+                    package_name.c_str(), errno);
             return false;
         }
 
         bool truncated = ftruncate(out_fd.get(), 0) == 0;
         if (!truncated) {
-            PLOG(WARNING) << "Could not truncate " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Could not truncate %s: %d",
+                    package_name.c_str(), errno);
         }
 
         // Copy over data.
@@ -755,7 +759,8 @@
             write(out_fd.get(), buffer, bytes);
         }
         if (flock(out_fd.get(), LOCK_UN) != 0) {
-            PLOG(WARNING) << "Error unlocking profile " << package_name;
+            async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Error unlocking profile %s: %d",
+                    package_name.c_str(), errno);
         }
         // Use _exit since we don't want to run the global destructors in the child.
         // b/62597429
@@ -1513,7 +1518,8 @@
 
         // Validate the path structure.
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
-            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(kSecondaryDexDexoptAnalyzerSkippedValidatePath);
         }
 
@@ -1809,7 +1815,8 @@
         drop_capabilities(uid);
 
         if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
-            PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "flock(%s) failed",
+                    out_oat.path().c_str());
             _exit(DexoptReturnCodes::kFlock);
         }
 
@@ -1904,7 +1911,8 @@
         const char* volume_uuid_cstr = volume_uuid ? volume_uuid->c_str() : nullptr;
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
                 uid, storage_flag)) {
-            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(kReconcileSecondaryDexValidationError);
         }
 
@@ -1917,7 +1925,8 @@
             case kSecondaryDexAccessIOError: _exit(kReconcileSecondaryDexAccessIOError);
             case kSecondaryDexAccessPermissionError: _exit(kReconcileSecondaryDexValidationError);
             default:
-                LOG(ERROR) << "Unexpected result from check_secondary_dex_access: " << access_check;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                        "Unexpected result from check_secondary_dex_access: %d", access_check);
                 _exit(kReconcileSecondaryDexValidationError);
         }
 
@@ -1930,7 +1939,7 @@
             std::string error_msg;
             if (!create_secondary_dex_oat_layout(
                     dex_path,isas[i], oat_dir, oat_isa_dir, oat_path, &error_msg)) {
-                LOG(ERROR) << error_msg;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "%s", error_msg.c_str());
                 _exit(kReconcileSecondaryDexValidationError);
             }
 
@@ -1957,7 +1966,8 @@
             result = rmdir_if_empty(oat_dir) && result;
         }
         if (!result) {
-            PLOG(ERROR) << "Failed to clean secondary dex artifacts for location " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
         }
         _exit(result ? kReconcileSecondaryDexCleanedUp : kReconcileSecondaryDexAccessIOError);
     }
@@ -2030,7 +2040,8 @@
         pipe_read.reset();
 
         if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr, uid, storage_flag)) {
-            LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Could not validate secondary dex path %s", dex_path.c_str());
             _exit(DexoptReturnCodes::kHashValidatePath);
         }
 
@@ -2041,6 +2052,8 @@
                 _exit(0);
             }
             PLOG(ERROR) << "Failed to open secondary dex " << dex_path;
+            async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                    "Failed to open secondary dex %s: %d", dex_path.c_str(), errno);
             _exit(DexoptReturnCodes::kHashOpenPath);
         }
 
@@ -2053,7 +2066,8 @@
             if (bytes_read == 0) {
                 break;
             } else if (bytes_read == -1) {
-                PLOG(ERROR) << "Failed to read secondary dex " << dex_path;
+                async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG,
+                        "Failed to read secondary dex %s: %d", dex_path.c_str(), errno);
                 _exit(DexoptReturnCodes::kHashReadDex);
             }
 
diff --git a/cmds/installd/file_parsing.h b/cmds/installd/file_parsing.h
index 3e2f815..88801ca 100644
--- a/cmds/installd/file_parsing.h
+++ b/cmds/installd/file_parsing.h
@@ -19,18 +19,14 @@
 
 #include <fstream>
 #include <functional>
-#include <string>
+#include <string_view>
+#include "android-base/unique_fd.h"
 
 namespace android {
 namespace installd {
 
-bool ParseFile(const std::string& strFile, std::function<bool (const std::string&)> parse) {
-    std::ifstream input_stream(strFile);
-
-    if (!input_stream.is_open()) {
-        return false;
-    }
-
+template<typename Func>
+bool ParseFile(std::istream& input_stream, Func parse) {
     while (!input_stream.eof()) {
         // Read the next line.
         std::string line;
@@ -54,6 +50,15 @@
     return true;
 }
 
+template<typename Func>
+bool ParseFile(std::string_view str_file, Func parse) {
+  std::ifstream ifs(str_file);
+  if (!ifs.is_open()) {
+    return false;
+  }
+  return ParseFile(ifs, parse);
+}
+
 }  // namespace installd
 }  // namespace android
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index ed31ad9..6aa32b8 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,6 +26,7 @@
 #include <sys/capability.h>
 #include <sys/prctl.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
 
 #include <android-base/logging.h>
 #include <android-base/macros.h>
@@ -36,6 +37,7 @@
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
 
+#include "android-base/file.h"
 #include "dexopt.h"
 #include "file_parsing.h"
 #include "globals.h"
@@ -195,38 +197,63 @@
         //   export NAME VALUE
         // For simplicity, don't respect string quotation. The values we are interested in can be
         // encoded without them.
-        // init.environ.rc and etc/classpath have the same format for
-        // environment variable exports and can be matched by the same regex.
+        //
+        // init.environ.rc and derive_classpath all have the same format for
+        // environment variable exports (since they are all meant to be read by
+        // init) and can be matched by the same regex.
+
+        std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+        auto parse_results = [&](auto& input) {
+          ParseFile(input, [&](const std::string& line) {
+              std::smatch export_match;
+              if (!std::regex_match(line, export_match, export_regex)) {
+                  return true;
+              }
+
+              if (export_match.size() != 3) {
+                  return true;
+              }
+
+              std::string name = export_match[1].str();
+              std::string value = export_match[2].str();
+
+              system_properties_.SetProperty(name, value);
+
+              return true;
+          });
+        };
+
         // TODO Just like with the system-properties above we really should have
         // common code between init and otapreopt to deal with reading these
         // things. See b/181182967
+        // There have been a variety of places the various env-vars have been
+        // over the years.  Expand or reduce this list as needed.
         static constexpr const char* kEnvironmentVariableSources[] = {
-                "/init.environ.rc", "/etc/classpath"
+                "/init.environ.rc",
         };
-
-        std::regex export_regex("\\s*export\\s+(\\S+)\\s+(\\S+)");
+        // First get everything from the static files.
         for (const char* env_vars_file : kEnvironmentVariableSources) {
-            bool parse_result = ParseFile(env_vars_file, [&](const std::string& line) {
-                std::smatch export_match;
-                if (!std::regex_match(line, export_match, export_regex)) {
-                    return true;
-                }
-
-                if (export_match.size() != 3) {
-                    return true;
-                }
-
-                std::string name = export_match[1].str();
-                std::string value = export_match[2].str();
-
-                system_properties_.SetProperty(name, value);
-
-                return true;
-            });
-            if (!parse_result) {
-                return false;
-            }
+          parse_results(env_vars_file);
         }
+
+        // Next get everything from derive_classpath, since we're already in the
+        // chroot it will get the new versions of any dependencies.
+        {
+          android::base::unique_fd fd(memfd_create("derive_classpath_temp", MFD_CLOEXEC));
+          if (!fd.ok()) {
+            LOG(ERROR) << "Unable to create fd for derive_classpath";
+            return false;
+          }
+          std::string memfd_file = StringPrintf("/proc/%d/fd/%d", getpid(), fd.get());
+          std::string error_msg;
+          if (!Exec({"/apex/com.android.sdkext/bin/derive_classpath", memfd_file}, &error_msg)) {
+            PLOG(ERROR) << "Running derive_classpath failed: " << error_msg;
+            return false;
+          }
+          std::ifstream ifs(memfd_file);
+          parse_results(ifs);
+        }
+
         if (system_properties_.GetProperty(kAndroidDataPathPropertyName) == nullptr) {
             return false;
         }
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index 83f01de..c62734a 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -275,6 +275,7 @@
     static constexpr const std::string_view kRequiredApexs[] = {
       "com.android.art",
       "com.android.runtime",
+      "com.android.sdkext",  // For derive_classpath
     };
     std::array<bool, arraysize(kRequiredApexs)> found_apexs{ false, false };
     DIR* apex_dir = opendir("/apex");
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index f67ab81..7082017 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -20,6 +20,7 @@
         "libcutils",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
@@ -44,6 +45,7 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
@@ -84,6 +86,7 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
@@ -124,6 +127,7 @@
         "server_configurable_flags",
     ],
     static_libs: [
+        "libasync_safe",
         "libdiskusage",
         "libinstalld",
         "liblog",
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index b429fb3..90db509 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -481,7 +481,12 @@
           name.c_str());
 
     std::thread([=] {
-        (void)base::SetProperty("ctl.interface_start", "aidl/" + name);
+        if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) {
+            LOG(INFO) << "Tried to start aidl service " << name
+                      << " as a lazy service, but was unable to. Usually this happens when a "
+                         "service is not installed, but if the service is intended to be used as a "
+                         "lazy service, then it may be configured incorrectly.";
+        }
     }).detach();
 }
 
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index d964d25..d5bdd1c 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -29,6 +29,16 @@
 
 namespace android {
 
+// Service implementations inherit from BBinder and IBinder, and this is frozen
+// in prebuilts.
+#ifdef __LP64__
+static_assert(sizeof(IBinder) == 24);
+static_assert(sizeof(BBinder) == 40);
+#else
+static_assert(sizeof(IBinder) == 12);
+static_assert(sizeof(BBinder) == 20);
+#endif
+
 // ---------------------------------------------------------------------------
 
 IBinder::IBinder()
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 98ca829..39d6a2e 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -78,7 +78,11 @@
 namespace android {
 
 // many things compile this into prebuilts on the stack
-static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+#ifdef __LP64__
+static_assert(sizeof(Parcel) == 120);
+#else
+static_assert(sizeof(Parcel) == 60);
+#endif
 
 static std::atomic<size_t> gParcelGlobalAllocCount;
 static std::atomic<size_t> gParcelGlobalAllocSize;
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
index 6eae5ef..670fd55 100644
--- a/libs/binder/PermissionCache.cpp
+++ b/libs/binder/PermissionCache.cpp
@@ -109,5 +109,10 @@
     return granted;
 }
 
+void PermissionCache::purgeCache() {
+    PermissionCache& pc(PermissionCache::getInstance());
+    pc.purge();
+}
+
 // ---------------------------------------------------------------------------
 } // namespace android
diff --git a/libs/binder/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index f2302f7..95eba87 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -18,12 +18,7 @@
 
 #include <binder/RpcConnection.h>
 
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
+#include <inttypes.h>
 #include <unistd.h>
 
 #include <string_view>
@@ -32,6 +27,7 @@
 #include <binder/Stability.h>
 #include <utils/String8.h>
 
+#include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
 
@@ -39,16 +35,9 @@
 extern "C" pid_t gettid();
 #endif
 
-#ifdef __BIONIC__
-#include <linux/vm_sockets.h>
-#endif
-
 namespace android {
 
 using base::unique_fd;
-using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
-
-RpcConnection::SocketAddress::~SocketAddress() {}
 
 RpcConnection::RpcConnection() {
     LOG_RPC_DETAIL("RpcConnection created %p", this);
@@ -67,125 +56,24 @@
     return sp<RpcConnection>::make();
 }
 
-class UnixSocketAddress : public RpcConnection::SocketAddress {
-public:
-    explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
-        unsigned int pathLen = strlen(path) + 1;
-        LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
-                            pathLen, path);
-        memcpy(mAddr.sun_path, path, pathLen);
-    }
-    virtual ~UnixSocketAddress() {}
-    std::string toString() const override {
-        return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
-                               mAddr.sun_path)
-                .c_str();
-    }
-    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
-    size_t addrSize() const override { return sizeof(mAddr); }
-
-private:
-    sockaddr_un mAddr;
-};
-
-bool RpcConnection::setupUnixDomainServer(const char* path) {
-    return setupSocketServer(UnixSocketAddress(path));
-}
-
-bool RpcConnection::addUnixDomainClient(const char* path) {
-    return addSocketClient(UnixSocketAddress(path));
+bool RpcConnection::setupUnixDomainClient(const char* path) {
+    return setupSocketClient(UnixSocketAddress(path));
 }
 
 #ifdef __BIONIC__
 
-class VsockSocketAddress : public RpcConnection::SocketAddress {
-public:
-    VsockSocketAddress(unsigned int cid, unsigned int port)
-          : mAddr({
-                    .svm_family = AF_VSOCK,
-                    .svm_port = port,
-                    .svm_cid = cid,
-            }) {}
-    virtual ~VsockSocketAddress() {}
-    std::string toString() const override {
-        return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
-    }
-    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
-    size_t addrSize() const override { return sizeof(mAddr); }
-
-private:
-    sockaddr_vm mAddr;
-};
-
-bool RpcConnection::setupVsockServer(unsigned int port) {
-    // realizing value w/ this type at compile time to avoid ubsan abort
-    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
-
-    return setupSocketServer(VsockSocketAddress(kAnyCid, port));
-}
-
-bool RpcConnection::addVsockClient(unsigned int cid, unsigned int port) {
-    return addSocketClient(VsockSocketAddress(cid, port));
+bool RpcConnection::setupVsockClient(unsigned int cid, unsigned int port) {
+    return setupSocketClient(VsockSocketAddress(cid, port));
 }
 
 #endif // __BIONIC__
 
-class InetSocketAddress : public RpcConnection::SocketAddress {
-public:
-    InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
-          : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
-    [[nodiscard]] std::string toString() const override {
-        return String8::format("%s:%u", mAddr, mPort).c_str();
-    }
-    [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
-    [[nodiscard]] size_t addrSize() const override { return mSize; }
-
-private:
-    const sockaddr* mSockAddr;
-    size_t mSize;
-    const char* mAddr;
-    unsigned int mPort;
-};
-
-AddrInfo GetAddrInfo(const char* addr, unsigned int port) {
-    addrinfo hint{
-            .ai_flags = 0,
-            .ai_family = AF_UNSPEC,
-            .ai_socktype = SOCK_STREAM,
-            .ai_protocol = 0,
-    };
-    addrinfo* aiStart = nullptr;
-    if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
-        ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
-        return AddrInfo(nullptr, nullptr);
-    }
-    if (aiStart == nullptr) {
-        ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
-        return AddrInfo(nullptr, nullptr);
-    }
-    return AddrInfo(aiStart, &freeaddrinfo);
-}
-
-bool RpcConnection::setupInetServer(unsigned int port) {
-    const char* kAddr = "127.0.0.1";
-
-    auto aiStart = GetAddrInfo(kAddr, port);
-    if (aiStart == nullptr) return false;
-    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
-        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
-        if (setupSocketServer(socketAddress)) return true;
-    }
-    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
-          port);
-    return false;
-}
-
-bool RpcConnection::addInetClient(const char* addr, unsigned int port) {
-    auto aiStart = GetAddrInfo(addr, port);
+bool RpcConnection::setupInetClient(const char* addr, unsigned int port) {
+    auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
     if (aiStart == nullptr) return false;
     for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
         InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, addr, port);
-        if (addSocketClient(socketAddress)) return true;
+        if (setupSocketClient(socketAddress)) return true;
     }
     ALOGE("None of the socket address resolved for %s:%u can be added as inet client.", addr, port);
     return false;
@@ -208,6 +96,11 @@
     return state()->getRootObject(socket.fd(), sp<RpcConnection>::fromExisting(this));
 }
 
+status_t RpcConnection::getMaxThreads(size_t* maxThreads) {
+    ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+    return state()->getMaxThreads(socket.fd(), sp<RpcConnection>::fromExisting(this), maxThreads);
+}
+
 status_t RpcConnection::transact(const RpcAddress& address, uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags) {
     ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this),
@@ -222,23 +115,28 @@
     return state()->sendDecStrong(socket.fd(), address);
 }
 
-void RpcConnection::join() {
-    // TODO(b/185167543): do this dynamically, instead of from a static number
-    // of threads
-    unique_fd clientFd(
-            TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
-    if (clientFd < 0) {
-        // If this log becomes confusing, should save more state from setupUnixDomainServer
-        // in order to output here.
-        ALOGE("Could not accept4 socket: %s", strerror(errno));
-        return;
+status_t RpcConnection::readId() {
+    {
+        std::lock_guard<std::mutex> _l(mSocketMutex);
+        LOG_ALWAYS_FATAL_IF(mForServer != nullptr, "Can only update ID for client.");
     }
 
-    LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+    int32_t id;
 
+    ExclusiveSocket socket(sp<RpcConnection>::fromExisting(this), SocketUse::CLIENT);
+    status_t status =
+            state()->getConnectionId(socket.fd(), sp<RpcConnection>::fromExisting(this), &id);
+    if (status != OK) return status;
+
+    LOG_RPC_DETAIL("RpcConnection %p has id %d", this, id);
+    mId = id;
+    return OK;
+}
+
+void RpcConnection::join(unique_fd client) {
     // must be registered to allow arbitrary client code executing commands to
     // be able to do nested calls (we can't only read from it)
-    sp<ConnectionSocket> socket = assignServerToThisThread(std::move(clientFd));
+    sp<ConnectionSocket> socket = assignServerToThisThread(std::move(client));
 
     while (true) {
         status_t error =
@@ -254,41 +152,49 @@
                         "bad state: socket object guaranteed to be in list");
 }
 
-void RpcConnection::setForServer(const wp<RpcServer>& server) {
-    mForServer = server;
-}
-
 wp<RpcServer> RpcConnection::server() {
     return mForServer;
 }
 
-bool RpcConnection::setupSocketServer(const SocketAddress& addr) {
-    LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcConnection can only have one server.");
+bool RpcConnection::setupSocketClient(const RpcSocketAddress& addr) {
+    {
+        std::lock_guard<std::mutex> _l(mSocketMutex);
+        LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
+                            "Must only setup connection once, but already has %zu clients",
+                            mClients.size());
+    }
 
-    unique_fd serverFd(
-            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
-    if (serverFd == -1) {
-        ALOGE("Could not create socket: %s", strerror(errno));
+    if (!setupOneSocketClient(addr)) return false;
+
+    // TODO(b/185167543): we should add additional connections dynamically
+    // instead of all at once.
+    // TODO(b/186470974): first risk of blocking
+    size_t numThreadsAvailable;
+    if (status_t status = getMaxThreads(&numThreadsAvailable); status != OK) {
+        ALOGE("Could not get max threads after initial connection to %s: %s",
+              addr.toString().c_str(), statusToString(status).c_str());
         return false;
     }
 
-    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
-        int savedErrno = errno;
-        ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+    if (status_t status = readId(); status != OK) {
+        ALOGE("Could not get connection id after initial connection to %s; %s",
+              addr.toString().c_str(), statusToString(status).c_str());
         return false;
     }
 
-    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
-        int savedErrno = errno;
-        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
-        return false;
+    // we've already setup one client
+    for (size_t i = 0; i + 1 < numThreadsAvailable; i++) {
+        // TODO(b/185167543): avoid race w/ accept4 not being called on server
+        for (size_t tries = 0; tries < 5; tries++) {
+            if (setupOneSocketClient(addr)) break;
+            usleep(10000);
+        }
     }
 
-    mServer = std::move(serverFd);
     return true;
 }
 
-bool RpcConnection::addSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr) {
     unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
     if (serverFd == -1) {
@@ -309,14 +215,19 @@
     return true;
 }
 
-void RpcConnection::addClient(unique_fd&& fd) {
+void RpcConnection::addClient(unique_fd fd) {
     std::lock_guard<std::mutex> _l(mSocketMutex);
     sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
     connection->fd = std::move(fd);
     mClients.push_back(connection);
 }
 
-sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd&& fd) {
+void RpcConnection::setForServer(const wp<RpcServer>& server, int32_t connectionId) {
+    mId = connectionId;
+    mForServer = server;
+}
+
+sp<RpcConnection::ConnectionSocket> RpcConnection::assignServerToThisThread(unique_fd fd) {
     std::lock_guard<std::mutex> _l(mSocketMutex);
     sp<ConnectionSocket> connection = sp<ConnectionSocket>::make();
     connection->fd = std::move(fd);
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 6dc4f95..5f024ca 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -19,6 +19,7 @@
 #include <sys/socket.h>
 #include <sys/un.h>
 
+#include <thread>
 #include <vector>
 
 #include <binder/Parcel.h>
@@ -26,6 +27,7 @@
 #include <log/log.h>
 #include "RpcState.h"
 
+#include "RpcSocketAddress.h"
 #include "RpcWireFormat.h"
 
 namespace android {
@@ -43,16 +45,68 @@
     mAgreedExperimental = true;
 }
 
-sp<RpcConnection> RpcServer::addClientConnection() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+bool RpcServer::setupUnixDomainServer(const char* path) {
+    return setupSocketServer(UnixSocketAddress(path));
+}
 
-    auto connection = RpcConnection::make();
-    connection->setForServer(sp<RpcServer>::fromExisting(this));
-    {
-        std::lock_guard<std::mutex> _l(mLock);
-        mConnections.push_back(connection);
+#ifdef __BIONIC__
+
+bool RpcServer::setupVsockServer(unsigned int port) {
+    // realizing value w/ this type at compile time to avoid ubsan abort
+    constexpr unsigned int kAnyCid = VMADDR_CID_ANY;
+
+    return setupSocketServer(VsockSocketAddress(kAnyCid, port));
+}
+
+#endif // __BIONIC__
+
+bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
+    const char* kAddr = "127.0.0.1";
+
+    if (assignedPort != nullptr) *assignedPort = 0;
+    auto aiStart = InetSocketAddress::getAddrInfo(kAddr, port);
+    if (aiStart == nullptr) return false;
+    for (auto ai = aiStart.get(); ai != nullptr; ai = ai->ai_next) {
+        InetSocketAddress socketAddress(ai->ai_addr, ai->ai_addrlen, kAddr, port);
+        if (!setupSocketServer(socketAddress)) {
+            continue;
+        }
+
+        LOG_ALWAYS_FATAL_IF(socketAddress.addr()->sa_family != AF_INET, "expecting inet");
+        sockaddr_in addr{};
+        socklen_t len = sizeof(addr);
+        if (0 != getsockname(mServer.get(), reinterpret_cast<sockaddr*>(&addr), &len)) {
+            int savedErrno = errno;
+            ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
+                  strerror(savedErrno));
+            return false;
+        }
+        LOG_ALWAYS_FATAL_IF(len != sizeof(addr), "Wrong socket type: len %zu vs len %zu",
+                            static_cast<size_t>(len), sizeof(addr));
+        unsigned int realPort = ntohs(addr.sin_port);
+        LOG_ALWAYS_FATAL_IF(port != 0 && realPort != port,
+                            "Requesting inet server on %s but it is set up on %u.",
+                            socketAddress.toString().c_str(), realPort);
+
+        if (assignedPort != nullptr) {
+            *assignedPort = realPort;
+        }
+
+        return true;
     }
-    return connection;
+    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
+          port);
+    return false;
+}
+
+void RpcServer::setMaxThreads(size_t threads) {
+    LOG_ALWAYS_FATAL_IF(threads <= 0, "RpcServer is useless without threads");
+    LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started");
+    mMaxThreads = threads;
+}
+
+size_t RpcServer::getMaxThreads() {
+    return mMaxThreads;
 }
 
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
@@ -65,4 +119,76 @@
     return mRootObject;
 }
 
+void RpcServer::join() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+
+    std::vector<std::thread> pool;
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+        LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
+        // TODO(b/185167543): support more than one client at once
+        mConnection = RpcConnection::make();
+        mConnection->setForServer(sp<RpcServer>::fromExisting(this), 42 /*placeholder id*/);
+
+        mStarted = true;
+            for (size_t i = 0; i < mMaxThreads; i++) {
+                pool.push_back(std::thread([=] {
+                    // TODO(b/185167543): do this dynamically, instead of from a static number
+                    // of threads
+                    unique_fd clientFd(TEMP_FAILURE_RETRY(
+                            accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
+                    if (clientFd < 0) {
+                        // If this log becomes confusing, should save more state from
+                        // setupUnixDomainServer in order to output here.
+                        ALOGE("Could not accept4 socket: %s", strerror(errno));
+                        return;
+                    }
+
+                    LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+                    mConnection->join(std::move(clientFd));
+                }));
+            }
+    }
+
+    // TODO(b/185167543): don't waste extra thread for join, and combine threads
+    // between clients
+    for (auto& t : pool) t.join();
+}
+
+std::vector<sp<RpcConnection>> RpcServer::listConnections() {
+    std::lock_guard<std::mutex> _l(mLock);
+    if (mConnection == nullptr) return {};
+    return {mConnection};
+}
+
+bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+    {
+        std::lock_guard<std::mutex> _l(mLock);
+        LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
+    }
+
+    unique_fd serverFd(
+            TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    if (serverFd == -1) {
+        ALOGE("Could not create socket: %s", strerror(errno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(bind(serverFd.get(), addr.addr(), addr.addrSize()))) {
+        int savedErrno = errno;
+        ALOGE("Could not bind socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    if (0 != TEMP_FAILURE_RETRY(listen(serverFd.get(), 1 /*backlog*/))) {
+        int savedErrno = errno;
+        ALOGE("Could not listen socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
+        return false;
+    }
+
+    mServer = std::move(serverFd);
+    return true;
+}
+
 } // namespace android
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
new file mode 100644
index 0000000..c6a06cf
--- /dev/null
+++ b/libs/binder/RpcSocketAddress.h
@@ -0,0 +1,122 @@
+/*
+ * 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 <string>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#endif
+
+namespace android {
+
+class RpcSocketAddress {
+public:
+    virtual ~RpcSocketAddress() {}
+    virtual std::string toString() const = 0;
+    virtual const sockaddr* addr() const = 0;
+    virtual size_t addrSize() const = 0;
+};
+
+class UnixSocketAddress : public RpcSocketAddress {
+public:
+    explicit UnixSocketAddress(const char* path) : mAddr({.sun_family = AF_UNIX}) {
+        unsigned int pathLen = strlen(path) + 1;
+        LOG_ALWAYS_FATAL_IF(pathLen > sizeof(mAddr.sun_path), "Socket path is too long: %u %s",
+                            pathLen, path);
+        memcpy(mAddr.sun_path, path, pathLen);
+    }
+    virtual ~UnixSocketAddress() {}
+    std::string toString() const override {
+        return String8::format("path '%.*s'", static_cast<int>(sizeof(mAddr.sun_path)),
+                               mAddr.sun_path)
+                .c_str();
+    }
+    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+    size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+    sockaddr_un mAddr;
+};
+
+#ifdef __BIONIC__
+
+class VsockSocketAddress : public RpcSocketAddress {
+public:
+    VsockSocketAddress(unsigned int cid, unsigned int port)
+          : mAddr({
+                    .svm_family = AF_VSOCK,
+                    .svm_port = port,
+                    .svm_cid = cid,
+            }) {}
+    virtual ~VsockSocketAddress() {}
+    std::string toString() const override {
+        return String8::format("cid %u port %u", mAddr.svm_cid, mAddr.svm_port).c_str();
+    }
+    const sockaddr* addr() const override { return reinterpret_cast<const sockaddr*>(&mAddr); }
+    size_t addrSize() const override { return sizeof(mAddr); }
+
+private:
+    sockaddr_vm mAddr;
+};
+
+#endif // __BIONIC__
+
+class InetSocketAddress : public RpcSocketAddress {
+public:
+    InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
+          : mSockAddr(sockAddr), mSize(size), mAddr(addr), mPort(port) {}
+    [[nodiscard]] std::string toString() const override {
+        return String8::format("%s:%u", mAddr, mPort).c_str();
+    }
+    [[nodiscard]] const sockaddr* addr() const override { return mSockAddr; }
+    [[nodiscard]] size_t addrSize() const override { return mSize; }
+
+    using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
+    static AddrInfo getAddrInfo(const char* addr, unsigned int port) {
+        addrinfo hint{
+                .ai_flags = 0,
+                .ai_family = AF_UNSPEC,
+                .ai_socktype = SOCK_STREAM,
+                .ai_protocol = 0,
+        };
+        addrinfo* aiStart = nullptr;
+        if (int rc = getaddrinfo(addr, std::to_string(port).data(), &hint, &aiStart); 0 != rc) {
+            ALOGE("Unable to resolve %s:%u: %s", addr, port, gai_strerror(rc));
+            return AddrInfo(nullptr, nullptr);
+        }
+        if (aiStart == nullptr) {
+            ALOGE("Unable to resolve %s:%u: getaddrinfo returns null", addr, port);
+            return AddrInfo(nullptr, nullptr);
+        }
+        return AddrInfo(aiStart, &freeaddrinfo);
+    }
+
+private:
+    const sockaddr* mSockAddr;
+    size_t mSize;
+    const char* mAddr;
+    unsigned int mPort;
+};
+
+} // namespace android
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index d934136..19dea7e 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -248,6 +248,52 @@
     return reply.readStrongBinder();
 }
 
+status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                                 size_t* maxThreadsOut) {
+    Parcel data;
+    data.markForRpc(connection);
+    Parcel reply;
+
+    status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_MAX_THREADS, data,
+                               connection, &reply, 0);
+    if (status != OK) {
+        ALOGE("Error getting max threads: %s", statusToString(status).c_str());
+        return status;
+    }
+
+    int32_t maxThreads;
+    status = reply.readInt32(&maxThreads);
+    if (status != OK) return status;
+    if (maxThreads <= 0) {
+        ALOGE("Error invalid max maxThreads: %d", maxThreads);
+        return BAD_VALUE;
+    }
+
+    *maxThreadsOut = maxThreads;
+    return OK;
+}
+
+status_t RpcState::getConnectionId(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                                   int32_t* connectionIdOut) {
+    Parcel data;
+    data.markForRpc(connection);
+    Parcel reply;
+
+    status_t status = transact(fd, RpcAddress::zero(), RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID, data,
+                               connection, &reply, 0);
+    if (status != OK) {
+        ALOGE("Error getting connection ID: %s", statusToString(status).c_str());
+        return status;
+    }
+
+    int32_t connectionId;
+    status = reply.readInt32(&connectionId);
+    if (status != OK) return status;
+
+    *connectionIdOut = connectionId;
+    return OK;
+}
+
 status_t RpcState::transact(const base::unique_fd& fd, const RpcAddress& address, uint32_t code,
                             const Parcel& data, const sp<RpcConnection>& connection, Parcel* reply,
                             uint32_t flags) {
@@ -516,23 +562,35 @@
             replyStatus = target->transact(transaction->code, data, &reply, transaction->flags);
         } else {
             LOG_RPC_DETAIL("Got special transaction %u", transaction->code);
-            // special case for 'zero' address (special server commands)
-            switch (transaction->code) {
-                case RPC_SPECIAL_TRANSACT_GET_ROOT: {
-                    sp<IBinder> root;
-                    sp<RpcServer> server = connection->server().promote();
-                    if (server) {
-                        root = server->getRootObject();
-                    } else {
-                        ALOGE("Root object requested, but no server attached.");
-                    }
 
-                    replyStatus = reply.writeStrongBinder(root);
-                    break;
+            sp<RpcServer> server = connection->server().promote();
+            if (server) {
+                // special case for 'zero' address (special server commands)
+                switch (transaction->code) {
+                    case RPC_SPECIAL_TRANSACT_GET_ROOT: {
+                        replyStatus = reply.writeStrongBinder(server->getRootObject());
+                        break;
+                    }
+                    case RPC_SPECIAL_TRANSACT_GET_MAX_THREADS: {
+                        replyStatus = reply.writeInt32(server->getMaxThreads());
+                        break;
+                    }
+                    case RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID: {
+                        // only connections w/ services can be the source of a
+                        // connection ID (so still guarded by non-null server)
+                        //
+                        // connections associated with servers must have an ID
+                        // (hence abort)
+                        int32_t id = connection->getPrivateAccessorForId().get().value();
+                        replyStatus = reply.writeInt32(id);
+                        break;
+                    }
+                    default: {
+                        replyStatus = UNKNOWN_TRANSACTION;
+                    }
                 }
-                default: {
-                    replyStatus = UNKNOWN_TRANSACTION;
-                }
+            } else {
+                ALOGE("Special command sent, but no server object attached.");
             }
         }
     }
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index f4f5151..825fd7c 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -50,7 +50,12 @@
     RpcState();
     ~RpcState();
 
+    // TODO(b/182940634): combine some special transactions into one "getServerInfo" call?
     sp<IBinder> getRootObject(const base::unique_fd& fd, const sp<RpcConnection>& connection);
+    status_t getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                           size_t* maxThreadsOut);
+    status_t getConnectionId(const base::unique_fd& fd, const sp<RpcConnection>& connection,
+                             int32_t* connectionIdOut);
 
     [[nodiscard]] status_t transact(const base::unique_fd& fd, const RpcAddress& address,
                                     uint32_t code, const Parcel& data,
diff --git a/libs/binder/RpcWireFormat.h b/libs/binder/RpcWireFormat.h
index 60ec6c9..56af0d3 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -47,6 +47,8 @@
  */
 enum : uint32_t {
     RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
+    RPC_SPECIAL_TRANSACT_GET_MAX_THREADS = 1,
+    RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID = 2,
 };
 
 // serialization is like:
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 52f221d..97c826c 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <android-base/unique_fd.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
diff --git a/libs/binder/include/binder/PermissionCache.h b/libs/binder/include/binder/PermissionCache.h
index 835a3a8..21aa705 100644
--- a/libs/binder/include/binder/PermissionCache.h
+++ b/libs/binder/include/binder/PermissionCache.h
@@ -73,6 +73,8 @@
 
     static bool checkPermission(const String16& permission,
             pid_t pid, uid_t uid);
+
+    static void purgeCache();
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/binder/include/binder/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 2395e78..7e31e8a 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -32,6 +32,7 @@
 
 class Parcel;
 class RpcServer;
+class RpcSocketAddress;
 class RpcState;
 
 /**
@@ -43,45 +44,22 @@
     static sp<RpcConnection> make();
 
     /**
-     * This represents a connection for responses, e.g.:
-     *
-     *     process A serves binder a
-     *     process B opens a connection to process A
-     *     process B makes binder b and sends it to A
-     *     A uses this 'back connection' to send things back to B
-     *
-     * This should be called once, and then a call should be made to join per
-     * connection thread.
-     */
-    [[nodiscard]] bool setupUnixDomainServer(const char* path);
-
-    /**
      * This should be called once per thread, matching 'join' in the remote
      * process.
      */
-    [[nodiscard]] bool addUnixDomainClient(const char* path);
+    [[nodiscard]] bool setupUnixDomainClient(const char* path);
 
 #ifdef __BIONIC__
     /**
-     * Creates an RPC server at the current port.
-     */
-    [[nodiscard]] bool setupVsockServer(unsigned int port);
-
-    /**
      * Connects to an RPC server at the CVD & port.
      */
-    [[nodiscard]] bool addVsockClient(unsigned int cvd, unsigned int port);
+    [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
 #endif // __BIONIC__
 
     /**
-     * Creates an RPC server at the current port.
-     */
-    [[nodiscard]] bool setupInetServer(unsigned int port);
-
-    /**
      * Connects to an RPC server at the given address and port.
      */
-    [[nodiscard]] bool addInetClient(const char* addr, unsigned int port);
+    [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
 
     /**
      * For debugging!
@@ -98,36 +76,45 @@
      */
     sp<IBinder> getRootObject();
 
+    /**
+     * Query the other side of the connection for the maximum number of threads
+     * it supports (maximum number of concurrent non-nested synchronous transactions)
+     */
+    status_t getMaxThreads(size_t* maxThreads);
+
     [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
                                     Parcel* reply, uint32_t flags);
     [[nodiscard]] status_t sendDecStrong(const RpcAddress& address);
 
-    /**
-     * Adds a server thread accepting connections. Must be called after
-     * setup*Server.
-     */
-    void join();
-
     ~RpcConnection();
 
-    void setForServer(const wp<RpcServer>& server);
     wp<RpcServer> server();
 
     // internal only
     const std::unique_ptr<RpcState>& state() { return mState; }
 
-    class SocketAddress {
-    public:
-        virtual ~SocketAddress();
-        virtual std::string toString() const = 0;
-        virtual const sockaddr* addr() const = 0;
-        virtual size_t addrSize() const = 0;
+    class PrivateAccessorForId {
+    private:
+        friend class RpcConnection;
+        friend class RpcState;
+        explicit PrivateAccessorForId(const RpcConnection* connection) : mConnection(connection) {}
+
+        const std::optional<int32_t> get() { return mConnection->mId; }
+
+        const RpcConnection* mConnection;
     };
+    PrivateAccessorForId getPrivateAccessorForId() const { return PrivateAccessorForId(this); }
 
 private:
+    friend PrivateAccessorForId;
     friend sp<RpcConnection>;
+    friend RpcServer;
     RpcConnection();
 
+    status_t readId();
+
+    void join(base::unique_fd client);
+
     struct ConnectionSocket : public RefBase {
         base::unique_fd fd;
 
@@ -136,10 +123,11 @@
         std::optional<pid_t> exclusiveTid;
     };
 
-    bool setupSocketServer(const SocketAddress& address);
-    bool addSocketClient(const SocketAddress& address);
-    void addClient(base::unique_fd&& fd);
-    sp<ConnectionSocket> assignServerToThisThread(base::unique_fd&& fd);
+    bool setupSocketClient(const RpcSocketAddress& address);
+    bool setupOneSocketClient(const RpcSocketAddress& address);
+    void addClient(base::unique_fd fd);
+    void setForServer(const wp<RpcServer>& server, int32_t connectionId);
+    sp<ConnectionSocket> assignServerToThisThread(base::unique_fd fd);
     bool removeServerSocket(const sp<ConnectionSocket>& socket);
 
     enum class SocketUse {
@@ -185,9 +173,10 @@
 
     wp<RpcServer> mForServer; // maybe null, for client connections
 
-    std::unique_ptr<RpcState> mState;
+    // TODO(b/183988761): this shouldn't be guessable
+    std::optional<int32_t> mId;
 
-    base::unique_fd mServer; // socket we are accepting connections on
+    std::unique_ptr<RpcState> mState;
 
     std::mutex mSocketMutex;           // for all below
     std::condition_variable mSocketCv; // for mWaitingThreads
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index a665fad..5535d8a 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -29,36 +29,81 @@
 
 namespace android {
 
+class RpcSocketAddress;
+
 /**
  * This represents a server of an interface, which may be connected to by any
  * number of clients over sockets.
+ *
+ * Usage:
+ *     auto server = RpcServer::make();
+ *     // only supports one now
+ *     if (!server->setup*Server(...)) {
+ *         :(
+ *     }
+ *     server->join();
  */
 class RpcServer final : public virtual RefBase {
 public:
     static sp<RpcServer> make();
 
+    /**
+     * This represents a connection for responses, e.g.:
+     *
+     *     process A serves binder a
+     *     process B opens a connection to process A
+     *     process B makes binder b and sends it to A
+     *     A uses this 'back connection' to send things back to B
+     */
+    [[nodiscard]] bool setupUnixDomainServer(const char* path);
+
+#ifdef __BIONIC__
+    /**
+     * Creates an RPC server at the current port.
+     */
+    [[nodiscard]] bool setupVsockServer(unsigned int port);
+#endif // __BIONIC__
+
+    /**
+     * Creates an RPC server at the current port using IPv4.
+     *
+     * TODO(b/182914638): IPv6 support
+     *
+     * Set |port| to 0 to pick an ephemeral port; see discussion of
+     * /proc/sys/net/ipv4/ip_local_port_range in ip(7). In this case, |assignedPort|
+     * will be set to the picked port number, if it is not null.
+     */
+    [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
+
     void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
 
     /**
-     * Setup a static connection, when the number of clients are known.
+     * This must be called before adding a client connection.
      *
-     * Each call to this function corresponds to a different client, and clients
-     * each have their own threadpools.
+     * If this is not specified, this will be a single-threaded server.
      *
-     * TODO(b/167966510): support dynamic creation of connections/threads
+     * TODO(b/185167543): these are currently created per client, but these
+     * should be shared.
      */
-    sp<RpcConnection> addClientConnection();
+    void setMaxThreads(size_t threads);
+    size_t getMaxThreads();
 
     /**
      * The root object can be retrieved by any client, without any
      * authentication. TODO(b/183988761)
      */
     void setRootObject(const sp<IBinder>& binder);
+    sp<IBinder> getRootObject();
 
     /**
-     * Root object set with setRootObject
+     * You must have at least one client connection before calling this.
      */
-    sp<IBinder> getRootObject();
+    void join();
+
+    /**
+     * For debugging!
+     */
+    std::vector<sp<RpcConnection>> listConnections();
 
     ~RpcServer();
 
@@ -66,11 +111,16 @@
     friend sp<RpcServer>;
     RpcServer();
 
-    bool mAgreedExperimental = false;
+    bool setupSocketServer(const RpcSocketAddress& address);
 
-    std::mutex mLock;
+    bool mAgreedExperimental = false;
+    bool mStarted = false; // TODO(b/185167543): support dynamically added clients
+    size_t mMaxThreads = 1;
+    base::unique_fd mServer; // socket we are accepting connections on
+
+    std::mutex mLock; // for below
     sp<IBinder> mRootObject;
-    std::vector<sp<RpcConnection>> mConnections; // per-client
+    sp<RpcConnection> mConnection;
 };
 
 } // namespace android
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index 7c82226..ce47c0d 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -121,18 +121,14 @@
     std::thread([addr]() {
         sp<RpcServer> server = RpcServer::make();
         server->setRootObject(sp<MyBinderRpcBenchmark>::make());
-
         server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
-        sp<RpcConnection> connection = server->addClientConnection();
-        CHECK(connection->setupUnixDomainServer(addr.c_str()));
-
-        connection->join();
+        CHECK(server->setupUnixDomainServer(addr.c_str()));
+        server->join();
     }).detach();
 
     for (size_t tries = 0; tries < 5; tries++) {
         usleep(10000);
-        if (gConnection->addUnixDomainClient(addr.c_str())) goto success;
+        if (gConnection->setupUnixDomainClient(addr.c_str())) goto success;
     }
     LOG(FATAL) << "Could not connect.";
 success:
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index dd68fdb..d23df8e 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -17,6 +17,7 @@
 #include <BnBinderRpcSession.h>
 #include <BnBinderRpcTest.h>
 #include <aidl/IBinderRpcTest.h>
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android/binder_auto_utils.h>
 #include <android/binder_libbinder.h>
@@ -77,7 +78,7 @@
 
 class MyBinderRpcTest : public BnBinderRpcTest {
 public:
-    sp<RpcConnection> connection;
+    wp<RpcServer> server;
 
     Status sendString(const std::string& str) override {
         (void)str;
@@ -88,13 +89,23 @@
         return Status::ok();
     }
     Status countBinders(int32_t* out) override {
-        if (connection == nullptr) {
+        sp<RpcServer> spServer = server.promote();
+        if (spServer == nullptr) {
             return Status::fromExceptionCode(Status::EX_NULL_POINTER);
         }
-        *out = connection->state()->countBinders();
-        if (*out != 1) {
-            connection->state()->dump();
+        size_t count = 0;
+        for (auto connection : spServer->listConnections()) {
+            count += connection->state()->countBinders();
         }
+        // help debugging if we don't have one binder (this call is always made
+        // in this test when exactly one binder is held, which is held only to
+        // call this method - all other binders should be cleaned up)
+        if (count != 1) {
+            for (auto connection : spServer->listConnections()) {
+                connection->state()->dump();
+            }
+        }
+        *out = count;
         return Status::ok();
     }
     Status pingMe(const sp<IBinder>& binder, int32_t* out) override {
@@ -176,14 +187,27 @@
 };
 sp<IBinder> MyBinderRpcTest::mHeldBinder;
 
+class Pipe {
+public:
+    Pipe() { CHECK(android::base::Pipe(&mRead, &mWrite)); }
+    Pipe(Pipe&&) = default;
+    android::base::borrowed_fd readEnd() { return mRead; }
+    android::base::borrowed_fd writeEnd() { return mWrite; }
+
+private:
+    android::base::unique_fd mRead;
+    android::base::unique_fd mWrite;
+};
+
 class Process {
 public:
-    Process(const std::function<void()>& f) {
+    Process(Process&&) = default;
+    Process(const std::function<void(Pipe*)>& f) {
         if (0 == (mPid = fork())) {
             // racey: assume parent doesn't crash before this is set
             prctl(PR_SET_PDEATHSIG, SIGHUP);
 
-            f();
+            f(&mPipe);
         }
     }
     ~Process() {
@@ -191,9 +215,11 @@
             kill(mPid, SIGKILL);
         }
     }
+    Pipe* getPipe() { return &mPipe; }
 
 private:
     pid_t mPid = 0;
+    Pipe mPipe;
 };
 
 static std::string allocateSocketAddress() {
@@ -215,6 +241,7 @@
     // whether connection should be invalidated by end of run
     bool expectInvalid = false;
 
+    ProcessConnection(ProcessConnection&&) = default;
     ~ProcessConnection() {
         rootBinder = nullptr;
         EXPECT_NE(nullptr, connection);
@@ -238,6 +265,7 @@
     // pre-casted root object
     sp<IBinderRpcTest> rootIface;
 
+    BinderRpcTestProcessConnection(BinderRpcTestProcessConnection&&) = default;
     ~BinderRpcTestProcessConnection() {
         if (!proc.expectInvalid) {
             int32_t remoteBinders = 0;
@@ -278,79 +306,78 @@
     // This creates a new process serving an interface on a certain number of
     // threads.
     ProcessConnection createRpcTestSocketServerProcess(
-            size_t numThreads,
-            const std::function<void(const sp<RpcServer>&, const sp<RpcConnection>&)>& configure) {
-        CHECK_GT(numThreads, 0);
-
+            size_t numThreads, const std::function<void(const sp<RpcServer>&)>& configure) {
         SocketType socketType = GetParam();
 
         std::string addr = allocateSocketAddress();
         unlink(addr.c_str());
-        static unsigned int port = 3456;
-        port++;
+        static unsigned int vsockPort = 3456;
+        vsockPort++;
 
         auto ret = ProcessConnection{
-                .host = Process([&] {
+                .host = Process([&](Pipe* pipe) {
                     sp<RpcServer> server = RpcServer::make();
 
                     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
-
-                    // server supporting one client on one socket
-                    sp<RpcConnection> connection = server->addClientConnection();
+                    server->setMaxThreads(numThreads);
 
                     switch (socketType) {
                         case SocketType::UNIX:
-                            CHECK(connection->setupUnixDomainServer(addr.c_str())) << addr;
+                            CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
                             break;
 #ifdef __BIONIC__
                         case SocketType::VSOCK:
-                            CHECK(connection->setupVsockServer(port));
+                            CHECK(server->setupVsockServer(vsockPort));
                             break;
 #endif // __BIONIC__
-                        case SocketType::INET:
-                            CHECK(connection->setupInetServer(port));
+                        case SocketType::INET: {
+                            unsigned int outPort = 0;
+                            CHECK(server->setupInetServer(0, &outPort));
+                            CHECK_NE(0, outPort);
+                            CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
+                                                            sizeof(outPort)));
                             break;
+                        }
                         default:
                             LOG_ALWAYS_FATAL("Unknown socket type");
                     }
 
-                    configure(server, connection);
+                    configure(server);
 
-                    // accept 'numThreads' connections
-                    std::vector<std::thread> pool;
-                    for (size_t i = 0; i + 1 < numThreads; i++) {
-                        pool.push_back(std::thread([=] { connection->join(); }));
-                    }
-                    connection->join();
-                    for (auto& t : pool) t.join();
+                    server->join();
                 }),
                 .connection = RpcConnection::make(),
         };
 
-        // create remainder of connections
-        for (size_t i = 0; i < numThreads; i++) {
-            for (size_t tries = 0; tries < 5; tries++) {
-                usleep(10000);
-                switch (socketType) {
-                    case SocketType::UNIX:
-                        if (ret.connection->addUnixDomainClient(addr.c_str())) goto success;
-                        break;
-#ifdef __BIONIC__
-                    case SocketType::VSOCK:
-                        if (ret.connection->addVsockClient(VMADDR_CID_LOCAL, port)) goto success;
-                        break;
-#endif // __BIONIC__
-                    case SocketType::INET:
-                        if (ret.connection->addInetClient("127.0.0.1", port)) goto success;
-                        break;
-                    default:
-                        LOG_ALWAYS_FATAL("Unknown socket type");
-                }
-            }
-            LOG_ALWAYS_FATAL("Could not connect");
-        success:;
+        unsigned int inetPort = 0;
+        if (socketType == SocketType::INET) {
+            CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &inetPort,
+                                           sizeof(inetPort)));
+            CHECK_NE(0, inetPort);
         }
 
+        // create remainder of connections
+        for (size_t tries = 0; tries < 10; tries++) {
+            usleep(10000);
+            switch (socketType) {
+                case SocketType::UNIX:
+                    if (ret.connection->setupUnixDomainClient(addr.c_str())) goto success;
+                    break;
+#ifdef __BIONIC__
+                case SocketType::VSOCK:
+                    if (ret.connection->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+                    break;
+#endif // __BIONIC__
+                case SocketType::INET:
+                    if (ret.connection->setupInetClient("127.0.0.1", inetPort)) goto success;
+                    break;
+                default:
+                    LOG_ALWAYS_FATAL("Unknown socket type");
+            }
+        }
+        LOG_ALWAYS_FATAL("Could not connect");
+    success:
+
         ret.rootBinder = ret.connection->getRootObject();
         return ret;
     }
@@ -358,13 +385,11 @@
     BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
         BinderRpcTestProcessConnection ret{
                 .proc = createRpcTestSocketServerProcess(numThreads,
-                                                         [&](const sp<RpcServer>& server,
-                                                             const sp<RpcConnection>& connection) {
+                                                         [&](const sp<RpcServer>& server) {
                                                              sp<MyBinderRpcTest> service =
                                                                      new MyBinderRpcTest;
                                                              server->setRootObject(service);
-                                                             service->connection =
-                                                                     connection; // for testing only
+                                                             service->server = server;
                                                          }),
         };
 
@@ -376,12 +401,10 @@
 };
 
 TEST_P(BinderRpc, RootObjectIsNull) {
-    auto proc = createRpcTestSocketServerProcess(1,
-                                                 [](const sp<RpcServer>& server,
-                                                    const sp<RpcConnection>&) {
-                                                     // this is the default, but to be explicit
-                                                     server->setRootObject(nullptr);
-                                                 });
+    auto proc = createRpcTestSocketServerProcess(1, [](const sp<RpcServer>& server) {
+        // this is the default, but to be explicit
+        server->setRootObject(nullptr);
+    });
 
     // retrieved by getRootObject when process is created above
     EXPECT_EQ(nullptr, proc.rootBinder);
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 748f795..16ce15b 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -68,11 +68,9 @@
     name: "gl_headers",
     vendor_available: true,
     export_include_dirs: ["include"],
-}
-
-llndk_headers {
-    name: "gl_llndk_headers",
-    export_include_dirs: ["include"],
+    llndk: {
+        llndk_headers: true,
+    },
 }
 
 subdirs = [
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 6d59ac0..daaaf88 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -144,7 +144,7 @@
     defaults: ["egl_libs_defaults"],
     llndk: {
         symbol_file: "libEGL.map.txt",
-        export_llndk_headers: ["gl_llndk_headers"],
+        export_llndk_headers: ["gl_headers"],
         // Don't export EGL/include from the LLNDK variant.
         override_export_include_dirs: [],
     },
@@ -215,7 +215,7 @@
     defaults: ["gles_libs_defaults"],
     llndk: {
         symbol_file: "libGLESv1_CM.map.txt",
-        export_llndk_headers: ["gl_llndk_headers"],
+        export_llndk_headers: ["gl_headers"],
         // Don't export EGL/include from the LLNDK variant.
         override_export_include_dirs: [],
     },
@@ -232,7 +232,7 @@
     defaults: ["gles_libs_defaults"],
     llndk: {
         symbol_file: "libGLESv2.map.txt",
-        export_llndk_headers: ["gl_llndk_headers"],
+        export_llndk_headers: ["gl_headers"],
         // Don't export EGL/include from the LLNDK variant.
         override_export_include_dirs: [],
     },
@@ -252,7 +252,7 @@
     defaults: ["gles_libs_defaults"],
     llndk: {
         symbol_file: "libGLESv3.map.txt",
-        export_llndk_headers: ["gl_llndk_headers"],
+        export_llndk_headers: ["gl_headers"],
         // Don't export EGL/include from the LLNDK variant.
         override_export_include_dirs: [],
     },
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index afd2b71..536207d 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -120,7 +120,8 @@
 
 namespace {
 
-TEST_F(LayerHistoryTestV2, oneLayer) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(LayerHistoryTestV2, DISABLED_oneLayer) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
@@ -631,7 +632,8 @@
     EXPECT_EQ(1, animatingLayerCount(time));
 }
 
-TEST_F(LayerHistoryTestV2, heuristicLayer60Hz) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(LayerHistoryTestV2, DISABLED_heuristicLayer60Hz) {
     const auto layer = createLayer();
     EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
     EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 0208728..0b1b8ad 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -80,7 +80,8 @@
     mIdleTimer->stop();
 }
 
-TEST_F(OneShotTimerTest, resetTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
@@ -105,7 +106,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(OneShotTimerTest, resetBackToBackTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
@@ -136,7 +138,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(OneShotTimerTest, startNotCalledTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_startNotCalledTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     // The start hasn't happened, so the callback does not happen.
@@ -148,7 +151,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_idleTimerIdlesTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
@@ -168,7 +172,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_timeoutCallbackExecutionTest) {
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
                                                            mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index d4cb928..440c5b1 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -34,7 +34,7 @@
     llndk: {
         symbol_file: "libvulkan.map.txt",
         export_llndk_headers: [
-            "vulkan_headers_llndk",
+            "vulkan_headers",
         ],
     },
     clang: true,