Merge "Update SurfaceFlinger to handle stretching of surfaces that are part of a scrolling container" into sc-dev
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 a735309..cbe590f 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/RpcConnection.cpp b/libs/binder/RpcConnection.cpp
index ee5f508..4b3a53f 100644
--- a/libs/binder/RpcConnection.cpp
+++ b/libs/binder/RpcConnection.cpp
@@ -18,13 +18,7 @@
 
 #include <binder/RpcConnection.h>
 
-#include <arpa/inet.h>
 #include <inttypes.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
 #include <unistd.h>
 
 #include <string_view>
@@ -33,6 +27,7 @@
 #include <binder/Stability.h>
 #include <utils/String8.h>
 
+#include "RpcSocketAddress.h"
 #include "RpcState.h"
 #include "RpcWireFormat.h"
 
@@ -40,62 +35,9 @@
 extern "C" pid_t gettid();
 #endif
 
-#ifdef __BIONIC__
-#include <linux/vm_sockets.h>
-#endif
-
 namespace android {
 
-using base::borrowed_fd;
 using base::unique_fd;
-using AddrInfo = std::unique_ptr<addrinfo, decltype(&freeaddrinfo)>;
-
-namespace {
-bool checkSockaddrSize(const char* name, size_t actual, size_t expected) {
-    if (actual >= expected) return true;
-    ALOGW("getSockaddrPort: family is %s but size is %zu < %zu", name, actual, expected);
-    return false;
-}
-
-// Get the port number of |storage| for certain families. Requires storage->sa_family to be
-// set to a known family; otherwise, return nullopt.
-std::optional<unsigned int> getSockaddrPort(const sockaddr* storage, socklen_t len) {
-    switch (storage->sa_family) {
-        case AF_INET: {
-            if (!checkSockaddrSize("INET", len, sizeof(sockaddr_in))) return std::nullopt;
-            auto inetStorage = reinterpret_cast<const sockaddr_in*>(storage);
-            return ntohs(inetStorage->sin_port);
-        }
-        default: {
-            uint16_t family = storage->sa_family;
-            ALOGW("Don't know how to infer port for family %" PRIu16, family);
-            return std::nullopt;
-        }
-    }
-}
-
-std::optional<unsigned int> getSocketPort(borrowed_fd socketfd,
-                                          const RpcConnection::SocketAddress& socketAddress) {
-    sockaddr_storage storage{};
-    socklen_t len = sizeof(storage);
-    auto storagePtr = reinterpret_cast<sockaddr*>(&storage);
-    if (0 != getsockname(socketfd.get(), storagePtr, &len)) {
-        int savedErrno = errno;
-        ALOGE("Could not getsockname at %s: %s", socketAddress.toString().c_str(),
-              strerror(savedErrno));
-        return std::nullopt;
-    }
-
-    // getsockname does not fill in family, but getSockaddrPort() needs it.
-    if (storage.ss_family == AF_UNSPEC) {
-        storage.ss_family = socketAddress.addr()->sa_family;
-    }
-    return getSockaddrPort(storagePtr, len);
-}
-
-} // namespace
-
-RpcConnection::SocketAddress::~SocketAddress() {}
 
 RpcConnection::RpcConnection() {
     LOG_RPC_DETAIL("RpcConnection created %p", this);
@@ -114,134 +56,20 @@
     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::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::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, unsigned int* assignedPort) {
-    const char* kAddr = "127.0.0.1";
-
-    if (assignedPort != nullptr) *assignedPort = 0;
-    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)) {
-            continue;
-        }
-        auto realPort = getSocketPort(mServer.get(), socketAddress);
-        LOG_ALWAYS_FATAL_IF(!realPort.has_value(), "Unable to get port number after setting up %s",
-                            socketAddress.toString().c_str());
-        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;
-    }
-    ALOGE("None of the socket address resolved for %s:%u can be set up as inet server.", kAddr,
-          port);
-    return false;
-}
-
 bool RpcConnection::setupInetClient(const char* addr, unsigned int port) {
-    auto aiStart = GetAddrInfo(addr, 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);
@@ -287,23 +115,43 @@
     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::startThread(unique_fd client) {
+    std::lock_guard<std::mutex> _l(mSocketMutex);
+    sp<RpcConnection> holdThis = sp<RpcConnection>::fromExisting(this);
+    int fd = client.release();
+    auto thread = std::thread([=] {
+        holdThis->join(unique_fd(fd));
+        {
+            std::lock_guard<std::mutex> _l(holdThis->mSocketMutex);
+            size_t erased = mThreads.erase(std::this_thread::get_id());
+            LOG_ALWAYS_FATAL_IF(erased != 0, "Could not erase thread.");
+        }
+    });
+    mThreads[thread.get_id()] = std::move(thread);
+}
+
+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 =
@@ -319,41 +167,11 @@
                         "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.");
-
-    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;
-}
-
-bool RpcConnection::setupSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupSocketClient(const RpcSocketAddress& addr) {
     {
         std::lock_guard<std::mutex> _l(mSocketMutex);
         LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
@@ -361,7 +179,7 @@
                             mClients.size());
     }
 
-    if (!setupOneSocketClient(addr)) return false;
+    if (!setupOneSocketClient(addr, RPC_CONNECTION_ID_NEW)) return false;
 
     // TODO(b/185167543): we should add additional connections dynamically
     // instead of all at once.
@@ -373,11 +191,17 @@
         return false;
     }
 
+    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;
+    }
+
     // 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;
+            if (setupOneSocketClient(addr, mId.value())) break;
             usleep(10000);
         }
     }
@@ -385,7 +209,7 @@
     return true;
 }
 
-bool RpcConnection::setupOneSocketClient(const SocketAddress& addr) {
+bool RpcConnection::setupOneSocketClient(const RpcSocketAddress& addr, int32_t id) {
     unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
     if (serverFd == -1) {
@@ -400,20 +224,32 @@
         return false;
     }
 
+    if (sizeof(id) != TEMP_FAILURE_RETRY(write(serverFd.get(), &id, sizeof(id)))) {
+        int savedErrno = errno;
+        ALOGE("Could not write id to socket at %s: %s", addr.toString().c_str(),
+              strerror(savedErrno));
+        return false;
+    }
+
     LOG_RPC_DETAIL("Socket at %s client with fd %d", addr.toString().c_str(), serverFd.get());
 
     addClient(std::move(serverFd));
     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 8f2805f..4df12ce 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -27,10 +27,13 @@
 #include <log/log.h>
 #include "RpcState.h"
 
+#include "RpcSocketAddress.h"
 #include "RpcWireFormat.h"
 
 namespace android {
 
+using base::unique_fd;
+
 RpcServer::RpcServer() {}
 RpcServer::~RpcServer() {}
 
@@ -42,14 +45,63 @@
     mAgreedExperimental = true;
 }
 
+bool RpcServer::setupUnixDomainServer(const char* path) {
+    return setupSocketServer(UnixSocketAddress(path));
+}
+
+#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;
+    }
+    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");
-    {
-        // this lock should only ever be needed in the error case
-        std::lock_guard<std::mutex> _l(mLock);
-        LOG_ALWAYS_FATAL_IF(mConnections.size() > 0,
-                            "Must specify max threads before creating a connection");
-    }
+    LOG_ALWAYS_FATAL_IF(mStarted, "must be called before started");
     mMaxThreads = threads;
 }
 
