[automerger skipped] Merge "DO NOT MERGE -  Mark RQ2A.210105.001 as merged." am: f2a516095e -s ours am: f4f6e27ce7 -s ours am: f60bb2159c -s ours am: c34fb62965 -s ours am: 7373c1c4ea -s ours am: 14f8090d92 -s ours

am skip reason: subject contains skip directive

Original change: https://android-review.googlesource.com/c/platform/frameworks/native/+/1700266

Change-Id: Iae9a1ca62f934c8a36062ef10934244380f6e975
diff --git a/cmds/bugreport/OWNERS b/cmds/bugreport/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreport/OWNERS
+++ b/cmds/bugreport/OWNERS
@@ -1,4 +1,5 @@
 set noparent
 
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
diff --git a/cmds/bugreportz/OWNERS b/cmds/bugreportz/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/bugreportz/OWNERS
+++ b/cmds/bugreportz/OWNERS
@@ -1,4 +1,5 @@
 set noparent
 
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
diff --git a/cmds/dumpstate/OWNERS b/cmds/dumpstate/OWNERS
index 2a9b681..5f56531 100644
--- a/cmds/dumpstate/OWNERS
+++ b/cmds/dumpstate/OWNERS
@@ -1,4 +1,5 @@
 set noparent
 
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 336c5a2..8ac4ff8 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1641,6 +1641,10 @@
         MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
     } else {
         RunCommand("LSMOD", {"lsmod"});
+        RunCommand("MODULES INFO",
+                   {"sh", "-c", "cat /proc/modules | cut -d' ' -f1 | "
+                    "    while read MOD ; do echo modinfo:$MOD ; modinfo $MOD ; "
+                    "done"}, CommandOptions::AS_ROOT);
     }
 
     if (android::base::GetBoolProperty("ro.logd.kernel", false)) {
@@ -1960,6 +1964,8 @@
 
     RunDumpsys("DUMPSYS", {"connectivity"}, CommandOptions::WithTimeout(90).Build(),
                SEC_TO_MSEC(10));
+    RunDumpsys("DUMPSYS", {"vcn_management"}, CommandOptions::WithTimeout(90).Build(),
+               SEC_TO_MSEC(10));
     if (include_sensitive_info) {
         // Carrier apps' services will be dumped below in dumpsys activity service all-non-platform.
         RunDumpsys("DUMPSYS", {"carrier_config"}, CommandOptions::WithTimeout(90).Build(),
@@ -3183,6 +3189,11 @@
         // Since we do not have user consent to share the bugreport it does not get
         // copied over to the calling app but remains in the internal directory from
         // where the user can manually pull it.
+        std::string final_path = GetPath(".zip");
+        bool copy_succeeded = android::os::CopyFileToFile(path_, final_path);
+        if (copy_succeeded) {
+            android::os::UnlinkAndLogOnError(path_);
+        }
         return Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT;
     }
     // Unknown result; must be a programming error.
diff --git a/cmds/dumpsys/OWNERS b/cmds/dumpsys/OWNERS
index 4f6a89e..97a63ca 100644
--- a/cmds/dumpsys/OWNERS
+++ b/cmds/dumpsys/OWNERS
@@ -1,5 +1,6 @@
 set noparent
 
+gavincorkery@google.com
 nandana@google.com
 jsharkey@android.com
 
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
index fc745d0..d6807ff 100644
--- a/cmds/installd/OWNERS
+++ b/cmds/installd/OWNERS
@@ -9,3 +9,4 @@
 ngeoffray@google.com
 rpl@google.com
 toddke@google.com
+patb@google.com
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 9881371..059bc41 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -133,6 +133,9 @@
  * ASurfaceTransaction_OnComplete callback can be used to be notified when a frame
  * including the updates in a transaction was presented.
  *
+ * Buffers which are replaced or removed from the scene in the transaction invoking
+ * this callback may be reused after this point.
+ *
  * \param context Optional context provided by the client that is passed into
  * the callback.
  *
@@ -153,6 +156,13 @@
  * are ready to be presented. This callback will be invoked before the
  * ASurfaceTransaction_OnComplete callback.
  *
+ * This callback does not mean buffers have been released! It simply means that any new
+ * transactions applied will not overwrite the transaction for which we are receiving
+ * a callback and instead will be included in the next frame. If you are trying to avoid
+ * dropping frames (overwriting transactions), and unable to use timestamps (Which provide
+ * a more efficient solution), then this method provides a method to pace your transaction
+ * application.
+ *
  * \param context Optional context provided by the client that is passed into the callback.
  *
  * \param stats Opaque handle that can be passed to ASurfaceTransactionStats functions to query
@@ -358,6 +368,11 @@
  * enum.
  *
  * Available since API level 29.
+ *
+ * @deprecated Use setCrop, setPosition, setBufferTransform, and setScale instead. Those functions
+ * provide well defined behavior and allows for more control by the apps. It also allows the caller
+ * to set different properties at different times, instead of having to specify all the desired
+ * properties at once.
  */
 void ASurfaceTransaction_setGeometry(ASurfaceTransaction* transaction,
                                      ASurfaceControl* surface_control, const ARect& source,
diff --git a/include/input/Input.h b/include/input/Input.h
index d4defa8..389b1bd 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -356,8 +356,6 @@
     float getAxisValue(int32_t axis) const;
     status_t setAxisValue(int32_t axis, float value);
 
-    void scale(float globalScale);
-
     // Scale the pointer coordinates according to a global scale and a
     // window scale. The global scale will be applied to TOUCH/TOOL_MAJOR/MINOR
     // axes, however the window scaling will not.
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index ef7fd44..18b77e6 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -366,19 +366,45 @@
 
 pid_t IPCThreadState::getCallingPid() const
 {
+    checkContextIsBinderForUse(__func__);
     return mCallingPid;
 }
 
 const char* IPCThreadState::getCallingSid() const
 {
+    checkContextIsBinderForUse(__func__);
     return mCallingSid;
 }
 
 uid_t IPCThreadState::getCallingUid() const
 {
+    checkContextIsBinderForUse(__func__);
     return mCallingUid;
 }
 
+IPCThreadState::SpGuard* IPCThreadState::pushGetCallingSpGuard(SpGuard* guard) {
+    SpGuard* orig = mServingStackPointerGuard;
+    mServingStackPointerGuard = guard;
+    return orig;
+}
+
+void IPCThreadState::restoreGetCallingSpGuard(SpGuard* guard) {
+    mServingStackPointerGuard = guard;
+}
+
+void IPCThreadState::checkContextIsBinderForUse(const char* use) const {
+    if (mServingStackPointerGuard == nullptr) return;
+
+    if (!mServingStackPointer || mServingStackPointerGuard < mServingStackPointer) {
+        LOG_ALWAYS_FATAL("In context %s, %s does not make sense.",
+                         mServingStackPointerGuard->context, use);
+    }
+
+    // in the case mServingStackPointer is deeper in the stack than the guard,
+    // we must be serving a binder transaction (maybe nested). This is a binder
+    // context, so we don't abort
+}
+
 int64_t IPCThreadState::clearCallingIdentity()
 {
     // ignore mCallingSid for legacy reasons
@@ -847,15 +873,15 @@
 }
 
 IPCThreadState::IPCThreadState()
-    : mProcess(ProcessState::self()),
-      mServingStackPointer(nullptr),
-      mWorkSource(kUnsetWorkSource),
-      mPropagateWorkSource(false),
-      mIsLooper(false),
-      mStrictModePolicy(0),
-      mLastTransactionBinderFlags(0),
-      mCallRestriction(mProcess->mCallRestriction)
-{
+      : mProcess(ProcessState::self()),
+        mServingStackPointer(nullptr),
+        mServingStackPointerGuard(nullptr),
+        mWorkSource(kUnsetWorkSource),
+        mPropagateWorkSource(false),
+        mIsLooper(false),
+        mStrictModePolicy(0),
+        mLastTransactionBinderFlags(0),
+        mCallRestriction(mProcess->mCallRestriction) {
     pthread_setspecific(gTLS, this);
     clearCaller();
     mIn.setDataCapacity(256);
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index b503beb..6165911 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -123,16 +123,20 @@
     std::string regStr = (reRegister) ? "Re-registering" : "Registering";
     ALOGI("%s service %s", regStr.c_str(), name.c_str());
 
-    if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
-        ALOGE("Failed to register service %s", name.c_str());
+    if (Status status = manager->addService(name.c_str(), service, allowIsolated, dumpFlags);
+        !status.isOk()) {
+        ALOGE("Failed to register service %s (%s)", name.c_str(), status.toString8().c_str());
         return false;
     }
 
     if (!reRegister) {
-        if (!manager->registerClientCallback(name, service,
-                                             sp<android::os::IClientCallback>::fromExisting(this))
-                     .isOk()) {
-            ALOGE("Failed to add client callback for service %s", name.c_str());
+        if (Status status =
+                    manager->registerClientCallback(name, service,
+                                                    sp<android::os::IClientCallback>::fromExisting(
+                                                            this));
+            !status.isOk()) {
+            ALOGE("Failed to add client callback for service %s (%s)", name.c_str(),
+                  status.toString8().c_str());
             return false;
         }
 
@@ -171,10 +175,10 @@
     auto manager = interface_cast<AidlServiceManager>(asBinder(defaultServiceManager()));
 
     for (auto& [name, entry] : mRegisteredServices) {
-        bool success = manager->tryUnregisterService(name, entry.service).isOk();
+        Status status = manager->tryUnregisterService(name, entry.service);
 
-        if (!success) {
-            ALOGI("Failed to unregister service %s", name.c_str());
+        if (!status.isOk()) {
+            ALOGI("Failed to unregister service %s (%s)", name.c_str(), status.toString8().c_str());
             return false;
         }
         entry.registered = false;
diff --git a/libs/binder/RpcServer.cpp b/libs/binder/RpcServer.cpp
index 786e2db..9cc6e7f 100644
--- a/libs/binder/RpcServer.cpp
+++ b/libs/binder/RpcServer.cpp
@@ -22,6 +22,7 @@
 #include <thread>
 #include <vector>
 
+#include <android-base/scopeguard.h>
 #include <binder/Parcel.h>
 #include <binder/RpcServer.h>
 #include <log/log.h>
@@ -32,6 +33,7 @@
 
 namespace android {
 
+using base::ScopeGuard;
 using base::unique_fd;
 
 RpcServer::RpcServer() {}
@@ -49,8 +51,6 @@
     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;
@@ -58,8 +58,6 @@
     return setupSocketServer(VsockSocketAddress(kAnyCid, port));
 }
 
-#endif // __BIONIC__
-
 bool RpcServer::setupInetServer(unsigned int port, unsigned int* assignedPort) {
     const char* kAddr = "127.0.0.1";
 
@@ -111,66 +109,51 @@
 
 void RpcServer::setRootObject(const sp<IBinder>& binder) {
     std::lock_guard<std::mutex> _l(mLock);
-    mRootObject = binder;
+    mRootObjectWeak = mRootObject = binder;
+}
+
+void RpcServer::setRootObjectWeak(const wp<IBinder>& binder) {
+    std::lock_guard<std::mutex> _l(mLock);
+    mRootObject.clear();
+    mRootObjectWeak = binder;
 }
 
 sp<IBinder> RpcServer::getRootObject() {
     std::lock_guard<std::mutex> _l(mLock);
-    return mRootObject;
+    bool hasWeak = mRootObjectWeak.unsafe_get();
+    sp<IBinder> ret = mRootObjectWeak.promote();
+    ALOGW_IF(hasWeak && ret == nullptr, "RpcServer root object is freed, returning nullptr");
+    return ret;
 }
 
 void RpcServer::join() {
-    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    while (true) {
+        (void)acceptOne();
+    }
+}
 
-    std::vector<std::thread> pool;
+bool RpcServer::acceptOne() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    LOG_ALWAYS_FATAL_IF(!hasServer(), "RpcServer must be setup to join.");
+
+    unique_fd clientFd(
+            TEMP_FAILURE_RETRY(accept4(mServer.get(), nullptr, nullptr /*length*/, SOCK_CLOEXEC)));
+
+    if (clientFd < 0) {
+        ALOGE("Could not accept4 socket: %s", strerror(errno));
+        return false;
+    }
+    LOG_RPC_DETAIL("accept4 on fd %d yields fd %d", mServer.get(), clientFd.get());
+
     {
         std::lock_guard<std::mutex> _l(mLock);
-        LOG_ALWAYS_FATAL_IF(mServer.get() == -1, "RpcServer must be setup to join.");
+        std::thread thread =
+                std::thread(&RpcServer::establishConnection, this,
+                            std::move(sp<RpcServer>::fromExisting(this)), std::move(clientFd));
+        mConnectingThreads[thread.get_id()] = std::move(thread);
     }
 
-    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<RpcSession> session;
-            if (id == RPC_SESSION_ID_NEW) {
-                // new client!
-                LOG_ALWAYS_FATAL_IF(mSessionIdCounter >= INT32_MAX, "Out of session IDs");
-                mSessionIdCounter++;
-
-                session = RpcSession::make();
-                session->setForServer(wp<RpcServer>::fromExisting(this), mSessionIdCounter);
-
-                mSessions[mSessionIdCounter] = session;
-            } else {
-                auto it = mSessions.find(id);
-                if (it == mSessions.end()) {
-                    ALOGE("Cannot add thread, no record of session with ID %d", id);
-                    continue;
-                }
-                session = it->second;
-            }
-
-            session->startThread(std::move(clientFd));
-        }
-    }
+    return true;
 }
 
 std::vector<sp<RpcSession>> RpcServer::listSessions() {
@@ -183,14 +166,74 @@
     return sessions;
 }
 
-bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
-    LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
+size_t RpcServer::numUninitializedSessions() {
+    std::lock_guard<std::mutex> _l(mLock);
+    return mConnectingThreads.size();
+}
 
+void RpcServer::establishConnection(sp<RpcServer>&& server, base::unique_fd clientFd) {
+    LOG_ALWAYS_FATAL_IF(this != server.get(), "Must pass same ownership object");
+
+    // TODO(b/183988761): cannot trust this simple ID
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    bool idValid = true;
+    int32_t id;
+    if (sizeof(id) != read(clientFd.get(), &id, sizeof(id))) {
+        ALOGE("Could not read ID from fd %d", clientFd.get());
+        idValid = false;
+    }
+
+    std::thread thisThread;
+    sp<RpcSession> session;
     {
         std::lock_guard<std::mutex> _l(mLock);
-        LOG_ALWAYS_FATAL_IF(mServer.get() != -1, "Each RpcServer can only have one server.");
+
+        auto threadId = mConnectingThreads.find(std::this_thread::get_id());
+        LOG_ALWAYS_FATAL_IF(threadId == mConnectingThreads.end(),
+                            "Must establish connection on owned thread");
+        thisThread = std::move(threadId->second);
+        ScopeGuard detachGuard = [&]() { thisThread.detach(); };
+        mConnectingThreads.erase(threadId);
+
+        if (!idValid) {
+            return;
+        }
+
+        if (id == RPC_SESSION_ID_NEW) {
+            LOG_ALWAYS_FATAL_IF(mSessionIdCounter >= INT32_MAX, "Out of session IDs");
+            mSessionIdCounter++;
+
+            session = RpcSession::make();
+            session->setForServer(wp<RpcServer>::fromExisting(this), mSessionIdCounter);
+
+            mSessions[mSessionIdCounter] = session;
+        } else {
+            auto it = mSessions.find(id);
+            if (it == mSessions.end()) {
+                ALOGE("Cannot add thread, no record of session with ID %d", id);
+                return;
+            }
+            session = it->second;
+        }
+
+        detachGuard.Disable();
+        session->preJoin(std::move(thisThread));
     }
 
+    // avoid strong cycle
+    server = nullptr;
+    //
+    //
+    // DO NOT ACCESS MEMBER VARIABLES BELOW
+    //
+
+    session->join(std::move(clientFd));
+}
+
+bool RpcServer::setupSocketServer(const RpcSocketAddress& addr) {
+    LOG_RPC_DETAIL("Setting up socket server %s", addr.toString().c_str());
+    LOG_ALWAYS_FATAL_IF(hasServer(), "Each RpcServer can only have one server.");
+
     unique_fd serverFd(
             TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
     if (serverFd == -1) {
@@ -216,4 +259,39 @@
     return true;
 }
 
+void RpcServer::onSessionTerminating(const sp<RpcSession>& session) {
+    auto id = session->mId;
+    LOG_ALWAYS_FATAL_IF(id == std::nullopt, "Server sessions must be initialized with ID");
+    LOG_RPC_DETAIL("Dropping session %d", *id);
+
+    std::lock_guard<std::mutex> _l(mLock);
+    auto it = mSessions.find(*id);
+    LOG_ALWAYS_FATAL_IF(it == mSessions.end(), "Bad state, unknown session id %d", *id);
+    LOG_ALWAYS_FATAL_IF(it->second != session, "Bad state, session has id mismatch %d", *id);
+    (void)mSessions.erase(it);
+}
+
+bool RpcServer::hasServer() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    std::lock_guard<std::mutex> _l(mLock);
+    return mServer.ok();
+}
+
+unique_fd RpcServer::releaseServer() {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    std::lock_guard<std::mutex> _l(mLock);
+    return std::move(mServer);
+}
+
+bool RpcServer::setupExternalServer(base::unique_fd serverFd) {
+    LOG_ALWAYS_FATAL_IF(!mAgreedExperimental, "no!");
+    std::lock_guard<std::mutex> _l(mLock);
+    if (mServer.ok()) {
+        ALOGE("Each RpcServer can only have one server.");
+        return false;
+    }
+    mServer = std::move(serverFd);
+    return true;
+}
+
 } // namespace android
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 09ec20d..05fa49e 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -24,6 +24,7 @@
 #include <string_view>
 
 #include <binder/Parcel.h>
+#include <binder/RpcServer.h>
 #include <binder/Stability.h>
 #include <utils/String8.h>
 
@@ -48,7 +49,7 @@
     LOG_RPC_DETAIL("RpcSession destroyed %p", this);
 
     std::lock_guard<std::mutex> _l(mMutex);
-    LOG_ALWAYS_FATAL_IF(mServers.size() != 0,
+    LOG_ALWAYS_FATAL_IF(mServerConnections.size() != 0,
                         "Should not be able to destroy a session with servers in use.");
 }
 
@@ -60,14 +61,10 @@
     return setupSocketClient(UnixSocketAddress(path));
 }
 
-#ifdef __BIONIC__
-
 bool RpcSession::setupVsockClient(unsigned int cid, unsigned int port) {
     return setupSocketClient(VsockSocketAddress(cid, port));
 }
 
-#endif // __BIONIC__
-
 bool RpcSession::setupInetClient(const char* addr, unsigned int port) {
     auto aiStart = InetSocketAddress::getAddrInfo(addr, port);
     if (aiStart == nullptr) return false;
@@ -87,7 +84,7 @@
         return false;
     }
 
-    addClient(std::move(serverFd));
+    addClientConnection(std::move(serverFd));
     return true;
 }
 
@@ -96,7 +93,7 @@
     return state()->getRootObject(connection.fd(), sp<RpcSession>::fromExisting(this));
 }
 
-status_t RpcSession::getMaxThreads(size_t* maxThreads) {
+status_t RpcSession::getRemoteMaxThreads(size_t* maxThreads) {
     ExclusiveConnection connection(sp<RpcSession>::fromExisting(this), ConnectionUse::CLIENT);
     return state()->getMaxThreads(connection.fd(), sp<RpcSession>::fromExisting(this), maxThreads);
 }
@@ -134,19 +131,13 @@
     return OK;
 }
 
-void RpcSession::startThread(unique_fd client) {
-    std::lock_guard<std::mutex> _l(mMutex);
-    sp<RpcSession> holdThis = sp<RpcSession>::fromExisting(this);
-    int fd = client.release();
-    auto thread = std::thread([=] {
-        holdThis->join(unique_fd(fd));
-        {
-            std::lock_guard<std::mutex> _l(holdThis->mMutex);
-            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 RpcSession::preJoin(std::thread thread) {
+    LOG_ALWAYS_FATAL_IF(thread.get_id() != std::this_thread::get_id(), "Must own this thread");
+
+    {
+        std::lock_guard<std::mutex> _l(mMutex);
+        mThreads[thread.get_id()] = std::move(thread);
+    }
 }
 
 void RpcSession::join(unique_fd client) {
@@ -166,6 +157,30 @@
 
     LOG_ALWAYS_FATAL_IF(!removeServerConnection(connection),
                         "bad state: connection object guaranteed to be in list");
+
+    {
+        std::lock_guard<std::mutex> _l(mMutex);
+        auto it = mThreads.find(std::this_thread::get_id());
+        LOG_ALWAYS_FATAL_IF(it == mThreads.end());
+        it->second.detach();
+        mThreads.erase(it);
+    }
+}
+
+void RpcSession::terminateLocked() {
+    // TODO(b/185167543):
+    // - kindly notify other side of the connection of termination (can't be
+    // locked)
+    // - prevent new client/servers from being added
+    // - stop all threads which are currently reading/writing
+    // - terminate RpcState?
+
+    if (mTerminated) return;
+
+    sp<RpcServer> server = mForServer.promote();
+    if (server) {
+        server->onSessionTerminating(sp<RpcSession>::fromExisting(this));
+    }
 }
 
 wp<RpcServer> RpcSession::server() {
@@ -175,9 +190,9 @@
 bool RpcSession::setupSocketClient(const RpcSocketAddress& addr) {
     {
         std::lock_guard<std::mutex> _l(mMutex);
-        LOG_ALWAYS_FATAL_IF(mClients.size() != 0,
+        LOG_ALWAYS_FATAL_IF(mClientConnections.size() != 0,
                             "Must only setup session once, but already has %zu clients",
-                            mClients.size());
+                            mClientConnections.size());
     }
 
     if (!setupOneSocketClient(addr, RPC_SESSION_ID_NEW)) return false;
@@ -186,7 +201,7 @@
     // instead of all at once.
     // TODO(b/186470974): first risk of blocking
     size_t numThreadsAvailable;
-    if (status_t status = getMaxThreads(&numThreadsAvailable); status != OK) {
+    if (status_t status = getRemoteMaxThreads(&numThreadsAvailable); status != OK) {
         ALOGE("Could not get max threads after initial session to %s: %s", addr.toString().c_str(),
               statusToString(status).c_str());
         return false;
@@ -200,49 +215,59 @@
 
     // 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, mId.value())) break;
-            usleep(10000);
-        }
+        // TODO(b/185167543): shutdown existing connections?
+        if (!setupOneSocketClient(addr, mId.value())) return false;
     }
 
     return true;
 }
 
 bool RpcSession::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) {
-        int savedErrno = errno;
-        ALOGE("Could not create socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
-        return false;
+    for (size_t tries = 0; tries < 5; tries++) {
+        if (tries > 0) usleep(10000);
+
+        unique_fd serverFd(
+                TEMP_FAILURE_RETRY(socket(addr.addr()->sa_family, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+        if (serverFd == -1) {
+            int savedErrno = errno;
+            ALOGE("Could not create socket at %s: %s", addr.toString().c_str(),
+                  strerror(savedErrno));
+            return false;
+        }
+
+        if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
+            if (errno == ECONNRESET) {
+                ALOGW("Connection reset on %s", addr.toString().c_str());
+                continue;
+            }
+            int savedErrno = errno;
+            ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(),
+                  strerror(savedErrno));
+            return false;
+        }
+
+        if (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());
+
+        addClientConnection(std::move(serverFd));
+        return true;
     }
 
-    if (0 != TEMP_FAILURE_RETRY(connect(serverFd.get(), addr.addr(), addr.addrSize()))) {
-        int savedErrno = errno;
-        ALOGE("Could not connect socket at %s: %s", addr.toString().c_str(), strerror(savedErrno));
-        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;
+    ALOGE("Ran out of retries to connect to %s", addr.toString().c_str());
+    return false;
 }
 
-void RpcSession::addClient(unique_fd fd) {
+void RpcSession::addClientConnection(unique_fd fd) {
     std::lock_guard<std::mutex> _l(mMutex);
     sp<RpcConnection> session = sp<RpcConnection>::make();
     session->fd = std::move(fd);
-    mClients.push_back(session);
+    mClientConnections.push_back(session);
 }
 
 void RpcSession::setForServer(const wp<RpcServer>& server, int32_t sessionId) {
@@ -255,15 +280,19 @@
     sp<RpcConnection> session = sp<RpcConnection>::make();
     session->fd = std::move(fd);
     session->exclusiveTid = gettid();
-    mServers.push_back(session);
+    mServerConnections.push_back(session);
 
     return session;
 }
 
 bool RpcSession::removeServerConnection(const sp<RpcConnection>& connection) {
     std::lock_guard<std::mutex> _l(mMutex);
-    if (auto it = std::find(mServers.begin(), mServers.end(), connection); it != mServers.end()) {
-        mServers.erase(it);
+    if (auto it = std::find(mServerConnections.begin(), mServerConnections.end(), connection);
+        it != mServerConnections.end()) {
+        mServerConnections.erase(it);
+        if (mServerConnections.size() == 0) {
+            terminateLocked();
+        }
         return true;
     }
     return false;
@@ -283,10 +312,11 @@
         // CHECK FOR DEDICATED CLIENT SOCKET
         //
         // A server/looper should always use a dedicated session if available
-        findConnection(tid, &exclusive, &available, mSession->mClients, mSession->mClientsOffset);
+        findConnection(tid, &exclusive, &available, mSession->mClientConnections,
+                       mSession->mClientConnectionsOffset);
 
         // WARNING: this assumes a server cannot request its client to send
-        // a transaction, as mServers is excluded below.
+        // a transaction, as mServerConnections is excluded below.
         //
         // Imagine we have more than one thread in play, and a single thread
         // sends a synchronous, then an asynchronous command. Imagine the
@@ -296,7 +326,8 @@
         // command. So, we move to considering the second available thread
         // for subsequent calls.
         if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
-            mSession->mClientsOffset = (mSession->mClientsOffset + 1) % mSession->mClients.size();
+            mSession->mClientConnectionsOffset =
+                    (mSession->mClientConnectionsOffset + 1) % mSession->mClientConnections.size();
         }
 
         // USE SERVING SOCKET (for nested transaction)
@@ -304,7 +335,7 @@
         // asynchronous calls cannot be nested
         if (use != ConnectionUse::CLIENT_ASYNC) {
             // server connections are always assigned to a thread
-            findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServers,
+            findConnection(tid, &exclusive, nullptr /*available*/, mSession->mServerConnections,
                            0 /* index hint */);
         }
 
@@ -320,13 +351,13 @@
         }
 
         // in regular binder, this would usually be a deadlock :)
-        LOG_ALWAYS_FATAL_IF(mSession->mClients.size() == 0,
+        LOG_ALWAYS_FATAL_IF(mSession->mClientConnections.size() == 0,
                             "Not a client of any session. You must create a session to an "
                             "RPC server to make any non-nested (e.g. oneway or on another thread) "
                             "calls.");
 
         LOG_RPC_DETAIL("No available session (have %zu clients and %zu servers). Waiting...",
-                       mSession->mClients.size(), mSession->mServers.size());
+                       mSession->mClientConnections.size(), mSession->mServerConnections.size());
         mSession->mAvailableConnectionCv.wait(_l);
     }
     mSession->mWaitingThreads--;
diff --git a/libs/binder/RpcSocketAddress.h b/libs/binder/RpcSocketAddress.h
index c6a06cf..c7ba5d9 100644
--- a/libs/binder/RpcSocketAddress.h
+++ b/libs/binder/RpcSocketAddress.h
@@ -24,9 +24,7 @@
 #include <sys/types.h>
 #include <sys/un.h>
 
-#ifdef __BIONIC__
-#include <linux/vm_sockets.h>
-#endif
+#include "vm_sockets.h"
 
 namespace android {
 
@@ -59,8 +57,6 @@
     sockaddr_un mAddr;
 };
 
-#ifdef __BIONIC__
-
 class VsockSocketAddress : public RpcSocketAddress {
 public:
     VsockSocketAddress(unsigned int cid, unsigned int port)
@@ -80,8 +76,6 @@
     sockaddr_vm mAddr;
 };
 
-#endif // __BIONIC__
-
 class InetSocketAddress : public RpcSocketAddress {
 public:
     InetSocketAddress(const sockaddr* sockAddr, size_t size, const char* addr, unsigned int port)
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 96190dc..e5a6026 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -18,7 +18,9 @@
 
 #include "RpcState.h"
 
+#include <android-base/scopeguard.h>
 #include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
 #include <binder/RpcServer.h>
 
 #include "Debug.h"
@@ -28,6 +30,8 @@
 
 namespace android {
 
+using base::ScopeGuard;
+
 RpcState::RpcState() {}
 RpcState::~RpcState() {}
 
@@ -182,6 +186,27 @@
     }
 }
 
+RpcState::CommandData::CommandData(size_t size) : mSize(size) {
+    // The maximum size for regular binder is 1MB for all concurrent
+    // transactions. A very small proportion of transactions are even
+    // larger than a page, but we need to avoid allocating too much
+    // data on behalf of an arbitrary client, or we could risk being in
+    // a position where a single additional allocation could run out of
+    // memory.
+    //
+    // Note, this limit may not reflect the total amount of data allocated for a
+    // transaction (in some cases, additional fixed size amounts are added),
+    // though for rough consistency, we should avoid cases where this data type
+    // is used for multiple dynamic allocations for a single transaction.
+    constexpr size_t kMaxTransactionAllocation = 100 * 1000;
+    if (size == 0) return;
+    if (size > kMaxTransactionAllocation) {
+        ALOGW("Transaction requested too much data allocation %zu", size);
+        return;
+    }
+    mData.reset(new (std::nothrow) uint8_t[size]);
+}
+
 bool RpcState::rpcSend(const base::unique_fd& fd, const char* what, const void* data, size_t size) {
     LOG_RPC_DETAIL("Sending %s on fd %d: %s", what, fd.get(), hexString(data, size).c_str());
 
@@ -326,7 +351,11 @@
             .asyncNumber = asyncNumber,
     };
 
-    std::vector<uint8_t> transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+    CommandData transactionData(sizeof(RpcWireTransaction) + data.dataSize());
+    if (!transactionData.valid()) {
+        return NO_MEMORY;
+    }
+
     memcpy(transactionData.data() + 0, &transaction, sizeof(RpcWireTransaction));
     memcpy(transactionData.data() + sizeof(RpcWireTransaction), data.data(), data.dataSize());
 
@@ -379,9 +408,12 @@
         if (status != OK) return status;
     }
 
-    uint8_t* data = new uint8_t[command.bodySize];
+    CommandData data(command.bodySize);
+    if (!data.valid()) {
+        return NO_MEMORY;
+    }
 
-    if (!rpcRec(fd, "reply body", data, command.bodySize)) {
+    if (!rpcRec(fd, "reply body", data.data(), command.bodySize)) {
         return DEAD_OBJECT;
     }
 
@@ -391,9 +423,10 @@
         terminate();
         return BAD_VALUE;
     }
-    RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data);
+    RpcWireReply* rpcReply = reinterpret_cast<RpcWireReply*>(data.data());
     if (rpcReply->status != OK) return rpcReply->status;
 
+    data.release();
     reply->ipcSetDataReference(rpcReply->data, command.bodySize - offsetof(RpcWireReply, data),
                                nullptr, 0, cleanup_reply_data);
 
@@ -441,6 +474,18 @@
 
 status_t RpcState::processServerCommand(const base::unique_fd& fd, const sp<RpcSession>& session,
                                         const RpcWireHeader& command) {
+    IPCThreadState* kernelBinderState = IPCThreadState::selfOrNull();
+    IPCThreadState::SpGuard spGuard{"processing binder RPC command"};
+    IPCThreadState::SpGuard* origGuard;
+    if (kernelBinderState != nullptr) {
+        origGuard = kernelBinderState->pushGetCallingSpGuard(&spGuard);
+    }
+    ScopeGuard guardUnguard = [&]() {
+        if (kernelBinderState != nullptr) {
+            kernelBinderState->restoreGetCallingSpGuard(origGuard);
+        }
+    };
+
     switch (command.command) {
         case RPC_COMMAND_TRANSACT:
             return processTransact(fd, session, command);
@@ -461,7 +506,10 @@
                                    const RpcWireHeader& command) {
     LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_TRANSACT, "command: %d", command.command);
 
-    std::vector<uint8_t> transactionData(command.bodySize);
+    CommandData transactionData(command.bodySize);
+    if (!transactionData.valid()) {
+        return NO_MEMORY;
+    }
     if (!rpcRec(fd, "transaction body", transactionData.data(), transactionData.size())) {
         return DEAD_OBJECT;
     }
@@ -479,7 +527,7 @@
 }
 
 status_t RpcState::processTransactInternal(const base::unique_fd& fd, const sp<RpcSession>& session,
-                                           std::vector<uint8_t>&& transactionData) {
+                                           CommandData transactionData) {
     if (transactionData.size() < sizeof(RpcWireTransaction)) {
         ALOGE("Expecting %zu but got %zu bytes for RpcWireTransaction. Terminating!",
               sizeof(RpcWireTransaction), transactionData.size());
@@ -500,7 +548,6 @@
         auto it = mNodeForAddress.find(addr);
         if (it == mNodeForAddress.end()) {
             ALOGE("Unknown binder address %s.", addr.toString().c_str());
-            dump();
             replyStatus = BAD_VALUE;
         } else {
             target = it->second.binder.promote();
@@ -630,7 +677,7 @@
                 // justification for const_cast (consider avoiding priority_queue):
                 // - AsyncTodo operator< doesn't depend on 'data' object
                 // - gotta go fast
-                std::vector<uint8_t> data = std::move(
+                CommandData data = std::move(
                         const_cast<BinderNode::AsyncTodo&>(it->second.asyncTodo.top()).data);
                 it->second.asyncTodo.pop();
                 _l.unlock();
@@ -644,7 +691,10 @@
             .status = replyStatus,
     };
 
-    std::vector<uint8_t> replyData(sizeof(RpcWireReply) + reply.dataSize());
+    CommandData replyData(sizeof(RpcWireReply) + reply.dataSize());
+    if (!replyData.valid()) {
+        return NO_MEMORY;
+    }
     memcpy(replyData.data() + 0, &rpcReply, sizeof(RpcWireReply));
     memcpy(replyData.data() + sizeof(RpcWireReply), reply.data(), reply.dataSize());
 
@@ -671,7 +721,10 @@
 status_t RpcState::processDecStrong(const base::unique_fd& fd, const RpcWireHeader& command) {
     LOG_ALWAYS_FATAL_IF(command.command != RPC_COMMAND_DEC_STRONG, "command: %d", command.command);
 
-    std::vector<uint8_t> commandData(command.bodySize);
+    CommandData commandData(command.bodySize);
+    if (!commandData.valid()) {
+        return NO_MEMORY;
+    }
     if (!rpcRec(fd, "dec ref body", commandData.data(), commandData.size())) {
         return DEAD_OBJECT;
     }
@@ -690,7 +743,6 @@
     auto it = mNodeForAddress.find(addr);
     if (it == mNodeForAddress.end()) {
         ALOGE("Unknown binder address %s for dec strong.", addr.toString().c_str());
-        dump();
         return OK;
     }
 
diff --git a/libs/binder/RpcState.h b/libs/binder/RpcState.h
index 3f3eb1c..31f8a22 100644
--- a/libs/binder/RpcState.h
+++ b/libs/binder/RpcState.h
@@ -21,6 +21,7 @@
 #include <binder/RpcSession.h>
 
 #include <map>
+#include <optional>
 #include <queue>
 
 namespace android {
@@ -100,6 +101,20 @@
      */
     void terminate();
 
+    // Alternative to std::vector<uint8_t> that doesn't abort on allocation failure and caps
+    // large allocations to avoid being requested from allocating too much data.
+    struct CommandData {
+        explicit CommandData(size_t size);
+        bool valid() { return mSize == 0 || mData != nullptr; }
+        size_t size() { return mSize; }
+        uint8_t* data() { return mData.get(); }
+        uint8_t* release() { return mData.release(); }
+
+    private:
+        std::unique_ptr<uint8_t[]> mData;
+        size_t mSize;
+    };
+
     [[nodiscard]] bool rpcSend(const base::unique_fd& fd, const char* what, const void* data,
                                size_t size);
     [[nodiscard]] bool rpcRec(const base::unique_fd& fd, const char* what, void* data, size_t size);
@@ -113,7 +128,7 @@
                                            const RpcWireHeader& command);
     [[nodiscard]] status_t processTransactInternal(const base::unique_fd& fd,
                                                    const sp<RpcSession>& session,
-                                                   std::vector<uint8_t>&& transactionData);
+                                                   CommandData transactionData);
     [[nodiscard]] status_t processDecStrong(const base::unique_fd& fd,
                                             const RpcWireHeader& command);
 
@@ -148,7 +163,7 @@
 
         // async transaction queue, _only_ for local binder
         struct AsyncTodo {
-            std::vector<uint8_t> data; // most convenient format, to move it here
+            CommandData data;
             uint64_t asyncNumber = 0;
 
             bool operator<(const AsyncTodo& o) const {
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 23a0cb0..5220b62 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -81,6 +81,32 @@
              */
             uid_t               getCallingUid() const;
 
+            /**
+             * Make it an abort to rely on getCalling* for a section of
+             * execution.
+             *
+             * Usage:
+             *     IPCThreadState::SpGuard guard { "..." };
+             *     auto* orig = pushGetCallingSpGuard(&guard);
+             *     {
+             *         // will abort if you call getCalling*, unless you are
+             *         // serving a nested binder transaction
+             *     }
+             *     restoreCallingSpGuard(orig);
+             */
+            struct SpGuard {
+                const char* context;
+            };
+            SpGuard* pushGetCallingSpGuard(SpGuard* guard);
+            void restoreGetCallingSpGuard(SpGuard* guard);
+            /**
+             * Used internally by getCalling*. Can also be used to assert that
+             * you are in a binder context (getCalling* is valid). This is
+             * intentionally not exposed as a boolean API since code should be
+             * written to know its environment.
+             */
+            void checkContextIsBinderForUse(const char* use) const;
+
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
 
@@ -203,6 +229,7 @@
             Parcel              mOut;
             status_t            mLastError;
             const void*         mServingStackPointer;
+            SpGuard* mServingStackPointerGuard;
             pid_t               mCallingPid;
             const char*         mCallingSid;
             uid_t               mCallingUid;
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 9659732..f3ba830 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -50,8 +50,12 @@
                               int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
      /**
       * Force the service to persist, even when it has 0 clients.
-      * If setting this flag from the server side, make sure to do so before calling registerService,
-      * or there may be a race with the default dynamic shutdown.
+      * If setting this flag from the server side, make sure to do so before calling
+      * registerService, or there may be a race with the default dynamic shutdown.
+      *
+      * This should only be used if it is every eventually set to false. If a
+      * service needs to persist but doesn't need to dynamically shut down,
+      * prefer to control it with another mechanism such as ctl.start.
       */
      void forcePersist(bool persist);
 
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index c98151d..8f0c6fd 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -22,6 +22,7 @@
 #include <utils/RefBase.h>
 
 #include <mutex>
+#include <thread>
 
 // WARNING: This is a feature which is still in development, and it is subject
 // to radical change. Any production use of this may subject your code to any
@@ -57,12 +58,10 @@
      */
     [[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.
@@ -75,6 +74,22 @@
      */
     [[nodiscard]] bool setupInetServer(unsigned int port, unsigned int* assignedPort);
 
+    /**
+     * If setup*Server has been successful, return true. Otherwise return false.
+     */
+    [[nodiscard]] bool hasServer();
+
+    /**
+     * If hasServer(), return the server FD. Otherwise return invalid FD.
+     */
+    [[nodiscard]] base::unique_fd releaseServer();
+
+    /**
+     * Set up server using an external FD previously set up by releaseServer().
+     * Return false if there's already a server.
+     */
+    bool setupExternalServer(base::unique_fd serverFd);
+
     void iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
 
     /**
@@ -91,8 +106,14 @@
     /**
      * The root object can be retrieved by any client, without any
      * authentication. TODO(b/183988761)
+     *
+     * Holds a strong reference to the root object.
      */
     void setRootObject(const sp<IBinder>& binder);
+    /**
+     * Holds a weak reference to the root object.
+     */
+    void setRootObjectWeak(const wp<IBinder>& binder);
     sp<IBinder> getRootObject();
 
     /**
@@ -103,16 +124,28 @@
     void join();
 
     /**
+     * Accept one connection on this server. You must have at least one client
+     * session before calling this.
+     */
+    [[nodiscard]] bool acceptOne();
+
+    /**
      * For debugging!
      */
     std::vector<sp<RpcSession>> listSessions();
+    size_t numUninitializedSessions();
 
     ~RpcServer();
 
+    // internal use only
+
+    void onSessionTerminating(const sp<RpcSession>& session);
+
 private:
     friend sp<RpcServer>;
     RpcServer();
 
+    void establishConnection(sp<RpcServer>&& session, base::unique_fd clientFd);
     bool setupSocketServer(const RpcSocketAddress& address);
 
     bool mAgreedExperimental = false;
@@ -121,7 +154,9 @@
     base::unique_fd mServer; // socket we are accepting sessions on
 
     std::mutex mLock; // for below
+    std::map<std::thread::id, std::thread> mConnectingThreads;
     sp<IBinder> mRootObject;
+    wp<IBinder> mRootObjectWeak;
     std::map<int32_t, sp<RpcSession>> mSessions;
     int32_t mSessionIdCounter = 0;
 };
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 3f58b2c..bcc213c 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -52,12 +52,10 @@
      */
     [[nodiscard]] bool setupUnixDomainClient(const char* path);
 
-#ifdef __BIONIC__
     /**
      * Connects to an RPC server at the CVD & port.
      */
     [[nodiscard]] bool setupVsockClient(unsigned int cvd, unsigned int port);
-#endif // __BIONIC__
 
     /**
      * Connects to an RPC server at the given address and port.
@@ -83,7 +81,7 @@
      * Query the other side of the session for the maximum number of threads
      * it supports (maximum number of concurrent non-nested synchronous transactions)
      */
-    status_t getMaxThreads(size_t* maxThreads);
+    status_t getRemoteMaxThreads(size_t* maxThreads);
 
     [[nodiscard]] status_t transact(const RpcAddress& address, uint32_t code, const Parcel& data,
                                     Parcel* reply, uint32_t flags);
@@ -116,8 +114,11 @@
 
     status_t readId();
 
-    void startThread(base::unique_fd client);
+    // transfer ownership of thread
+    void preJoin(std::thread thread);
+    // join on thread passed to preJoin
     void join(base::unique_fd client);
+    void terminateLocked();
 
     struct RpcConnection : public RefBase {
         base::unique_fd fd;
@@ -129,7 +130,7 @@
 
     bool setupSocketClient(const RpcSocketAddress& address);
     bool setupOneSocketClient(const RpcSocketAddress& address, int32_t sessionId);
-    void addClient(base::unique_fd fd);
+    void addClientConnection(base::unique_fd fd);
     void setForServer(const wp<RpcServer>& server, int32_t sessionId);
     sp<RpcConnection> assignServerToThisThread(base::unique_fd fd);
     bool removeServerConnection(const sp<RpcConnection>& connection);
@@ -162,13 +163,13 @@
         bool mReentrant = false;
     };
 
-    // On the other side of a session, for each of mClients here, there should
-    // be one of mServers on the other side (and vice versa).
+    // On the other side of a session, for each of mClientConnections here, there should
+    // be one of mServerConnections on the other side (and vice versa).
     //
     // For the simplest session, a single server with one client, you would
     // have:
-    //  - the server has a single 'mServers' and a thread listening on this
-    //  - the client has a single 'mClients' and makes calls to this
+    //  - the server has a single 'mServerConnections' and a thread listening on this
+    //  - the client has a single 'mClientConnections' and makes calls to this
     //  - here, when the client makes a call, the server can call back into it
     //    (nested calls), but outside of this, the client will only ever read
     //    calls from the server when it makes a call itself.
@@ -187,15 +188,17 @@
 
     std::condition_variable mAvailableConnectionCv; // for mWaitingThreads
     size_t mWaitingThreads = 0;
-    size_t mClientsOffset = 0; // hint index into clients, ++ when sending an async transaction
-    std::vector<sp<RpcConnection>> mClients;
-    std::vector<sp<RpcConnection>> mServers;
+    // hint index into clients, ++ when sending an async transaction
+    size_t mClientConnectionsOffset = 0;
+    std::vector<sp<RpcConnection>> mClientConnections;
+    std::vector<sp<RpcConnection>> mServerConnections;
 
     // TODO(b/185167543): use for reverse sessions (allow client to also
     // serve calls on a session).
     // TODO(b/185167543): allow sharing between different sessions in a
-    // process? (or combine with mServers)
+    // process? (or combine with mServerConnections)
     std::map<std::thread::id, std::thread> mThreads;
+    bool mTerminated = false;
 };
 
 } // namespace android
diff --git a/libs/binder/ndk/include_platform/android/binder_manager.h b/libs/binder/ndk/include_platform/android/binder_manager.h
index a90b4aa..2a66941 100644
--- a/libs/binder/ndk/include_platform/android/binder_manager.h
+++ b/libs/binder/ndk/include_platform/android/binder_manager.h
@@ -35,7 +35,7 @@
  * \return EX_NONE on success.
  */
 __attribute__((warn_unused_result)) binder_exception_t AServiceManager_addService(
-        AIBinder* binder, const char* instance);
+        AIBinder* binder, const char* instance) __INTRODUCED_IN(29);
 
 /**
  * Gets a binder object with this specific instance name. Will return nullptr immediately if the
@@ -47,7 +47,8 @@
  *
  * \param instance identifier of the service used to lookup the service.
  */
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_checkService(const char* instance)
+        __INTRODUCED_IN(29);
 
 /**
  * Gets a binder object with this specific instance name. Blocks for a couple of seconds waiting on
@@ -59,7 +60,8 @@
  *
  * \param instance identifier of the service used to lookup the service.
  */
-__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance);
+__attribute__((warn_unused_result)) AIBinder* AServiceManager_getService(const char* instance)
+        __INTRODUCED_IN(29);
 
 /**
  * Registers a lazy service with the default service manager under the 'instance' name.
@@ -135,6 +137,10 @@
 /**
  * Prevent lazy services without client from shutting down their process
  *
+ * This should only be used if it is every eventually set to false. If a
+ * service needs to persist but doesn't need to dynamically shut down,
+ * prefer to control it with another mechanism.
+ *
  * \param persist 'true' if the process should not exit.
  */
 void AServiceManager_forceLazyServicesPersist(bool persist) __INTRODUCED_IN(31);
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index c0f7c99..ec231b2 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -63,6 +63,9 @@
         "libbinder",
         "libutils",
     ],
+    static_libs: [
+        "libgmock",
+    ],
     compile_multilib: "32",
     multilib: { lib32: { suffix: "" } },
     cflags: ["-DBINDER_IPC_32BIT=1"],
@@ -101,6 +104,9 @@
         "libbinder",
         "libutils",
     ],
+    static_libs: [
+        "libgmock",
+    ],
     test_suites: ["device-tests", "vts"],
     require_root: true,
 }
diff --git a/libs/binder/tests/IBinderRpcTest.aidl b/libs/binder/tests/IBinderRpcTest.aidl
index ef4198d..41daccc 100644
--- a/libs/binder/tests/IBinderRpcTest.aidl
+++ b/libs/binder/tests/IBinderRpcTest.aidl
@@ -55,4 +55,6 @@
     oneway void sleepMsAsync(int ms);
 
     void die(boolean cleanup);
+
+    void useKernelBinderCallingId();
 }
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 5676bd1..45b2776 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <thread>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <binder/Binder.h>
@@ -41,6 +42,13 @@
 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
 
 using namespace android;
+using testing::Not;
+
+// e.g. EXPECT_THAT(expr, StatusEq(OK)) << "additional message";
+MATCHER_P(StatusEq, expected, (negation ? "not " : "") + statusToString(expected)) {
+    *result_listener << statusToString(arg);
+    return expected == arg;
+}
 
 static ::testing::AssertionResult IsPageAligned(void *buf) {
     if (((unsigned long)buf & ((unsigned long)PAGE_SIZE - 1)) == 0)
@@ -65,6 +73,7 @@
     BINDER_LIB_TEST_REGISTER_SERVER,
     BINDER_LIB_TEST_ADD_SERVER,
     BINDER_LIB_TEST_ADD_POLL_SERVER,
+    BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION,
     BINDER_LIB_TEST_CALL_BACK,
     BINDER_LIB_TEST_CALL_BACK_VERIFY_BUF,
     BINDER_LIB_TEST_DELAYED_CALL_BACK,
@@ -205,19 +214,16 @@
     protected:
         sp<IBinder> addServerEtc(int32_t *idPtr, int code)
         {
-            int ret;
             int32_t id;
             Parcel data, reply;
             sp<IBinder> binder;
 
-            ret = m_server->transact(code, data, &reply);
-            EXPECT_EQ(NO_ERROR, ret);
+            EXPECT_THAT(m_server->transact(code, data, &reply), StatusEq(NO_ERROR));
 
             EXPECT_FALSE(binder != nullptr);
             binder = reply.readStrongBinder();
             EXPECT_TRUE(binder != nullptr);
-            ret = reply.readInt32(&id);
-            EXPECT_EQ(NO_ERROR, ret);
+            EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
             if (idPtr)
                 *idPtr = id;
             return binder;
@@ -401,29 +407,25 @@
 };
 
 TEST_F(BinderLibTest, NopTransaction) {
-    status_t ret;
     Parcel data, reply;
-    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, NopTransactionOneway) {
-    status_t ret;
     Parcel data, reply;
-    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY),
+                StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, NopTransactionClear) {
-    status_t ret;
     Parcel data, reply;
     // make sure it accepts the transaction flag
-    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_CLEAR_BUF),
+                StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, Freeze) {
-    status_t ret;
     Parcel data, reply, replypid;
     std::ifstream freezer_file("/sys/fs/cgroup/freezer/cgroup.freeze");
 
@@ -442,9 +444,8 @@
         return;
     }
 
-    ret = m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GETPID, data, &replypid), StatusEq(NO_ERROR));
     int32_t pid = replypid.readInt32();
-    EXPECT_EQ(NO_ERROR, ret);
     for (int i = 0; i < 10; i++) {
         EXPECT_EQ(NO_ERROR, m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION_WAIT, data, &reply, TF_ONE_WAY));
     }
@@ -468,42 +469,36 @@
 TEST_F(BinderLibTest, SetError) {
     int32_t testValue[] = { 0, -123, 123 };
     for (size_t i = 0; i < ARRAY_SIZE(testValue); i++) {
-        status_t ret;
         Parcel data, reply;
         data.writeInt32(testValue[i]);
-        ret = m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply);
-        EXPECT_EQ(testValue[i], ret);
+        EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_SET_ERROR_TRANSACTION, data, &reply),
+                    StatusEq(testValue[i]));
     }
 }
 
 TEST_F(BinderLibTest, GetId) {
-    status_t ret;
     int32_t id;
     Parcel data, reply;
-    ret = m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = reply.readInt32(&id);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_ID_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
+    EXPECT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
     EXPECT_EQ(0, id);
 }
 
 TEST_F(BinderLibTest, PtrSize) {
-    status_t ret;
     int32_t ptrsize;
     Parcel data, reply;
     sp<IBinder> server = addServer();
     ASSERT_TRUE(server != nullptr);
-    ret = server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = reply.readInt32(&ptrsize);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
+    EXPECT_THAT(reply.readInt32(&ptrsize), StatusEq(NO_ERROR));
     RecordProperty("TestPtrSize", sizeof(void *));
     RecordProperty("ServerPtrSize", sizeof(void *));
 }
 
 TEST_F(BinderLibTest, IndirectGetId2)
 {
-    status_t ret;
     int32_t id;
     int32_t count;
     Parcel data, reply;
@@ -521,22 +516,19 @@
         datai.appendTo(&data);
     }
 