@@ -67,35 +119,97 @@
     return mRootObject;
 }
 
-sp<RpcConnection> RpcServer::addClientConnection() {
+void RpcServer::join() {
     LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
 
-    auto connection = RpcConnection::make();
-    connection->setForServer(sp<RpcServer>::fromExisting(this));
-    {
-        std::lock_guard<std::mutex> _l(mLock);
-        LOG_ALWAYS_FATAL_IF(mStarted,
-                            "currently only supports adding client connections at creation time");
-        mConnections.push_back(connection);
-    }
-    return connection;
-}
-
-void RpcServer::join() {
     std::vector<std::thread> pool;
     {
         std::lock_guard<std::mutex> _l(mLock);
-        mStarted = true;
-        for (const sp<RpcConnection>& connection : mConnections) {
-            for (size_t i = 0; i < mMaxThreads; i++) {
-                pool.push_back(std::thread([=] { connection->join(); }));
-            }
-        }
+        LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
     }
 
-    // TODO(b/185167543): don't waste extra thread for join, and combine threads
-    // between clients
-    for (auto& t : pool) t.join();
+    while (true) {
+        unique_fd clientFd(
+                TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, 0 /*length*/, SOCK_CLOEXEC)));
+
+        if (clientFd < 0) {
+            ALOGE("Could not accept4 socket: %s", strerror(errno));
+            continue;
+        }
+        LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
+        // TODO(b/183988761): cannot trust this simple ID
+        LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+        int32_t id;
+        if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
+            ALOGE("Could not read ID from fd %d", clientFd.get());
+            continue;
+        }
+
+        {
+            std::lock_guard<std::mutex> _l(mLock);
+
+            sp<RpcConnection> connection;
+            if (id == RPC_CONNECTION_ID_NEW) {
+                // new client!
+                LOG_ALWAYS_FATAL_IF(mConnectionIdCounter >= INT32_MAX, "Out of connection IDs");
+                mConnectionIdCounter++;
+
+                connection = RpcConnection::make();
+                connection->setForServer(wp<RpcServer>::fromExisting(this), mConnectionIdCounter);
+
+                mConnections[mConnectionIdCounter] = connection;
+            } else {
+                auto it = mConnections.find(id);
+                if (it == mConnections.end()) {
+                    ALOGE("Cannot add thread, no record of connection with ID %d", id);
+                    continue;
+                }
+                connection = it->second;
+            }
+
+            connection->startThread(std::move(clientFd));
+        }
+    }
+}
+
+std::vector<sp<RpcConnection>> RpcServer::listConnections() {
+    std::lock_guard<std::mutex> _l(mLock);
+    std::vector<sp<RpcConnection>> connections;
+    for (auto& [id, connection] : mConnections) {
+        (void)id;
+        connections.push_back(connection);
+    }
+    return connections;
+}
+
+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 6bfcc42..19dea7e 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -249,7 +249,7 @@
 }
 
 status_t RpcState::getMaxThreads(const base::unique_fd& fd, const sp<RpcConnection>& connection,
-                                 size_t* maxThreads) {
+                                 size_t* maxThreadsOut) {
     Parcel data;
     data.markForRpc(connection);
     Parcel reply;
@@ -261,15 +261,36 @@
         return status;
     }
 
-    int32_t threads;
-    status = reply.readInt32(&threads);
+    int32_t maxThreads;
+    status = reply.readInt32(&maxThreads);
     if (status != OK) return status;
-    if (threads <= 0) {
-        ALOGE("Error invalid max threads: %d", threads);
+    if (maxThreads <= 0) {
+        ALOGE("Error invalid max maxThreads: %d", maxThreads);
         return BAD_VALUE;
     }
 
-    *maxThreads = threads;
+    *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;
 }
 
@@ -554,6 +575,16 @@
                         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;
                     }
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 1cfa406..825fd7c 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -50,9 +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 cc7cacb..a7e8a52 100644
--- a/libs/binder/RpcWireFormat.h
+++ b/libs/binder/RpcWireFormat.h
@@ -48,8 +48,11 @@
 enum : uint32_t {
     RPC_SPECIAL_TRANSACT_GET_ROOT = 0,
     RPC_SPECIAL_TRANSACT_GET_MAX_THREADS = 1,
+    RPC_SPECIAL_TRANSACT_GET_CONNECTION_ID = 2,
 };
 
+constexpr int32_t RPC_CONNECTION_ID_NEW = -1;
+
 // serialization is like:
 // |RpcWireHeader|struct desginated by 'command'| (over and over again)
 
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/RpcConnection.h b/libs/binder/include/binder/RpcConnection.h
index 3a2d8e5..87984d7 100644
--- a/libs/binder/include/binder/RpcConnection.h
+++ b/libs/binder/include/binder/RpcConnection.h
@@ -21,7 +21,9 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+#include <map>
 #include <optional>
+#include <thread>
 #include <vector>
 
 // WARNING: This is a feature which is still in development, and it is subject
@@ -32,6 +34,7 @@
 
 class Parcel;
 class RpcServer;
+class RpcSocketAddress;
 class RpcState;
 
 /**
@@ -43,19 +46,6 @@
     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.
      */
@@ -63,28 +53,12 @@
 
 #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 setupVsockClient(unsigned int cvd, 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);
-
-    /**
      * Connects to an RPC server at the given address and port.
      */
     [[nodiscard]] bool setupInetClient(const char* addr, unsigned int port);
@@ -116,26 +90,33 @@
 
     ~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();
 
-    void join();
+    status_t readId();
+
+    void startThread(base::unique_fd client);
+    void join(base::unique_fd client);
 
     struct ConnectionSocket : public RefBase {
         base::unique_fd fd;
@@ -145,11 +126,11 @@
         std::optional<pid_t> exclusiveTid;
     };
 
-    bool setupSocketServer(const SocketAddress& address);
-    bool setupSocketClient(const SocketAddress& address);
-    bool setupOneSocketClient(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, int32_t connectionId);
+    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 {
@@ -195,16 +176,24 @@
 
     wp<RpcServer> mForServer; // maybe null, for client connections
 
+    // TODO(b/183988761): this shouldn't be guessable
+    std::optional<int32_t> mId;
+
     std::unique_ptr<RpcState> mState;
 
-    base::unique_fd mServer; // socket we are accepting connections on
-
     std::mutex mSocketMutex;           // for all below
+
     std::condition_variable mSocketCv; // for mWaitingThreads
     size_t mWaitingThreads = 0;
     size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
     std::vector<sp<ConnectionSocket>> mClients;
     std::vector<sp<ConnectionSocket>> mServers;
+
+    // TODO(b/185167543): use for reverse connections (allow client to also
+    // serve calls on a connection).
+    // TODO(b/185167543): allow sharing between different connections in a
+    // process? (or combine with mServers)
+    std::map<std::thread::id, std::thread> mThreads;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index 9247128..81ea3a7 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -29,14 +29,52 @@
 
 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();
 
     /**
@@ -58,33 +96,34 @@
     sp<IBinder> getRootObject();
 
     /**
-     * Setup a static connection, when the number of clients are known.
-     *
-     * Each call to this function corresponds to a different client, and clients
-     * each have their own threadpools.
-     *
-     * TODO(b/167966510): support dynamic creation of connections/threads
-     */
-    sp<RpcConnection> addClientConnection();
-
-    /**
      * You must have at least one client connection before calling this.
+     *
+     * TODO(b/185167543): way to shut down?
      */
     void join();
 
+    /**
+     * For debugging!
+     */
+    std::vector<sp<RpcConnection>> listConnections();
+
     ~RpcServer();
 
 private:
     friend sp<RpcServer>;
     RpcServer();
 
+    bool setupSocketServer(const RpcSocketAddress& address);
+
     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
+    std::map<int32_t, sp<RpcConnection>> mConnections;
+    int32_t mConnectionIdCounter = 0;
 };
 
 } // namespace android
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index 2bdb264..814e094 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -18,8 +18,8 @@
     oneway void sendString(@utf8InCpp String str);
     @utf8InCpp String doubleString(@utf8InCpp String str);
 
-    // number of known RPC binders to process, RpcState::countBinders
-    int countBinders();
+    // number of known RPC binders to process, RpcState::countBinders by connection
+    int[] countBinders();
 
     // Caller sends server, callee pings caller's server and returns error code.
     int pingMe(IBinder binder);
diff --git a/libs/binder/tests/binderRpcBenchmark.cpp b/libs/binder/tests/binderRpcBenchmark.cpp
index b3282ff..ce47c0d 100644
--- a/libs/binder/tests/binderRpcBenchmark.cpp
+++ b/libs/binder/tests/binderRpcBenchmark.cpp
@@ -121,12 +121,8 @@
     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()));
-
+        CHECK(server->setupUnixDomainServer(addr.c_str()));
         server->join();
     }).detach();
 
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index f3ec904..50bff91 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -78,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 +88,20 @@
         *strstr = str + str;
         return Status::ok();
     }
-    Status countBinders(int32_t* out) override {
-        if (connection == nullptr) {
+    Status countBinders(std::vector<int32_t>* out) override {
+        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();
+        out->clear();
+        for (auto connection : spServer->listConnections()) {
+            size_t count = connection->state()->countBinders();
+            if (count != 1) {
+                // this is called when there is only one binder held remaining,
+                // so to aid debugging
+                connection->state()->dump();
+            }
+            out->push_back(count);
         }
         return Status::ok();
     }
@@ -222,25 +229,33 @@
     // reference to process hosting a socket server
     Process host;
 
-    // client connection object associated with other process
-    sp<RpcConnection> connection;
+    struct ConnectionInfo {
+        sp<RpcConnection> connection;
+        sp<IBinder> root;
+    };
 
-    // pre-fetched root object
-    sp<IBinder> rootBinder;
-
-    // whether connection should be invalidated by end of run
-    bool expectInvalid = false;
+    // client connection objects associated with other process
+    // each one represents a separate connection
+    std::vector<ConnectionInfo> connections;
 
     ProcessConnection(ProcessConnection&&) = default;
     ~ProcessConnection() {
-        rootBinder = nullptr;
-        EXPECT_NE(nullptr, connection);
-        EXPECT_NE(nullptr, connection->state());
-        EXPECT_EQ(0, connection->state()->countBinders()) << (connection->state()->dump(), "dump:");
+        for (auto& connection : connections) {
+            connection.root = nullptr;
+        }
 
-        wp<RpcConnection> weakConnection = connection;
-        connection = nullptr;
-        EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+        for (auto& info : connections) {
+            sp<RpcConnection>& connection = info.connection;
+
+            EXPECT_NE(nullptr, connection);
+            EXPECT_NE(nullptr, connection->state());
+            EXPECT_EQ(0, connection->state()->countBinders())
+                    << (connection->state()->dump(), "dump:");
+
+            wp<RpcConnection> weakConnection = connection;
+            connection = nullptr;
+            EXPECT_EQ(nullptr, weakConnection.promote()) << "Leaked connection";
+        }
     }
 };
 
@@ -249,19 +264,25 @@
 struct BinderRpcTestProcessConnection {
     ProcessConnection proc;
 
-    // pre-fetched root object
+    // pre-fetched root object (for first connection)
     sp<IBinder> rootBinder;
 
-    // pre-casted root object
+    // pre-casted root object (for first connection)
     sp<IBinderRpcTest> rootIface;
 
+    // whether connection should be invalidated by end of run
+    bool expectInvalid = false;
+
     BinderRpcTestProcessConnection(BinderRpcTestProcessConnection&&) = default;
     ~BinderRpcTestProcessConnection() {
-        if (!proc.expectInvalid) {
-            int32_t remoteBinders = 0;
-            EXPECT_OK(rootIface->countBinders(&remoteBinders));
-            // should only be the root binder object, iface
-            EXPECT_EQ(remoteBinders, 1);
+        if (!expectInvalid) {
+            std::vector<int32_t> remoteCounts;
+            // calling over any connections counts across all connections
+            EXPECT_OK(rootIface->countBinders(&remoteCounts));
+            EXPECT_EQ(remoteCounts.size(), proc.connections.size());
+            for (auto remoteCount : remoteCounts) {
+                EXPECT_EQ(remoteCount, 1);
+            }
         }
 
         rootIface = nullptr;
@@ -296,8 +317,10 @@
     // 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) {
+            size_t numThreads, size_t numConnections,
+            const std::function<void(const sp<RpcServer>&)>& configure) {
+        CHECK_GE(numConnections, 1) << "Must have at least one connection to a server";
+
         SocketType socketType = GetParam();
 
         std::string addr = allocateSocketAddress();
@@ -312,21 +335,18 @@
                     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
                     server->setMaxThreads(numThreads);
 
-                    // server supporting one client on one socket
-                    sp<RpcConnection> connection = server->addClientConnection();
-
                     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(vsockPort));
+                            CHECK(server->setupVsockServer(vsockPort));
                             break;
 #endif // __BIONIC__
                         case SocketType::INET: {
                             unsigned int outPort = 0;
-                            CHECK(connection->setupInetServer(0, &outPort));
+                            CHECK(server->setupInetServer(0, &outPort));
                             CHECK_NE(0, outPort);
                             CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
                                                             sizeof(outPort)));
@@ -336,11 +356,10 @@
                             LOG_ALWAYS_FATAL("Unknown socket type");
                     }
 
-                    configure(server, connection);
+                    configure(server);
 
                     server->join();
                 }),
-                .connection = RpcConnection::make(),
         };
 
         unsigned int inetPort = 0;
@@ -350,46 +369,46 @@
             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;