-    ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
 
-    ret = reply.readInt32(&id);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
     EXPECT_EQ(0, id);
 
-    ret = reply.readInt32(&count);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR));
     EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
         BinderLibTestBundle replyi(&reply);
         EXPECT_TRUE(replyi.isValid());
-        ret = replyi.readInt32(&id);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(replyi.readInt32(&id), StatusEq(NO_ERROR));
         EXPECT_EQ(serverId[i], id);
         EXPECT_EQ(replyi.dataSize(), replyi.dataPosition());
     }
@@ -546,7 +538,6 @@
 
 TEST_F(BinderLibTest, IndirectGetId3)
 {
-    status_t ret;
     int32_t id;
     int32_t count;
     Parcel data, reply;
@@ -571,15 +562,13 @@
         datai.appendTo(&data);
     }
 
-    ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
 
-    ret = reply.readInt32(&id);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(reply.readInt32(&id), StatusEq(NO_ERROR));
     EXPECT_EQ(0, id);
 
-    ret = reply.readInt32(&count);
-    ASSERT_EQ(NO_ERROR, ret);
+    ASSERT_THAT(reply.readInt32(&count), StatusEq(NO_ERROR));
     EXPECT_EQ(ARRAY_SIZE(serverId), (size_t)count);
 
     for (size_t i = 0; i < (size_t)count; i++) {
@@ -587,18 +576,15 @@
 
         BinderLibTestBundle replyi(&reply);
         EXPECT_TRUE(replyi.isValid());
-        ret = replyi.readInt32(&id);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(replyi.readInt32(&id), StatusEq(NO_ERROR));
         EXPECT_EQ(serverId[i], id);
 
-        ret = replyi.readInt32(&counti);
-        ASSERT_EQ(NO_ERROR, ret);
+        ASSERT_THAT(replyi.readInt32(&counti), StatusEq(NO_ERROR));
         EXPECT_EQ(1, counti);
 
         BinderLibTestBundle replyi2(&replyi);
         EXPECT_TRUE(replyi2.isValid());
-        ret = replyi2.readInt32(&id);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(replyi2.readInt32(&id), StatusEq(NO_ERROR));
         EXPECT_EQ(0, id);
         EXPECT_EQ(replyi2.dataSize(), replyi2.dataPosition());
 
@@ -610,16 +596,31 @@
 
 TEST_F(BinderLibTest, CallBack)
 {
-    status_t ret;
     Parcel data, reply;
     sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
     data.writeStrongBinder(callBack);
-    ret = m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = callBack->waitEvent(5);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = callBack->getResult();
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_NOP_CALL_BACK, data, &reply, TF_ONE_WAY),
+                StatusEq(NO_ERROR));
+    EXPECT_THAT(callBack->waitEvent(5), StatusEq(NO_ERROR));
+    EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
+}
+
+TEST_F(BinderLibTest, NoBinderCallContextGuard) {
+    IPCThreadState::SpGuard spGuard{"NoBinderCallContext"};
+    IPCThreadState::SpGuard *origGuard = IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
+    // yes, this test uses threads, but it's careful and uses fork in addServer
+    EXPECT_DEATH({ IPCThreadState::self()->getCallingPid(); },
+                 "In context NoBinderCallContext, getCallingPid does not make sense.");
+
+    IPCThreadState::self()->restoreGetCallingSpGuard(origGuard);
+}
+
+TEST_F(BinderLibTest, BinderCallContextGuard) {
+    sp<IBinder> binder = addServer();
+    Parcel data, reply;
+    EXPECT_THAT(binder->transact(BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION, data, &reply),
+                StatusEq(DEAD_OBJECT));
 }
 
 TEST_F(BinderLibTest, AddServer)