+        for (size_t i = 0; i < numConnections; i++) {
+            sp<RpcConnection> connection = RpcConnection::make();
+            for (size_t tries = 0; tries < 10; tries++) {
+                usleep(10000);
+                switch (socketType) {
+                    case SocketType::UNIX:
+                        if (connection->setupUnixDomainClient(addr.c_str())) goto success;
+                        break;
 #ifdef __BIONIC__
-                case SocketType::VSOCK:
-                    if (ret.connection->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
-                    break;
+                    case SocketType::VSOCK:
+                        if (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");
+                    case SocketType::INET:
+                        if (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.connections.push_back({connection, connection->getRootObject()});
         }
-        LOG_ALWAYS_FATAL("Could not connect");
-    success:
-
-        ret.rootBinder = ret.connection->getRootObject();
         return ret;
     }
 
-    BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads) {
+    BinderRpcTestProcessConnection createRpcTestSocketServerProcess(size_t numThreads,
+                                                                    size_t numConnections = 1) {
         BinderRpcTestProcessConnection ret{
-                .proc = createRpcTestSocketServerProcess(numThreads,
-                                                         [&](const sp<RpcServer>& server,
-                                                             const sp<RpcConnection>& connection) {
+                .proc = createRpcTestSocketServerProcess(numThreads, numConnections,
+                                                         [&](const sp<RpcServer>& server) {
                                                              sp<MyBinderRpcTest> service =
                                                                      new MyBinderRpcTest;
                                                              server->setRootObject(service);
-                                                             service->connection =
-                                                                     connection; // for testing only
+                                                             service->server = server;
                                                          }),
         };
 
-        ret.rootBinder = ret.proc.rootBinder;
+        ret.rootBinder = ret.proc.connections.at(0).root;
         ret.rootIface = interface_cast<IBinderRpcTest>(ret.rootBinder);
 
         return ret;
@@ -397,18 +416,12 @@
 };
 
 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, 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);
-
-    // make sure we can retrieve it again (process doesn't crash)
-    EXPECT_EQ(nullptr, proc.connection->getRootObject());
+    EXPECT_EQ(nullptr, proc.connections.at(0).root);
 }
 
 TEST_P(BinderRpc, Ping) {
@@ -423,6 +436,14 @@
     EXPECT_EQ(IBinderRpcTest::descriptor, proc.rootBinder->getInterfaceDescriptor());
 }
 
+TEST_P(BinderRpc, MultipleConnections) {
+    auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 5 /*connections*/);
+    for (auto connection : proc.proc.connections) {
+        ASSERT_NE(nullptr, connection.root);
+        EXPECT_EQ(OK, connection.root->pingBinder());
+    }
+}
+
 TEST_P(BinderRpc, TransactionsMustBeMarkedRpc) {
     auto proc = createRpcTestSocketServerProcess(1);
     Parcel data;
@@ -570,6 +591,15 @@
               proc1.rootIface->repeatBinder(proc2.rootBinder, &outBinder).transactionError());
 }
 
+TEST_P(BinderRpc, CannotMixBindersBetweenTwoConnectionsToTheSameServer) {
+    auto proc = createRpcTestSocketServerProcess(1 /*threads*/, 2 /*connections*/);
+
+    sp<IBinder> outBinder;
+    EXPECT_EQ(INVALID_OPERATION,
+              proc.rootIface->repeatBinder(proc.proc.connections.at(1).root, &outBinder)
+                      .transactionError());
+}
+
 TEST_P(BinderRpc, CannotSendRegularBinderOverSocketBinder) {
     auto proc = createRpcTestSocketServerProcess(1);
 
@@ -854,7 +884,7 @@
         EXPECT_EQ(DEAD_OBJECT, proc.rootIface->die(doDeathCleanup).transactionError())
                 << "Do death cleanup: " << doDeathCleanup;
 
-        proc.proc.expectInvalid = true;
+        proc.expectInvalid = true;
     }
 }
 
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 31027b6..61d72ad 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -87,8 +87,10 @@
     // Search system repository.
     std::string path;
 
-    // Treblized input device config files will be located /odm/usr or /vendor/usr.
-    const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
+    // Treblized input device config files will be located /product/usr, /system_ext/usr,
+    // /odm/usr or /vendor/usr.
+    const char* rootsForPartition[]{"/product", "/system_ext", "/odm", "/vendor",
+                                    getenv("ANDROID_ROOT")};
     for (size_t i = 0; i < size(rootsForPartition); i++) {
         if (rootsForPartition[i] == nullptr) {
             continue;
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 67ca3a2..570c7bc 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -118,7 +118,7 @@
     include_dirs: [
         "external/skia/src/gpu",
     ],
-    whole_static_libs: ["libskia"],
+    whole_static_libs: ["libskia_renderengine"],
     lto: {
         thin: true,
     },
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d87315f..9400037 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -249,7 +249,7 @@
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (!eglInitialize(display, nullptr, nullptr)) {
-        LOG_ALWAYS_FATAL("failed to initialize EGL");
+        LOG_ALWAYS_FATAL("failed to initialize EGL. EGL error=0x%x", eglGetError());
     }
 
     const auto eglVersion = eglQueryString(display, EGL_VERSION);
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index 2028def..5cba8fb 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -86,8 +86,8 @@
     float radiusByPasses = tmpRadius / (float)numberOfPasses;
 
     // create blur surface with the bit depth and colorspace of the original surface
-    SkImageInfo scaledInfo = input->imageInfo().makeWH(blurRect.width() * kInputScale,
-                                                       blurRect.height() * kInputScale);
+    SkImageInfo scaledInfo = input->imageInfo().makeWH(std::ceil(blurRect.width() * kInputScale),
+                                                       std::ceil(blurRect.height() * kInputScale));
 
     const float stepX = radiusByPasses;
     const float stepY = radiusByPasses;
@@ -105,7 +105,7 @@
             input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
     blurBuilder.uniform("in_blurOffset") = SkV2{stepX * kInputScale, stepY * kInputScale};
     blurBuilder.uniform("in_maxSizeXY") =
-            SkV2{blurRect.width() * kInputScale - 1, blurRect.height() * kInputScale - 1};
+            SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
 
     sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
 
@@ -116,7 +116,7 @@
                 tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
         blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
         blurBuilder.uniform("in_maxSizeXY") =
-                SkV2{blurRect.width() * kInputScale - 1, blurRect.height() * kInputScale - 1};
+                SkV2{blurRect.width() * kInputScale, blurRect.height() * kInputScale};
         tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
     }
 
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 34ef0a4..85322a9 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -487,6 +487,9 @@
     void fillBufferAndBlurBackground();
 
     template <typename SourceVariant>
+    void fillSmallLayerAndBlurBackground();
+
+    template <typename SourceVariant>
     void overlayCorners();
 
     void fillRedBufferTextureTransform();
@@ -966,11 +969,44 @@
     if (mRE->supportsBackgroundBlur()) {
         // blurred color (downsampling should result in the center color being close to 128)
         expectBufferColor(Rect(center - 1, center - 5, center + 1, center + 5), 128, 128, 0, 255,
-                          10 /* tolerance */);
+                          50 /* tolerance */);
     }
 }
 
 template <typename SourceVariant>