@@ -630,7 +631,6 @@
 
 TEST_F(BinderLibTest, DeathNotificationStrongRef)
 {
-    status_t ret;
     sp<IBinder> sbinder;
 
     sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
@@ -638,20 +638,17 @@
     {
         sp<IBinder> binder = addServer();
         ASSERT_TRUE(binder != nullptr);
-        ret = binder->linkToDeath(testDeathRecipient);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(binder->linkToDeath(testDeathRecipient), StatusEq(NO_ERROR));
         sbinder = binder;
     }
     {
         Parcel data, reply;
-        ret = sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY);
-        EXPECT_EQ(0, ret);
+        EXPECT_THAT(sbinder->transact(BINDER_LIB_TEST_EXIT_TRANSACTION, data, &reply, TF_ONE_WAY),
+                    StatusEq(OK));
     }
     IPCThreadState::self()->flushCommands();
-    ret = testDeathRecipient->waitEvent(5);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = sbinder->unlinkToDeath(testDeathRecipient);
-    EXPECT_EQ(DEAD_OBJECT, ret);
+    EXPECT_THAT(testDeathRecipient->waitEvent(5), StatusEq(NO_ERROR));
+    EXPECT_THAT(sbinder->unlinkToDeath(testDeathRecipient), StatusEq(DEAD_OBJECT));
 }
 
 TEST_F(BinderLibTest, DeathNotificationMultiple)
@@ -674,8 +671,9 @@
             callBack[i] = new BinderLibTestCallBack();
             data.writeStrongBinder(target);
             data.writeStrongBinder(callBack[i]);
-            ret = linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
-            EXPECT_EQ(NO_ERROR, ret);
+            EXPECT_THAT(linkedclient[i]->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data,
+                                                  &reply, TF_ONE_WAY),
+                        StatusEq(NO_ERROR));
         }
         {
             Parcel data, reply;
@@ -683,8 +681,9 @@
             passiveclient[i] = addServer();
             ASSERT_TRUE(passiveclient[i] != nullptr);
             data.writeStrongBinder(target);
-            ret = passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data, &reply, TF_ONE_WAY);
-            EXPECT_EQ(NO_ERROR, ret);
+            EXPECT_THAT(passiveclient[i]->transact(BINDER_LIB_TEST_ADD_STRONG_REF_TRANSACTION, data,
+                                                   &reply, TF_ONE_WAY),
+                        StatusEq(NO_ERROR));
         }
     }
     {
@@ -694,10 +693,8 @@
     }
 
     for (int i = 0; i < clientcount; i++) {
-        ret = callBack[i]->waitEvent(5);
-        EXPECT_EQ(NO_ERROR, ret);
-        ret = callBack[i]->getResult();
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(callBack[i]->waitEvent(5), StatusEq(NO_ERROR));
+        EXPECT_THAT(callBack[i]->getResult(), StatusEq(NO_ERROR));
     }
 }
 
@@ -712,8 +709,7 @@
 
     sp<TestDeathRecipient> testDeathRecipient = new TestDeathRecipient();
 
-    ret = target->linkToDeath(testDeathRecipient);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(target->linkToDeath(testDeathRecipient), StatusEq(NO_ERROR));
 
     {
         Parcel data, reply;
@@ -750,14 +746,13 @@
         callback = new BinderLibTestCallBack();
         data.writeStrongBinder(target);
         data.writeStrongBinder(callback);
-        ret = client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply, TF_ONE_WAY);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(client->transact(BINDER_LIB_TEST_LINK_DEATH_TRANSACTION, data, &reply,
+                                     TF_ONE_WAY),
+                    StatusEq(NO_ERROR));
     }
 
-    ret = callback->waitEvent(5);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = callback->getResult();
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(callback->waitEvent(5), StatusEq(NO_ERROR));
+    EXPECT_THAT(callback->getResult(), StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, PassFile) {
@@ -773,17 +768,14 @@
         Parcel data, reply;
         uint8_t writebuf[1] = { write_value };
 
-        ret = data.writeFileDescriptor(pipefd[1], true);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(data.writeFileDescriptor(pipefd[1], true), StatusEq(NO_ERROR));
 
-        ret = data.writeInt32(sizeof(writebuf));
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(data.writeInt32(sizeof(writebuf)), StatusEq(NO_ERROR));
 
-        ret = data.write(writebuf, sizeof(writebuf));
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(data.write(writebuf, sizeof(writebuf)), StatusEq(NO_ERROR));
 
-        ret = m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply);
-        EXPECT_EQ(NO_ERROR, ret);
+        EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_WRITE_FILE_TRANSACTION, data, &reply),
+                    StatusEq(NO_ERROR));
     }
 
     ret = read(pipefd[0], buf, sizeof(buf));