+void RenderEngineTest::fillSmallLayerAndBlurBackground() {
+    auto blurRadius = 50;
+    renderengine::DisplaySettings settings;
+    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    renderengine::LayerSettings backgroundLayer;
+    backgroundLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    backgroundLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    SourceVariant::fillColor(backgroundLayer, 1.0f, 0.0f, 0.0f, this);
+    backgroundLayer.alpha = 1.0f;
+    layers.push_back(&backgroundLayer);
+
+    renderengine::LayerSettings blurLayer;
+    blurLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    blurLayer.geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f);
+    blurLayer.backgroundBlurRadius = blurRadius;
+    SourceVariant::fillColor(blurLayer, 0.0f, 0.0f, 1.0f, this);
+    blurLayer.alpha = 0;
+    layers.push_back(&blurLayer);
+
+    invokeDraw(settings, layers);
+
+    // Give a generous tolerance - the blur rectangle is very small and this test is
+    // mainly concerned with ensuring that there's no device failure.
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT), 255, 0, 0, 255,
+                      40 /* tolerance */);
+}
+
+template <typename SourceVariant>
 void RenderEngineTest::overlayCorners() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1402,12 +1438,16 @@
     fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
 }
 
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_colorSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<ColorSourceVariant>();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_colorSource) {
+    initializeRenderEngine();
+    fillSmallLayerAndBlurBackground<ColorSourceVariant>();
+}
+
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
     initializeRenderEngine();
     overlayCorners<ColorSourceVariant>();
@@ -1478,12 +1518,16 @@
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_opaqueBufferSource) {
+    initializeRenderEngine();
+    fillSmallLayerAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
+
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
     initializeRenderEngine();
     overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
@@ -1554,12 +1598,16 @@
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
-// TODO(b/186010146): reenable once swiftshader is happy with this test
-TEST_P(RenderEngineTest, DISABLED_drawLayers_fillBufferAndBlurBackground_bufferSource) {
+TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
     initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillSmallLayerAndBlurBackground_bufferSource) {
+    initializeRenderEngine();
+    fillSmallLayerAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
     initializeRenderEngine();
     overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 9885352..f20bfe1 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -25,7 +25,7 @@
     name: "libsurfaceflinger_defaults",
     defaults: [
         "surfaceflinger_defaults",
-        "skia_deps",
+        "skia_renderengine_deps",
     ],
     cflags: [
         "-DLOG_TAG=\"SurfaceFlinger\"",
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 570a41a..a273230 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -51,9 +51,6 @@
         return flags;
     }
 
-    uint32_t getActiveWidth(const Layer::State& s) const override { return s.width; }
-    uint32_t getActiveHeight(const Layer::State& s) const override { return s.height; }
-    ui::Transform getActiveTransform(const Layer::State& s) const override { return s.transform; }
     Region getActiveTransparentRegion(const Layer::State& s) const override {
         return s.transparentRegionHint;
     }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index aa049a8..fd22aa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -57,11 +57,15 @@
     void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer);
 
+    // Special caching slot for the layer caching feature.
+    static const constexpr size_t FLATTENER_CACHING_SLOT = BufferQueue::NUM_BUFFER_SLOTS;
+
 private:
     // an array where the index corresponds to a slot and the value corresponds to a (counter,
     // buffer) pair. "counter" is a unique value that indicates the last time this slot was updated
     // or used and allows us to keep track of the least-recently used buffer.
-    wp<GraphicBuffer> mBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+    static const constexpr size_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
+    wp<GraphicBuffer> mBuffers[kMaxLayerBufferCount];
 };
 
 } // namespace compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index cedc333..f95382d 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -36,7 +36,7 @@
                                   sp<GraphicBuffer>* outBuffer) {
     // default is 0
     if (slot == BufferQueue::INVALID_BUFFER_SLOT || slot < 0 ||
-        slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        slot >= static_cast<int32_t>(kMaxLayerBufferCount)) {
         *outSlot = 0;
     } else {
         *outSlot = static_cast<uint32_t>(slot);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 7f5c01c..01da070 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -18,6 +18,7 @@
 #include <compositionengine/DisplayColorProfile.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/Output.h>
+#include <compositionengine/impl/HwcBufferCache.h>
 #include <compositionengine/impl/OutputCompositionState.h>
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -548,9 +549,11 @@
 
     sp<GraphicBuffer> buffer = outputIndependentState.buffer;
     sp<Fence> acquireFence = outputIndependentState.acquireFence;
+    int slot = outputIndependentState.bufferSlot;
     if (getState().overrideInfo.buffer != nullptr) {
         buffer = getState().overrideInfo.buffer->getBuffer();
         acquireFence = getState().overrideInfo.acquireFence;
+        slot = HwcBufferCache::FLATTENER_CACHING_SLOT;
     }
 
     ALOGV("Writing buffer %p", buffer.get());
@@ -559,8 +562,7 @@
     sp<GraphicBuffer> hwcBuffer;
     // We need access to the output-dependent state for the buffer cache there,
     // though otherwise the buffer is not output-dependent.
-    editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot, buffer,
-                                                 &hwcSlot, &hwcBuffer);
+    editState().hwc->hwcBufferCache.getHwcBuffer(slot, buffer, &hwcSlot, &hwcBuffer);
 
     if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
         error != hal::Error::NONE) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index e876a61..3adfe40 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <compositionengine/impl/HwcBufferCache.h>
 #include <compositionengine/impl/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <compositionengine/mock/CompositionEngine.h>
@@ -702,6 +703,7 @@
     static constexpr ui::Dataspace kOverrideDataspace = static_cast<ui::Dataspace>(72);
     static constexpr int kSupportedPerFrameMetadata = 101;
     static constexpr int kExpectedHwcSlot = 0;
+    static constexpr int kOverrideHwcSlot = impl::HwcBufferCache::FLATTENER_CACHING_SLOT;
     static constexpr bool kLayerGenericMetadata1Mandatory = true;
     static constexpr bool kLayerGenericMetadata2Mandatory = true;
 
@@ -824,10 +826,11 @@
         EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
     }
 
-    void expectSetHdrMetadataAndBufferCalls(sp<GraphicBuffer> buffer = kBuffer,
+    void expectSetHdrMetadataAndBufferCalls(uint32_t hwcSlot = kExpectedHwcSlot,
+                                            sp<GraphicBuffer> buffer = kBuffer,
                                             sp<Fence> fence = kFence) {
         EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
-        EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, buffer, fence));
+        EXPECT_CALL(*mHwcLayer, setBuffer(hwcSlot, buffer, fence));
     }
 
     void expectGenericLayerMetadataCalls() {
@@ -1060,7 +1063,7 @@
                               kOverrideBlendMode, kOverrideAlpha);
     expectPerFrameCommonCalls(SimulateUnsupported::None, kOverrideDataspace, kOverrideVisibleRegion,
                               kOverrideSurfaceDamage);
-    expectSetHdrMetadataAndBufferCalls(kOverrideBuffer, kOverrideFence);
+    expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
     expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index fd70988..1cbcf59 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -25,7 +25,6 @@
 #include "ComposerHal.h"
 
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
-#include <gui/BufferQueue.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/HidlTransportUtils.h>
 #include <log/log.h>
@@ -266,15 +265,15 @@
 Error Composer::createLayer(Display display, Layer* outLayer)
 {
     Error error = kDefaultError;
-    mClient->createLayer(display, BufferQueue::NUM_BUFFER_SLOTS,
-            [&](const auto& tmpError, const auto& tmpLayer) {
-                error = tmpError;
-                if (error != Error::NONE) {
-                    return;
-                }
+    mClient->createLayer(display, kMaxLayerBufferCount,
+                         [&](const auto& tmpError, const auto& tmpLayer) {
+                             error = tmpError;
+                             if (error != Error::NONE) {
+                                 return;
+                             }
 
-                *outLayer = tmpLayer;
-            });
+                             *outLayer = tmpLayer;
+                         });
 
     return error;
 }
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c756d65..0619b8c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -32,6 +32,7 @@
 #include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <android/hardware/graphics/composer/2.4/IComposerClient.h>
 #include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <gui/BufferQueue.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
 #include <ui/DisplayedFrameStats.h>
@@ -491,6 +492,11 @@
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
         64 * 1024 / sizeof(uint32_t) - 16;
+    // Max number of buffers that may be cached for a given layer
+    // We obtain this number by:
+    // 1. Tightly coupling this cache to the max size of BufferQueue
+    // 2. Adding an additional slot for the layer caching feature in SurfaceFlinger (see: Planner.h)
+    static const constexpr uint32_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS + 1;
     CommandWriter mWriter;
     CommandReader mReader;
 };
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 0033dbe..f19e2a7 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -730,9 +730,11 @@
 int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) {
     ATRACE_CALL();
     std::scoped_lock lock(mMutex);
+    while (mPredictions.size() >= kMaxTokens) {
+        mPredictions.erase(mPredictions.begin());
+    }
     const int64_t assignedToken = mCurrentToken++;
-    mPredictions[assignedToken] = {systemTime(), predictions};
-    flushTokens(systemTime());
+    mPredictions[assignedToken] = predictions;
     return assignedToken;
 }
 
@@ -740,23 +742,11 @@
     std::scoped_lock lock(mMutex);
     auto predictionsIterator = mPredictions.find(token);
     if (predictionsIterator != mPredictions.end()) {
-        return predictionsIterator->second.predictions;
+        return predictionsIterator->second;
     }
     return {};
 }
 
-void TokenManager::flushTokens(nsecs_t flushTime) {
-    for (auto it = mPredictions.begin(); it != mPredictions.end();) {
-        if (flushTime - it->second.timestamp >= kMaxRetentionTime) {
-            it = mPredictions.erase(it);
-        } else {
-            // Tokens are ordered by time. If i'th token is within the retention time, then the
-            // i+1'th token will also be within retention time.
-            break;
-        }
-    }
-}
-
 FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
                              JankClassificationThresholds thresholds)
       : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index 0563a53..42be55a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -92,11 +92,6 @@
     bool operator!=(const TimelineItem& other) const { return !(*this == other); }
 };
 
-struct TokenManagerPrediction {
-    nsecs_t timestamp = 0;
-    TimelineItem predictions;
-};
-
 struct JankClassificationThresholds {
     // The various thresholds for App and SF. If the actual timestamp falls within the threshold
     // compared to prediction, we treat it as on time.
@@ -334,11 +329,10 @@
 
     void flushTokens(nsecs_t flushTime) REQUIRES(mMutex);
 
-    std::map<int64_t, TokenManagerPrediction> mPredictions GUARDED_BY(mMutex);
+    std::map<int64_t, TimelineItem> mPredictions GUARDED_BY(mMutex);
     int64_t mCurrentToken GUARDED_BY(mMutex);
     mutable std::mutex mMutex;
-    static constexpr nsecs_t kMaxRetentionTime =
-            std::chrono::duration_cast<std::chrono::nanoseconds>(120ms).count();
+    static constexpr size_t kMaxTokens = 500;
 };
 
 class FrameTimeline : public android::frametimeline::FrameTimeline {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a833c85..21c9d74 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -858,7 +858,7 @@
     const State& s(getDrawingState());
     State& c(getCurrentState());
 
-    if (getActiveGeometry(c) != getActiveGeometry(s)) {
+    if (c.width != s.width || c.height != s.height || !(c.transform == s.transform)) {
         // invalidate and recompute the visible regions if needed
         flags |= Layer::eVisibleRegion;
     }
@@ -933,20 +933,18 @@
 }
 
 bool Layer::setPosition(float x, float y) {
-    if (mCurrentState.requested_legacy.transform.tx() == x &&
-        mCurrentState.requested_legacy.transform.ty() == y)
-        return false;
+    if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) return false;
     mCurrentState.sequence++;
 
     // We update the requested and active position simultaneously because
     // we want to apply the position portion of the transform matrix immediately,
     // but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
-    mCurrentState.requested_legacy.transform.set(x, y);
+    mCurrentState.transform.set(x, y);
     // Here we directly update the active state
     // unlike other setters, because we store it within
     // the transform, but use different latching rules.
     // b/38182305
-    mCurrentState.active_legacy.transform.set(x, y);
+    mCurrentState.transform.set(x, y);
 
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
@@ -1065,6 +1063,7 @@
     setDefaultBufferSize(mCurrentState.requested_legacy.w, mCurrentState.requested_legacy.h);
     return true;
 }
+
 bool Layer::setAlpha(float alpha) {
     if (mCurrentState.color.a == alpha) return false;
     mCurrentState.sequence++;
@@ -1143,8 +1142,7 @@
         return false;
     }
     mCurrentState.sequence++;
-    mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
-                                                 matrix.dsdy);
+    mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1560,20 +1558,20 @@
     info.mVisibleRegion = getVisibleRegion(display);
     info.mSurfaceDamageRegion = surfaceDamageRegion;
     info.mLayerStack = getLayerStack();
-    info.mX = ds.active_legacy.transform.tx();
-    info.mY = ds.active_legacy.transform.ty();
+    info.mX = ds.transform.tx();
+    info.mY = ds.transform.ty();
     info.mZ = ds.z;
-    info.mWidth = ds.active_legacy.w;
-    info.mHeight = ds.active_legacy.h;
+    info.mWidth = ds.width;
+    info.mHeight = ds.height;
     info.mCrop = ds.crop;
     info.mColor = ds.color;
     info.mFlags = ds.flags;
     info.mPixelFormat = getPixelFormat();
     info.mDataSpace = static_cast<android_dataspace>(getDataSpace());