@@ -864,11 +856,10 @@
 }
 
 TEST_F(BinderLibTest, CheckHandleZeroBinderHighBitsZeroCookie) {
-    status_t ret;
     Parcel data, reply;
 
-    ret = m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_GET_SELF_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
 
     const flat_binder_object *fb = reply.readObject(false);
     ASSERT_TRUE(fb != nullptr);
@@ -888,8 +879,8 @@
     wp<IBinder> keepFreedBinder;
     {
         Parcel data, reply;
-        ret = server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply);
-        ASSERT_EQ(NO_ERROR, ret);
+        ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply),
+                    StatusEq(NO_ERROR));
         struct flat_binder_object *freed = (struct flat_binder_object *)(reply.data());
         freedHandle = freed->handle;
         /* Add a weak ref to the freed binder so the driver does not
@@ -950,7 +941,6 @@
 }
 
 TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
-    status_t ret;
     Parcel data, reply;
     sp<BinderLibTestCallBack> callBack = new BinderLibTestCallBack();
     for (int i = 0; i < 2; i++) {
@@ -964,13 +954,12 @@
 
         datai.appendTo(&data);
     }
-    ret = m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(m_server->transact(BINDER_LIB_TEST_INDIRECT_TRANSACTION, data, &reply),
+                StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, OnewayQueueing)
 {
-    status_t ret;
     Parcel data, data2;
 
     sp<IBinder> pollServer = addPollServer();
@@ -983,25 +972,21 @@
     data2.writeStrongBinder(callBack2);
     data2.writeInt32(0); // delay in us
 
-    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, nullptr, TF_ONE_WAY);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data, nullptr, TF_ONE_WAY),
+                StatusEq(NO_ERROR));
 
     // The delay ensures that this second transaction will end up on the async_todo list
     // (for a single-threaded server)
-    ret = pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, nullptr, TF_ONE_WAY);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(pollServer->transact(BINDER_LIB_TEST_DELAYED_CALL_BACK, data2, nullptr, TF_ONE_WAY),
+                StatusEq(NO_ERROR));
 
     // The server will ensure that the two transactions are handled in the expected order;
     // If the ordering is not as expected, an error will be returned through the callbacks.
-    ret = callBack->waitEvent(2);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = callBack->getResult();
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(callBack->waitEvent(2), StatusEq(NO_ERROR));
+    EXPECT_THAT(callBack->getResult(), StatusEq(NO_ERROR));
 
-    ret = callBack2->waitEvent(2);
-    EXPECT_EQ(NO_ERROR, ret);
-    ret = callBack2->getResult();
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(callBack2->waitEvent(2), StatusEq(NO_ERROR));
+    EXPECT_THAT(callBack2->getResult(), StatusEq(NO_ERROR));
 }
 
 TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
@@ -1120,8 +1105,8 @@
     ASSERT_TRUE(server != nullptr);
 
     Parcel data, reply;
-    status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply),
+                StatusEq(NO_ERROR));
 
     int policy = reply.readInt32();
     int priority = reply.readInt32();
@@ -1140,8 +1125,8 @@
     EXPECT_EQ(0, sched_setscheduler(getpid(), SCHED_RR, &param));
 
     Parcel data, reply;
-    status_t ret = server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_GET_SCHEDULING_POLICY, data, &reply),
+                StatusEq(NO_ERROR));
 
     int policy = reply.readInt32();
     int priority = reply.readInt32();
@@ -1158,10 +1143,9 @@
     std::vector<uint64_t> const testValue = { std::numeric_limits<uint64_t>::max(), 0, 200 };
     data.writeUint64Vector(testValue);
 
-    status_t ret = server->transact(BINDER_LIB_TEST_ECHO_VECTOR, data, &reply);
-    EXPECT_EQ(NO_ERROR, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_ECHO_VECTOR, data, &reply), StatusEq(NO_ERROR));
     std::vector<uint64_t> readValue;
-    ret = reply.readUint64Vector(&readValue);
+    EXPECT_THAT(reply.readUint64Vector(&readValue), StatusEq(OK));
     EXPECT_EQ(readValue, testValue);
 }
 
@@ -1186,19 +1170,18 @@
     memcpy(parcelData, &obj, sizeof(obj));
     data.setDataSize(sizeof(obj));
 
-    status_t ret = server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply);
     // Either the kernel should reject this transaction (if it's correct), but
     // if it's not, the server implementation should return an error if it
     // finds an object in the received Parcel.
-    EXPECT_NE(NO_ERROR, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply),
+                Not(StatusEq(NO_ERROR)));
 }
 
 TEST_F(BinderLibTest, GotSid) {
     sp<IBinder> server = addServer();
 
     Parcel data;
-    status_t ret = server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr);
-    EXPECT_EQ(OK, ret);
+    EXPECT_THAT(server->transact(BINDER_LIB_TEST_CAN_GET_SID, data, nullptr), StatusEq(OK));
 }
 
 class BinderLibTestService : public BBinder
@@ -1298,6 +1281,18 @@
                 pthread_mutex_unlock(&m_serverWaitMutex);
                 return ret;
             }
+            case BINDER_LIB_TEST_USE_CALLING_GUARD_TRANSACTION: {
+                IPCThreadState::SpGuard spGuard{"GuardInBinderTransaction"};
+                IPCThreadState::SpGuard *origGuard =
+                        IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
+                // if the guard works, this should abort
+                (void)IPCThreadState::self()->getCallingPid();
+
+                IPCThreadState::self()->restoreGetCallingSpGuard(origGuard);
+                return NO_ERROR;
+            }
+
             case BINDER_LIB_TEST_GETPID:
                 reply->writeInt32(getpid());
                 return NO_ERROR;
@@ -1525,6 +1520,11 @@
 {
     binderLibTestServiceName += String16(binderserversuffix);
 
+    // Testing to make sure that calls that we are serving can use getCallin*
+    // even though we don't here.
+    IPCThreadState::SpGuard spGuard{"main server thread"};
+    (void)IPCThreadState::self()->pushGetCallingSpGuard(&spGuard);
+
     status_t ret;
     sp<IServiceManager> sm = defaultServiceManager();
     BinderLibTestService* testServicePtr;
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 8d10727..3f94df2 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -23,6 +23,7 @@
 #include <android/binder_libbinder.h>
 #include <binder/Binder.h>
 #include <binder/BpBinder.h>
+#include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
@@ -34,14 +35,11 @@
 #include <iostream>
 #include <thread>
 
-#ifdef __BIONIC__
-#include <linux/vm_sockets.h>
-#endif //__BIONIC__
-
 #include <sys/prctl.h>
 #include <unistd.h>
 
-#include "../RpcState.h" // for debugging
+#include "../RpcState.h"   // for debugging
+#include "../vm_sockets.h" // for VMADDR_*
 
 namespace android {
 
@@ -52,6 +50,19 @@
     EXPECT_DEATH(p.markForBinder(sp<BBinder>::make()), "");
 }
 
+TEST(BinderRpc, SetExternalServer) {
+    base::unique_fd sink(TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR)));
+    int sinkFd = sink.get();
+    auto server = RpcServer::make();
+    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+    ASSERT_FALSE(server->hasServer());
+    ASSERT_TRUE(server->setupExternalServer(std::move(sink)));
+    ASSERT_TRUE(server->hasServer());
+    base::unique_fd retrieved = server->releaseServer();
+    ASSERT_FALSE(server->hasServer());
+    ASSERT_EQ(sinkFd, retrieved.get());
+}
+
 using android::binder::Status;
 
 #define EXPECT_OK(status)                 \
@@ -181,6 +192,13 @@
             _exit(1);
         }
     }
+    Status useKernelBinderCallingId() override {
+        // this is WRONG! It does not make sense when using RPC binder, and
+        // because it is SO wrong, and so much code calls this, it should abort!
+
+        (void)IPCThreadState::self()->getCallingPid();
+        return Status::ok();
+    }
 };
 sp<IBinder> MyBinderRpcTest::mHeldBinder;
 
@@ -291,19 +309,15 @@
 
 enum class SocketType {
     UNIX,
-#ifdef __BIONIC__
     VSOCK,
-#endif // __BIONIC__
     INET,
 };
 static inline std::string PrintSocketType(const testing::TestParamInfo<SocketType>& info) {
     switch (info.param) {
         case SocketType::UNIX:
             return "unix_domain_socket";
-#ifdef __BIONIC__
         case SocketType::VSOCK:
             return "vm_socket";
-#endif // __BIONIC__
         case SocketType::INET:
             return "inet_socket";
         default:
@@ -334,59 +348,53 @@
                     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
                     server->setMaxThreads(numThreads);
 
+                    unsigned int outPort = 0;
+
                     switch (socketType) {
                         case SocketType::UNIX:
                             CHECK(server->setupUnixDomainServer(addr.c_str())) << addr;
                             break;
-#ifdef __BIONIC__
                         case SocketType::VSOCK:
                             CHECK(server->setupVsockServer(vsockPort));
                             break;
-#endif // __BIONIC__
                         case SocketType::INET: {
-                            unsigned int outPort = 0;
                             CHECK(server->setupInetServer(0, &outPort));
                             CHECK_NE(0, outPort);
-                            CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort,
-                                                            sizeof(outPort)));
                             break;
                         }
                         default:
                             LOG_ALWAYS_FATAL("Unknown socket type");
                     }
 
+                    CHECK(android::base::WriteFully(pipe->writeEnd(), &outPort, sizeof(outPort)));
+
                     configure(server);
 
                     server->join();
                 }),
         };
 
-        unsigned int inetPort = 0;
+        // always read socket, so that we have waited for the server to start
+        unsigned int outPort = 0;
+        CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &outPort, sizeof(outPort)));
         if (socketType == SocketType::INET) {
-            CHECK(android::base::ReadFully(ret.host.getPipe()->readEnd(), &inetPort,
-                                           sizeof(inetPort)));
-            CHECK_NE(0, inetPort);
+            CHECK_NE(0, outPort);
         }
 
         for (size_t i = 0; i < numSessions; i++) {
             sp<RpcSession> session = RpcSession::make();
-            for (size_t tries = 0; tries < 10; tries++) {
-                usleep(10000);
-                switch (socketType) {
-                    case SocketType::UNIX:
-                        if (session->setupUnixDomainClient(addr.c_str())) goto success;
-                        break;
-#ifdef __BIONIC__
-                    case SocketType::VSOCK:
-                        if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
-                        break;
-#endif // __BIONIC__
-                    case SocketType::INET:
-                        if (session->setupInetClient("127.0.0.1", inetPort)) goto success;
-                        break;
-                    default:
-                        LOG_ALWAYS_FATAL("Unknown socket type");
-                }
+            switch (socketType) {
+                case SocketType::UNIX:
+                    if (session->setupUnixDomainClient(addr.c_str())) goto success;
+                    break;
+                case SocketType::VSOCK:
+                    if (session->setupVsockClient(VMADDR_CID_LOCAL, vsockPort)) goto success;
+                    break;
+                case SocketType::INET:
+                    if (session->setupInetClient("127.0.0.1", outPort)) goto success;
+                    break;
+                default:
+                    LOG_ALWAYS_FATAL("Unknown socket type");
             }
             LOG_ALWAYS_FATAL("Could not connect");
         success:
@@ -887,6 +895,19 @@
     }
 }
 
+TEST_P(BinderRpc, UseKernelBinderCallingId) {
+    auto proc = createRpcTestSocketServerProcess(1);
+
+    // we can't allocate IPCThreadState so actually the first time should
+    // succeed :(
+    EXPECT_OK(proc.rootIface->useKernelBinderCallingId());
+
+    // second time! we catch the error :)
+    EXPECT_EQ(DEAD_OBJECT, proc.rootIface->useKernelBinderCallingId().transactionError());
+
+    proc.expectInvalid = true;
+}
+
 TEST_P(BinderRpc, WorksWithLibbinderNdkPing) {
     auto proc = createRpcTestSocketServerProcess(1);
 
@@ -934,13 +955,42 @@
 INSTANTIATE_TEST_CASE_P(PerSocket, BinderRpc,
                         ::testing::ValuesIn({
                                 SocketType::UNIX,
+// TODO(b/185269356): working on host
 #ifdef __BIONIC__
                                 SocketType::VSOCK,
-#endif // __BIONIC__
+#endif
                                 SocketType::INET,
                         }),
                         PrintSocketType);
 
+class BinderRpcServerRootObject : public ::testing::TestWithParam<std::tuple<bool, bool>> {};
+
+TEST_P(BinderRpcServerRootObject, WeakRootObject) {
+    using SetFn = std::function<void(RpcServer*, sp<IBinder>)>;
+    auto setRootObject = [](bool isStrong) -> SetFn {
+        return isStrong ? SetFn(&RpcServer::setRootObject) : SetFn(&RpcServer::setRootObjectWeak);
+    };
+
+    auto server = RpcServer::make();
+    auto [isStrong1, isStrong2] = GetParam();
+    auto binder1 = sp<BBinder>::make();
+    IBinder* binderRaw1 = binder1.get();
+    setRootObject(isStrong1)(server.get(), binder1);
+    EXPECT_EQ(binderRaw1, server->getRootObject());
+    binder1.clear();
+    EXPECT_EQ((isStrong1 ? binderRaw1 : nullptr), server->getRootObject());
+
+    auto binder2 = sp<BBinder>::make();
+    IBinder* binderRaw2 = binder2.get();
+    setRootObject(isStrong2)(server.get(), binder2);
+    EXPECT_EQ(binderRaw2, server->getRootObject());
+    binder2.clear();
+    EXPECT_EQ((isStrong2 ? binderRaw2 : nullptr), server->getRootObject());
+}
+
+INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcServerRootObject,
+                        ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+
 } // namespace android
 
 int main(int argc, char** argv) {
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/tests/parcel_fuzzer/Android.bp
similarity index 100%
rename from libs/binder/parcel_fuzzer/Android.bp
rename to libs/binder/tests/parcel_fuzzer/Android.bp
diff --git a/libs/binder/parcel_fuzzer/binder.cpp b/libs/binder/tests/parcel_fuzzer/binder.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder.cpp
rename to libs/binder/tests/parcel_fuzzer/binder.cpp
diff --git a/libs/binder/parcel_fuzzer/binder.h b/libs/binder/tests/parcel_fuzzer/binder.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder.h
rename to libs/binder/tests/parcel_fuzzer/binder.h
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.cpp b/libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/binder_ndk.cpp
rename to libs/binder/tests/parcel_fuzzer/binder_ndk.cpp
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.h b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
similarity index 97%
rename from libs/binder/parcel_fuzzer/binder_ndk.h
rename to libs/binder/tests/parcel_fuzzer/binder_ndk.h
index e69d9c1..cf24ab9 100644
--- a/libs/binder/parcel_fuzzer/binder_ndk.h
+++ b/libs/binder/tests/parcel_fuzzer/binder_ndk.h
@@ -23,7 +23,7 @@
 
 // libbinder_ndk doesn't export this header which breaks down its API for NDK
 // and APEX users, but we need access to it to fuzz.
-#include "../ndk/parcel_internal.h"
+#include "../../ndk/parcel_internal.h"
 
 class NdkParcelAdapter {
 public:
diff --git a/libs/binder/parcel_fuzzer/hwbinder.cpp b/libs/binder/tests/parcel_fuzzer/hwbinder.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/hwbinder.cpp
rename to libs/binder/tests/parcel_fuzzer/hwbinder.cpp
diff --git a/libs/binder/parcel_fuzzer/hwbinder.h b/libs/binder/tests/parcel_fuzzer/hwbinder.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/hwbinder.h
rename to libs/binder/tests/parcel_fuzzer/hwbinder.h
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
rename to libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
diff --git a/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
rename to libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/main.cpp
rename to libs/binder/tests/parcel_fuzzer/main.cpp
diff --git a/libs/binder/parcel_fuzzer/parcel_fuzzer.h b/libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/parcel_fuzzer.h
rename to libs/binder/tests/parcel_fuzzer/parcel_fuzzer.h
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/tests/parcel_fuzzer/random_fd.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_fd.cpp
rename to libs/binder/tests/parcel_fuzzer/random_fd.cpp
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_parcel.cpp
rename to libs/binder/tests/parcel_fuzzer/random_parcel.cpp
diff --git a/libs/binder/parcel_fuzzer/util.cpp b/libs/binder/tests/parcel_fuzzer/util.cpp
similarity index 100%
rename from libs/binder/parcel_fuzzer/util.cpp
rename to libs/binder/tests/parcel_fuzzer/util.cpp
diff --git a/libs/binder/parcel_fuzzer/util.h b/libs/binder/tests/parcel_fuzzer/util.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/util.h
rename to libs/binder/tests/parcel_fuzzer/util.h
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
new file mode 100644
index 0000000..1c75306
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -0,0 +1,40 @@
+package {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_native_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_fuzz {
+    name: "binder_rpc_fuzzer",
+    host_supported: true,
+
+    fuzz_config: {
+        cc: ["smoreland@google.com"],
+    },
+
+    srcs: [
+        "main.cpp",
+    ],
+    static_libs: [
+        "libbase",
+        "libcutils",
+        "liblog",
+        "libutils",
+    ],
+
+    target: {
+        android: {
+            shared_libs: [
+                "libbinder",
+            ],
+        },
+        host: {
+            static_libs: [
+                "libbinder",
+            ],
+        },
+    },
+}
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
new file mode 100644
index 0000000..3603ebe
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <binder/Binder.h>
+#include <binder/Parcel.h>
+#include <binder/RpcServer.h>
+#include <binder/RpcSession.h>
+
+#include <sys/resource.h>
+#include <sys/un.h>
+
+namespace android {
+
+static const std::string kSock = std::string(getenv("TMPDIR") ?: "/tmp") +
+        "/binderRpcFuzzerSocket_" + std::to_string(getpid());
+
+size_t getHardMemoryLimit() {
+    struct rlimit limit;
+    CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+    return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+    const struct rlimit kLimit = {
+            .rlim_cur = cur,
+            .rlim_max = max,
+    };
+    CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
+class SomeBinder : public BBinder {
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
+        (void)flags;
+
+        if ((code & 1) == 0) {
+            sp<IBinder> binder;
+            (void)data.readStrongBinder(&binder);
+            if (binder != nullptr) {
+                (void)binder->pingBinder();
+            }
+        }
+        if ((code & 2) == 0) {
+            (void)data.readInt32();
+        }
+        if ((code & 4) == 0) {
+            (void)reply->writeStrongBinder(sp<BBinder>::make());
+        }
+
+        return OK;
+    }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    if (size > 50000) return 0;
+
+    unlink(kSock.c_str());
+
+    sp<RpcServer> server = RpcServer::make();
+    server->setRootObject(sp<SomeBinder>::make());
+    server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
+    CHECK(server->setupUnixDomainServer(kSock.c_str()));
+
+    static constexpr size_t kMemLimit = 1llu * 1024 * 1024 * 1024;
+    size_t hardLimit = getHardMemoryLimit();
+    setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
+    std::thread serverThread([=] { (void)server->acceptOne(); });
+
+    sockaddr_un addr{
+            .sun_family = AF_UNIX,
+    };
+    CHECK_LT(kSock.size(), sizeof(addr.sun_path));
+    memcpy(&addr.sun_path, kSock.c_str(), kSock.size());
+
+    base::unique_fd clientFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
+    CHECK_NE(clientFd.get(), -1);
+    CHECK_EQ(0,
+             TEMP_FAILURE_RETRY(
+                     connect(clientFd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))
+            << strerror(errno);
+
+    serverThread.join();
+
+    // TODO(b/182938024): fuzz multiple sessions, instead of just one
+
+#if 0
+    // make fuzzer more productive locally by forcing it to create a new session
+    int32_t id = -1;
+    CHECK(base::WriteFully(clientFd, &id, sizeof(id)));
+#endif
+
+    CHECK(base::WriteFully(clientFd, data, size));
+
+    clientFd.reset();
+
+    // TODO(b/185167543): better way to force a server to shutdown
+    while (!server->listSessions().empty() && server->numUninitializedSessions()) {
+        usleep(1);
+    }
+
+    setMemoryLimit(hardLimit, hardLimit);
+
+    return 0;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/fuzzers/Android.bp b/libs/binder/tests/unit_fuzzers/Android.bp
similarity index 100%
rename from libs/binder/tests/fuzzers/Android.bp
rename to libs/binder/tests/unit_fuzzers/Android.bp
diff --git a/libs/binder/tests/fuzzers/BinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BinderFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BinderFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BinderFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/BinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/BinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/BinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzz.cpp b/libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BpBinderFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BpBinderFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/BpBinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/BpBinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/BufferedTextOutputFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/BufferedTextOutputFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/IBinderFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/IBinderFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/IBinderFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp b/libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/MemoryDealerFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/MemoryDealerFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp b/libs/binder/tests/unit_fuzzers/PersistableBundleFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/PersistableBundleFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/PersistableBundleFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/PersistableBundleFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/PersistableBundleFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/PersistableBundleFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/StabilityFuzz.cpp b/libs/binder/tests/unit_fuzzers/StabilityFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/StabilityFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/StabilityFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/StabilityFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/StabilityFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/StabilityFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/StatusFuzz.cpp b/libs/binder/tests/unit_fuzzers/StatusFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/StatusFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/StatusFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/StatusFuzzFunctions.h b/libs/binder/tests/unit_fuzzers/StatusFuzzFunctions.h
similarity index 100%
rename from libs/binder/tests/fuzzers/StatusFuzzFunctions.h
rename to libs/binder/tests/unit_fuzzers/StatusFuzzFunctions.h
diff --git a/libs/binder/tests/fuzzers/TextOutputFuzz.cpp b/libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp
similarity index 100%
rename from libs/binder/tests/fuzzers/TextOutputFuzz.cpp
rename to libs/binder/tests/unit_fuzzers/TextOutputFuzz.cpp
diff --git a/libs/binder/tests/fuzzers/commonFuzzHelpers.h b/libs/binder/tests/unit_fuzzers/commonFuzzHelpers.h
similarity index 100%
rename from libs/binder/tests/fuzzers/commonFuzzHelpers.h
rename to libs/binder/tests/unit_fuzzers/commonFuzzHelpers.h
diff --git a/libs/binder/vm_sockets.h b/libs/binder/vm_sockets.h
new file mode 100644
index 0000000..7d9732b
--- /dev/null
+++ b/libs/binder/vm_sockets.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ***   Copied and modified from bionic/libc/kernel/uapi/linux/vm_sockets.h
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#pragma once
+
+#ifdef __BIONIC__
+#include <linux/vm_sockets.h>
+#else
+
+#ifndef _UAPI_VM_SOCKETS_H
+#define _UAPI_VM_SOCKETS_H
+#define SO_VM_SOCKETS_BUFFER_SIZE 0
+#define SO_VM_SOCKETS_BUFFER_MIN_SIZE 1
+#define SO_VM_SOCKETS_BUFFER_MAX_SIZE 2
+#define SO_VM_SOCKETS_PEER_HOST_VM_ID 3
+#define SO_VM_SOCKETS_TRUSTED 5
+#define SO_VM_SOCKETS_CONNECT_TIMEOUT 6
+#define SO_VM_SOCKETS_NONBLOCK_TXRX 7
+#define VMADDR_CID_ANY (-1U)
+#define VMADDR_PORT_ANY (-1U)
+#define VMADDR_CID_HYPERVISOR 0
+#define VMADDR_CID_LOCAL 1
+#define VMADDR_CID_HOST 2
+#define VM_SOCKETS_INVALID_VERSION (-1U)
+#define VM_SOCKETS_VERSION_EPOCH(_v) (((_v)&0xFF000000) >> 24)
+#define VM_SOCKETS_VERSION_MAJOR(_v) (((_v)&0x00FF0000) >> 16)
+#define VM_SOCKETS_VERSION_MINOR(_v) (((_v)&0x0000FFFF))
+struct sockaddr_vm {
+    sa_family_t svm_family;
+    // NOLINTNEXTLINE(google-runtime-int)
+    unsigned short svm_reserved1;
+    unsigned int svm_port;
+    unsigned int svm_cid;
+    // NOLINTNEXTLINE(google-runtime-int)
+    unsigned char svm_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - sizeof(unsigned short) -
+                           sizeof(unsigned int) - sizeof(unsigned int)];
+};
+#define IOCTL_VM_SOCKETS_GET_LOCAL_CID _IO(7, 0xb9)
+#ifndef AF_VSOCK
+#define AF_VSOCK 40
+#endif
+#endif
+
+#endif
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 37fb844..08800f7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -213,7 +213,8 @@
             // for this is the scale is calculated based on the requested size and buffer size.
             // If there's no buffer, the scale will always be 1.
             if (mLastBufferInfo.hasBuffer) {
-                setMatrix(&t, mLastBufferInfo);
+                t.setDestinationFrame(mSurfaceControl,
+                                      Rect(0, 0, newSize.getWidth(), newSize.getHeight()));
             }
             applyTransaction = true;
         }
@@ -416,8 +417,8 @@
     t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
     mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
 
-    setMatrix(t, mLastBufferInfo);
-    t->setCrop(mSurfaceControl, crop);
+    t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
+    t->setBufferCrop(mSurfaceControl, crop);
     t->setTransform(mSurfaceControl, bufferItem.mTransform);
     t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
     if (!bufferItem.mIsAutoTimestamp) {
@@ -543,19 +544,6 @@
     return mSize != bufferSize;
 }
 
-void BLASTBufferQueue::setMatrix(SurfaceComposerClient::Transaction* t,
-                                 const BufferInfo& bufferInfo) {
-    uint32_t bufWidth = bufferInfo.crop.getWidth();
-    uint32_t bufHeight = bufferInfo.crop.getHeight();
-
-    float sx = mSize.width / static_cast<float>(bufWidth);
-    float sy = mSize.height / static_cast<float>(bufHeight);
-
-    t->setMatrix(mSurfaceControl, sx, 0, 0, sy);
-    // Update position based on crop.
-    t->setPosition(mSurfaceControl, bufferInfo.crop.left * sx * -1, bufferInfo.crop.top * sy * -1);
-}
-
 void BLASTBufferQueue::setTransactionCompleteCallback(
         uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) {
     std::lock_guard _lock{mMutex};
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 53721cf..0436758 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -123,11 +123,11 @@
         return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply);
     }
 
-    status_t captureDisplay(uint64_t displayOrLayerStack,
+    status_t captureDisplay(DisplayId displayId,
                             const sp<IScreenCaptureListener>& captureListener) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        SAFE_PARCEL(data.writeUint64, displayOrLayerStack);
+        SAFE_PARCEL(data.writeUint64, displayId.value);
         SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(captureListener));
 
         return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply);
@@ -281,9 +281,14 @@
             NO_ERROR) {
             std::vector<uint64_t> rawIds;
             if (reply.readUint64Vector(&rawIds) == NO_ERROR) {
-                std::vector<PhysicalDisplayId> displayIds(rawIds.size());
-                std::transform(rawIds.begin(), rawIds.end(), displayIds.begin(),
-                               [](uint64_t rawId) { return PhysicalDisplayId(rawId); });
+                std::vector<PhysicalDisplayId> displayIds;
+                displayIds.reserve(rawIds.size());
+
+                for (const uint64_t rawId : rawIds) {
+                    if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
+                        displayIds.push_back(*id);
+                    }
+                }
                 return displayIds;
             }
         }
@@ -1296,12 +1301,15 @@
         }
         case CAPTURE_DISPLAY_BY_ID: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            uint64_t displayOrLayerStack = 0;
+            uint64_t value;
+            SAFE_PARCEL(data.readUint64, &value);
+            const auto id = DisplayId::fromValue(value);
+            if (!id) return BAD_VALUE;
+
             sp<IScreenCaptureListener> captureListener;
-            SAFE_PARCEL(data.readUint64, &displayOrLayerStack);
             SAFE_PARCEL(data.readStrongBinder, &captureListener);
 
-            return captureDisplay(displayOrLayerStack, captureListener);
+            return captureDisplay(*id, captureListener);
         }
         case CAPTURE_LAYERS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -1368,9 +1376,9 @@
         }
         case GET_PHYSICAL_DISPLAY_TOKEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            PhysicalDisplayId displayId(data.readUint64());
-            sp<IBinder> display = getPhysicalDisplayToken(displayId);
-            reply->writeStrongBinder(display);
+            const auto id = DisplayId::fromValue<PhysicalDisplayId>(data.readUint64());
+            if (!id) return BAD_VALUE;
+            reply->writeStrongBinder(getPhysicalDisplayToken(*id));
             return NO_ERROR;
         }
         case GET_DISPLAY_STATE: {
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 267db76..e65c721 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -64,6 +64,8 @@
         fixedTransformHint(ui::Transform::ROT_INVALID),
         frameNumber(0),
         autoRefresh(false),
+        bufferCrop(Rect::INVALID_RECT),
+        destinationFrame(Rect::INVALID_RECT),
         releaseBufferListener(nullptr) {
     matrix.dsdx = matrix.dtdy = 1.0f;
     matrix.dsdy = matrix.dtdx = 0.0f;
@@ -167,6 +169,7 @@
 
     SAFE_PARCEL(output.write, stretchEffect);
     SAFE_PARCEL(output.write, bufferCrop);
+    SAFE_PARCEL(output.write, destinationFrame);
 
     return NO_ERROR;
 }
@@ -296,6 +299,7 @@
 
     SAFE_PARCEL(input.read, stretchEffect);
     SAFE_PARCEL(input.read, bufferCrop);
+    SAFE_PARCEL(input.read, destinationFrame);
 
     return NO_ERROR;
 }
@@ -543,6 +547,10 @@
         what |= eBufferCropChanged;
         bufferCrop = other.bufferCrop;
     }
+    if (other.what & eDestinationFrameChanged) {
+        what |= eDestinationFrameChanged;
+        destinationFrame = other.destinationFrame;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIu64 " what=0x%" PRIu64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 11b8eba..1bb6393 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1675,6 +1675,21 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDestinationFrame(
+        const sp<SurfaceControl>& sc, const Rect& destinationFrame) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eDestinationFrameChanged;
+    s->destinationFrame = destinationFrame;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -2110,12 +2125,12 @@
     return s->captureDisplay(captureArgs, captureListener);
 }
 
-status_t ScreenshotClient::captureDisplay(uint64_t displayOrLayerStack,
+status_t ScreenshotClient::captureDisplay(DisplayId displayId,
                                           const sp<IScreenCaptureListener>& captureListener) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
 
-    return s->captureDisplay(displayOrLayerStack, captureListener);
+    return s->captureDisplay(displayId, captureListener);
 }
 
 status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index cb04689..c420e4a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -114,6 +114,11 @@
 
     using EventRegistrationFlags = Flags<EventRegistration>;
 
+    template <typename T>
+    struct SpHash {
+        size_t operator()(const sp<T>& k) const { return std::hash<T*>()(k.get()); }
+    };
+
     /*
      * Create a connection with SurfaceFlinger.
      */
@@ -237,24 +242,17 @@
      * The subregion can be optionally rotated.  It will also be scaled to
      * match the size of the output buffer.
      */
-    virtual status_t captureDisplay(const DisplayCaptureArgs& args,
-                                    const sp<IScreenCaptureListener>& captureListener) = 0;
+    virtual status_t captureDisplay(const DisplayCaptureArgs&,
+                                    const sp<IScreenCaptureListener>&) = 0;
 
-    virtual status_t captureDisplay(uint64_t displayOrLayerStack,
-                                    const sp<IScreenCaptureListener>& captureListener) = 0;
-
-    template <class AA>
-    struct SpHash {
-        size_t operator()(const sp<AA>& k) const { return std::hash<AA*>()(k.get()); }
-    };
+    virtual status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) = 0;
 
     /**
      * Capture a subtree of the layer hierarchy, potentially ignoring the root node.
      * This requires READ_FRAME_BUFFER permission. This function will fail if there
      * is a secure window on screen
      */
-    virtual status_t captureLayers(const LayerCaptureArgs& args,
-                                   const sp<IScreenCaptureListener>& captureListener) = 0;
+    virtual status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) = 0;
 
     /* Clears the frame statistics for animations.
      *
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 3947f22..16430b3 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -104,7 +104,7 @@
         eHasListenerCallbacksChanged = 0x20000000,
         eInputInfoChanged = 0x40000000,
         eCornerRadiusChanged = 0x80000000,
-        /* was eFrameChanged, now available 0x1'00000000, */
+        eDestinationFrameChanged = 0x1'00000000,
         eCachedBufferChanged = 0x2'00000000,
         eBackgroundColorChanged = 0x4'00000000,
         eMetadataChanged = 0x8'00000000,
@@ -228,6 +228,7 @@
     StretchEffect stretchEffect;
 
     Rect bufferCrop;
+    Rect destinationFrame;
 
     // Listens to when the buffer is safe to be released. This is used for blast
     // layers only. The callback includes a release fence as well as the graphic
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 35757be..86f1b63 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -554,6 +554,8 @@
                                       const StretchEffect& stretchEffect);
 
         Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop);
+        Transaction& setDestinationFrame(const sp<SurfaceControl>& sc,
+                                         const Rect& destinationFrame);
 
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
@@ -621,12 +623,9 @@
 
 class ScreenshotClient {
 public:
-    static status_t captureDisplay(const DisplayCaptureArgs& captureArgs,
-                                   const sp<IScreenCaptureListener>& captureListener);
-    static status_t captureDisplay(uint64_t displayOrLayerStack,
-                                   const sp<IScreenCaptureListener>& captureListener);
-    static status_t captureLayers(const LayerCaptureArgs& captureArgs,
-                                  const sp<IScreenCaptureListener>& captureListener);
+    static status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&);
+    static status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&);
+    static status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ea8c295..7002adf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -752,21 +752,19 @@
     }
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
-    status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */,
-                            const sp<IScreenCaptureListener>& /* captureListener */) override {
-        return NO_ERROR;
-    }
     void setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {}
     void setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override {}
-    status_t captureDisplay(uint64_t /*displayOrLayerStack*/,
-                            const sp<IScreenCaptureListener>& /* captureListener */) override {
+
+    status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override {
         return NO_ERROR;
     }
-    virtual status_t captureLayers(
-            const LayerCaptureArgs& /* captureArgs */,
-            const sp<IScreenCaptureListener>& /* captureListener */) override {
+    status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override {
         return NO_ERROR;
     }
+    status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override {
+        return NO_ERROR;
+    }
+
     status_t clearAnimationFrameStats() override { return NO_ERROR; }
     status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override {
         return NO_ERROR;
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 649a140..e8c05e5 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -253,10 +253,6 @@
     scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, globalScaleFactor);
 }
 
-void PointerCoords::scale(float globalScaleFactor) {
-    scale(globalScaleFactor, globalScaleFactor, globalScaleFactor);
-}
-
 void PointerCoords::applyOffset(float xOffset, float yOffset) {
     setAxisValue(AMOTION_EVENT_AXIS_X, getX() + xOffset);
     setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 0edb213..e7bd977 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -306,8 +306,9 @@
         // Fortunately, these events are small so sending packets across the
         // socket should be atomic across processes.
         DisplayEventReceiver::Event event;
-        event.header = DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
-                                                           PhysicalDisplayId(0), systemTime()};
+        event.header =
+                DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+                                                    PhysicalDisplayId::fromPort(0), systemTime()};
         injectEvent(event);
     }
 }
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index d93a84c..d5e7cb2 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -556,6 +556,7 @@
                                    int32_t* _Nonnull outBytesPerPixel,
                                    int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29);
 
+
 /**
  * Get the system wide unique id for an AHardwareBuffer.
  *
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index c5ad64e..6d2af4a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -560,10 +560,14 @@
         const LayerSettings* layer, const DisplaySettings& display, bool undoPremultipliedAlpha,
         bool requiresLinearEffect) {
     const auto stretchEffect = layer->stretchEffect;
+    // The given surface will be stretched by HWUI via matrix transformation
+    // which gets similar results for most surfaces
+    // Determine later on if we need to leverage the stertch shader within
+    // surface flinger
     if (stretchEffect.hasEffect()) {
         const auto targetBuffer = layer->source.buffer.buffer;
-        const auto graphicsBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
-        if (graphicsBuffer && shader) {
+        const auto graphicBuffer = targetBuffer ? targetBuffer->getBuffer() : nullptr;
+        if (graphicBuffer && shader) {
             shader = mStretchShaderFactory.createSkShader(shader, stretchEffect);
         }
     }
@@ -653,33 +657,6 @@
     int mSaveCount;
 };
 
-void drawStretch(const SkRect& bounds, const StretchEffect& stretchEffect,
-                 SkCanvas* canvas, const SkPaint& paint) {
-    float top = bounds.top();
-    float left = bounds.left();
-    float bottom = bounds.bottom();
-    float right = bounds.right();
-    // Adjust the drawing bounds based on the stretch itself.
-    float stretchOffsetX =
-        round(bounds.width() * stretchEffect.getStretchWidthMultiplier());
-    float stretchOffsetY =
-        round(bounds.height() * stretchEffect.getStretchHeightMultiplier());
-    if (stretchEffect.vectorY < 0.f) {
-        top -= stretchOffsetY;
-    } else if (stretchEffect.vectorY > 0.f){
-        bottom += stretchOffsetY;
-    }
-
-    if (stretchEffect.vectorX < 0.f) {
-        left -= stretchOffsetX;
-    } else if (stretchEffect.vectorX > 0.f) {
-        right += stretchOffsetX;
-    }
-
-    auto stretchBounds = SkRect::MakeLTRB(left, top, right, bottom);
-    canvas->drawRect(stretchBounds, paint);
-}
-
 static SkRRect getBlurRRect(const BlurRegion& region) {
     const auto rect = SkRect::MakeLTRB(region.left, region.top, region.right, region.bottom);
     const SkVector radii[4] = {SkVector::Make(region.cornerRadiusTL, region.cornerRadiusTL),
@@ -919,12 +896,9 @@
         // TODO(b/175915334): consider relaxing this restriction to enable more flexible
         // composition - using a well-defined invalid color is long-term less error-prone.
         if (layer->shadow.length > 0) {
-            const auto rect = layer->geometry.roundedCornersRadius > 0
-                    ? getSkRect(layer->geometry.roundedCornersCrop)
-                    : bounds.rect();
             // This would require a new parameter/flag to SkShadowUtils::DrawShadow
             LOG_ALWAYS_FATAL_IF(layer->disableBlending, "Cannot disableBlending with a shadow");
-            drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+            drawShadow(canvas, bounds, layer->shadow);
             continue;
         }
 
@@ -1056,17 +1030,7 @@
             paint.setAntiAlias(true);
             canvas->drawRRect(bounds, paint);
         } else {
-            auto& stretchEffect = layer->stretchEffect;
-            // TODO (njawad) temporarily disable manipulation of geometry
-            //  the layer bounds will be updated in HWUI instead of RenderEngine
-            //  in a subsequent CL
-            // Keep the method call in a dead code path to make -Werror happy
-            // with unused methods
-            if (stretchEffect.hasEffect() && /* DISABLES CODE */ (false)) {
-                drawStretch(bounds.rect(), stretchEffect, canvas, paint);
-            } else {
-                canvas->drawRect(bounds.rect(), paint);
-            }
+            canvas->drawRect(bounds.rect(), paint);
         }
         if (kFlushAfterEveryLayer) {
             ATRACE_NAME("flush surface");
@@ -1213,17 +1177,14 @@
     return mGrContext->maxRenderTargetSize();
 }
 
-void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect, float cornerRadius,
+void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
                                     const ShadowSettings& settings) {
     ATRACE_CALL();
     const float casterZ = settings.length / 2.0f;
-    const auto shadowShape = cornerRadius > 0
-            ? SkPath::RRect(SkRRect::MakeRectXY(casterRect, cornerRadius, cornerRadius))
-            : SkPath::Rect(casterRect);
     const auto flags =
             settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
 
-    SkShadowUtils::DrawShadow(canvas, shadowShape, SkPoint3::Make(0, 0, casterZ),
+    SkShadowUtils::DrawShadow(canvas, SkPath::RRect(casterRRect), SkPoint3::Make(0, 0, casterZ),
                               getSkPoint3(settings.lightPos), settings.lightRadius,
                               getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
                               flags);
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index d9caf35..1f528b7 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -98,7 +98,7 @@
     base::unique_fd flush();
     bool waitFence(base::unique_fd fenceFd);
     void initCanvas(SkCanvas* canvas, const DisplaySettings& display);
-    void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
+    void drawShadow(SkCanvas* canvas, const SkRRect& casterRRect,
                     const ShadowSettings& shadowSettings);
     // If requiresLinearEffect is true or the layer has a stretchEffect a new shader is returned.
     // Otherwise it returns the input shader.
@@ -120,14 +120,15 @@
 
     // Identifier used or various mappings of layers to various
     // textures or shaders
-    using LayerId = uint64_t;
+    using GraphicBufferId = uint64_t;
 
     // Number of external holders of ExternalTexture references, per GraphicBuffer ID.
-    std::unordered_map<LayerId, int32_t> mGraphicBufferExternalRefs GUARDED_BY(mRenderingMutex);
-    // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context.
-    std::unordered_map<LayerId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
+    std::unordered_map<GraphicBufferId, int32_t> mGraphicBufferExternalRefs
             GUARDED_BY(mRenderingMutex);
-    std::unordered_map<LayerId, std::shared_ptr<AutoBackendTexture::LocalRef>>
+    // Cache of GL textures that we'll store per GraphicBuffer ID, sliced by GPU context.
+    std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>> mTextureCache
+            GUARDED_BY(mRenderingMutex);
+    std::unordered_map<GraphicBufferId, std::shared_ptr<AutoBackendTexture::LocalRef>>
             mProtectedTextureCache GUARDED_BY(mRenderingMutex);
     std::unordered_map<LinearEffect, sk_sp<SkRuntimeEffect>, LinearEffectHasher> mRuntimeEffects;
 
diff --git a/libs/renderengine/skia/filters/StretchShaderFactory.cpp b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
index 9b62789..4ac5c40 100644
--- a/libs/renderengine/skia/filters/StretchShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/StretchShaderFactory.cpp
@@ -69,9 +69,8 @@
     // and the other way around.
     uniform float uInterpolationStrength;
 
-    float easeInCubic(float t, float d) {
-        float tmp = t * d;
-        return tmp * tmp * tmp;
+    float easeIn(float t, float d) {
+        return t * d;
     }
 
     float computeOverscrollStart(
@@ -84,7 +83,7 @@
     ) {
         float offsetPos = uStretchAffectedDist - inPos;
         float posBasedVariation = mix(
-                1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
+                1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
         float stretchIntensity = overscroll * posBasedVariation;
         return distanceStretched - (offsetPos / (1. + stretchIntensity));
     }
@@ -100,7 +99,7 @@
     ) {
         float offsetPos = inPos - reverseStretchDist;
         float posBasedVariation = mix(
-                1. ,easeInCubic(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
+                1. ,easeIn(offsetPos, uInverseStretchAffectedDist), interpolationStrength);
         float stretchIntensity = (-overscroll) * posBasedVariation;
         return 1 - (distanceStretched - (offsetPos / (1. + stretchIntensity)));
     }
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index c87a836..9009ce4 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -101,6 +101,7 @@
 }
 
 void RenderEngineThreaded::primeCache() {
+    ATRACE_CALL();
     // This function is designed so it can run asynchronously, so we do not need to wait
     // for the futures.
     {
@@ -131,6 +132,7 @@
 }
 
 void RenderEngineThreaded::genTextures(size_t count, uint32_t* names) {
+    ATRACE_CALL();
     std::promise<void> resultPromise;
     std::future<void> resultFuture = resultPromise.get_future();
     {
@@ -146,6 +148,7 @@
 }
 
 void RenderEngineThreaded::deleteTextures(size_t count, uint32_t const* names) {
+    ATRACE_CALL();
     std::promise<void> resultPromise;
     std::future<void> resultFuture = resultPromise.get_future();
     {
@@ -162,6 +165,7 @@
 
 void RenderEngineThreaded::mapExternalTextureBuffer(const sp<GraphicBuffer>& buffer,
                                                     bool isRenderable) {
+    ATRACE_CALL();
     // This function is designed so it can run asynchronously, so we do not need to wait
     // for the futures.
     {
@@ -175,6 +179,7 @@
 }
 
 void RenderEngineThreaded::unmapExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+    ATRACE_CALL();
     // This function is designed so it can run asynchronously, so we do not need to wait
     // for the futures.
     {
@@ -247,6 +252,7 @@
                                           const bool useFramebufferCache,
                                           base::unique_fd&& bufferFence,
                                           base::unique_fd* drawFence) {
+    ATRACE_CALL();
     std::promise<status_t> resultPromise;
     std::future<status_t> resultFuture = resultPromise.get_future();
     {
@@ -264,6 +270,7 @@
 }
 
 void RenderEngineThreaded::cleanFramebufferCache() {
+    ATRACE_CALL();
     // This function is designed so it can run asynchronously, so we do not need to wait
     // for the futures.
     {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index 240738d..0a49008 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -231,6 +231,10 @@
             mFlags |= SENSOR_FLAG_WAKE_UP;
         }
         break;
+    case SENSOR_TYPE_DEVICE_ORIENTATION:
+        mStringType = SENSOR_STRING_TYPE_DEVICE_ORIENTATION;
+        mFlags |= SENSOR_FLAG_ON_CHANGE_MODE;
+        break;
     case SENSOR_TYPE_DYNAMIC_SENSOR_META:
         mStringType = SENSOR_STRING_TYPE_DYNAMIC_SENSOR_META;
         mFlags |= SENSOR_FLAG_SPECIAL_REPORTING_MODE; // special trigger
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 74d17ce..5a118ec 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -137,7 +137,6 @@
         "HdrCapabilities.cpp",
         "PixelFormat.cpp",
         "PublicFormat.cpp",
-        "Size.cpp",
         "StaticDisplayInfo.cpp",
     ],
 
diff --git a/libs/ui/Size.cpp b/libs/ui/Size.cpp
deleted file mode 100644
index d2996d1..0000000
--- a/libs/ui/Size.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ui/Size.h>
-
-namespace android::ui {
-
-const Size Size::INVALID{-1, -1};
-const Size Size::EMPTY{0, 0};
-
-} // namespace android::ui
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index f196ab9..9120972 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -38,12 +38,22 @@
 
     uint64_t value;
 
+    // For deserialization.
+    static constexpr std::optional<DisplayId> fromValue(uint64_t);
+
+    // As above, but also upcast to Id.
+    template <typename Id>
+    static constexpr std::optional<Id> fromValue(uint64_t value) {
+        if (const auto id = Id::tryCast(DisplayId(value))) {
+            return id;
+        }
+        return {};
+    }
+
 protected:
     explicit constexpr DisplayId(uint64_t id) : value(id) {}
 };
 
-static_assert(sizeof(DisplayId) == sizeof(uint64_t));
-
 inline bool operator==(DisplayId lhs, DisplayId rhs) {
     return lhs.value == rhs.value;
 }
@@ -80,11 +90,8 @@
 
     // TODO(b/162612135) Remove default constructor
     PhysicalDisplayId() = default;
-    // TODO(b/162612135) Remove constructor
-    explicit constexpr PhysicalDisplayId(uint64_t id) : DisplayId(id) {}
 
     constexpr uint16_t getManufacturerId() const { return static_cast<uint16_t>(value >> 40); }
-
     constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); }
 
 private:
@@ -96,10 +103,9 @@
     explicit constexpr PhysicalDisplayId(DisplayId other) : DisplayId(other) {}
 };
 
-static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t));
-
 struct VirtualDisplayId : DisplayId {
     using BaseId = uint32_t;
+
     // Flag indicating that this virtual display is backed by the GPU.
     static constexpr uint64_t FLAG_GPU = 1ULL << 61;
 
@@ -163,10 +169,23 @@
     explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {}
 };
 
+constexpr std::optional<DisplayId> DisplayId::fromValue(uint64_t value) {
+    if (const auto id = fromValue<PhysicalDisplayId>(value)) {
+        return id;
+    }
+    if (const auto id = fromValue<VirtualDisplayId>(value)) {
+        return id;
+    }
+    return {};
+}
+
+static_assert(sizeof(DisplayId) == sizeof(uint64_t));
+static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
 static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t));
+
+static_assert(sizeof(PhysicalDisplayId) == sizeof(uint64_t));
 static_assert(sizeof(HalVirtualDisplayId) == sizeof(uint64_t));
 static_assert(sizeof(GpuVirtualDisplayId) == sizeof(uint64_t));
-static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
 
 } // namespace android
 
diff --git a/libs/ui/include/ui/Size.h b/libs/ui/include/ui/Size.h
index f1e8252..ecc192d 100644
--- a/libs/ui/include/ui/Size.h
+++ b/libs/ui/include/ui/Size.h
@@ -23,103 +23,70 @@
 #include <type_traits>
 #include <utility>
 
-namespace android {
-namespace ui {
+namespace android::ui {
 
-// Forward declare a few things.
-struct Size;
-bool operator==(const Size& lhs, const Size& rhs);
-
-/**
- * A simple value type representing a two-dimensional size
- */
+// A simple value type representing a two-dimensional size.
 struct Size {
-    int32_t width;
-    int32_t height;
+    int32_t width = -1;
+    int32_t height = -1;
 
-    // Special values
-    static const Size INVALID;
-    static const Size EMPTY;
+    constexpr Size() = default;
 
-    // ------------------------------------------------------------------------
-    // Construction
-    // ------------------------------------------------------------------------
-
-    Size() : Size(INVALID) {}
     template <typename T>
-    Size(T&& w, T&& h)
-          : width(Size::clamp<int32_t, T>(std::forward<T>(w))),
-            height(Size::clamp<int32_t, T>(std::forward<T>(h))) {}
-
-    // ------------------------------------------------------------------------
-    // Accessors
-    // ------------------------------------------------------------------------
+    constexpr Size(T w, T h) : width(clamp<int32_t>(w)), height(clamp<int32_t>(h)) {}
 
     int32_t getWidth() const { return width; }
     int32_t getHeight() const { return height; }
 
-    template <typename T>
-    void setWidth(T&& v) {
-        width = Size::clamp<int32_t, T>(std::forward<T>(v));
-    }
-    template <typename T>
-    void setHeight(T&& v) {
-        height = Size::clamp<int32_t, T>(std::forward<T>(v));
-    }
-
-    // ------------------------------------------------------------------------
-    // Assignment
-    // ------------------------------------------------------------------------
-
-    void set(const Size& size) { *this = size; }
-    template <typename T>
-    void set(T&& w, T&& h) {
-        set(Size(std::forward<T>(w), std::forward<T>(h)));
-    }
-
-    // Sets the value to INVALID
-    void makeInvalid() { set(INVALID); }
-
-    // Sets the value to EMPTY
-    void clear() { set(EMPTY); }
-
-    // ------------------------------------------------------------------------
-    // Semantic checks
-    // ------------------------------------------------------------------------
-
     // Valid means non-negative width and height
     bool isValid() const { return width >= 0 && height >= 0; }
 
     // Empty means zero width and height
-    bool isEmpty() const { return *this == EMPTY; }
+    bool isEmpty() const;
 
-    // ------------------------------------------------------------------------
-    // Clamp Helpers
-    // ------------------------------------------------------------------------
-
-    // Note: We use only features available in C++11 here for compatibility with
-    // external targets which include this file directly or indirectly and which
-    // themselves use C++11.
-
-    // C++11 compatible replacement for std::remove_cv_reference_t [C++20]
     template <typename T>
-    using remove_cv_reference_t =
-            typename std::remove_cv<typename std::remove_reference<T>::type>::type;
+    void setWidth(T v) {
+        width = clamp<int32_t>(v);
+    }
+
+    template <typename T>
+    void setHeight(T v) {
+        height = clamp<int32_t>(v);
+    }
+
+    void set(Size size) { *this = size; }
+
+    template <typename T>
+    void set(T w, T h) {
+        set(Size(w, h));
+    }
+
+    // Sets the value to kInvalidSize
+    void makeInvalid();
+
+    // Sets the value to kEmptySize
+    void clear();
+
+    // TODO: Replace with std::remove_cvref_t in C++20.
+    template <typename T>
+    using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
 
     // Takes a value of type FromType, and ensures it can be represented as a value of type ToType,
     // clamping the input value to the output range if necessary.
     template <typename ToType, typename FromType>
-    static Size::remove_cv_reference_t<ToType>
-    clamp(typename std::enable_if<
-            std::numeric_limits<Size::remove_cv_reference_t<ToType>>::is_specialized &&
-                    std::numeric_limits<Size::remove_cv_reference_t<FromType>>::is_specialized,
-            FromType>::type v) {
-        using BareToType = remove_cv_reference_t<ToType>;
-        using BareFromType = remove_cv_reference_t<FromType>;
-        static constexpr auto toHighest = std::numeric_limits<BareToType>::max();
-        static constexpr auto toLowest = std::numeric_limits<BareToType>::lowest();
-        static constexpr auto fromHighest = std::numeric_limits<BareFromType>::max();
-        static constexpr auto fromLowest = std::numeric_limits<BareFromType>::lowest();
+    static constexpr remove_cvref_t<ToType> clamp(FromType v) {
+        using BareToType = remove_cvref_t<ToType>;
+        using ToLimits = std::numeric_limits<BareToType>;
+
+        using BareFromType = remove_cvref_t<FromType>;
+        using FromLimits = std::numeric_limits<BareFromType>;
+
+        static_assert(ToLimits::is_specialized && FromLimits::is_specialized);
+
+        constexpr auto toHighest = ToLimits::max();
+        constexpr auto toLowest = ToLimits::lowest();
+        constexpr auto fromHighest = FromLimits::max();
+        constexpr auto fromLowest = FromLimits::lowest();
 
         // Get the closest representation of [toLowest, toHighest] in type
         // FromType to use to clamp the input value before conversion.
@@ -127,37 +94,35 @@
         // std::common_type<...> is used to get a value-preserving type for the
         // top end of the range.
         using CommonHighestType = std::common_type_t<BareToType, BareFromType>;
+        using CommonLimits = std::numeric_limits<CommonHighestType>;
 
         // std::make_signed<std::common_type<...>> is used to get a
         // value-preserving type for the bottom end of the range, except this is
         // a bit trickier for non-integer types like float.
-        using CommonLowestType =
-                std::conditional_t<std::numeric_limits<CommonHighestType>::is_integer,
-                                   std::make_signed_t<std::conditional_t<
-                                           std::numeric_limits<CommonHighestType>::is_integer,
-                                           CommonHighestType, int /* not used */>>,
-                                   CommonHighestType>;
+        using CommonLowestType = std::conditional_t<
+                CommonLimits::is_integer,
+                std::make_signed_t<std::conditional_t<CommonLimits::is_integer, CommonHighestType,
+                                                      int /* not used */>>,
+                CommonHighestType>;
 
         // We can then compute the clamp range in a way that can be later
         // trivially converted to either the 'from' or 'to' types, and be
-        // representabile in either.
-        static constexpr auto commonClampHighest =
-                std::min(static_cast<CommonHighestType>(fromHighest),
-                         static_cast<CommonHighestType>(toHighest));
-        static constexpr auto commonClampLowest =
-                std::max(static_cast<CommonLowestType>(fromLowest),
-                         static_cast<CommonLowestType>(toLowest));
+        // representable in either.
+        constexpr auto commonClampHighest = std::min(static_cast<CommonHighestType>(fromHighest),
+                                                     static_cast<CommonHighestType>(toHighest));
+        constexpr auto commonClampLowest = std::max(static_cast<CommonLowestType>(fromLowest),
+                                                    static_cast<CommonLowestType>(toLowest));
 
-        static constexpr auto fromClampHighest = static_cast<BareFromType>(commonClampHighest);
-        static constexpr auto fromClampLowest = static_cast<BareFromType>(commonClampLowest);
+        constexpr auto fromClampHighest = static_cast<BareFromType>(commonClampHighest);
+        constexpr auto fromClampLowest = static_cast<BareFromType>(commonClampLowest);
 
         // A clamp is needed only if the range we are clamping to is not the
         // same as the range of the input.
-        static constexpr bool isClampNeeded =
+        constexpr bool isClampNeeded =
                 (fromLowest != fromClampLowest) || (fromHighest != fromClampHighest);
 
         // If a clamp is not needed, the conversion is just a trivial cast.
-        if (!isClampNeeded) {
+        if constexpr (!isClampNeeded) {
             return static_cast<BareToType>(v);
         }
 
@@ -170,34 +135,46 @@
 
         // Otherwise clamping is done by using the already computed endpoints
         // for each type.
-        return (v <= fromClampLowest)
-                ? toClampLowest
-                : ((v >= fromClampHighest) ? toClampHighest : static_cast<BareToType>(v));
+        if (v <= fromClampLowest) {
+            return toClampLowest;
+        }
+
+        return v >= fromClampHighest ? toClampHighest : static_cast<BareToType>(v);
     }
 };
 
-// ------------------------------------------------------------------------
-// Comparisons
-// ------------------------------------------------------------------------
+constexpr Size kInvalidSize;
+constexpr Size kEmptySize{0, 0};
 
-inline bool operator==(const Size& lhs, const Size& rhs) {
+inline void Size::makeInvalid() {
+    set(kInvalidSize);
+}
+
+inline void Size::clear() {
+    set(kEmptySize);
+}
+
+inline bool operator==(Size lhs, Size rhs) {
     return lhs.width == rhs.width && lhs.height == rhs.height;
 }
 
-inline bool operator!=(const Size& lhs, const Size& rhs) {
-    return !operator==(lhs, rhs);
+inline bool Size::isEmpty() const {
+    return *this == kEmptySize;
 }
 
-inline bool operator<(const Size& lhs, const Size& rhs) {
+inline bool operator!=(Size lhs, Size rhs) {
+    return !(lhs == rhs);
+}
+
+inline bool operator<(Size lhs, Size rhs) {
     // Orders by increasing width, then height.
     if (lhs.width != rhs.width) return lhs.width < rhs.width;
     return lhs.height < rhs.height;
 }
 
 // Defining PrintTo helps with Google Tests.
-static inline void PrintTo(const Size& size, ::std::ostream* os) {
-    *os << "Size(" << size.width << ", " << size.height << ")";
+inline void PrintTo(Size size, std::ostream* stream) {
+    *stream << "Size(" << size.width << ", " << size.height << ')';
 }
 
-} // namespace ui
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp
index 1d908b8..8ddee7e 100644
--- a/libs/ui/tests/DisplayId_test.cpp
+++ b/libs/ui/tests/DisplayId_test.cpp
@@ -32,6 +32,9 @@
     EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
     EXPECT_TRUE(PhysicalDisplayId::tryCast(id));
     EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+    EXPECT_EQ(id, DisplayId::fromValue(id.value));
+    EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
 }
 
 TEST(DisplayIdTest, createPhysicalIdFromPort) {
@@ -43,6 +46,9 @@
     EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
     EXPECT_TRUE(PhysicalDisplayId::tryCast(id));
     EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+    EXPECT_EQ(id, DisplayId::fromValue(id.value));
+    EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
 }
 
 TEST(DisplayIdTest, createGpuVirtualId) {
@@ -52,6 +58,9 @@
     EXPECT_FALSE(HalVirtualDisplayId::tryCast(id));
     EXPECT_FALSE(PhysicalDisplayId::tryCast(id));
     EXPECT_FALSE(HalDisplayId::tryCast(id));
+
+    EXPECT_EQ(id, DisplayId::fromValue(id.value));
+    EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value));
 }
 
 TEST(DisplayIdTest, createHalVirtualId) {
@@ -61,6 +70,9 @@
     EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id));
     EXPECT_FALSE(PhysicalDisplayId::tryCast(id));
     EXPECT_TRUE(HalDisplayId::tryCast(id));
+
+    EXPECT_EQ(id, DisplayId::fromValue(id.value));
+    EXPECT_EQ(id, DisplayId::fromValue<HalVirtualDisplayId>(id.value));
 }
 
 } // namespace android::ui
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
index 5f75aea..acef47f 100644
--- a/libs/ui/tests/Size_test.cpp
+++ b/libs/ui/tests/Size_test.cpp
@@ -93,9 +93,8 @@
     }
 
     {
-        const auto& s = Size::INVALID;
-        EXPECT_FALSE(s.isValid());
-        EXPECT_FALSE(s.isEmpty());
+        EXPECT_FALSE(kInvalidSize.isValid());
+        EXPECT_FALSE(kInvalidSize.isEmpty());
     }
 
     {
@@ -112,9 +111,8 @@
     }
 
     {
-        const auto& s = Size::EMPTY;
-        EXPECT_TRUE(s.isValid());
-        EXPECT_TRUE(s.isEmpty());
+        EXPECT_TRUE(kEmptySize.isValid());
+        EXPECT_TRUE(kEmptySize.isEmpty());
     }
 
     {
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index d6fc695..d205231 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -34,7 +34,10 @@
     sp<IBinder> displayToken = nullptr;
     sp<SurfaceControl> surfaceControl = nullptr;
     if (it == mDisplays.end()) {
-        displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id));
+        if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
+            displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+        }
+
         if (displayToken == nullptr) {
             ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
             return nullptr;
@@ -157,7 +160,11 @@
     HwDisplayConfig activeConfig;
     HwDisplayState  activeState;
 
-    auto displayToken = SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId(id));
+    sp<IBinder> displayToken;
+    if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
+        displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+    }
+
     if (displayToken == nullptr) {
         ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
     } else {
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 6ed9593..0539e4f 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -176,10 +176,11 @@
     }
     return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64
                         ", source=0x%08x, displayId=%" PRId32 ", action=%s, "