-    info.mMatrix[0][0] = ds.active_legacy.transform[0][0];
-    info.mMatrix[0][1] = ds.active_legacy.transform[0][1];
-    info.mMatrix[1][0] = ds.active_legacy.transform[1][0];
-    info.mMatrix[1][1] = ds.active_legacy.transform[1][1];
+    info.mMatrix[0][0] = ds.transform[0][0];
+    info.mMatrix[0][1] = ds.transform[0][1];
+    info.mMatrix[1][0] = ds.transform[1][0];
+    info.mMatrix[1][1] = ds.transform[1][1];
     {
         sp<const GraphicBuffer> buffer = getBuffer();
         if (buffer != 0) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a83408b..284adbd 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -484,12 +484,9 @@
     // to avoid grabbing the lock again to avoid deadlock
     virtual bool isCreatedFromMainThread() const { return false; }
 
-    virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
-    virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
-    virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
-    virtual ui::Transform getActiveTransform(const Layer::State& s) const {
-        return s.active_legacy.transform;
-    }
+    uint32_t getActiveWidth(const Layer::State& s) const { return s.width; }
+    uint32_t getActiveHeight(const Layer::State& s) const { return s.height; }
+    ui::Transform getActiveTransform(const Layer::State& s) const { return s.transform; }
     virtual Region getActiveTransparentRegion(const Layer::State& s) const {
         return s.activeTransparentRegion_legacy;
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6497919..beda834 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1741,12 +1741,6 @@
 }
 
 void SurfaceFlinger::onMessageReceived(int32_t what, int64_t vsyncId, nsecs_t expectedVSyncTime) {
-    const auto vsyncIn = [&] {
-        if (!ATRACE_ENABLED()) return 0.f;
-        return (expectedVSyncTime - systemTime()) / 1e6f;
-    }();
-
-    ATRACE_FORMAT("onMessageReceived %" PRId64 " vsyncIn %.2fms", vsyncId, vsyncIn);
     switch (what) {
         case MessageQueue::INVALIDATE: {
             onMessageInvalidate(vsyncId, expectedVSyncTime);
@@ -1760,8 +1754,6 @@
 }
 
 void SurfaceFlinger::onMessageInvalidate(int64_t vsyncId, nsecs_t expectedVSyncTime) {
-    ATRACE_CALL();
-
     const nsecs_t frameStart = systemTime();
     // calculate the expected present time once and use the cached
     // value throughout this frame to make sure all layers are
@@ -1776,6 +1768,13 @@
     const nsecs_t lastScheduledPresentTime = mScheduledPresentTime;
     mScheduledPresentTime = expectedVSyncTime;
 
+    const auto vsyncIn = [&] {
+        if (!ATRACE_ENABLED()) return 0.f;
+        return (mExpectedPresentTime - systemTime()) / 1e6f;
+    }();
+    ATRACE_FORMAT("onMessageInvalidate %" PRId64 " vsyncIn %.2fms%s", vsyncId, vsyncIn,
+                  mExpectedPresentTime == expectedVSyncTime ? "" : " (adjusted)");
+
     // When Backpressure propagation is enabled we want to give a small grace period
     // for the present fence to fire instead of just giving up on this frame to handle cases
     // where present fence is just about to get signaled.
@@ -3105,7 +3104,7 @@
 
 void SurfaceFlinger::commitTransaction() {
     commitTransactionLocked();
-    signalSynchronousTransactions();
+    signalSynchronousTransactions(CountDownLatch::eSyncTransaction);
     mAnimTransactionPending = false;
 }
 
@@ -3527,7 +3526,9 @@
     // Generate a CountDownLatch pending state if this is a synchronous transaction.
     if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) {
         state.transactionCommittedSignal = std::make_shared<CountDownLatch>(
-                (state.inputWindowCommands.syncInputWindows ? 2 : 1));
+                (state.inputWindowCommands.syncInputWindows
+                         ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction)
+                         : CountDownLatch::eSyncTransaction));
     }
 
     mTransactionQueue.emplace(state);
@@ -3552,10 +3553,10 @@
     }
 }
 