-                        "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
+                        "flags=0x%08x, keyCode=%s(%d), scanCode=%d, metaState=0x%08x, "
                         "repeatCount=%d), policyFlags=0x%08x",
                         deviceId, eventTime, source, displayId, KeyEvent::actionToString(action),
-                        flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+                        flags, KeyEvent::getLabel(keyCode), keyCode, scanCode, metaState,
+                        repeatCount, policyFlags);
 }
 
 void KeyEntry::recycle() {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 446c913..8bc877f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4747,6 +4747,40 @@
     return true;
 }
 
+// Binder call
+bool InputDispatcher::transferTouch(const sp<IBinder>& destChannelToken) {
+    sp<IBinder> fromToken;
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+
+        sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(destChannelToken);
+        if (toWindowHandle == nullptr) {
+            ALOGW("Could not find window associated with token=%p", destChannelToken.get());
+            return false;
+        }
+
+        const int32_t displayId = toWindowHandle->getInfo()->displayId;
+
+        auto touchStateIt = mTouchStatesByDisplay.find(displayId);
+        if (touchStateIt == mTouchStatesByDisplay.end()) {
+            ALOGD("Could not transfer touch because the display %" PRId32 " is not being touched",
+                  displayId);
+            return false;
+        }
+
+        TouchState& state = touchStateIt->second;
+        if (state.windows.size() != 1) {
+            ALOGW("Cannot transfer touch state because there are %zu windows being touched",
+                  state.windows.size());
+            return false;
+        }
+        const TouchedWindow& touchedWindow = state.windows[0];
+        fromToken = touchedWindow.windowHandle->getToken();
+    } // release lock
+
+    return transferTouchFocus(fromToken, destChannelToken);
+}
+
 void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
     if (DEBUG_FOCUS) {
         ALOGD("Resetting and dropping all events (%s).", reason);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7ba03e8..6edc5f1 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -81,60 +81,60 @@
  */
 class InputDispatcher : public android::InputDispatcherInterface {
 protected:
-    virtual ~InputDispatcher();
+    ~InputDispatcher() override;
 
 public:
     explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
 
-    virtual void dump(std::string& dump) override;
-    virtual void monitor() override;
-    virtual bool waitForIdle() override;
-    virtual status_t start() override;
-    virtual status_t stop() override;
+    void dump(std::string& dump) override;
+    void monitor() override;
+    bool waitForIdle() override;
+    status_t start() override;
+    status_t stop() override;
 
-    virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
-    virtual void notifyKey(const NotifyKeyArgs* args) override;
-    virtual void notifyMotion(const NotifyMotionArgs* args) override;
-    virtual void notifySwitch(const NotifySwitchArgs* args) override;
-    virtual void notifySensor(const NotifySensorArgs* args) override;
-    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
-    virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
-    virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
+    void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) override;
+    void notifyKey(const NotifyKeyArgs* args) override;
+    void notifyMotion(const NotifyMotionArgs* args) override;
+    void notifySwitch(const NotifySwitchArgs* args) override;
+    void notifySensor(const NotifySensorArgs* args) override;
+    void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
+    void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
-    virtual android::os::InputEventInjectionResult injectInputEvent(
+    android::os::InputEventInjectionResult injectInputEvent(
             const InputEvent* event, int32_t injectorPid, int32_t injectorUid,
             android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
             uint32_t policyFlags) override;
 
-    virtual std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
+    std::unique_ptr<VerifiedInputEvent> verifyInputEvent(const InputEvent& event) override;
 
-    virtual void setInputWindows(
-            const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
-                    handlesPerDisplay) override;
-    virtual void setFocusedApplication(
+    void setInputWindows(const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>&
+                                 handlesPerDisplay) override;
+    void setFocusedApplication(
             int32_t displayId,
             const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) override;
-    virtual void setFocusedDisplay(int32_t displayId) override;
-    virtual void setInputDispatchMode(bool enabled, bool frozen) override;
-    virtual void setInputFilterEnabled(bool enabled) override;
-    virtual void setInTouchMode(bool inTouchMode) override;
-    virtual void setMaximumObscuringOpacityForTouch(float opacity) override;
-    virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;
+    void setFocusedDisplay(int32_t displayId) override;
+    void setInputDispatchMode(bool enabled, bool frozen) override;
+    void setInputFilterEnabled(bool enabled) override;
+    void setInTouchMode(bool inTouchMode) override;
+    void setMaximumObscuringOpacityForTouch(float opacity) override;
+    void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override;
 
-    virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
-                                    bool isDragDrop = false) override;
+    bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
+                            bool isDragDrop = false) override;
+    bool transferTouch(const sp<IBinder>& destChannelToken) override;
 
-    virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
+    base::Result<std::unique_ptr<InputChannel>> createInputChannel(
             const std::string& name) override;
-    virtual void setFocusedWindow(const FocusRequest&) override;
-    virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
-                                                                           bool isGestureMonitor,
-                                                                           const std::string& name,
-                                                                           int32_t pid) override;
-    virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
-    virtual status_t pilferPointers(const sp<IBinder>& token) override;
-    virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
-    virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override;
+    void setFocusedWindow(const FocusRequest&) override;
+    base::Result<std::unique_ptr<InputChannel>> createInputMonitor(int32_t displayId,
+                                                                   bool isGestureMonitor,
+                                                                   const std::string& name,
+                                                                   int32_t pid) override;
+    status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
+    status_t pilferPointers(const sp<IBinder>& token) override;
+    void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
+    bool flushSensor(int deviceId, InputDeviceSensorType sensorType) override;
 
     std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
 
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index b601dfc..7f85e53 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -151,6 +151,14 @@
      */
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                                     bool isDragDrop) = 0;
+
+    /**
+     * Transfer touch focus to the provided channel, no matter where the current touch is.
+     *
+     * Return true on success, false if there was no on-going touch.
+     */
+    virtual bool transferTouch(const sp<IBinder>& destChannelToken) = 0;
+
     /**
      * Sets focus on the specified window.
      */
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 2d0fdf7..e91f84e 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -413,8 +413,7 @@
     }
 }
 
-void InputReader::dispatchExternalStylusState(const StylusState& state) {
-    std::scoped_lock _l(mLock);
+void InputReader::dispatchExternalStylusStateLocked(const StylusState& state) {
     for (auto& devicePair : mDevices) {
         std::shared_ptr<InputDevice>& device = devicePair.second;
         device->updateExternalStylusState(state);
@@ -945,7 +944,7 @@
 }
 
 void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) {
-    mReader->dispatchExternalStylusState(state);
+    mReader->dispatchExternalStylusStateLocked(state);
 }
 
 InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() {
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 1405671..bc79ccf 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -203,7 +203,7 @@
 
     void notifyExternalStylusPresenceChangedLocked() REQUIRES(mLock);
     void getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) REQUIRES(mLock);
-    void dispatchExternalStylusState(const StylusState& state);
+    void dispatchExternalStylusStateLocked(const StylusState& state) REQUIRES(mLock);
 
     // The PointerController that is shared among all the input devices that need it.
     std::weak_ptr<PointerControllerInterface> mPointerController;
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index bbf51f6..855453e 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1714,7 +1714,13 @@
                          0 /*expectedFlags*/);
 }
 
-TEST_F(InputDispatcherTest, TransferTouchFocus_OnePointer) {
+using TransferFunction =
+        std::function<bool(sp<InputDispatcher> dispatcher, sp<IBinder>, sp<IBinder>)>;
+
+class TransferTouchFixture : public InputDispatcherTest,
+                             public ::testing::WithParamInterface<TransferFunction> {};
+
+TEST_P(TransferTouchFixture, TransferTouch_OnePointer) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     // Create a couple of windows
@@ -1735,8 +1741,10 @@
     firstWindow->consumeMotionDown();
     secondWindow->assertNoEvents();
 
-    // Transfer touch focus to the second window
-    mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
+    // Transfer touch to the second window
+    TransferFunction f = GetParam();
+    const bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+    ASSERT_TRUE(success);
     // The first window gets cancel and the second gets down
     firstWindow->consumeMotionCancel();
     secondWindow->consumeMotionDown();
@@ -1751,7 +1759,7 @@
     secondWindow->consumeMotionUp();
 }
 
-TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointerNoSplitTouch) {
+TEST_P(TransferTouchFixture, TransferTouch_TwoPointersNonSplitTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     PointF touchPoint = {10, 10};
@@ -1786,7 +1794,9 @@
     secondWindow->assertNoEvents();
 
     // Transfer touch focus to the second window
-    mDispatcher->transferTouchFocus(firstWindow->getToken(), secondWindow->getToken());
+    TransferFunction f = GetParam();
+    bool success = f(mDispatcher, firstWindow->getToken(), secondWindow->getToken());
+    ASSERT_TRUE(success);
     // The first window gets cancel and the second gets down and pointer down
     firstWindow->consumeMotionCancel();
     secondWindow->consumeMotionDown();
@@ -1813,6 +1823,21 @@
     secondWindow->consumeMotionUp();
 }
 
+// For the cases of single pointer touch and two pointers non-split touch, the api's
+// 'transferTouch' and 'transferTouchFocus' are equivalent in behaviour. They only differ
+// for the case where there are multiple pointers split across several windows.
+INSTANTIATE_TEST_SUITE_P(TransferFunctionTests, TransferTouchFixture,
+                         ::testing::Values(
+                                 [&](sp<InputDispatcher> dispatcher, sp<IBinder> /*ignored*/,
+                                     sp<IBinder> destChannelToken) {
+                                     return dispatcher->transferTouch(destChannelToken);
+                                 },
+                                 [&](sp<InputDispatcher> dispatcher, sp<IBinder> from,
+                                     sp<IBinder> to) {
+                                     return dispatcher->transferTouchFocus(from, to,
+                                                                           false /*isDragAndDrop*/);
+                                 }));
+
 TEST_F(InputDispatcherTest, TransferTouchFocus_TwoPointersSplitTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
@@ -1883,6 +1908,82 @@
     secondWindow->consumeMotionUp();
 }
 
+// Same as TransferTouchFocus_TwoPointersSplitTouch, but using 'transferTouch' api.
+// Unlike 'transferTouchFocus', calling 'transferTouch' when there are two windows receiving
+// touch is not supported, so the touch should continue on those windows and the transferred-to
+// window should get nothing.
+TEST_F(InputDispatcherTest, TransferTouch_TwoPointersSplitTouch) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+    // Create a non touch modal window that supports split touch
+    sp<FakeWindowHandle> firstWindow =
+            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+    firstWindow->setFrame(Rect(0, 0, 600, 400));
+    firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                          InputWindowInfo::Flag::SPLIT_TOUCH);
+
+    // Create a non touch modal window that supports split touch
+    sp<FakeWindowHandle> secondWindow =
+            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
+    secondWindow->setFrame(Rect(0, 400, 600, 800));
+    secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                           InputWindowInfo::Flag::SPLIT_TOUCH);
+
+    // Add the windows to the dispatcher
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
+
+    PointF pointInFirst = {300, 200};
+    PointF pointInSecond = {300, 600};
+
+    // Send down to the first window
+    NotifyMotionArgs firstDownMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {pointInFirst});
+    mDispatcher->notifyMotion(&firstDownMotionArgs);
+    // Only the first window should get the down event
+    firstWindow->consumeMotionDown();
+    secondWindow->assertNoEvents();
+
+    // Send down to the second window
+    NotifyMotionArgs secondDownMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {pointInFirst, pointInSecond});
+    mDispatcher->notifyMotion(&secondDownMotionArgs);
+    // The first window gets a move and the second a down
+    firstWindow->consumeMotionMove();
+    secondWindow->consumeMotionDown();
+
+    // Transfer touch focus to the second window
+    const bool transferred = mDispatcher->transferTouch(secondWindow->getToken());
+    // The 'transferTouch' call should not succeed, because there are 2 touched windows
+    ASSERT_FALSE(transferred);
+    firstWindow->assertNoEvents();
+    secondWindow->assertNoEvents();
+
+    // The rest of the dispatch should proceed as normal
+    // Send pointer up to the second window
+    NotifyMotionArgs pointerUpMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {pointInFirst, pointInSecond});
+    mDispatcher->notifyMotion(&pointerUpMotionArgs);
+    // The first window gets MOVE and the second gets pointer up
+    firstWindow->consumeMotionMove();
+    secondWindow->consumeMotionUp();
+
+    // Send up event to the first window
+    NotifyMotionArgs upMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
+    mDispatcher->notifyMotion(&upMotionArgs);
+    // The first window gets nothing and the second gets up
+    firstWindow->consumeMotionUp();
+    secondWindow->assertNoEvents();
+}
+
 TEST_F(InputDispatcherTest, FocusedWindow_ReceivesFocusEventAndKeyEvent) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
     sp<FakeWindowHandle> window =
diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats@1.0-service.xml
index 5fd361c..c564b7b 100644
--- a/services/stats/android.frameworks.stats@1.0-service.xml
+++ b/services/stats/android.frameworks.stats@1.0-service.xml
@@ -1,5 +1,5 @@
 <manifest version="1.0" type="framework">
-    <hal>
+    <hal max-level="5">
         <name>android.frameworks.stats</name>
         <transport>hwbinder</transport>
         <version>1.0</version>
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 24b3599..fcf8299 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -295,12 +295,72 @@
     return true;
 }
 
+bool BufferStateLayer::setDestinationFrame(const Rect& destinationFrame) {
+    if (mCurrentState.destinationFrame == destinationFrame) return false;
+
+    mCurrentState.sequence++;
+    mCurrentState.destinationFrame = destinationFrame;
+
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+// Translate destination frame into scale and position. If a destination frame is not set, use the
+// provided scale and position
+void BufferStateLayer::updateGeometry() {
+    if (mCurrentState.destinationFrame.isEmpty()) {
+        // If destination frame is not set, use the requested transform set via
+        // BufferStateLayer::setPosition and BufferStateLayer::setMatrix.
+        mCurrentState.transform = mRequestedTransform;
+        return;
+    }
+
+    Rect destRect = mCurrentState.destinationFrame;
+    int32_t destW = destRect.width();
+    int32_t destH = destRect.height();
+    if (destRect.left < 0) {
+        destRect.left = 0;
+        destRect.right = destW;
+    }
+    if (destRect.top < 0) {
+        destRect.top = 0;
+        destRect.bottom = destH;
+    }
+
+    if (!mCurrentState.buffer) {
+        ui::Transform t;
+        t.set(destRect.left, destRect.top);
+        mCurrentState.transform = t;
+        return;
+    }
+
+    uint32_t bufferWidth = mCurrentState.buffer->getBuffer()->getWidth();
+    uint32_t bufferHeight = mCurrentState.buffer->getBuffer()->getHeight();
+    // Undo any transformations on the buffer.
+    if (mCurrentState.bufferTransform & ui::Transform::ROT_90) {
+        std::swap(bufferWidth, bufferHeight);
+    }
+    uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+    if (mCurrentState.transformToDisplayInverse) {
+        if (invTransform & ui::Transform::ROT_90) {
+            std::swap(bufferWidth, bufferHeight);
+        }
+    }
+
+    float sx = destW / static_cast<float>(bufferWidth);
+    float sy = destH / static_cast<float>(bufferHeight);
+    ui::Transform t;
+    t.set(sx, 0, 0, sy);
+    t.set(destRect.left, destRect.top);
+    mCurrentState.transform = t;
+    return;
+}
+
 bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
                                  bool allowNonRectPreservingTransforms) {
-    if (mCurrentState.transform.dsdx() == matrix.dsdx &&
-        mCurrentState.transform.dtdy() == matrix.dtdy &&
-        mCurrentState.transform.dtdx() == matrix.dtdx &&
-        mCurrentState.transform.dsdy() == matrix.dsdy) {
+    if (mRequestedTransform.dsdx() == matrix.dsdx && mRequestedTransform.dtdy() == matrix.dtdy &&
+        mRequestedTransform.dtdx() == matrix.dtdx && mRequestedTransform.dsdy() == matrix.dsdy) {
         return false;
     }
 
@@ -313,7 +373,7 @@
         return false;
     }
 
-    mCurrentState.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+    mRequestedTransform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
 
     mCurrentState.sequence++;
     mCurrentState.modified = true;
@@ -323,11 +383,11 @@
 }
 
 bool BufferStateLayer::setPosition(float x, float y) {
-    if (mCurrentState.transform.tx() == x && mCurrentState.transform.ty() == y) {
+    if (mRequestedTransform.tx() == x && mRequestedTransform.ty() == y) {
         return false;
     }
 
-    mCurrentState.transform.set(x, y);
+    mRequestedTransform.set(x, y);
 
     mCurrentState.sequence++;
     mCurrentState.modified = true;
@@ -523,35 +583,35 @@
 
 Rect BufferStateLayer::getBufferSize(const State& s) const {
     // for buffer state layers we use the display frame size as the buffer size.
-    if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
-        return Rect(getActiveWidth(s), getActiveHeight(s));
-    }
 
     if (mBufferInfo.mBuffer == nullptr) {
         return Rect::INVALID_RECT;
     }
 
-    // if the display frame is not defined, use the parent bounds as the buffer size.
-    const auto& p = mDrawingParent.promote();
-    if (p != nullptr) {
-        Rect parentBounds = Rect(p->getBounds(Region()));
-        if (!parentBounds.isEmpty()) {
-            return parentBounds;
+    uint32_t bufWidth = mBufferInfo.mBuffer->getBuffer()->getWidth();
+    uint32_t bufHeight = mBufferInfo.mBuffer->getBuffer()->getHeight();
+
+    // Undo any transformations on the buffer and return the result.
+    if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
+        std::swap(bufWidth, bufHeight);
+    }
+
+    if (getTransformToDisplayInverse()) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+        if (invTransform & ui::Transform::ROT_90) {
+            std::swap(bufWidth, bufHeight);
         }
     }
 
-    return Rect::INVALID_RECT;
+    return Rect(0, 0, bufWidth, bufHeight);
 }
 
 FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) const {
-    const State& s(getDrawingState());
-    // for buffer state layers we use the display frame size as the buffer size.
-    if (getActiveWidth(s) < UINT32_MAX && getActiveHeight(s) < UINT32_MAX) {
-        return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
+    if (mBufferInfo.mBuffer == nullptr) {
+        return parentBounds;
     }
 
-    // if the display frame is not defined, use the parent bounds as the buffer size.
-    return parentBounds;
+    return getBufferSize(getDrawingState()).toFloatRect();
 }
 
 // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index a273230..2e48452 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -86,6 +86,8 @@
     void setAutoRefresh(bool autoRefresh) override;
 
     bool setBufferCrop(const Rect& bufferCrop) override;
+    bool setDestinationFrame(const Rect& destinationFrame) override;
+    void updateGeometry() override;
 
     // -----------------------------------------------------------------------
 
@@ -178,6 +180,10 @@
     //     - If the integer decreases in setBuffer or doTransaction, a buffer was dropped
     std::atomic<int32_t> mPendingBufferTransactions{0};
 
+    // Contains requested position and matrix updates. This will be applied if the client does
+    // not specify a destination frame.
+    ui::Transform mRequestedTransform;
+
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 
     class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 633668e..317d333 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -47,7 +47,7 @@
     std::optional<Physical> physical;
 
     // Size of the display in pixels
-    ui::Size pixels = ui::Size::INVALID;
+    ui::Size pixels = ui::kInvalidSize;
 
     // Pixel format of the display
     ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4976213..9fba7aa 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,6 +163,9 @@
     // Enables (or disables) composition on this output
     virtual void setCompositionEnabled(bool) = 0;
 
+    // Enables (or disables) layer caching on this output
+    virtual void setLayerCachingEnabled(bool) = 0;
+
     // Sets the projection state to use
     virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                                const Rect& orientedDisplaySpaceRect) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
index a8d372c..4110346 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurfaceCreationArgs.h
@@ -24,21 +24,17 @@
 
 struct ANativeWindow;
 
-namespace android {
-
-namespace compositionengine {
-
-class Display;
+namespace android::compositionengine {
 
 /**
  * A parameter object for creating RenderSurface instances
  */
 struct RenderSurfaceCreationArgs {
     // The initial width of the surface
-    int32_t displayWidth;
+    int32_t displayWidth = -1;
 
     // The initial height of the surface
-    int32_t displayHeight;
+    int32_t displayHeight = -1;
 
     // The ANativeWindow for the buffer queue for this surface
     sp<ANativeWindow> nativeWindow;
@@ -46,22 +42,16 @@
     // The DisplaySurface for this surface
     sp<DisplaySurface> displaySurface;
 
-    size_t maxTextureCacheSize;
+    // The maximum size of the renderengine::ExternalTexture cache
+    size_t maxTextureCacheSize = 0;
+
+private:
+    friend class RenderSurfaceCreationArgsBuilder;
+
+    // Not defaulted to disable aggregate initialization.
+    RenderSurfaceCreationArgs() {}
 };
 
-/**
- * A helper for setting up a RenderSurfaceCreationArgs value in-line.
- * Prefer this builder over raw structure initialization.
- *
- * Instead of:
- *
- *   RenderSurfaceCreationArgs{1000, 1000, nativeWindow, displaySurface}
- *
- * Prefer:
- *
- *  RenderSurfaceCreationArgsBuilder().setDisplayWidth(1000).setDisplayHeight(1000)
- *      .setNativeWindow(nativeWindow).setDisplaySurface(displaySurface).Build();
- */
 class RenderSurfaceCreationArgsBuilder {
 public:
     RenderSurfaceCreationArgs build() { return std::move(mArgs); }
@@ -75,11 +65,11 @@
         return *this;
     }
     RenderSurfaceCreationArgsBuilder& setNativeWindow(sp<ANativeWindow> nativeWindow) {
-        mArgs.nativeWindow = nativeWindow;
+        mArgs.nativeWindow = std::move(nativeWindow);
         return *this;
     }
     RenderSurfaceCreationArgsBuilder& setDisplaySurface(sp<DisplaySurface> displaySurface) {
-        mArgs.displaySurface = displaySurface;
+        mArgs.displaySurface = std::move(displaySurface);
         return *this;
     }
 
@@ -92,5 +82,4 @@
     RenderSurfaceCreationArgs mArgs;
 };
 
-} // namespace compositionengine
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index eeb20fc..2893c3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -20,6 +20,7 @@
 #include <compositionengine/Output.h>
 #include <compositionengine/impl/ClientCompositionRequestCache.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/planner/Planner.h>
 #include <renderengine/DisplaySettings.h>
 #include <renderengine/LayerSettings.h>
 #include <memory>
@@ -28,21 +29,18 @@
 
 namespace android::compositionengine::impl {
 
-namespace planner {
-class Planner;
-} // namespace planner
-
 // The implementation class contains the common implementation, but does not
 // actually contain the final output state.
 class Output : public virtual compositionengine::Output {
 public:
-    Output();
+    Output() = default;
     ~Output() override;
 
     // compositionengine::Output overrides
     bool isValid() const override;
     std::optional<DisplayId> getDisplayId() const override;
     void setCompositionEnabled(bool) override;
+    void setLayerCachingEnabled(bool) override;
     void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                        const Rect& orientedDisplaySpaceRect) override;
     void setDisplaySize(const ui::Size&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 2488c66..2ffd472 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -78,9 +78,10 @@
     void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
     void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition,
-                                   bool isPeekingThrough);
+                                   bool isPeekingThrough, bool skipLayer);
     void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
                                                Hwc2::IComposerClient::Composition to) const;
+    bool isClientCompositionForced(bool isPeekingThrough) const;
 };
 
 // This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b98043b..3f670a1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -125,6 +125,9 @@
 
         // Set to true when overridden info has been sent to HW composer
         bool stateOverridden = false;
+
+        // True when this layer was skipped as part of SF-side layer caching.
+        bool layerSkipped = false;
     };
 
     // The HWC state is optional, and is only set up if there is any potential
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
index b09f1d1..864251f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Flattener.h
@@ -36,8 +36,7 @@
 
 class Flattener {
 public:
-    Flattener(Predictor& predictor, bool enableHolePunch = false)
-          : mEnableHolePunch(enableHolePunch), mPredictor(predictor) {}
+    Flattener(bool enableHolePunch = false) : mEnableHolePunch(enableHolePunch) {}
 
     void setDisplaySize(ui::Size size) { mDisplaySize = size; }
 
@@ -64,7 +63,6 @@
     void buildCachedSets(std::chrono::steady_clock::time_point now);
 
     const bool mEnableHolePunch;
-    Predictor& mPredictor;
 
     ui::Size mDisplaySize;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
index c2037a8..4365b93 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/Planner.h
@@ -76,6 +76,8 @@
 
     std::optional<Predictor::PredictedPlan> mPredictedPlan;
     NonBufferHash mFlattenedHash = 0;
+
+    bool mPredictorEnabled = false;
 };
 
 } // namespace compositionengine::impl::planner
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 5aa53e5..749675d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -36,6 +36,7 @@
     MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
 
     MOCK_METHOD1(setCompositionEnabled, void(bool));
+    MOCK_METHOD1(setLayerCachingEnabled, void(bool));
     MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
     MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 297e687..796fe7d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -55,18 +55,6 @@
 
 namespace impl {
 
-Output::Output() {
-    const bool enableLayerCaching = [] {
-        const bool enable =
-                android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
-        return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
-    }();
-
-    if (enableLayerCaching) {
-        mPlanner = std::make_unique<planner::Planner>();
-    }
-}
-
 namespace {
 
 template <typename T>
@@ -135,6 +123,21 @@
     dirtyEntireOutput();
 }
 
+void Output::setLayerCachingEnabled(bool enabled) {
+    if (enabled == (mPlanner != nullptr)) {
+        return;
+    }
+
+    if (enabled) {
+        mPlanner = std::make_unique<planner::Planner>();
+        if (mRenderSurface) {
+            mPlanner->setDisplaySize(mRenderSurface->getSize());
+        }
+    } else {
+        mPlanner.reset();
+    }
+}
+
 void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                            const Rect& orientedDisplaySpaceRect) {
     auto& outputState = editState();
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 01da070..cd14327 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <DisplayHardware/Hal.h>
 #include <android-base/stringprintf.h>
 #include <compositionengine/DisplayColorProfile.h>
 #include <compositionengine/LayerFECompositionState.h>
@@ -350,12 +351,14 @@
     writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
     writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), *outputIndependentState);
 
-    writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough);
+    writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough,
+                              skipLayer);
 
     // Always set the layer color after setting the composition type.
     writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState);
 
     editState().hwc->stateOverridden = isOverridden;
+    editState().hwc->layerSkipped = skipLayer;
 }
 
 void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
@@ -482,7 +485,8 @@
 
     const Region& surfaceDamage = getState().overrideInfo.buffer
             ? getState().overrideInfo.damageRegion
-            : outputIndependentState.surfaceDamage;
+            : (getState().hwc->stateOverridden ? Region::INVALID_REGION
+                                               : outputIndependentState.surfaceDamage);
 
     if (auto error = hwcLayer->setSurfaceDamage(surfaceDamage); error != hal::Error::NONE) {
         ALOGE("[%s] Failed to set surface damage: %s (%d)", getLayerFE().getDebugName(),
@@ -573,17 +577,19 @@
 
 void OutputLayer::writeCompositionTypeToHWC(HWC2::Layer* hwcLayer,
                                             hal::Composition requestedCompositionType,
-                                            bool isPeekingThrough) {
+                                            bool isPeekingThrough, bool skipLayer) {
     auto& outputDependentState = editState();
 
-    // If we are forcing client composition, we need to tell the HWC
-    if (outputDependentState.forceClientComposition ||
-        (!isPeekingThrough && getLayerFE().hasRoundedCorners())) {
+    if (isClientCompositionForced(isPeekingThrough)) {
+        // If we are forcing client composition, we need to tell the HWC
         requestedCompositionType = hal::Composition::CLIENT;
     }
 
     // Set the requested composition type with the HWC whenever it changes
-    if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+    // We also resend the composition type when this layer was previously skipped, to ensure that
+    // the composition type is up-to-date.
+    if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType ||
+        (outputDependentState.hwc->layerSkipped && !skipLayer)) {
         outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
 
         if (auto error = hwcLayer->setCompositionType(requestedCompositionType);
@@ -663,12 +669,22 @@
     }
 }
 
+bool OutputLayer::isClientCompositionForced(bool isPeekingThrough) const {
+    return getState().forceClientComposition ||
+            (!isPeekingThrough && getLayerFE().hasRoundedCorners());
+}
+
 void OutputLayer::applyDeviceCompositionTypeChange(hal::Composition compositionType) {
     auto& state = editState();
     LOG_FATAL_IF(!state.hwc);
     auto& hwcState = *state.hwc;
 
-    detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+    // Only detected disallowed changes if this was not a skip layer, because the
+    // validated composition type may be arbitrary (usually DEVICE, to reflect that there were
+    // fewer GPU layers)
+    if (!hwcState.layerSkipped) {
+        detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+    }
 
     hwcState.hwcCompositionType = compositionType;
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index a63f21f..4453a99 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -20,7 +20,6 @@
 
 #include <compositionengine/impl/planner/Flattener.h>
 #include <compositionengine/impl/planner/LayerState.h>
-#include <compositionengine/impl/planner/Predictor.h>
 
 using time_point = std::chrono::steady_clock::time_point;
 using namespace std::chrono_literals;
@@ -126,9 +125,11 @@
         return left.first < right.first;
     };
 
-    const size_t maxLayerCount = std::max_element(mInitialLayerCounts.cbegin(),
-                                                  mInitialLayerCounts.cend(), compareLayerCounts)
-                                         ->first;
+    const size_t maxLayerCount = mInitialLayerCounts.empty()
+            ? 0u
+            : std::max_element(mInitialLayerCounts.cbegin(), mInitialLayerCounts.cend(),
+                               compareLayerCounts)
+                      ->first;
 
     result.append("\n    Initial counts:\n");
     for (size_t count = 1; count < maxLayerCount; ++count) {
@@ -408,7 +409,7 @@
     }
 
     // TODO(b/181192467): Actually compute new LayerState vector and corresponding hash for each run
-    mPredictor.getPredictedPlan({}, 0);
+    // and feedback into the predictor
 
     ++mCachedSetCreationCount;
     mCachedSetCreationCost += mNewCachedSet->getCreationCost();
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index 7e85dca..c26eb1e 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -27,8 +27,13 @@
 namespace android::compositionengine::impl::planner {
 
 Planner::Planner()
-      : mFlattener(mPredictor,
-                   base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) {}
+      : mFlattener(base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), false)) {
+    // Implicitly, layer caching must also be enabled.
+    // E.g., setprop debug.sf.enable_layer_caching 1, or
+    // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
+    mPredictorEnabled =
+            base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
+}
 
 void Planner::setDisplaySize(ui::Size size) {
     mFlattener.setDisplaySize(size);
@@ -99,19 +104,25 @@
     const bool layersWereFlattened = hash != mFlattenedHash;
     ALOGV("[%s] Initial hash %zx flattened hash %zx", __func__, hash, mFlattenedHash);
 
-    mPredictedPlan =
-            mPredictor.getPredictedPlan(layersWereFlattened ? std::vector<const LayerState*>()
-                                                            : mCurrentLayers,
-                                        mFlattenedHash);
-    if (mPredictedPlan) {
-        ALOGV("[%s] Predicting plan %s", __func__, to_string(mPredictedPlan->plan).c_str());
-    } else {
-        ALOGV("[%s] No prediction found\n", __func__);
+    if (mPredictorEnabled) {
+        mPredictedPlan =
+                mPredictor.getPredictedPlan(layersWereFlattened ? std::vector<const LayerState*>()
+                                                                : mCurrentLayers,
+                                            mFlattenedHash);
+        if (mPredictedPlan) {
+            ALOGV("[%s] Predicting plan %s", __func__, to_string(mPredictedPlan->plan).c_str());
+        } else {
+            ALOGV("[%s] No prediction found\n", __func__);
+        }
     }
 }
 
 void Planner::reportFinalPlan(
         compositionengine::Output::OutputLayersEnumerator<compositionengine::Output>&& layers) {
+    if (!mPredictorEnabled) {
+        return;
+    }
+
     Plan finalPlan;
     const GraphicBuffer* currentOverrideBuffer = nullptr;
     bool hasSkippedLayers = false;
@@ -185,7 +196,9 @@
                 return;
             }
 
-            mPredictor.compareLayerStacks(leftHash, rightHash, result);
+            if (mPredictorEnabled) {
+                mPredictor.compareLayerStacks(leftHash, rightHash, result);
+            }
         } else if (command == "--describe" || command == "-d") {
             if (args.size() < 3) {
                 base::StringAppendF(&result,
@@ -209,7 +222,9 @@
                 return;
             }
 
-            mPredictor.describeLayerStack(hash, result);
+            if (mPredictorEnabled) {
+                mPredictor.describeLayerStack(hash, result);
+            }
         } else if (command == "--help" || command == "-h") {
             dumpUsage(result);
         } else if (command == "--similar" || command == "-s") {
@@ -232,7 +247,9 @@
                 return;
             }
 
-            mPredictor.listSimilarStacks(*plan, result);
+            if (mPredictorEnabled) {
+                mPredictor.listSimilarStacks(*plan, result);
+            }
         } else if (command == "--layers" || command == "-l") {
             mFlattener.dumpLayers(result);
         } else {
@@ -247,7 +264,9 @@
     mFlattener.dump(result);
     result.append("\n");
 
-    mPredictor.dump(result);
+    if (mPredictorEnabled) {
+        mPredictor.dump(result);
+    }
 }
 
 void Planner::dumpUsage(std::string& result) const {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 8a83639..492db43 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -60,9 +60,10 @@
 using testing::SetArgPointee;
 using testing::StrictMock;
 
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId{42};
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
 // TODO(b/160679868) Use VirtualDisplayId
-constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId{43};
+constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId::fromPort(43u);
+
 constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
 constexpr int32_t DEFAULT_LAYER_STACK = 123;
@@ -521,7 +522,11 @@
 TEST_F(DisplayCreateRenderSurfaceTest, setsRenderSurface) {
     EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR));
     EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr);
-    mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr});
+    mDisplay->createRenderSurface(RenderSurfaceCreationArgsBuilder()
+                                          .setDisplayWidth(640)
+                                          .setDisplayHeight(480)
+                                          .setNativeWindow(mNativeWindow)
+                                          .build());
     EXPECT_TRUE(mDisplay->getRenderSurface() != nullptr);
 }
 
@@ -1029,9 +1034,12 @@
     );
     impl::RenderSurface* mRenderSurface =
             new impl::RenderSurface{mCompositionEngine, *mDisplay,
-                                    RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
-                                                              DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
-                                                              mDisplaySurface}};
+                                    RenderSurfaceCreationArgsBuilder()
+                                            .setDisplayWidth(DEFAULT_DISPLAY_WIDTH)
+                                            .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT)
+                                            .setNativeWindow(mNativeWindow)
+                                            .setDisplaySurface(mDisplaySurface)
+                                            .build()};
 };
 
 TEST_F(DisplayFunctionalTest, postFramebufferCriticalCallsAreOrdered) {
@@ -1049,4 +1057,4 @@
 } // namespace android::compositionengine
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
+#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 3adfe40..5bd1216 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -1065,12 +1065,62 @@
                               kOverrideSurfaceDamage);
     expectSetHdrMetadataAndBufferCalls(kOverrideHwcSlot, kOverrideBuffer, kOverrideFence);
     expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    mOutputLayer.editState().hwc->stateOverridden = true;
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+                              Region::INVALID_REGION);
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompositionInfo) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    mOutputLayer.editState().hwc->stateOverridden = true;
+    mOutputLayer.editState().hwc->layerSkipped = true;
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+                              Region::INVALID_REGION);
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
     EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillOnce(Return(false));
 
     mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
                                  /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
 }
 
+TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompositionInfo) {
+    mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+    mOutputLayer.editState().forceClientComposition = true;
+    mOutputLayer.editState().hwc->stateOverridden = true;
+    mOutputLayer.editState().hwc->layerSkipped = true;
+    mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+    expectGeometryCommonCalls();
+    expectPerFrameCommonCalls(SimulateUnsupported::None, kDataspace, kOutputSpaceVisibleRegion,
+                              Region::INVALID_REGION);
+    expectSetHdrMetadataAndBufferCalls();
+    expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+    EXPECT_CALL(*mLayerFE, hasRoundedCorners()).WillRepeatedly(Return(false));
+
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+}
+
 TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) {
     auto peekThroughLayerFE = sp<compositionengine::mock::LayerFE>::make();
     OutputLayer peekThroughLayer{mOutput, peekThroughLayerFE};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 27980a0..11736d1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -238,6 +238,28 @@
 }
 
 /*
+ * Output::setLayerCachingEnabled()
+ */
+
+TEST_F(OutputTest, setLayerCachingEnabled_enablesCaching) {
+    const auto kSize = ui::Size(1, 1);
+    EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+    mOutput->setLayerCachingEnabled(false);
+    mOutput->setLayerCachingEnabled(true);
+
+    EXPECT_TRUE(mOutput->plannerEnabled());
+}
+
+TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) {
+    const auto kSize = ui::Size(1, 1);
+    EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+    mOutput->setLayerCachingEnabled(true);
+    mOutput->setLayerCachingEnabled(false);
+
+    EXPECT_FALSE(mOutput->plannerEnabled());
+}
+
+/*
  * Output::setProjection()
  */
 
@@ -972,9 +994,7 @@
     mOutput.editState().usesDeviceComposition = true;
 
     EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
-    if (mOutput.plannerEnabled()) {
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
-    }
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
     EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
 
     mOutput.prepareFrame();
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 9aeb290..431cc93 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -14,12 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#include "renderengine/ExternalTexture.h"
-#include "ui/GraphicBuffer.h"
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
-
 #include <cstdarg>
 #include <cstdint>
 
@@ -32,14 +26,16 @@
 #include <compositionengine/mock/NativeWindow.h>
 #include <compositionengine/mock/OutputLayer.h>
 #include <gtest/gtest.h>
+#include <renderengine/ExternalTexture.h>
 #include <renderengine/mock/RenderEngine.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android::compositionengine {
 namespace {
 
 constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
-constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId(123u);
+constexpr DisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123u);
 const std::string DEFAULT_DISPLAY_NAME = "Mock Display";
 
 using testing::_;
@@ -67,9 +63,12 @@
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
     sp<mock::DisplaySurface> mDisplaySurface = new StrictMock<mock::DisplaySurface>();
     impl::RenderSurface mSurface{mCompositionEngine, mDisplay,
-                                 RenderSurfaceCreationArgs{DEFAULT_DISPLAY_WIDTH,
-                                                           DEFAULT_DISPLAY_HEIGHT, mNativeWindow,
-                                                           mDisplaySurface}};
+                                 RenderSurfaceCreationArgsBuilder()
+                                         .setDisplayWidth(DEFAULT_DISPLAY_WIDTH)
+                                         .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT)
+                                         .setNativeWindow(mNativeWindow)
+                                         .setDisplaySurface(mDisplaySurface)
+                                         .build()};
 };
 
 /*
@@ -367,11 +366,8 @@
 
     mSurface.flip();
 
-    EXPECT_EQ(501, mSurface.getPageFlipCount());
+    EXPECT_EQ(501u, mSurface.getPageFlipCount());
 }
 
 } // namespace
 } // namespace android::compositionengine
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
index 71757f6..25fab49 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/FlattenerTest.cpp
@@ -18,7 +18,6 @@
 #include <compositionengine/impl/planner/CachedSet.h>
 #include <compositionengine/impl/planner/Flattener.h>
 #include <compositionengine/impl/planner/LayerState.h>
-#include <compositionengine/impl/planner/Predictor.h>
 #include <compositionengine/mock/LayerFE.h>
 #include <compositionengine/mock/OutputLayer.h>
 #include <gtest/gtest.h>
@@ -31,7 +30,6 @@
 using impl::planner::Flattener;
 using impl::planner::LayerState;
 using impl::planner::NonBufferHash;
-using impl::planner::Predictor;
 
 using testing::_;
 using testing::ByMove;
@@ -47,7 +45,7 @@
 
 class FlattenerTest : public testing::Test {
 public:
-    FlattenerTest() : mFlattener(std::make_unique<Flattener>(mPredictor, true)) {}
+    FlattenerTest() : mFlattener(std::make_unique<Flattener>(true)) {}
     void SetUp() override;
 
 protected:
@@ -55,10 +53,6 @@
     void initializeFlattener(const std::vector<const LayerState*>& layers);
     void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
 
-    // TODO(b/181192467): Once Flattener starts to do something useful with Predictor,
-    // mPredictor should be mocked and checked for expectations.
-    Predictor mPredictor;
-
     // mRenderEngine may be held as a pointer to mFlattener, so mFlattener must be destroyed first.
     renderengine::mock::RenderEngine mRenderEngine;
     std::unique_ptr<Flattener> mFlattener;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 8692ee6..ca4b6ab 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -70,13 +70,14 @@
         mIsPrimary(args.isPrimary) {
     mCompositionDisplay->editState().isSecure = args.isSecure;
     mCompositionDisplay->createRenderSurface(
-            compositionengine::
-                    RenderSurfaceCreationArgs{ANativeWindow_getWidth(args.nativeWindow.get()),
-                                              ANativeWindow_getHeight(args.nativeWindow.get()),
-                                              args.nativeWindow, args.displaySurface,
-                                              static_cast<size_t>(
-                                                      SurfaceFlinger::
-                                                              maxFrameBufferAcquiredBuffers)});
+            compositionengine::RenderSurfaceCreationArgsBuilder()
+                    .setDisplayWidth(ANativeWindow_getWidth(args.nativeWindow.get()))
+                    .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get()))
+                    .setNativeWindow(std::move(args.nativeWindow))
+                    .setDisplaySurface(std::move(args.displaySurface))
+                    .setMaxTextureCacheSize(
+                            static_cast<size_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers))
+                    .build());
 
     if (!mFlinger->mDisableClientCompositionCache &&
         SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
@@ -138,6 +139,10 @@
     getCompositionDisplay()->setCompositionEnabled(mPowerMode != hal::PowerMode::OFF);
 }
 
+void DisplayDevice::enableLayerCaching(bool enable) {
+    getCompositionDisplay()->setLayerCachingEnabled(enable);
+}
+
 hal::PowerMode DisplayDevice::getPowerMode() const {
     return mPowerMode;
 }
@@ -268,8 +273,9 @@
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
     StringAppendF(&result, "   powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
                   static_cast<int32_t>(mPowerMode));
+    const auto activeMode = getActiveMode();
     StringAppendF(&result, "   activeMode=%s\n",
-                  mSupportedModes.size() ? to_string(*getActiveMode()).c_str() : "none");
+                  activeMode ? to_string(*activeMode).c_str() : "none");
 
     result.append("   supportedModes=\n");
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 68846d3..bf249cd 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -157,6 +157,9 @@
     void setPowerMode(hardware::graphics::composer::hal::PowerMode mode);
     bool isPoweredOn() const;
 
+    // Enables layer caching on this DisplayDevice
+    void enableLayerCaching(bool enable);
+
     ui::Dataspace getCompositionDataSpace() const;
 
     /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 21c9d74..4fee723 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -129,10 +129,10 @@
     mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
     mCurrentState.metadata = args.metadata;
     mCurrentState.shadowRadius = 0.f;
-    mCurrentState.treeHasFrameRateVote = false;
     mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID;
     mCurrentState.frameTimelineInfo = {};
     mCurrentState.postTime = -1;
+    mCurrentState.destinationFrame.makeInvalid();
 
     if (args.flags & ISurfaceComposerClient::eNoColorFill) {
         // Set an invalid color so there is no color fill.
@@ -315,55 +315,6 @@
     return reduce(mBounds, activeTransparentRegion);
 }
 
-ui::Transform Layer::getBufferScaleTransform() const {
-    // If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
-    // it isFixedSize) then there may be additional scaling not accounted
-    // for in the layer transform.
-    if (!isFixedSize() || getBuffer() == nullptr) {
-        return {};
-    }
-
-    // If the layer is a buffer state layer, the active width and height
-    // could be infinite. In that case, return the effective transform.
-    const uint32_t activeWidth = getActiveWidth(getDrawingState());
-    const uint32_t activeHeight = getActiveHeight(getDrawingState());
-    if (activeWidth >= UINT32_MAX && activeHeight >= UINT32_MAX) {
-        return {};
-    }
-
-    int bufferWidth = getBuffer()->getWidth();
-    int bufferHeight = getBuffer()->getHeight();
-
-    if (getBufferTransform() & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        std::swap(bufferWidth, bufferHeight);
-    }
-
-    float sx = activeWidth / static_cast<float>(bufferWidth);
-    float sy = activeHeight / static_cast<float>(bufferHeight);
-
-    ui::Transform extraParentScaling;
-    extraParentScaling.set(sx, 0, 0, sy);
-    return extraParentScaling;
-}
-
-ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const {
-    // We need to mirror this scaling to child surfaces or we will break the contract where WM can
-    // treat child surfaces as pixels in the parent surface.
-    if (!isFixedSize() || getBuffer() == nullptr) {
-        return mEffectiveTransform;
-    }
-    return mEffectiveTransform * bufferScaleTransform;
-}
-
-FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const {
-    // We need the pre scaled layer bounds when computing child bounds to make sure the child is
-    // cropped to its parent layer after any buffer transform scaling is applied.
-    if (!isFixedSize() || getBuffer() == nullptr) {
-        return mBounds;
-    }
-    return bufferScaleTransform.inverse().transform(mBounds);
-}
-
 void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform,
                           float parentShadowRadius) {
     const State& s(getDrawingState());
@@ -400,11 +351,8 @@
     // don't pass it to its children.
     const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius;
 
-    // Add any buffer scaling to the layer's children.
-    ui::Transform bufferScaleTransform = getBufferScaleTransform();
     for (const sp<Layer>& child : mDrawingChildren) {
-        child->computeBounds(getBoundsPreScaling(bufferScaleTransform),
-                             getTransformWithScale(bufferScaleTransform), childShadowRadius);
+        child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
     }
 }
 
@@ -858,6 +806,11 @@
     const State& s(getDrawingState());
     State& c(getCurrentState());
 
+    // Translates dest frame into scale and position updates. This helps align geometry calculations
+    // for BufferStateLayer with other layers. This should ideally happen in the client once client
+    // has the display orientation details from WM.
+    updateGeometry();
+
     if (c.width != s.width || c.height != s.height || !(c.transform == s.transform)) {
         // invalidate and recompute the visible regions if needed
         flags |= Layer::eVisibleRegion;
@@ -907,8 +860,15 @@
         // list.
         addSurfaceFrameDroppedForBuffer(bufferSurfaceFrame);
     }
+    const bool frameRateVoteChanged =
+            mDrawingState.frameRateForLayerTree != stateToCommit.frameRateForLayerTree;
     mDrawingState = stateToCommit;
 
+    if (frameRateVoteChanged) {
+        mFlinger->mScheduler->recordLayerHistory(this, systemTime(),
+                                                 LayerHistory::LayerUpdateType::SetFrameRate);
+    }
+
     // Set the present state for all bufferlessSurfaceFramesTX to Presented. The
     // bufferSurfaceFrameTX will be presented in latchBuffer.
     for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
@@ -1311,8 +1271,7 @@
     };
 
     // update parents and children about the vote
-    // First traverse the tree and count how many layers has votes. In addition
-    // activate the layers in Scheduler's LayerHistory for it to check for changes
+    // First traverse the tree and count how many layers has votes.
     int layersWithVote = 0;
     traverseTree([&layersWithVote](Layer* layer) {
         const auto layerVotedWithDefaultCompatibility =
@@ -1332,20 +1291,11 @@
         }
     });
 
-    // Now update the other layers
+    // Now we can update the tree frame rate vote for each layer in the tree
+    const bool treeHasFrameRateVote = layersWithVote > 0;
     bool transactionNeeded = false;
-    traverseTree([layersWithVote, &transactionNeeded, this](Layer* layer) {
-        const bool treeHasFrameRateVote = layersWithVote > 0;
-        if (layer->mCurrentState.treeHasFrameRateVote != treeHasFrameRateVote) {
-            layer->mCurrentState.sequence++;
-            layer->mCurrentState.treeHasFrameRateVote = treeHasFrameRateVote;
-            layer->mCurrentState.modified = true;
-            layer->setTransactionFlags(eTransactionNeeded);
-            transactionNeeded = true;
-
-            mFlinger->mScheduler->recordLayerHistory(layer, systemTime(),
-                                                     LayerHistory::LayerUpdateType::SetFrameRate);
-        }
+    traverseTree([treeHasFrameRateVote, &transactionNeeded](Layer* layer) {
+        transactionNeeded = layer->updateFrameRateForLayerTree(treeHasFrameRateVote);
     });
 
     if (transactionNeeded) {
@@ -1474,32 +1424,42 @@
     return surfaceFrame;
 }
 
-Layer::FrameRate Layer::getFrameRateForLayerTree() const {
-    const auto frameRate = getDrawingState().frameRate;
+bool Layer::updateFrameRateForLayerTree(bool treeHasFrameRateVote) {
+    const auto updateCurrentState = [&](FrameRate frameRate) {
+        if (mCurrentState.frameRateForLayerTree == frameRate) {
+            return false;
+        }
+        mCurrentState.frameRateForLayerTree = frameRate;
+        mCurrentState.sequence++;
+        mCurrentState.modified = true;
+        setTransactionFlags(eTransactionNeeded);
+        return true;
+    };
+
+    const auto frameRate = mCurrentState.frameRate;
     if (frameRate.rate.isValid() || frameRate.type == FrameRateCompatibility::NoVote) {
-        return frameRate;
+        return updateCurrentState(frameRate);
     }
 
     // This layer doesn't have a frame rate. Check if its ancestors have a vote
-    if (sp<Layer> parent = getParent(); parent) {
-        if (const auto parentFrameRate = parent->getFrameRateForLayerTree();
-            parentFrameRate.rate.isValid()) {
-            return parentFrameRate;
+    for (sp<Layer> parent = getParent(); parent; parent = parent->getParent()) {
+        if (parent->mCurrentState.frameRate.rate.isValid()) {
+            return updateCurrentState(parent->mCurrentState.frameRate);
         }
     }
 
     // This layer and its ancestors don't have a frame rate. If one of successors
     // has a vote, return a NoVote for successors to set the vote
-    if (getDrawingState().treeHasFrameRateVote) {
-        return {Fps(0.0f), FrameRateCompatibility::NoVote};
+    if (treeHasFrameRateVote) {
+        return updateCurrentState(FrameRate(Fps(0.0f), FrameRateCompatibility::NoVote));
     }
 
-    return frameRate;
+    return updateCurrentState(frameRate);
 }
 
-// ----------------------------------------------------------------------------
-// pageflip handling...
-// ----------------------------------------------------------------------------
+Layer::FrameRate Layer::getFrameRateForLayerTree() const {
+    return getDrawingState().frameRateForLayerTree;
+}
 
 bool Layer::isHiddenByPolicy() const {
     const State& s(mDrawingState);
@@ -1768,8 +1728,7 @@
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
         child->mDrawingParent = newParent;
-        child->computeBounds(newParent->mBounds,
-                             newParent->getTransformWithScale(newParent->getBufferScaleTransform()),
+        child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
                              newParent->mEffectiveShadowRadius);
     }
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 284adbd..8139d8a 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -239,8 +239,8 @@
 
         FrameRate frameRate;
 
-        // Indicates whether parents / children of this layer had set FrameRate
-        bool treeHasFrameRateVote;
+        // The combined frame rate of parents / children of this layer
+        FrameRate frameRateForLayerTree;
 
         // Set by window manager indicating the layer and all its children are
         // in a different orientation than the display. The hint suggests that
@@ -276,6 +276,7 @@
         StretchEffect stretchEffect;
 
         Rect bufferCrop;
+        Rect destinationFrame;
     };
 
     /*
@@ -646,16 +647,6 @@
     // Compute bounds for the layer and cache the results.
     void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
 
-    // Returns the buffer scale transform if a scaling mode is set.
-    ui::Transform getBufferScaleTransform() const;
-
-    // Get effective layer transform, taking into account all its parent transform with any
-    // scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
-    ui::Transform getTransformWithScale(const ui::Transform& bufferScaleTransform) const;
-
-    // Returns the bounds of the layer without any buffer scaling.
-    FloatRect getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const;
-
     int32_t getSequence() const override { return sequence; }
 
     // For tracing.
@@ -885,8 +876,10 @@
     StretchEffect getStretchEffect() const;
 
     virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; }
+    virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; }
     virtual std::atomic<int32_t>* getPendingBufferCounter() { return nullptr; }
     virtual std::string getPendingBufferCounterName() { return ""; }
+    virtual void updateGeometry() {}
 
 protected:
     friend class impl::SurfaceInterceptor;
@@ -1064,6 +1057,8 @@
     // Fills in the frame and transform info for the InputWindowInfo
     void fillInputFrameInfo(InputWindowInfo& info, const ui::Transform& toPhysicalDisplay);
 
+    bool updateFrameRateForLayerTree(bool treeHasFrameRateVote);
+
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling, which is
     // a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index beda834..4b0bdcb 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -287,6 +287,8 @@
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sControlDisplayBrightness("android.permission.CONTROL_DISPLAY_BRIGHTNESS");
 const String16 sDump("android.permission.DUMP");
+const String16 sCaptureBlackoutContent("android.permission.CAPTURE_BLACKOUT_CONTENT");
+
 const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
 
 // ---------------------------------------------------------------------------
@@ -381,6 +383,12 @@
     mColorSpaceAgnosticDataspace =
             static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN));
 
+    mLayerCachingEnabled = [] {
+        const bool enable =
+                android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
+        return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
+    }();
+
     useContextPriority = use_context_priority(true);
 
     using Values = SurfaceFlingerProperties::primary_display_orientation_values;
@@ -2174,11 +2182,10 @@
             mFpsReporter->dispatchLayerFps();
         }
         hdrInfoListeners.reserve(mHdrLayerInfoListeners.size());
-        for (auto& [key, value] : mHdrLayerInfoListeners) {
-            if (value && value->hasListeners()) {
-                auto listenersDisplay = getDisplayById(key);
-                if (listenersDisplay) {
-                    hdrInfoListeners.emplace_back(listenersDisplay->getCompositionDisplay(), value);
+        for (const auto& [displayId, reporter] : mHdrLayerInfoListeners) {
+            if (reporter && reporter->hasListeners()) {
+                if (const auto display = getDisplayDeviceLocked(displayId)) {
+                    hdrInfoListeners.emplace_back(display->getCompositionDisplay(), reporter);
                 }
             }
         }
@@ -2642,6 +2649,7 @@
     builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator);
     builder.setName(state.displayName);
     const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
+    compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
 
     sp<compositionengine::DisplaySurface> displaySurface;
     sp<IGraphicBufferProducer> producer;
@@ -2816,16 +2824,19 @@
 }
 
 void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags) {
-    /*
-     * Traversal of the children
-     * (perform the transaction for each of them if needed)
-     */
+    // Commit display transactions
+    const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
+    if (displayTransactionNeeded) {
+        processDisplayChangesLocked();
+        processDisplayHotplugEventsLocked();
+    }
 