-void SurfaceFlinger::signalSynchronousTransactions() {
+void SurfaceFlinger::signalSynchronousTransactions(const uint32_t flag) {
     for (auto it = mTransactionCommittedSignals.begin();
          it != mTransactionCommittedSignals.end();) {
-        if ((*it)->countDown() == 0) {
+        if ((*it)->countDown(flag)) {
             it = mTransactionCommittedSignals.erase(it);
         } else {
             it++;
@@ -6175,7 +6176,7 @@
 
 void SurfaceFlinger::setInputWindowsFinished() {
     Mutex::Autolock _l(mStateLock);
-    signalSynchronousTransactions();
+    signalSynchronousTransactions(CountDownLatch::eSyncInputWindows);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index cf1a545..4bbdd48 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -467,24 +467,31 @@
 
     class CountDownLatch {
     public:
-        explicit CountDownLatch(int32_t count) : mCount(count) {}
+        enum {
+            eSyncTransaction = 1 << 0,
+            eSyncInputWindows = 1 << 1,
+        };
+        explicit CountDownLatch(uint32_t flags) : mFlags(flags) {}
 
-        int32_t countDown() {
+        // True if there is no waiting condition after count down.
+        bool countDown(uint32_t flag) {
             std::unique_lock<std::mutex> lock(mMutex);
-            if (mCount == 0) {
-                return 0;
+            if (mFlags == 0) {
+                return true;
             }
-            if (--mCount == 0) {
+            mFlags &= ~flag;
+            if (mFlags == 0) {
                 mCountDownComplete.notify_all();
+                return true;
             }
-            return mCount;
+            return false;
         }
 
         // Return true if triggered.
         bool wait_until(const std::chrono::seconds& timeout) const {
             std::unique_lock<std::mutex> lock(mMutex);
             const auto untilTime = std::chrono::system_clock::now() + timeout;
-            while (mCount != 0) {
+            while (mFlags != 0) {
                 // Conditional variables can be woken up sporadically, so we check count
                 // to verify the wakeup was triggered by |countDown|.
                 if (std::cv_status::timeout == mCountDownComplete.wait_until(lock, untilTime)) {
@@ -495,7 +502,7 @@
         }
 
     private:
-        int32_t mCount;
+        uint32_t mFlags;
         mutable std::condition_variable mCountDownComplete;
         mutable std::mutex mMutex;
     };
@@ -1124,7 +1131,7 @@
     // Add transaction to the Transaction Queue
     void queueTransaction(TransactionState& state) EXCLUDES(mQueueLock);
     void waitForSynchronousTransaction(const CountDownLatch& transactionCommittedSignal);
-    void signalSynchronousTransactions();
+    void signalSynchronousTransactions(const uint32_t flag);
 
     /*
      * Generic Layer Metadata
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 113f463..c5f1598 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -130,8 +130,8 @@
     transaction->set_animation(layerFlags & BnSurfaceComposer::eAnimation);
 
     const int32_t layerId(getLayerId(layer));
-    addPositionLocked(transaction, layerId, layer->mCurrentState.active_legacy.transform.tx(),
-                      layer->mCurrentState.active_legacy.transform.ty());
+    addPositionLocked(transaction, layerId, layer->mCurrentState.transform.tx(),
+                      layer->mCurrentState.transform.ty());
     addDepthLocked(transaction, layerId, layer->mCurrentState.z);
     addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
     addTransparentRegionLocked(transaction, layerId,
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 6ed6148..c6a4115 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -73,7 +73,7 @@
         mTokenManager = &mFrameTimeline->mTokenManager;
         mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
         maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames;
-        maxTokenRetentionTime = mTokenManager->kMaxRetentionTime;
+        maxTokens = mTokenManager->kMaxTokens;
     }
 
     // Each tracing session can be used for a single block of Start -> Stop.
@@ -111,9 +111,11 @@
         mFrameTimeline->setSfPresent(2500, presentFence1);
     }
 
-    void flushTokens(nsecs_t flushTime) {
-        std::lock_guard<std::mutex> lock(mTokenManager->mMutex);
-        mTokenManager->flushTokens(flushTime);
+    void flushTokens() {
+        for (size_t i = 0; i < maxTokens; i++) {
+            mTokenManager->generateTokenForPredictions({});
+        }
+        EXPECT_EQ(getPredictions().size(), maxTokens);
     }
 
     SurfaceFrame& getSurfaceFrame(size_t displayFrameIdx, size_t surfaceFrameIdx) {
@@ -132,7 +134,7 @@
                 a.presentTime == b.presentTime;
     }
 
-    const std::map<int64_t, TokenManagerPrediction>& getPredictions() const {
+    const std::map<int64_t, TimelineItem>& getPredictions() const {
         return mTokenManager->mPredictions;
     }
 
@@ -155,7 +157,7 @@
     TraceCookieCounter* mTraceCookieCounter;
     FenceToFenceTimeMap fenceFactory;
     uint32_t* maxDisplayFrames;
-    nsecs_t maxTokenRetentionTime;
+    size_t maxTokens;
     static constexpr pid_t kSurfaceFlingerPid = 666;
     static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count();
     static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count();
@@ -177,12 +179,11 @@
 TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
     EXPECT_EQ(getPredictions().size(), 1u);
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
     int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30});
     std::optional<TimelineItem> predictions = mTokenManager->getPredictionsForToken(token1);
 
     // token1 should have expired
-    EXPECT_EQ(getPredictions().size(), 1u);
     EXPECT_EQ(predictions.has_value(), false);
 
     predictions = mTokenManager->getPredictionsForToken(token2);
@@ -212,7 +213,7 @@
 
 TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) {
     int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0});
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
     auto surfaceFrame =
             mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne,
                                                        sLayerIdOne, sLayerNameOne, sLayerNameOne,
@@ -707,7 +708,7 @@
                                                        sLayerNameOne, /*isBuffer*/ true);
     surfaceFrame1->setAcquireFenceTime(45);
     // Trigger a prediction expiry
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
     mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
 
     surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
@@ -1065,7 +1066,7 @@
     tracingSession->StartBlocking();
     int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
     // Flush the token so that it would expire
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
@@ -1283,7 +1284,7 @@
             mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
 
     // Flush the token so that it would expire
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
                                                        sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1359,7 +1360,7 @@
             mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
 
     // Flush the token so that it would expire
-    flushTokens(systemTime() + maxTokenRetentionTime);
+    flushTokens();
     auto surfaceFrame1 =
             mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0},
                                                        sPidOne, sUidOne, sLayerIdOne, sLayerNameOne,
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index eb24a22..80e9a3c 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -106,42 +106,6 @@
     ],
 }
 
-cc_binary {
-    name: "vr_hwc",
-    enabled: false,
-    system_ext_specific: true,
-    vintf_fragments: ["manifest_vr_hwc.xml"],
-    srcs: [
-        "vr_hardware_composer_service.cpp",
-    ],
-    static_libs: [
-        "libvr_hwc-impl",
-        // NOTE: This needs to be included after the *-impl lib otherwise the
-        // symbols in the *-binder library get optimized out.
-        "libvr_hwc-binder",
-    ],
-    shared_libs: [
-        "android.frameworks.vr.composer@2.0",
-        "android.hardware.graphics.composer@2.3",
-        "libbase",
-        "libbinder",
-        "liblog",
-        "libhardware",
-        "libhidlbase",
-        "libui",
-        "libutils",
-        "libvr_hwc-hal",
-    ],
-    cflags: [
-        "-DLOG_TAG=\"vr_hwc\"",
-        "-Wall",
-        "-Werror",
-    ],
-    init_rc: [
-        "vr_hwc.rc",
-    ],
-}
-
 cc_test {
     name: "vr_hwc_test",
     gtest: true,
diff --git a/services/vr/hardware_composer/manifest_vr_hwc.xml b/services/vr/hardware_composer/manifest_vr_hwc.xml
deleted file mode 100644
index 1068cac..0000000
--- a/services/vr/hardware_composer/manifest_vr_hwc.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
-    <hal>
-      <name>android.hardware.graphics.composer</name>
-      <transport>hwbinder</transport>
-      <version>2.1</version>
-      <interface>
-          <name>IComposer</name>
-          <instance>vr</instance>
-      </interface>
-    </hal>
-</manifest>
diff --git a/services/vr/hardware_composer/vr_hardware_composer_service.cpp b/services/vr/hardware_composer/vr_hardware_composer_service.cpp
deleted file mode 100644
index 7701847..0000000
--- a/services/vr/hardware_composer/vr_hardware_composer_service.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2017 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/ProcessState.h>
-#include <binder/IServiceManager.h>
-#include <hwbinder/IPCThreadState.h>
-#include <impl/vr_hwc.h>
-#include <inttypes.h>
-
-#include "vr_composer.h"
-
-int main() {
-  android::ProcessState::self()->startThreadPool();
-
-  // Register the hwbinder HWC HAL service used by SurfaceFlinger while in VR
-  // mode.
-  android::sp<android::dvr::VrHwc> service = new android::dvr::VrHwc();
-
-  LOG_ALWAYS_FATAL_IF(!service.get(), "Failed to get service");
-  LOG_ALWAYS_FATAL_IF(service->isRemote(), "Service is remote");
-
-  const char instance[] = "vr";
-  LOG_ALWAYS_FATAL_IF(service->registerAsService(instance) != android::OK,
-                      "Failed to register service");
-
-  android::sp<android::dvr::VrComposer> composer =
-      new android::dvr::VrComposer(service.get());
-
-  android::sp<android::IServiceManager> sm(android::defaultServiceManager());
-
-  // Register the binder service used by VR Window Manager service to receive
-  // frame information from VR HWC HAL.
-  android::status_t status = sm->addService(
-      android::dvr::VrComposer::SERVICE_NAME(), composer.get(),
-      false /* allowIsolated */);
-  LOG_ALWAYS_FATAL_IF(status != android::OK,
-                      "VrDisplay service failed to start: %" PRId32, status);
-
-  android::hardware::ProcessState::self()->startThreadPool();
-  android::hardware::IPCThreadState::self()->joinThreadPool();
-
-  return 0;
-}
diff --git a/services/vr/hardware_composer/vr_hwc.rc b/services/vr/hardware_composer/vr_hwc.rc
deleted file mode 100644
index 645ab80..0000000
--- a/services/vr/hardware_composer/vr_hwc.rc
+++ /dev/null
@@ -1,6 +0,0 @@
-service vr_hwc /system/bin/vr_hwc
-  class hal animation
-  user system
-  group system graphics
-  onrestart restart surfaceflinger
-  writepid /dev/cpuset/system-background/tasks