-    if ((transactionFlags & eTraversalNeeded) || mForceTraversal) {
-        mForceTraversal = false;
+    // Commit layer transactions. This needs to happen after display transactions are
+    // committed because some geometry logic relies on display orientation.
+    if ((transactionFlags & eTraversalNeeded) || mForceTraversal || displayTransactionNeeded) {
         mCurrentState.traverse([&](Layer* layer) {
             uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
-            if (!trFlags) return;
+            if (!trFlags && !displayTransactionNeeded) return;
 
             const uint32_t flags = layer->doTransaction(0);
             if (flags & Layer::eVisibleRegion)
@@ -2837,15 +2848,7 @@
         });
     }
 
-    /*
-     * Perform display own transactions if needed
-     */
-
-    if (transactionFlags & eDisplayTransactionNeeded) {
-        processDisplayChangesLocked();
-        processDisplayHotplugEventsLocked();
-    }
-
+    // Update transform hint
     if (transactionFlags & (eTransformHintUpdateNeeded | eDisplayTransactionNeeded)) {
         // The transform hint might have changed for some layers
         // (either because a display has changed, or because a layer
@@ -4039,6 +4042,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eDestinationFrameChanged) {
+        if (layer->setDestinationFrame(s.destinationFrame)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -5187,9 +5195,9 @@
         code == IBinder::SYSPROPS_TRANSACTION) {
         return OK;
     }
-    // Numbers from 1000 to 1038 are currently used for backdoors. The code
+    // Numbers from 1000 to 1040 are currently used for backdoors. The code
     // in onTransact verifies that the user is root, and has access to use SF.
-    if (code >= 1000 && code <= 1039) {
+    if (code >= 1000 && code <= 1040) {
         ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code);
         return OK;
     }
@@ -5504,37 +5512,24 @@
             }
             case 1035: {
                 const int modeId = data.readInt32();
-                mDebugDisplayModeSetByBackdoor = false;
 
-                const auto displayId = [&]() -> std::optional<PhysicalDisplayId> {
-                    uint64_t inputDisplayId = 0;
-                    if (data.readUint64(&inputDisplayId) == NO_ERROR) {
-                        const auto token = getPhysicalDisplayToken(
-                                static_cast<PhysicalDisplayId>(inputDisplayId));
-                        if (!token) {
-                            ALOGE("No display with id: %" PRIu64, inputDisplayId);
-                            return std::nullopt;
-                        }
-
-                        return std::make_optional<PhysicalDisplayId>(inputDisplayId);
+                const auto display = [&]() -> sp<IBinder> {
+                    uint64_t value;
+                    if (data.readUint64(&value) != NO_ERROR) {
+                        return getInternalDisplayToken();
                     }
 
-                    return getInternalDisplayId();
+                    if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) {
+                        return getPhysicalDisplayToken(*id);
+                    }
+
+                    ALOGE("Invalid physical display ID");
+                    return nullptr;
                 }();
 
-                if (!displayId) {
-                    ALOGE("No display found");
-                    return NO_ERROR;
-                }
-
-                status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId);
-                if (result != NO_ERROR) {
-                    return result;
-                }
-
-                mDebugDisplayModeSetByBackdoor = true;
-
-                return NO_ERROR;
+                const status_t result = setActiveMode(display, modeId);
+                mDebugDisplayModeSetByBackdoor = result == NO_ERROR;
+                return result;
             }
             case 1036: {
                 if (data.readInt32() > 0) {
@@ -5586,6 +5581,33 @@
                 mScheduler->onFrameRateOverridesChanged(mAppConnectionHandle, displayId);
                 return NO_ERROR;
             }
+            // Toggle caching feature
+            // First argument is an int32 - nonzero enables caching and zero disables caching
+            // Second argument is an optional uint64 - if present, then limits enabling/disabling
+            // caching to a particular physical display
+            case 1040: {
+                n = data.readInt32();
+                std::optional<PhysicalDisplayId> inputId = std::nullopt;
+                if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) {
+                    inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
+                    if (!inputId || getPhysicalDisplayToken(*inputId)) {
+                        ALOGE("No display with id: %" PRIu64, inputDisplayId);
+                        return NAME_NOT_FOUND;
+                    }
+                }
+                {
+                    Mutex::Autolock lock(mStateLock);
+                    mLayerCachingEnabled = n != 0;
+                    for (const auto& [_, display] : mDisplays) {
+                        if (!inputId || *inputId == display->getPhysicalId()) {
+                            display->enableLayerCaching(mLayerCachingEnabled);
+                        }
+                    }
+                }
+                invalidateHwcGeometry();
+                repaintEverything();
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -5681,6 +5703,14 @@
     }
 }
 
+static bool hasCaptureBlackoutContentPermission() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+            PermissionCache::checkPermission(sCaptureBlackoutContent, pid, uid);
+}
+
 static status_t validateScreenshotPermissions(const CaptureArgs& captureArgs) {
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
@@ -5719,34 +5749,6 @@
     return NO_ERROR;
 }
 
-sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
-    if (const sp<IBinder> displayToken =
-                getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
-        return getDisplayDeviceLocked(displayToken);
-    }
-    // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
-    // may not have a displayId.
-    return getDisplayByLayerStack(displayOrLayerStack);
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayById(DisplayId displayId) const {
-    for (const auto& [token, display] : mDisplays) {
-        if (display->getId() == displayId) {
-            return display;
-        }
-    }
-    return nullptr;
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
-    for (const auto& [token, display] : mDisplays) {
-        if (display->getLayerStack() == layerStack) {
-            return display;
-        }
-    }
-    return nullptr;
-}
-
 status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
                                         const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
@@ -5758,7 +5760,7 @@
 
     if (!args.displayToken) return BAD_VALUE;
 
-    wp<DisplayDevice> displayWeak;
+    wp<const DisplayDevice> displayWeak;
     ui::LayerStack layerStack;
     ui::Size reqSize(args.width, args.height);
     ui::Dataspace dataspace;
@@ -5799,21 +5801,22 @@
                                captureListener);
 }
 
-status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
+status_t SurfaceFlinger::captureDisplay(DisplayId displayId,
                                         const sp<IScreenCaptureListener>& captureListener) {
     ui::LayerStack layerStack;
-    wp<DisplayDevice> displayWeak;
+    wp<const DisplayDevice> displayWeak;
     ui::Size size;
     ui::Dataspace dataspace;
     {
         Mutex::Autolock lock(mStateLock);
-        sp<DisplayDevice> display = getDisplayByIdOrLayerStack(displayOrLayerStack);
+
+        const auto display = getDisplayDeviceLocked(displayId);
         if (!display) {
             return NAME_NOT_FOUND;
         }
-        layerStack = display->getLayerStack();
-        displayWeak = display;
 
+        displayWeak = display;
+        layerStack = display->getLayerStack();
         size = display->getLayerStackSpaceRect().getSize();
 
         dataspace =
@@ -5851,6 +5854,10 @@
     Rect layerStackSpaceRect;
     ui::Dataspace dataspace;
     bool captureSecureLayers;
+
+    // Call this before holding mStateLock to avoid any deadlocking.
+    bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
+
     {
         Mutex::Autolock lock(mStateLock);
 
@@ -5860,9 +5867,8 @@
             return NAME_NOT_FOUND;
         }
 
-        const int uid = IPCThreadState::self()->getCallingUid();
-        const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
-        if (!forSystem && parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
+        if (!canCaptureBlackoutContent &&
+            parent->getCurrentState().flags & layer_state_t::eLayerSecure) {
             ALOGW("Attempting to capture secure layer: PERMISSION_DENIED");
             return PERMISSION_DENIED;
         }
@@ -5895,7 +5901,11 @@
             }
         }
 
-        const auto display = getDisplayByLayerStack(parent->getLayerStack());
+        const auto display =
+                findDisplay([layerStack = parent->getLayerStack()](const auto& display) {
+                    return display.getLayerStack() == layerStack;
+                });
+
         if (!display) {
             return NAME_NOT_FOUND;
         }
@@ -6012,8 +6022,7 @@
         return BAD_VALUE;
     }
 
-    const int uid = IPCThreadState::self()->getCallingUid();
-    const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
+    bool canCaptureBlackoutContent = hasCaptureBlackoutContentPermission();
 
     static_cast<void>(schedule([=, renderAreaFuture = std::move(renderAreaFuture)]() mutable {
         if (mRefreshPending) {
@@ -6033,8 +6042,9 @@
 
         status_t result = NO_ERROR;
         renderArea->render([&] {
-            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer, forSystem,
-                                            regionSampling, grayscale, captureResults);
+            result = renderScreenImplLocked(*renderArea, traverseLayers, buffer,
+                                            canCaptureBlackoutContent, regionSampling, grayscale,
+                                            captureResults);
         });
 
         captureResults.result = result;
@@ -6046,8 +6056,9 @@
 
 status_t SurfaceFlinger::renderScreenImplLocked(
         const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
-        const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool forSystem,
-        bool regionSampling, bool grayscale, ScreenCaptureResults& captureResults) {
+        const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+        bool canCaptureBlackoutContent, bool regionSampling, bool grayscale,
+        ScreenCaptureResults& captureResults) {
     ATRACE_CALL();
 
     traverseLayers([&](Layer* layer) {
@@ -6060,7 +6071,7 @@
     // We allow the system server to take screenshots of secure layers for
     // use in situations like the Screen-rotation animation and place
     // the impetus on WindowManager to not persist them.
-    if (captureResults.capturedSecureLayers && !forSystem) {
+    if (captureResults.capturedSecureLayers && !canCaptureBlackoutContent) {
         ALOGW("FB is protected: PERMISSION_DENIED");
         return PERMISSION_DENIED;
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4bbdd48..4aa047a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -620,12 +620,10 @@
     sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
             ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override;
-    status_t captureDisplay(const DisplayCaptureArgs& args,
-                            const sp<IScreenCaptureListener>& captureListener) override;
-    status_t captureDisplay(uint64_t displayOrLayerStack,
-                            const sp<IScreenCaptureListener>& captureListener) override;
-    status_t captureLayers(const LayerCaptureArgs& args,
-                           const sp<IScreenCaptureListener>& captureListener) override;
+
+    status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&) override;
+    status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&) override;
+    status_t captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override;
 
     status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
     status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*)
@@ -911,12 +909,8 @@
                                  const sp<IScreenCaptureListener>&);
     status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                     const std::shared_ptr<renderengine::ExternalTexture>&,
-                                    bool forSystem, bool regionSampling, bool grayscale,
-                                    ScreenCaptureResults&);
-
-    sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
-    sp<DisplayDevice> getDisplayById(DisplayId displayId) const REQUIRES(mStateLock);
-    sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
+                                    bool canCaptureBlackoutContent, bool regionSampling,
+                                    bool grayscale, ScreenCaptureResults&);
 
     // If the uid provided is not UNSET_UID, the traverse will skip any layers that don't have a
     // matching ownerUid
@@ -959,6 +953,20 @@
         return getDefaultDisplayDeviceLocked();
     }
 
+    // Returns the first display that matches a `bool(const DisplayDevice&)` predicate.
+    template <typename Predicate>
+    sp<DisplayDevice> findDisplay(Predicate p) const REQUIRES(mStateLock) {
+        const auto it = std::find_if(mDisplays.begin(), mDisplays.end(),
+                                     [&](const auto& pair) { return p(*pair.second); });
+
+        return it == mDisplays.end() ? nullptr : it->second;
+    }
+
+    sp<const DisplayDevice> getDisplayDeviceLocked(DisplayId id) const REQUIRES(mStateLock) {
+        // TODO(b/182939859): Replace tokens with IDs for display lookup.
+        return findDisplay([id](const auto& display) { return display.getId() == id; });
+    }
+
     // mark a region of a layer stack dirty. this updates the dirty
     // region of all screens presenting this layer stack.
     void invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty);
@@ -1236,6 +1244,7 @@
     int mDebugRegion = 0;
     bool mDebugDisableHWC = false;
     bool mDebugDisableTransformHint = false;
+    bool mLayerCachingEnabled = false;
     volatile nsecs_t mDebugInTransaction = 0;
     bool mForceFullDamage = false;
     bool mPropagateBackpressureClientComposition = false;
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
index 4753362..34c9182 100644
--- a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -19,6 +19,7 @@
 #pragma clang diagnostic ignored "-Wconversion"
 
 #include <gui/BufferItemConsumer.h>
+#include <private/android_filesystem_config.h>
 #include "TransactionTestHarnesses.h"
 
 namespace android {
@@ -170,7 +171,11 @@
     args.displayToken = mDisplay;
 
     ScreenCaptureResults captureResults;
-    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
+    {
+        // Ensure the UID is not root because root has all permissions
+        UIDFaker f(AID_APP_START);
+        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(args, captureResults));
+    }
 
     Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
     ASSERT_EQ(NO_ERROR, ScreenCapture::captureDisplay(args, captureResults));
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 2e9c10c..6912fcf 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -84,7 +84,11 @@
 
     Transaction().show(layer).setLayer(layer, INT32_MAX).apply(true);
 
-    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
+    {
+        // Ensure the UID is not root because root has all permissions
+        UIDFaker f(AID_APP_START);
+        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureDisplay(mCaptureArgs, mCaptureResults));
+    }
 
     UIDFaker f(AID_SYSTEM);
 
@@ -528,7 +532,7 @@
     ASSERT_EQ(NAME_NOT_FOUND, ScreenCapture::captureLayers(args, captureResults));
 }
 
-TEST_F(ScreenCaptureTest, CaputureSecureLayer) {
+TEST_F(ScreenCaptureTest, CaptureSecureLayer) {
     sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60,
                                               ISurfaceComposerClient::eFXSurfaceBufferState);
     sp<SurfaceControl> secureLayer =
@@ -552,8 +556,12 @@
     args.childrenOnly = false;
     ScreenCaptureResults captureResults;
 
-    // Call from outside system with secure layers will result in permission denied
-    ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
+    {
+        // Ensure the UID is not root because root has all permissions
+        UIDFaker f(AID_APP_START);
+        // Call from outside system with secure layers will result in permission denied
+        ASSERT_EQ(PERMISSION_DENIED, ScreenCapture::captureLayers(args, captureResults));
+    }
 
     UIDFaker f(AID_SYSTEM);
 
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 162711d..a9e935d 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -279,7 +279,7 @@
     }
 
     bool waitForHotplugEvent(Display displayId, bool connected) {
-        return waitForHotplugEvent(PhysicalDisplayId(displayId), connected);
+        return waitForHotplugEvent(physicalIdFromHwcDisplayId(displayId), connected);
     }
 
     bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
@@ -305,7 +305,7 @@
     }
 
     bool waitForModeChangedEvent(Display display, int32_t modeId) {
-        PhysicalDisplayId displayId(display);
+        PhysicalDisplayId displayId = physicalIdFromHwcDisplayId(display);
         int waitCount = 20;
         while (waitCount--) {
             while (!mReceivedDisplayEvents.empty()) {
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3042450..e42cf47 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -77,7 +77,7 @@
 constexpr hal::HWLayerId HWC_LAYER = 5000;
 constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
 
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(42);
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
 constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index a3e8108..359e555 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -118,7 +118,7 @@
 
 sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
         std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
-    constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID(777);
+    constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
     constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
     constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
     constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index b4a1481..62acc6b 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -41,10 +41,13 @@
 
 namespace {
 
-constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID(111);
-constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID(222);
-constexpr PhysicalDisplayId DISPLAY_ID_64BIT(0xabcd12349876fedcULL);
+constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(111u);
+constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = PhysicalDisplayId::fromPort(222u);
+constexpr PhysicalDisplayId DISPLAY_ID_64BIT =
+        PhysicalDisplayId::fromEdid(0xffu, 0xffffu, 0xffff'ffffu);
+
 constexpr std::chrono::duration VSYNC_PERIOD(16ms);
+
 class MockVSyncSource : public VSyncSource {
 public:
     const char* getName() const override { return "test"; }
diff --git a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index 6916764..597e5e7 100644
--- a/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -72,7 +72,8 @@
     mIdleTimer->stop();
 }
 
-TEST_F(OneShotTimerTest, resetTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
                                                            mResetTimerCallback.getInvocable(),
@@ -94,7 +95,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
 }
 
-TEST_F(OneShotTimerTest, resetBackToBackTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_resetBackToBackTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
                                                            mResetTimerCallback.getInvocable(),
@@ -144,7 +146,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
 }
 
-TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_idleTimerIdlesTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
                                                            mResetTimerCallback.getInvocable(),
@@ -169,7 +172,8 @@
     EXPECT_FALSE(mResetTimerCallback.waitForUnexpectedCall().has_value());
 }
 
-TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+// TODO(b/186417847) This test is flaky. Reenable once fixed.
+TEST_F(OneShotTimerTest, DISABLED_timeoutCallbackExecutionTest) {
     fake::FakeClock* clock = new fake::FakeClock();
     mIdleTimer = std::make_unique<scheduler::OneShotTimer>("TestTimer", 1ms,
                                                            mResetTimerCallback.getInvocable(),
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 38e503f..7a6ae5b 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -34,7 +34,7 @@
 namespace android {
 namespace {
 
-constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID(999);
+constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = PhysicalDisplayId::fromPort(255u);
 
 class SchedulerTest : public testing::Test {
 protected: