Merge "TransactionCallbackInvoker: Send callbacks on thread"
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index 235990a..5fe4ea1 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -185,6 +185,12 @@
 }
 
 prebuilt_etc {
+    name: "android.hardware.wifi.passpoint.prebuilt.xml",
+    src: "android.hardware.wifi.passpoint.xml",
+    defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
     name: "android.software.device_id_attestation.prebuilt.xml",
     src: "android.software.device_id_attestation.xml",
     defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 89a31c5..bb1b513 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -303,6 +303,14 @@
         "aidl/android/content/pm/ApexStagedEvent.aidl",
         "aidl/android/content/pm/StagedApexInfo.aidl",
     ],
+    backend: {
+        rust: {
+            apex_available: [
+                "com.android.virt",
+            ],
+            enabled: true,
+        },
+    },
 }
 
 aidl_interface {
diff --git a/libs/binder/RpcSession.cpp b/libs/binder/RpcSession.cpp
index 4465b8e..37f6c7f 100644
--- a/libs/binder/RpcSession.cpp
+++ b/libs/binder/RpcSession.cpp
@@ -61,7 +61,7 @@
     LOG_RPC_DETAIL("RpcSession destroyed %p", this);
 
     std::lock_guard<std::mutex> _l(mMutex);
-    LOG_ALWAYS_FATAL_IF(mThreadState.mIncomingConnections.size() != 0,
+    LOG_ALWAYS_FATAL_IF(mConnections.mIncoming.size() != 0,
                         "Should not be able to destroy a session with servers in use.");
 }
 
@@ -78,12 +78,10 @@
 
 void RpcSession::setMaxThreads(size_t threads) {
     std::lock_guard<std::mutex> _l(mMutex);
-    LOG_ALWAYS_FATAL_IF(!mThreadState.mOutgoingConnections.empty() ||
-                                !mThreadState.mIncomingConnections.empty(),
+    LOG_ALWAYS_FATAL_IF(!mConnections.mOutgoing.empty() || !mConnections.mIncoming.empty(),
                         "Must set max threads before setting up connections, but has %zu client(s) "
                         "and %zu server(s)",
-                        mThreadState.mOutgoingConnections.size(),
-                        mThreadState.mIncomingConnections.size());
+                        mConnections.mOutgoing.size(), mConnections.mIncoming.size());
     mMaxThreads = threads;
 }
 
@@ -197,7 +195,7 @@
         LOG_ALWAYS_FATAL_IF(mShutdownListener == nullptr, "Shutdown listener not installed");
         mShutdownListener->waitForShutdown(_l, sp<RpcSession>::fromExisting(this));
 
-        LOG_ALWAYS_FATAL_IF(!mThreadState.mThreads.empty(), "Shutdown failed");
+        LOG_ALWAYS_FATAL_IF(!mConnections.mThreads.empty(), "Shutdown failed");
     }
 
     _l.unlock();
@@ -263,11 +261,11 @@
 
 void RpcSession::WaitForShutdownListener::waitForShutdown(std::unique_lock<std::mutex>& lock,
                                                           const sp<RpcSession>& session) {
-    while (session->mThreadState.mIncomingConnections.size() > 0) {
+    while (session->mConnections.mIncoming.size() > 0) {
         if (std::cv_status::timeout == mCv.wait_for(lock, std::chrono::seconds(1))) {
             ALOGE("Waiting for RpcSession to shut down (1s w/o progress): %zu incoming connections "
                   "still.",
-                  session->mThreadState.mIncomingConnections.size());
+                  session->mConnections.mIncoming.size());
         }
     }
 }
@@ -277,7 +275,7 @@
 
     {
         std::lock_guard<std::mutex> _l(mMutex);
-        mThreadState.mThreads[thread.get_id()] = std::move(thread);
+        mConnections.mThreads[thread.get_id()] = std::move(thread);
     }
 }
 
@@ -380,10 +378,10 @@
     sp<RpcSession::EventListener> listener;
     {
         std::lock_guard<std::mutex> _l(session->mMutex);
-        auto it = session->mThreadState.mThreads.find(std::this_thread::get_id());
-        LOG_ALWAYS_FATAL_IF(it == session->mThreadState.mThreads.end());
+        auto it = session->mConnections.mThreads.find(std::this_thread::get_id());
+        LOG_ALWAYS_FATAL_IF(it == session->mConnections.mThreads.end());
         it->second.detach();
-        session->mThreadState.mThreads.erase(it);
+        session->mConnections.mThreads.erase(it);
 
         listener = session->mEventListener.promote();
     }
@@ -414,9 +412,9 @@
                                                               bool incoming)>& connectAndInit) {
     {
         std::lock_guard<std::mutex> _l(mMutex);
-        LOG_ALWAYS_FATAL_IF(mThreadState.mOutgoingConnections.size() != 0,
+        LOG_ALWAYS_FATAL_IF(mConnections.mOutgoing.size() != 0,
                             "Must only setup session once, but already has %zu clients",
-                            mThreadState.mOutgoingConnections.size());
+                            mConnections.mOutgoing.size());
     }
 
     if (auto status = initShutdownTrigger(); status != OK) return status;
@@ -439,7 +437,7 @@
         // downgrade again
         mProtocolVersion = oldProtocolVersion;
 
-        mThreadState = {};
+        mConnections = {};
     });
 
     if (status_t status = connectAndInit({}, false /*incoming*/); status != OK) return status;
@@ -662,7 +660,7 @@
         std::lock_guard<std::mutex> _l(mMutex);
         connection->rpcTransport = std::move(rpcTransport);
         connection->exclusiveTid = gettid();
-        mThreadState.mOutgoingConnections.push_back(connection);
+        mConnections.mOutgoing.push_back(connection);
     }
 
     status_t status = OK;
@@ -699,9 +697,9 @@
         std::unique_ptr<RpcTransport> rpcTransport) {
     std::lock_guard<std::mutex> _l(mMutex);
 
-    if (mThreadState.mIncomingConnections.size() >= mMaxThreads) {
+    if (mConnections.mIncoming.size() >= mMaxThreads) {
         ALOGE("Cannot add thread to session with %zu threads (max is set to %zu)",
-              mThreadState.mIncomingConnections.size(), mMaxThreads);
+              mConnections.mIncoming.size(), mMaxThreads);
         return nullptr;
     }
 
@@ -709,7 +707,7 @@
     // happens when new connections are still being established as part of a
     // very short-lived session which shuts down after it already started
     // accepting new connections.
-    if (mThreadState.mIncomingConnections.size() < mThreadState.mMaxIncomingConnections) {
+    if (mConnections.mIncoming.size() < mConnections.mMaxIncoming) {
         return nullptr;
     }
 
@@ -717,19 +715,19 @@
     session->rpcTransport = std::move(rpcTransport);
     session->exclusiveTid = gettid();
 
-    mThreadState.mIncomingConnections.push_back(session);
-    mThreadState.mMaxIncomingConnections = mThreadState.mIncomingConnections.size();
+    mConnections.mIncoming.push_back(session);
+    mConnections.mMaxIncoming = mConnections.mIncoming.size();
 
     return session;
 }
 
 bool RpcSession::removeIncomingConnection(const sp<RpcConnection>& connection) {
     std::unique_lock<std::mutex> _l(mMutex);
-    if (auto it = std::find(mThreadState.mIncomingConnections.begin(),
-                            mThreadState.mIncomingConnections.end(), connection);
-        it != mThreadState.mIncomingConnections.end()) {
-        mThreadState.mIncomingConnections.erase(it);
-        if (mThreadState.mIncomingConnections.size() == 0) {
+    if (auto it =
+                std::find(mConnections.mIncoming.begin(), mConnections.mIncoming.end(), connection);
+        it != mConnections.mIncoming.end()) {
+        mConnections.mIncoming.erase(it);
+        if (mConnections.mIncoming.size() == 0) {
             sp<EventListener> listener = mEventListener.promote();
             if (listener) {
                 _l.unlock();
@@ -754,7 +752,7 @@
     pid_t tid = gettid();
     std::unique_lock<std::mutex> _l(session->mMutex);
 
-    session->mThreadState.mWaitingThreads++;
+    session->mConnections.mWaitingThreads++;
     while (true) {
         sp<RpcConnection> exclusive;
         sp<RpcConnection> available;
@@ -762,11 +760,11 @@
         // CHECK FOR DEDICATED CLIENT SOCKET
         //
         // A server/looper should always use a dedicated connection if available
-        findConnection(tid, &exclusive, &available, session->mThreadState.mOutgoingConnections,
-                       session->mThreadState.mOutgoingConnectionsOffset);
+        findConnection(tid, &exclusive, &available, session->mConnections.mOutgoing,
+                       session->mConnections.mOutgoingOffset);
 
         // WARNING: this assumes a server cannot request its client to send
-        // a transaction, as mIncomingConnections is excluded below.
+        // a transaction, as mIncoming 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
@@ -776,9 +774,8 @@
         // command. So, we move to considering the second available thread
         // for subsequent calls.
         if (use == ConnectionUse::CLIENT_ASYNC && (exclusive != nullptr || available != nullptr)) {
-            session->mThreadState.mOutgoingConnectionsOffset =
-                    (session->mThreadState.mOutgoingConnectionsOffset + 1) %
-                    session->mThreadState.mOutgoingConnections.size();
+            session->mConnections.mOutgoingOffset = (session->mConnections.mOutgoingOffset + 1) %
+                    session->mConnections.mOutgoing.size();
         }
 
         // USE SERVING SOCKET (e.g. nested transaction)
@@ -786,7 +783,7 @@
             sp<RpcConnection> exclusiveIncoming;
             // server connections are always assigned to a thread
             findConnection(tid, &exclusiveIncoming, nullptr /*available*/,
-                           session->mThreadState.mIncomingConnections, 0 /* index hint */);
+                           session->mConnections.mIncoming, 0 /* index hint */);
 
             // asynchronous calls cannot be nested, we currently allow ref count
             // calls to be nested (so that you can use this without having extra
@@ -815,20 +812,20 @@
             break;
         }
 
-        if (session->mThreadState.mOutgoingConnections.size() == 0) {
+        if (session->mConnections.mOutgoing.size() == 0) {
             ALOGE("Session has no client connections. This is required for an RPC server to make "
                   "any non-nested (e.g. oneway or on another thread) calls. Use: %d. Server "
                   "connections: %zu",
-                  static_cast<int>(use), session->mThreadState.mIncomingConnections.size());
+                  static_cast<int>(use), session->mConnections.mIncoming.size());
             return WOULD_BLOCK;
         }
 
         LOG_RPC_DETAIL("No available connections (have %zu clients and %zu servers). Waiting...",
-                       session->mThreadState.mOutgoingConnections.size(),
-                       session->mThreadState.mIncomingConnections.size());
+                       session->mConnections.mOutgoing.size(),
+                       session->mConnections.mIncoming.size());
         session->mAvailableConnectionCv.wait(_l);
     }
-    session->mThreadState.mWaitingThreads--;
+    session->mConnections.mWaitingThreads--;
 
     return OK;
 }
@@ -867,7 +864,7 @@
     if (!mReentrant && mConnection != nullptr) {
         std::unique_lock<std::mutex> _l(mSession->mMutex);
         mConnection->exclusiveTid = std::nullopt;
-        if (mSession->mThreadState.mWaitingThreads > 0) {
+        if (mSession->mConnections.mWaitingThreads > 0) {
             _l.unlock();
             mSession->mAvailableConnectionCv.notify_one();
         }
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index d71f496..7c99f76 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -144,5 +144,5 @@
      * Get information of APEX which is staged ready for installation.
      * Returns null if no such APEX is found.
      */
-    StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
+    @nullable StagedApexInfo getStagedApexInfo(in @utf8InCpp String moduleName);
 }
diff --git a/libs/binder/include/binder/RpcSession.h b/libs/binder/include/binder/RpcSession.h
index 19888b7..0fcee90 100644
--- a/libs/binder/include/binder/RpcSession.h
+++ b/libs/binder/include/binder/RpcSession.h
@@ -281,13 +281,13 @@
 
     const std::unique_ptr<RpcTransportCtx> mCtx;
 
-    // On the other side of a session, for each of mOutgoingConnections here, there should
-    // be one of mIncomingConnections on the other side (and vice versa).
+    // On the other side of a session, for each of mOutgoing here, there should
+    // be one of mIncoming 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 'mIncomingConnections' and a thread listening on this
-    //  - the client has a single 'mOutgoingConnections' and makes calls to this
+    //  - the server has a single 'mIncoming' and a thread listening on this
+    //  - the client has a single 'mOutgoing' 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.
@@ -315,12 +315,12 @@
     struct ThreadState {
         size_t mWaitingThreads = 0;
         // hint index into clients, ++ when sending an async transaction
-        size_t mOutgoingConnectionsOffset = 0;
-        std::vector<sp<RpcConnection>> mOutgoingConnections;
-        size_t mMaxIncomingConnections = 0;
-        std::vector<sp<RpcConnection>> mIncomingConnections;
+        size_t mOutgoingOffset = 0;
+        std::vector<sp<RpcConnection>> mOutgoing;
+        size_t mMaxIncoming = 0;
+        std::vector<sp<RpcConnection>> mIncoming;
         std::map<std::thread::id, std::thread> mThreads;
-    } mThreadState;
+    } mConnections;
 };
 
 } // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 680f0ed..86da588 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -87,6 +87,7 @@
     srcs: ["binderParcelUnitTest.cpp", "binderBinderUnitTest.cpp"],
     shared_libs: [
         "libbinder",
+        "libcutils",
         "libutils",
     ],
     test_suites: ["general-tests"],
diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp
index 841d47b..4950b23 100644
--- a/libs/binder/tests/binderParcelUnitTest.cpp
+++ b/libs/binder/tests/binderParcelUnitTest.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <binder/Parcel.h>
 #include <binder/IPCThreadState.h>
+#include <binder/Parcel.h>
+#include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 
 using android::IPCThreadState;
@@ -146,3 +147,18 @@
 TEST_READ_WRITE_INVERSE(int8_t, Byte, {-1, 0, 1});
 TEST_READ_WRITE_INVERSE(String8, String8, {String8(), String8("a"), String8("asdf")});
 TEST_READ_WRITE_INVERSE(String16, String16, {String16(), String16("a"), String16("asdf")});
+
+TEST(Parcel, GetOpenAshmemSize) {
+    constexpr size_t kSize = 1024;
+    constexpr size_t kCount = 3;
+
+    Parcel p;
+
+    for (size_t i = 0; i < kCount; i++) {
+        int fd = ashmem_create_region("test-getOpenAshmemSize", kSize);
+        ASSERT_GE(fd, 0);
+        ASSERT_EQ(OK, p.writeFileDescriptor(fd, true /* take ownership */));
+
+        ASSERT_EQ((kSize * (i + 1)), p.getOpenAshmemSize());
+    }
+}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 2b17616..36de581 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -162,6 +162,7 @@
 
     ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
     mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
+    mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers;
 
     mTransformHint = mSurfaceControl->getTransformHint();
     mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -325,31 +326,23 @@
 // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
 // Otherwise, this is a no-op.
 static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
-                                       const sp<Fence>& releaseFence, uint32_t transformHint,
-                                       uint32_t currentMaxAcquiredBufferCount) {
+                                       const sp<Fence>& releaseFence,
+                                       std::optional<uint32_t> currentMaxAcquiredBufferCount) {
     sp<BLASTBufferQueue> blastBufferQueue = context.promote();
     if (blastBufferQueue) {
-        blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint,
-                                                currentMaxAcquiredBufferCount);
+        blastBufferQueue->releaseBufferCallback(id, releaseFence, currentMaxAcquiredBufferCount);
     } else {
         ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
     }
 }
 
-void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
-                                             const sp<Fence>& releaseFence, uint32_t transformHint,
-                                             uint32_t currentMaxAcquiredBufferCount) {
+void BLASTBufferQueue::releaseBufferCallback(
+        const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
+        std::optional<uint32_t> currentMaxAcquiredBufferCount) {
     ATRACE_CALL();
     std::unique_lock _lock{mMutex};
     BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
 
-    if (mSurfaceControl != nullptr) {
-        mTransformHint = transformHint;
-        mSurfaceControl->setTransformHint(transformHint);
-        mBufferItemConsumer->setTransformHint(mTransformHint);
-        BQA_LOGV("updated mTransformHint=%d", mTransformHint);
-    }
-
     // Calculate how many buffers we need to hold before we release them back
     // to the buffer queue. This will prevent higher latency when we are running
     // on a lower refresh rate than the max supported. We only do that for EGL
@@ -359,8 +352,12 @@
         return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
     }();
 
+    if (currentMaxAcquiredBufferCount) {
+        mCurrentMaxAcquiredBufferCount = *currentMaxAcquiredBufferCount;
+    }
+
     const auto numPendingBuffersToHold =
-            isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
+            isEGL ? std::max(0u, mMaxAcquiredBuffers - mCurrentMaxAcquiredBufferCount) : 0;
     mPendingRelease.emplace_back(ReleasedBuffer{id, releaseFence});
 
     // Release all buffers that are beyond the ones that we need to hold
@@ -374,7 +371,7 @@
             return;
         }
         mNumAcquired--;
-        BQA_LOGV("released %s", id.to_string().c_str());
+        BQA_LOGV("released %s", releaseBuffer.callbackId.to_string().c_str());
         mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
         mSubmitted.erase(it);
         processNextBufferLocked(false /* useNextTransaction */);
@@ -466,8 +463,7 @@
 
     auto releaseBufferCallback =
             std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
-                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
-                      std::placeholders::_4);
+                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
     sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
     t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, releaseCallbackId,
                  releaseBufferCallback);
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 98e8b54..aa7ebc9 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -254,11 +254,10 @@
     }
 
     void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
-                         uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount) override {
+                         uint32_t currentMaxAcquiredBufferCount) override {
         callRemoteAsync<decltype(
                 &ITransactionCompletedListener::onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER,
                                                                   callbackId, releaseFence,
-                                                                  transformHint,
                                                                   currentMaxAcquiredBufferCount);
     }
 };
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index aca59b6..2713be0 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -214,12 +214,6 @@
     mReleaseBufferCallbacks[callbackId] = listener;
 }
 
-void TransactionCompletedListener::removeReleaseBufferCallback(
-        const ReleaseCallbackId& callbackId) {
-    std::scoped_lock<std::mutex> lock(mMutex);
-    mReleaseBufferCallbacks.erase(callbackId);
-}
-
 void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie,
         sp<SurfaceControl> surfaceControl, SurfaceStatsCallback listener) {
     std::scoped_lock<std::recursive_mutex> lock(mSurfaceStatsListenerMutex);
@@ -343,7 +337,6 @@
                                  surfaceStats.previousReleaseFence
                                          ? surfaceStats.previousReleaseFence
                                          : Fence::NO_FENCE,
-                                 surfaceStats.transformHint,
                                  surfaceStats.currentMaxAcquiredBufferCount);
                     }
                 }
@@ -389,7 +382,7 @@
 }
 
 void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
-                                                   sp<Fence> releaseFence, uint32_t transformHint,
+                                                   sp<Fence> releaseFence,
                                                    uint32_t currentMaxAcquiredBufferCount) {
     ReleaseBufferCallback callback;
     {
@@ -401,7 +394,11 @@
               callbackId.to_string().c_str());
         return;
     }
-    callback(callbackId, releaseFence, transformHint, currentMaxAcquiredBufferCount);
+    std::optional<uint32_t> optionalMaxAcquiredBufferCount =
+            currentMaxAcquiredBufferCount == UINT_MAX
+            ? std::nullopt
+            : std::make_optional<uint32_t>(currentMaxAcquiredBufferCount);
+    callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount);
 }
 
 ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
@@ -712,11 +709,34 @@
     return NO_ERROR;
 }
 
+void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) {
+    if (!(state.what & layer_state_t::eBufferChanged)) {
+        return;
+    }
+
+    auto listener = state.bufferData.releaseBufferListener;
+    sp<Fence> fence =
+            state.bufferData.acquireFence ? state.bufferData.acquireFence : Fence::NO_FENCE;
+    if (state.bufferData.releaseBufferEndpoint ==
+        IInterface::asBinder(TransactionCompletedListener::getIInstance())) {
+        // if the callback is in process, run on a different thread to avoid any lock contigency
+        // issues in the client.
+        SurfaceComposerClient::getDefault()
+                ->mReleaseCallbackThread.addReleaseCallback(state.bufferData.releaseCallbackId,
+                                                            fence);
+    } else {
+        listener->onReleaseBuffer(state.bufferData.releaseCallbackId, fence, UINT_MAX);
+    }
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
     for (auto const& [handle, composerState] : other.mComposerStates) {
         if (mComposerStates.count(handle) == 0) {
             mComposerStates[handle] = composerState;
         } else {
+            if (composerState.state.what & layer_state_t::eBufferChanged) {
+                releaseBufferIfOverwriting(mComposerStates[handle].state);
+            }
             mComposerStates[handle].state.merge(composerState.state);
         }
     }
@@ -1296,7 +1316,9 @@
         mStatus = BAD_INDEX;
         return *this;
     }
-    removeReleaseBufferCallback(s);
+
+    releaseBufferIfOverwriting(*s);
+
     BufferData bufferData;
     bufferData.buffer = buffer;
     if (frameNumber) {
@@ -1321,15 +1343,6 @@
     return *this;
 }
 
-void SurfaceComposerClient::Transaction::removeReleaseBufferCallback(layer_state_t* s) {
-    if (!(s->what & layer_state_t::eBufferChanged)) {
-        return;
-    }
-
-    auto listener = TransactionCompletedListener::getInstance();
-    listener->removeReleaseBufferCallback(s->bufferData.releaseCallbackId);
-}
-
 void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData,
                                                                   const ReleaseCallbackId& id,
                                                                   ReleaseBufferCallback callback) {
@@ -2210,4 +2223,43 @@
     return s->captureLayers(captureArgs, captureListener);
 }
 
+// ---------------------------------------------------------------------------------
+
+void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId,
+                                               sp<Fence> releaseFence) {
+    std::scoped_lock<std::mutex> lock(mMutex);
+    if (!mStarted) {
+        mThread = std::thread(&ReleaseCallbackThread::threadMain, this);
+        mStarted = true;
+    }
+
+    mCallbackInfos.emplace(callbackId, std::move(releaseFence));
+    mReleaseCallbackPending.notify_one();
+}
+
+void ReleaseCallbackThread::threadMain() {
+    const auto listener = TransactionCompletedListener::getInstance();
+    std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> callbackInfos;
+    while (true) {
+        {
+            std::unique_lock<std::mutex> lock(mMutex);
+            callbackInfos = std::move(mCallbackInfos);
+            mCallbackInfos = {};
+        }
+
+        while (!callbackInfos.empty()) {
+            auto [callbackId, releaseFence] = callbackInfos.front();
+            listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX);
+            callbackInfos.pop();
+        }
+
+        {
+            std::unique_lock<std::mutex> lock(mMutex);
+            if (mCallbackInfos.size() == 0) {
+                mReleaseCallbackPending.wait(lock);
+            }
+        }
+    }
+}
+
 } // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 1f517f6..49ece6e 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -91,7 +91,7 @@
     void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
             const std::vector<SurfaceControlStats>& stats);
     void releaseBufferCallback(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
-                               uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount);
+                               std::optional<uint32_t> currentMaxAcquiredBufferCount);
     void setNextTransaction(SurfaceComposerClient::Transaction *t);
     void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
     void applyPendingTransactions(uint64_t frameNumber);
@@ -236,6 +236,8 @@
     // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
     // callback for them.
     std::queue<sp<SurfaceControl>> mSurfaceControlsWithPendingCallback GUARDED_BY(mMutex);
+
+    uint32_t mCurrentMaxAcquiredBufferCount;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 937095c..0df5822 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -192,7 +192,6 @@
     virtual void onTransactionCompleted(ListenerStats stats) = 0;
 
     virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
-                                 uint32_t transformHint,
                                  uint32_t currentMaxAcquiredBufferCount) = 0;
 };
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 82249a3..e62c76e 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -19,6 +19,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <set>
+#include <thread>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -84,7 +85,7 @@
                            const std::vector<SurfaceControlStats>& /*stats*/)>;
 using ReleaseBufferCallback =
         std::function<void(const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/,
-                           uint32_t transformHint, uint32_t currentMaxAcquiredBufferCount)>;
+                           std::optional<uint32_t> currentMaxAcquiredBufferCount)>;
 
 using SurfaceStatsCallback =
         std::function<void(void* /*context*/, nsecs_t /*latchTime*/,
@@ -93,6 +94,22 @@
 
 // ---------------------------------------------------------------------------
 
+class ReleaseCallbackThread {
+public:
+    void addReleaseCallback(const ReleaseCallbackId, sp<Fence>);
+    void threadMain();
+
+private:
+    std::thread mThread;
+    std::mutex mMutex;
+    bool mStarted GUARDED_BY(mMutex) = false;
+    std::condition_variable mReleaseCallbackPending;
+    std::queue<std::tuple<const ReleaseCallbackId, const sp<Fence>>> mCallbackInfos
+            GUARDED_BY(mMutex);
+};
+
+// ---------------------------------------------------------------------------
+
 class SurfaceComposerClient : public RefBase
 {
     friend class Composer;
@@ -350,6 +367,7 @@
     private:
         static std::atomic<uint32_t> idCounter;
         int64_t generateId();
+        void releaseBufferIfOverwriting(const layer_state_t& state);
 
     protected:
         std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
@@ -400,7 +418,6 @@
         void cacheBuffers();
         void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc);
         void setReleaseBufferCallback(BufferData*, const ReleaseCallbackId&, ReleaseBufferCallback);
-        void removeReleaseBufferCallback(layer_state_t*);
 
     public:
         Transaction();
@@ -625,6 +642,9 @@
     status_t addWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
     status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener);
 
+protected:
+    ReleaseCallbackThread mReleaseCallbackThread;
+
 private:
     virtual void onFirstRef();
 
@@ -725,11 +745,10 @@
     void removeSurfaceStatsListener(void* context, void* cookie);
 
     void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback);
-    void removeReleaseBufferCallback(const ReleaseCallbackId&);
 
     // BnTransactionCompletedListener overrides
     void onTransactionCompleted(ListenerStats stats) override;
-    void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
+    void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
                          uint32_t currentMaxAcquiredBufferCount) override;
 
     // For Testing Only
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 75f2385..2db9992 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -133,12 +133,41 @@
 
 int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpace) {
     static_assert(static_cast<int>(ADATASPACE_UNKNOWN) == static_cast<int>(HAL_DATASPACE_UNKNOWN));
-    static_assert(static_cast<int>(ADATASPACE_SCRGB_LINEAR) == static_cast<int>(HAL_DATASPACE_V0_SCRGB_LINEAR));
+    static_assert(static_cast<int>(STANDARD_SHIFT) == static_cast<int>(HAL_DATASPACE_STANDARD_SHIFT));
+    static_assert(static_cast<int>(STANDARD_MASK) == static_cast<int>(HAL_DATASPACE_STANDARD_MASK));
+    static_assert(static_cast<int>(STANDARD_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_STANDARD_UNSPECIFIED));
+    static_assert(static_cast<int>(STANDARD_BT709) == static_cast<int>(HAL_DATASPACE_STANDARD_BT709));
+    static_assert(static_cast<int>(STANDARD_BT601_625) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625));
+    static_assert(static_cast<int>(STANDARD_BT601_625_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_625_UNADJUSTED));
+    static_assert(static_cast<int>(STANDARD_BT601_525) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525));
+    static_assert(static_cast<int>(STANDARD_BT601_525_UNADJUSTED) == static_cast<int>(HAL_DATASPACE_STANDARD_BT601_525_UNADJUSTED));
+    static_assert(static_cast<int>(STANDARD_BT470M) == static_cast<int>(HAL_DATASPACE_STANDARD_BT470M));
+    static_assert(static_cast<int>(STANDARD_FILM) == static_cast<int>(HAL_DATASPACE_STANDARD_FILM));
+    static_assert(static_cast<int>(STANDARD_DCI_P3) == static_cast<int>(HAL_DATASPACE_STANDARD_DCI_P3));
+    static_assert(static_cast<int>(STANDARD_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_STANDARD_ADOBE_RGB));
+    static_assert(static_cast<int>(TRANSFER_SHIFT) == static_cast<int>(HAL_DATASPACE_TRANSFER_SHIFT));
+    static_assert(static_cast<int>(TRANSFER_MASK) == static_cast<int>(HAL_DATASPACE_TRANSFER_MASK));
+    static_assert(static_cast<int>(TRANSFER_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_TRANSFER_UNSPECIFIED));
+    static_assert(static_cast<int>(TRANSFER_LINEAR) == static_cast<int>(HAL_DATASPACE_TRANSFER_LINEAR));
+    static_assert(static_cast<int>(TRANSFER_SMPTE_170M) == static_cast<int>(HAL_DATASPACE_TRANSFER_SMPTE_170M));
+    static_assert(static_cast<int>(TRANSFER_GAMMA2_2) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_2));
+    static_assert(static_cast<int>(TRANSFER_GAMMA2_6) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_6));
+    static_assert(static_cast<int>(TRANSFER_GAMMA2_8) == static_cast<int>(HAL_DATASPACE_TRANSFER_GAMMA2_8));
+    static_assert(static_cast<int>(TRANSFER_ST2084) == static_cast<int>(HAL_DATASPACE_TRANSFER_ST2084));
+    static_assert(static_cast<int>(TRANSFER_HLG) == static_cast<int>(HAL_DATASPACE_TRANSFER_HLG));
+    static_assert(static_cast<int>(RANGE_MASK) == static_cast<int>(HAL_DATASPACE_RANGE_MASK));
+    static_assert(static_cast<int>(RANGE_UNSPECIFIED) == static_cast<int>(HAL_DATASPACE_RANGE_UNSPECIFIED));
+    static_assert(static_cast<int>(RANGE_FULL) == static_cast<int>(HAL_DATASPACE_RANGE_FULL));
+    static_assert(static_cast<int>(RANGE_LIMITED) == static_cast<int>(HAL_DATASPACE_RANGE_LIMITED));
+    static_assert(static_cast<int>(RANGE_EXTENDED) == static_cast<int>(HAL_DATASPACE_RANGE_EXTENDED));
     static_assert(static_cast<int>(ADATASPACE_SRGB) == static_cast<int>(HAL_DATASPACE_V0_SRGB));
     static_assert(static_cast<int>(ADATASPACE_SCRGB) == static_cast<int>(HAL_DATASPACE_V0_SCRGB));
     static_assert(static_cast<int>(ADATASPACE_DISPLAY_P3) == static_cast<int>(HAL_DATASPACE_DISPLAY_P3));
     static_assert(static_cast<int>(ADATASPACE_BT2020_PQ) == static_cast<int>(HAL_DATASPACE_BT2020_PQ));
     static_assert(static_cast<int>(ADATASPACE_ADOBE_RGB) == static_cast<int>(HAL_DATASPACE_ADOBE_RGB));
+    static_assert(static_cast<int>(ADATASPACE_JFIF) == static_cast<int>(HAL_DATASPACE_V0_JFIF));
+    static_assert(static_cast<int>(ADATASPACE_BT601_625) == static_cast<int>(HAL_DATASPACE_V0_BT601_625));
+    static_assert(static_cast<int>(ADATASPACE_BT601_525) == static_cast<int>(HAL_DATASPACE_V0_BT601_525));
     static_assert(static_cast<int>(ADATASPACE_BT2020) == static_cast<int>(HAL_DATASPACE_BT2020));
     static_assert(static_cast<int>(ADATASPACE_BT709) == static_cast<int>(HAL_DATASPACE_V0_BT709));
     static_assert(static_cast<int>(ADATASPACE_DCI_P3) == static_cast<int>(HAL_DATASPACE_DCI_P3));
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index e759513..612fb39 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -43,6 +43,346 @@
     ADATASPACE_UNKNOWN = 0,
 
     /**
+     * Color-description aspects
+     *
+     * The following aspects define various characteristics of the color
+     * specification. These represent bitfields, so that a data space value
+     * can specify each of them independently.
+     */
+
+    /**
+     * Standard aspect
+     *
+     * Defines the chromaticity coordinates of the source primaries in terms of
+     * the CIE 1931 definition of x and y specified in ISO 11664-1.
+     */
+    STANDARD_SHIFT = 16,
+
+    STANDARD_MASK = 63 << 16, // 63 << STANDARD_SHIFT = 0x3F
+
+    /**
+     * Chromacity coordinates are unknown or are determined by the application.
+     * Implementations shall use the following suggested standards:
+     *
+     * All YCbCr formats: BT709 if size is 720p or larger (since most video
+     *                    content is letterboxed this corresponds to width is
+     *                    1280 or greater, or height is 720 or greater).
+     *                    BT601_625 if size is smaller than 720p or is JPEG.
+     * All RGB formats:   BT709.
+     *
+     * For all other formats standard is undefined, and implementations should use
+     * an appropriate standard for the data represented.
+     */
+    STANDARD_UNSPECIFIED = 0 << 16, // STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.300   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT709 = 1 << 16, // 1 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_625 = 2 << 16, // 2 << STANDARD_SHIFT,
+
+    /**
+     * Primaries:       x       y
+     *  green           0.290   0.600
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT601_625_UNADJUSTED = 3 << 16, // 3 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
+     *  for RGB conversion from the one purely determined by the primaries
+     *  to minimize the color shift into RGB space that uses BT.709
+     *  primaries.
+     */
+    STANDARD_BT601_525 = 4 << 16, // 4 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.310   0.595
+     *  blue            0.155   0.070
+     *  red             0.630   0.340
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
+     * for RGB conversion (as in SMPTE 240M).
+     */
+    STANDARD_BT601_525_UNADJUSTED = 5 << 16, // 5 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT2020 = 6 << 16, // 6 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.170   0.797
+     *  blue            0.131   0.046
+     *  red             0.708   0.292
+     *  white (D65)     0.3127  0.3290
+     *
+     * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
+     * for RGB conversion using the linear domain.
+     */
+    STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16, // 7 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x      y
+     *  green           0.21   0.71
+     *  blue            0.14   0.08
+     *  red             0.67   0.33
+     *  white (C)       0.310  0.316
+     *
+     * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_BT470M = 8 << 16, // 8 << STANDARD_SHIFT
+
+    /**
+     * Primaries:       x       y
+     *  green           0.243   0.692
+     *  blue            0.145   0.049
+     *  red             0.681   0.319
+     *  white (C)       0.310   0.316
+     *
+     * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
+     * for RGB conversion.
+     */
+    STANDARD_FILM = 9 << 16, // 9 << STANDARD_SHIFT
+
+    /**
+     * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+     * Primaries:       x       y
+     *  green           0.265   0.690
+     *  blue            0.150   0.060
+     *  red             0.680   0.320
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_DCI_P3 = 10 << 16, // 10 << STANDARD_SHIFT
+
+    /**
+     * Adobe RGB
+     * Primaries:       x       y
+     *  green           0.210   0.710
+     *  blue            0.150   0.060
+     *  red             0.640   0.330
+     *  white (D65)     0.3127  0.3290
+     */
+    STANDARD_ADOBE_RGB = 11 << 16, // 11 << STANDARD_SHIFT
+
+    /**
+     * Transfer aspect
+     *
+     * Transfer characteristics are the opto-electronic transfer characteristic
+     * at the source as a function of linear optical intensity (luminance).
+     *
+     * For digital signals, E corresponds to the recorded value. Normally, the
+     * transfer function is applied in RGB space to each of the R, G and B
+     * components independently. This may result in color shift that can be
+     * minized by applying the transfer function in Lab space only for the L
+     * component. Implementation may apply the transfer function in RGB space
+     * for all pixel formats if desired.
+     */
+    TRANSFER_SHIFT = 22,
+
+    TRANSFER_MASK = 31 << 22, // 31 << TRANSFER_SHIFT = 0x1F
+
+    /**
+     * Transfer characteristics are unknown or are determined by the
+     * application.
+     *
+     * Implementations should use the following transfer functions:
+     *
+     * For YCbCr formats: use TRANSFER_SMPTE_170M
+     * For RGB formats: use TRANSFER_SRGB
+     *
+     * For all other formats transfer function is undefined, and implementations
+     * should use an appropriate standard for the data represented.
+     */
+    TRANSFER_UNSPECIFIED = 0 << 22, // 0 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *  E = L
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_LINEAR = 1 << 22, // 1 << TRANSFER_SHIFT
+
+    /**
+     * Transfer characteristic curve:
+     *
+     * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
+     *   = 12.92 * L                  for 0 <= L < 0.0031308
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal
+     */
+    TRANSFER_SRGB = 2 << 22, // 2 << TRANSFER_SHIFT
+
+    /**
+     * BT.601 525, BT.601 625, BT.709, BT.2020
+     *
+     * Transfer characteristic curve:
+     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
+     *    = 4.500 * L                 for 0 <= L < 0.018
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_SMPTE_170M = 3 << 22, // 3 << TRANSFER_SHIFT
+
+    /**
+     * Assumed display gamma 2.2.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.2)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_2 = 4 << 22, // 4 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.6.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.6)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_6 = 5 << 22, // 5 << TRANSFER_SHIFT
+
+    /**
+     *  display gamma 2.8.
+     *
+     * Transfer characteristic curve:
+     *  E = L ^ (1/2.8)
+     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_GAMMA2_8 = 6 << 22, // 6 << TRANSFER_SHIFT
+
+    /**
+     * SMPTE ST 2084 (Dolby Perceptual Quantizer)
+     *
+     * Transfer characteristic curve:
+     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+     *  c2 = 32 * 2413 / 4096 = 18.8515625
+     *  c3 = 32 * 2392 / 4096 = 18.6875
+     *  m = 128 * 2523 / 4096 = 78.84375
+     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
+     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+     *          L = 1 corresponds to 10000 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_ST2084 = 7 << 22, // 7 << TRANSFER_SHIFT
+
+    /**
+     * ARIB STD-B67 Hybrid Log Gamma
+     *
+     * Transfer characteristic curve:
+     *  E = r * L^0.5                 for 0 <= L <= 1
+     *    = a * ln(L - b) + c         for 1 < L
+     *  a = 0.17883277
+     *  b = 0.28466892
+     *  c = 0.55991073
+     *  r = 0.5
+     *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
+     *          to reference white level of 100 cd/m2
+     *      E - corresponding electrical signal
+     */
+    TRANSFER_HLG = 8 << 22, // 8 << TRANSFER_SHIFT
+
+    /**
+     * Range aspect
+     *
+     * Defines the range of values corresponding to the unit range of 0-1.
+     * This is defined for YCbCr only, but can be expanded to RGB space.
+     */
+    RANGE_SHIFT = 27,
+
+    RANGE_MASK = 7 << 27, // 7 << RANGE_SHIFT = 0x7
+
+    /**
+     * Range is unknown or are determined by the application.  Implementations
+     * shall use the following suggested ranges:
+     *
+     * All YCbCr formats: limited range.
+     * All RGB or RGBA formats (including RAW and Bayer): full range.
+     * All Y formats: full range
+     *
+     * For all other formats range is undefined, and implementations should use
+     * an appropriate range for the data represented.
+     */
+    RANGE_UNSPECIFIED = 0 << 27, // 0 << RANGE_SHIFT = 0x0
+
+    /**
+     * Full range uses all values for Y, Cb and Cr from
+     * 0 to 2^b-1, where b is the bit depth of the color format.
+     */
+    RANGE_FULL = 1 << 27, // 1 << RANGE_SHIFT = 0x8000000
+
+    /**
+     * Limited range uses values 16/256*2^b to 235/256*2^b for Y, and
+     * 1/16*2^b to 15/16*2^b for Cb, Cr, R, G and B, where b is the bit depth of
+     * the color format.
+     *
+     * E.g. For 8-bit-depth formats:
+     * Luma (Y) samples should range from 16 to 235, inclusive
+     * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
+     *
+     * For 10-bit-depth formats:
+     * Luma (Y) samples should range from 64 to 940, inclusive
+     * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
+     */
+    RANGE_LIMITED = 2 << 27, // 2 << RANGE_SHIFT = 0x10000000
+
+    /**
+     * Extended range is used for scRGB. Intended for use with
+     * floating point pixel formats. [0.0 - 1.0] is the standard
+     * sRGB space. Values outside the range 0.0 - 1.0 can encode
+     * color outside the sRGB gamut.
+     * Used to blend / merge multiple dataspaces on a single display.
+     */
+    RANGE_EXTENDED = 3 << 27, // 3 << RANGE_SHIFT = 0x18000000
+
+    /**
      * scRGB linear encoding:
      *
      * The red, green, and blue components are stored in extended sRGB space,
@@ -112,6 +452,33 @@
     ADATASPACE_ADOBE_RGB = 151715840, // STANDARD_ADOBE_RGB | TRANSFER_GAMMA2_2 | RANGE_FULL
 
     /**
+     * JPEG File Interchange Format (JFIF)
+     *
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     *
+     * Use full range, SMPTE 170M transfer and BT.601_625 standard.
+     */
+    ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
+
+    /**
+     * ITU-R Recommendation 601 (BT.601) - 525-line
+     *
+     * Standard-definition television, 525 Lines (NTSC)
+     *
+     * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+     */
+    ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+    /**
+     * ITU-R Recommendation 709 (BT.709)
+     *
+     * High-definition television
+     *
+     * Use limited range, SMPTE 170M transfer and BT.709 standard.
+     */
+    ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
+
+    /**
      * ITU-R Recommendation 2020 (BT.2020)
      *
      * Ultra High-definition television
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1baa100..25b3005 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -88,6 +88,9 @@
 // Log debug messages about input focus tracking.
 constexpr bool DEBUG_FOCUS = false;
 
+// Log debug messages about touch mode event
+constexpr bool DEBUG_TOUCH_MODE = false;
+
 // Log debug messages about touch occlusion
 // STOPSHIP(b/169067926): Set to false
 constexpr bool DEBUG_TOUCH_OCCLUSION = true;
@@ -534,6 +537,23 @@
     return transformedXy - transformedOrigin;
 }
 
+// Returns true if the event type passed as argument represents a user activity.
+bool isUserActivityEvent(const EventEntry& eventEntry) {
+    switch (eventEntry.type) {
+        case EventEntry::Type::FOCUS:
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED:
+        case EventEntry::Type::DRAG:
+        case EventEntry::Type::TOUCH_MODE_CHANGED:
+        case EventEntry::Type::SENSOR:
+        case EventEntry::Type::CONFIGURATION_CHANGED:
+            return false;
+        case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::KEY:
+        case EventEntry::Type::MOTION:
+            return true;
+    }
+}
+
 } // namespace
 
 // --- InputDispatcher ---
@@ -552,7 +572,7 @@
         // mInTouchMode will be initialized by the WindowManager to the default device config.
         // To avoid leaking stack in case that call never comes, and for tests,
         // initialize it here anyways.
-        mInTouchMode(true),
+        mInTouchMode(kDefaultInTouchMode),
         mMaximumObscuringOpacityForTouch(1.0f),
         mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
         mWindowTokenWithPointerCapture(nullptr),
@@ -1789,9 +1809,9 @@
             displayId = motionEntry.displayId;
             break;
         }
+        case EventEntry::Type::TOUCH_MODE_CHANGED:
         case EventEntry::Type::POINTER_CAPTURE_CHANGED:
         case EventEntry::Type::FOCUS:
-        case EventEntry::Type::TOUCH_MODE_CHANGED:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET:
         case EventEntry::Type::SENSOR:
@@ -2541,24 +2561,9 @@
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
     ui::Transform t;
     if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
-        // Input monitors always get un-rotated display coordinates. We undo the display
-        // rotation that is present in the display transform so that display rotation is not
-        // applied to these input targets.
-        const auto& displayInfo = it->second;
-        int32_t width = displayInfo.logicalWidth;
-        int32_t height = displayInfo.logicalHeight;
-        const auto orientation = displayInfo.transform.getOrientation();
-        uint32_t inverseOrientation = orientation;
-        if (orientation == ui::Transform::ROT_90) {
-            inverseOrientation = ui::Transform::ROT_270;
-            std::swap(width, height);
-        } else if (orientation == ui::Transform::ROT_270) {
-            inverseOrientation = ui::Transform::ROT_90;
-            std::swap(width, height);
-        }
-        target.displayTransform =
-                ui::Transform(inverseOrientation, width, height) * displayInfo.transform;
-        t = t * target.displayTransform;
+        const auto& displayTransform = it->second.transform;
+        target.displayTransform = displayTransform;
+        t = displayTransform;
     }
     target.setDefaultPointerTransform(t);
     inputTargets.push_back(target);
@@ -2772,11 +2777,8 @@
 }
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
-    if (eventEntry.type == EventEntry::Type::FOCUS ||
-        eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED ||
-        eventEntry.type == EventEntry::Type::DRAG) {
-        // Focus or pointer capture changed events are passed to apps, but do not represent user
-        // activity.
+    if (!isUserActivityEvent(eventEntry)) {
+        // Not poking user activity if the event type does not represent a user activity
         return;
     }
     int32_t displayId = getTargetDisplayId(eventEntry);
@@ -2812,16 +2814,7 @@
             eventType = USER_ACTIVITY_EVENT_BUTTON;
             break;
         }
-        case EventEntry::Type::TOUCH_MODE_CHANGED: {
-            break;
-        }
-
-        case EventEntry::Type::FOCUS:
-        case EventEntry::Type::CONFIGURATION_CHANGED:
-        case EventEntry::Type::DEVICE_RESET:
-        case EventEntry::Type::SENSOR:
-        case EventEntry::Type::POINTER_CAPTURE_CHANGED:
-        case EventEntry::Type::DRAG: {
+        default: {
             LOG_ALWAYS_FATAL("%s events are not user activity",
                              ftl::enum_string(eventEntry.type).c_str());
             break;
@@ -3796,7 +3789,7 @@
         ALOGD("notifyConfigurationChanged - eventTime=%" PRId64, args->eventTime);
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         std::scoped_lock _l(mLock);
 
@@ -3891,7 +3884,7 @@
               std::to_string(t.duration().count()).c_str());
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         mLock.lock();
 
@@ -3968,7 +3961,7 @@
               std::to_string(t.duration().count()).c_str());
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         mLock.lock();
 
@@ -4033,7 +4026,7 @@
               ftl::enum_string(args->sensorType).c_str());
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         mLock.lock();
 
@@ -4083,7 +4076,7 @@
               args->deviceId);
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         std::scoped_lock _l(mLock);
 
@@ -4103,7 +4096,7 @@
               args->request.enable ? "true" : "false");
     }
 
-    bool needWake;
+    bool needWake = false;
     { // acquire lock
         std::scoped_lock _l(mLock);
         auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime,
@@ -4924,9 +4917,29 @@
 }
 
 void InputDispatcher::setInTouchMode(bool inTouchMode) {
-    std::scoped_lock lock(mLock);
-    mInTouchMode = inTouchMode;
-    // TODO(b/193718270): Fire TouchModeEvent here.
+    bool needWake = false;
+    {
+        std::scoped_lock lock(mLock);
+        if (mInTouchMode == inTouchMode) {
+            return;
+        }
+        if (DEBUG_TOUCH_MODE) {
+            ALOGD("Request to change touch mode from %s to %s", toString(mInTouchMode),
+                  toString(inTouchMode));
+            // TODO(b/198487159): Also print the current last interacted apps.
+        }
+
+        // TODO(b/198499018): Store touch mode per display.
+        mInTouchMode = inTouchMode;
+
+        // TODO(b/198487159): Enforce that only last interacted apps can change touch mode.
+        auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode);
+        needWake = enqueueInboundEventLocked(std::move(entry));
+    } // release lock
+
+    if (needWake) {
+        mLooper->wake();
+    }
 }
 
 void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 55ca6c9..8a551cf 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -82,6 +82,8 @@
  */
 class InputDispatcher : public android::InputDispatcherInterface {
 public:
+    static constexpr bool kDefaultInTouchMode = true;
+
     explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
     ~InputDispatcher() override;
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ca77d7a..1879cec 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -817,6 +817,9 @@
             case AINPUT_EVENT_TYPE_CAPTURE: {
                 FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
             }
+            case AINPUT_EVENT_TYPE_TOUCH_MODE: {
+                FAIL() << "Use 'consumeTouchModeEvent' for TOUCH_MODE events";
+            }
             case AINPUT_EVENT_TYPE_DRAG: {
                 FAIL() << "Use 'consumeDragEvent' for DRAG events";
             }
@@ -874,6 +877,20 @@
         EXPECT_EQ(y, dragEvent.getY());
     }
 
+    void consumeTouchModeEvent(bool inTouchMode) {
+        const InputEvent* event = consume();
+        ASSERT_NE(nullptr, event) << mName.c_str()
+                                  << ": consumer should have returned non-NULL event.";
+        ASSERT_EQ(AINPUT_EVENT_TYPE_TOUCH_MODE, event->getType())
+                << "Got " << inputEventTypeToString(event->getType())
+                << " event instead of TOUCH_MODE event";
+
+        ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+                << mName.c_str() << ": event displayId should always be NONE.";
+        const auto& touchModeEvent = static_cast<const TouchModeEvent&>(*event);
+        EXPECT_EQ(inTouchMode, touchModeEvent.isInTouchMode());
+    }
+
     void assertNoEvents() {
         InputEvent* event = consume();
         if (event == nullptr) {
@@ -895,6 +912,10 @@
             const auto& captureEvent = static_cast<CaptureEvent&>(*event);
             ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
                           << (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
+        } else if (event->getType() == AINPUT_EVENT_TYPE_TOUCH_MODE) {
+            const auto& touchModeEvent = static_cast<TouchModeEvent&>(*event);
+            ADD_FAILURE() << "Received touch mode event, inTouchMode = "
+                          << (touchModeEvent.isInTouchMode() ? "true" : "false");
         }
         FAIL() << mName.c_str()
                << ": should not have received any events, so consume() should return NULL";
@@ -976,14 +997,18 @@
 
     void setApplicationToken(sp<IBinder> token) { mInfo.applicationInfo.token = token; }
 
-    void setFrame(const Rect& frame) {
+    void setFrame(const Rect& frame, const ui::Transform& displayTransform = ui::Transform()) {
         mInfo.frameLeft = frame.left;
         mInfo.frameTop = frame.top;
         mInfo.frameRight = frame.right;
         mInfo.frameBottom = frame.bottom;
-        mInfo.transform.set(-frame.left, -frame.top);
         mInfo.touchableRegion.clear();
         mInfo.addTouchableRegion(frame);
+
+        const Rect logicalDisplayFrame = displayTransform.transform(frame);
+        ui::Transform translate;
+        translate.set(-logicalDisplayFrame.left, -logicalDisplayFrame.top);
+        mInfo.transform = translate * displayTransform;
     }
 
     void setType(WindowInfo::Type type) { mInfo.type = type; }
@@ -1087,6 +1112,12 @@
         mInputReceiver->consumeDragEvent(isExiting, x, y);
     }
 
+    void consumeTouchModeEvent(bool inTouchMode) {
+        ASSERT_NE(mInputReceiver, nullptr)
+                << "Cannot consume events from a window with no receiver";
+        mInputReceiver->consumeTouchModeEvent(inTouchMode);
+    }
+
     std::optional<uint32_t> receiveEvent(InputEvent** outEvent = nullptr) {
         if (mInputReceiver == nullptr) {
             ADD_FAILURE() << "Invalid receive event on window with no receiver";
@@ -1422,6 +1453,21 @@
     window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
 }
 
+TEST_F(InputDispatcherTest, WhenDisplayNotSpecified_InjectMotionToDefaultDisplay) {
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
+
+    mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+    // Inject a MotionEvent to an unknown display.
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_NONE))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    // Window should receive motion event.
+    window->consumeMotionDown(ADISPLAY_ID_DEFAULT);
+}
+
 /**
  * Calling setInputWindows once with FLAG_NOT_TOUCH_MODAL should not cause any issues.
  * To ensure that window receives only events that were directly inside of it, add
@@ -1945,6 +1991,119 @@
                          0 /*expectedFlags*/);
 }
 
+/**
+ * Ensure the correct coordinate spaces are used by InputDispatcher.
+ *
+ * InputDispatcher works in the display space, so its coordinate system is relative to the display
+ * panel. Windows get events in the window space, and get raw coordinates in the logical display
+ * space.
+ */
+class InputDispatcherDisplayProjectionTest : public InputDispatcherTest {
+public:
+    void SetUp() override {
+        InputDispatcherTest::SetUp();
+        mDisplayInfos.clear();
+        mWindowInfos.clear();
+    }
+
+    void addDisplayInfo(int displayId, const ui::Transform& transform) {
+        gui::DisplayInfo info;
+        info.displayId = displayId;
+        info.transform = transform;
+        mDisplayInfos.push_back(std::move(info));
+        mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
+    }
+
+    void addWindow(const sp<WindowInfoHandle>& windowHandle) {
+        mWindowInfos.push_back(*windowHandle->getInfo());
+        mDispatcher->onWindowInfosChanged(mWindowInfos, mDisplayInfos);
+    }
+
+    // Set up a test scenario where the display has a scaled projection and there are two windows
+    // on the display.
+    std::pair<sp<FakeWindowHandle>, sp<FakeWindowHandle>> setupScaledDisplayScenario() {
+        // The display has a projection that has a scale factor of 2 and 4 in the x and y directions
+        // respectively.
+        ui::Transform displayTransform;
+        displayTransform.set(2, 0, 0, 4);
+        addDisplayInfo(ADISPLAY_ID_DEFAULT, displayTransform);
+
+        std::shared_ptr<FakeApplicationHandle> application =
+                std::make_shared<FakeApplicationHandle>();
+
+        // Add two windows to the display. Their frames are represented in the display space.
+        sp<FakeWindowHandle> firstWindow =
+                new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+        firstWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+        firstWindow->setFrame(Rect(0, 0, 100, 200), displayTransform);
+        addWindow(firstWindow);
+
+        sp<FakeWindowHandle> secondWindow =
+                new FakeWindowHandle(application, mDispatcher, "Second Window",
+                                     ADISPLAY_ID_DEFAULT);
+        secondWindow->addFlags(WindowInfo::Flag::NOT_TOUCH_MODAL);
+        secondWindow->setFrame(Rect(100, 200, 200, 400), displayTransform);
+        addWindow(secondWindow);
+        return {std::move(firstWindow), std::move(secondWindow)};
+    }
+
+private:
+    std::vector<gui::DisplayInfo> mDisplayInfos;
+    std::vector<gui::WindowInfo> mWindowInfos;
+};
+
+TEST_F(InputDispatcherDisplayProjectionTest, HitTestsInDisplaySpace) {
+    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+    // Send down to the first window. The point is represented in the display space. The point is
+    // selected so that if the hit test was done with the transform applied to it, then it would
+    // end up in the incorrect window.
+    NotifyMotionArgs downMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {PointF{75, 55}});
+    mDispatcher->notifyMotion(&downMotionArgs);
+
+    firstWindow->consumeMotionDown();
+    secondWindow->assertNoEvents();
+}
+
+// Ensure that when a MotionEvent is injected through the InputDispatcher::injectInputEvent() API,
+// the event should be treated as being in the logical display space.
+TEST_F(InputDispatcherDisplayProjectionTest, InjectionInLogicalDisplaySpace) {
+    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+    // Send down to the first window. The point is represented in the logical display space. The
+    // point is selected so that if the hit test was done in logical display space, then it would
+    // end up in the incorrect window.
+    injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                     PointF{75 * 2, 55 * 4});
+
+    firstWindow->consumeMotionDown();
+    secondWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherDisplayProjectionTest, WindowGetsEventsInCorrectCoordinateSpace) {
+    auto [firstWindow, secondWindow] = setupScaledDisplayScenario();
+
+    // Send down to the second window.
+    NotifyMotionArgs downMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {PointF{150, 220}});
+    mDispatcher->notifyMotion(&downMotionArgs);
+
+    firstWindow->assertNoEvents();
+    const MotionEvent* event = secondWindow->consumeMotion();
+    EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, event->getAction());
+
+    // Ensure that the events from the "getRaw" API are in logical display coordinates.
+    EXPECT_EQ(300, event->getRawX(0));
+    EXPECT_EQ(880, event->getRawY(0));
+
+    // Ensure that the x and y values are in the window's coordinate space.
+    // The left-top of the second window is at (100, 200) in display space, which is (200, 800) in
+    // the logical display space. This will be the origin of the window space.
+    EXPECT_EQ(100, event->getX(0));
+    EXPECT_EQ(80, event->getY(0));
+}
+
 using TransferFunction = std::function<bool(const std::unique_ptr<InputDispatcher>& dispatcher,
                                             sp<IBinder>, sp<IBinder>)>;
 
@@ -2725,7 +2884,6 @@
     SCOPED_TRACE("Check default value of touch mode");
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     setFocusedWindow(window);
-
     window->consumeFocusEvent(true /*hasFocus*/, true /*inTouchMode*/);
 
     SCOPED_TRACE("Remove the window to trigger focus loss");
@@ -2735,6 +2893,7 @@
 
     SCOPED_TRACE("Disable touch mode");
     mDispatcher->setInTouchMode(false);
+    window->consumeTouchModeEvent(false);
     window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     setFocusedWindow(window);
@@ -2747,6 +2906,7 @@
 
     SCOPED_TRACE("Enable touch mode again");
     mDispatcher->setInTouchMode(true);
+    window->consumeTouchModeEvent(true);
     window->setFocusable(true);
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     setFocusedWindow(window);
@@ -5892,4 +6052,43 @@
     window->assertNoEvents();
 }
 
+class InputDispatcherTouchModeChangedTests : public InputDispatcherTest {
+protected:
+    std::shared_ptr<FakeApplicationHandle> mApp;
+    sp<FakeWindowHandle> mWindow;
+    sp<FakeWindowHandle> mSecondWindow;
+
+    void SetUp() override {
+        InputDispatcherTest::SetUp();
+
+        mApp = std::make_shared<FakeApplicationHandle>();
+        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow->setFocusable(true);
+        mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+        mSecondWindow->setFocusable(true);
+
+        mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
+        mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+
+        setFocusedWindow(mWindow);
+        mWindow->consumeFocusEvent(true);
+    }
+
+    void changeAndVerifyTouchMode(bool inTouchMode) {
+        mDispatcher->setInTouchMode(inTouchMode);
+        mWindow->consumeTouchModeEvent(inTouchMode);
+        mSecondWindow->consumeTouchModeEvent(inTouchMode);
+    }
+};
+
+TEST_F(InputDispatcherTouchModeChangedTests, ChangeTouchModeOnFocusedWindow) {
+    changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode);
+}
+
+TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) {
+    mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode);
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index ef05fe2..82c91e7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -223,7 +223,7 @@
          * of a camera where the buffer remains in native orientation,
          * we want the pixels to always be upright.
          */
-        sp<Layer> p = mDrawingParent.promote();
+        auto p = mDrawingParent;
         if (p != nullptr) {
             const auto parentTransform = p->getTransform();
             tr = tr * inverseOrientation(parentTransform.getOrientation());
@@ -346,13 +346,13 @@
 }
 } // namespace
 
-bool BufferLayer::onPostComposition(const DisplayDevice* display,
+void BufferLayer::onPostComposition(const DisplayDevice* display,
                                     const std::shared_ptr<FenceTime>& glDoneFence,
                                     const std::shared_ptr<FenceTime>& presentFence,
                                     const CompositorTiming& compositorTiming) {
     // mFrameLatencyNeeded is true when a new frame was latched for the
     // composition.
-    if (!mBufferInfo.mFrameLatencyNeeded) return false;
+    if (!mBufferInfo.mFrameLatencyNeeded) return;
 
     // Update mFrameEventHistory.
     {
@@ -426,7 +426,6 @@
 
     mFrameTracker.advanceFrame();
     mBufferInfo.mFrameLatencyNeeded = false;
-    return true;
 }
 
 void BufferLayer::gatherBufferInfo() {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 2da73f8..61e7ac5 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -77,7 +77,7 @@
 
     bool isHdrY410() const override;
 
-    bool onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
+    void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence,
                            const std::shared_ptr<FenceTime>& presentFence,
                            const CompositorTiming&) override;
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 96b2247..c79fa11 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -438,7 +438,7 @@
 }
 
 void BufferLayerConsumer::onSidebandStreamChanged() {
-    FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+    [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
     {
         Mutex::Autolock lock(mFrameAvailableMutex);
         unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 8bbe438..f98681e 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -65,16 +65,6 @@
     mConsumer->setTransformHint(mTransformHint);
 }
 
-std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
-    std::vector<OccupancyTracker::Segment> history;
-    status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
-    if (result != NO_ERROR) {
-        ALOGW("[%s] Failed to obtain occupancy history (%d)", getDebugName(), result);
-        return {};
-    }
-    return history;
-}
-
 void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     if (!mConsumer->releasePendingBuffer()) {
         return;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index be2902b..a3bd725 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -44,8 +44,6 @@
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
 
-    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
-
     // If a buffer was replaced this frame, release the former buffer
     void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
 
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 4eeaba1..132ee9d 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -40,13 +40,13 @@
 namespace {
 void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
                                const sp<GraphicBuffer>& buffer, uint64_t framenumber,
-                               const sp<Fence>& releaseFence, uint32_t transformHint,
+                               const sp<Fence>& releaseFence,
                                uint32_t currentMaxAcquiredBufferCount) {
     if (!listener) {
         return;
     }
     listener->onReleaseBuffer({buffer->getId(), framenumber},
-                              releaseFence ? releaseFence : Fence::NO_FENCE, transformHint,
+                              releaseFence ? releaseFence : Fence::NO_FENCE,
                               currentMaxAcquiredBufferCount);
 }
 } // namespace
@@ -64,7 +64,7 @@
     if (mBufferInfo.mBuffer != nullptr && !isClone()) {
         callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                   mBufferInfo.mBuffer->getBuffer(), mBufferInfo.mFrameNumber,
-                                  mBufferInfo.mFence, mTransformHint,
+                                  mBufferInfo.mFence,
                                   mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
                                           mOwnerUid));
     }
@@ -479,7 +479,7 @@
             // call any release buffer callbacks if set.
             callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                       mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
-                                      mDrawingState.acquireFence, mTransformHint,
+                                      mDrawingState.acquireFence,
                                       mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
                                               mOwnerUid));
             decrementPendingBufferCount();
@@ -491,9 +491,9 @@
         } else if (mLastClientCompositionFence != nullptr) {
             callReleaseBufferCallback(mDrawingState.releaseBufferListener,
                                       mDrawingState.buffer->getBuffer(), mDrawingState.frameNumber,
-                                      mLastClientCompositionFence, mTransformHint,
+                                      mLastClientCompositionFence,
                                       mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(
-                                          mOwnerUid));
+                                              mOwnerUid));
             mLastClientCompositionFence = nullptr;
         }
     }
@@ -989,7 +989,7 @@
  * how to go from screen space back to window space.
  */
 ui::Transform BufferStateLayer::getInputTransform() const {
-    sp<Layer> parent = mDrawingParent.promote();
+    auto parent = mDrawingParent;
     if (parent == nullptr) {
         return ui::Transform();
     }
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ecfd901..e958549 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -381,12 +381,7 @@
 
     if (outputDependentState.overrideInfo.buffer != nullptr) {
         displayFrame = outputDependentState.overrideInfo.displayFrame;
-        sourceCrop =
-                FloatRect(0.f, 0.f,
-                          static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
-                                                     ->getWidth()),
-                          static_cast<float>(outputDependentState.overrideInfo.buffer->getBuffer()
-                                                     ->getHeight()));
+        sourceCrop = displayFrame.toFloatRect();
     }
 
     ALOGV("Writing display frame [%d, %d, %d, %d]", displayFrame.left, displayFrame.top,
@@ -737,7 +732,7 @@
     // framebuffer space of the override buffer to layer space.
     const ProjectionSpace& layerSpace = getOutput().getState().layerStackSpace;
     const ui::Transform transform = getState().overrideInfo.displaySpace.getTransform(layerSpace);
-    const Rect boundaries = transform.transform(getState().overrideInfo.displayFrame);
+    const Rect boundaries = transform.transform(getState().overrideInfo.displaySpace.getContent());
 
     LayerFE::LayerSettings settings;
     settings.geometry = renderengine::Geometry{
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index ad5e931..2272099 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -315,7 +315,7 @@
                         state.overrideInfo = {
                                 .buffer = mNewCachedSet->getBuffer(),
                                 .acquireFence = mNewCachedSet->getDrawFence(),
-                                .displayFrame = mNewCachedSet->getTextureBounds(),
+                                .displayFrame = mNewCachedSet->getBounds(),
                                 .dataspace = mNewCachedSet->getOutputDataspace(),
                                 .displaySpace = mNewCachedSet->getOutputSpace(),
                                 .damageRegion = Region::INVALID_REGION,
@@ -355,7 +355,7 @@
                 state.overrideInfo = {
                         .buffer = currentLayerIter->getBuffer(),
                         .acquireFence = currentLayerIter->getDrawFence(),
-                        .displayFrame = currentLayerIter->getTextureBounds(),
+                        .displayFrame = currentLayerIter->getBounds(),
                         .dataspace = currentLayerIter->getOutputDataspace(),
                         .displaySpace = currentLayerIter->getOutputSpace(),
                         .damageRegion = Region(),
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 53b71b7..fbc2089 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -876,7 +876,7 @@
                                                    84.f / 255.f};
 const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
 const Rect OutputLayerWriteStateToHWCTest::kOverrideDisplayFrame{1002, 1003, 1004, 20044};
-const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{0.f, 0.f, 4.f, 5.f};
+const FloatRect OutputLayerWriteStateToHWCTest::kOverrideSourceCrop{1002, 1003, 1004, 20044};
 const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
         Rect{1005, 1006, 1007, 1008}};
 const Region OutputLayerWriteStateToHWCTest::kOverrideVisibleRegion{Rect{1006, 1007, 1008, 1009}};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 87afa22..5707c67 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -179,9 +179,23 @@
     if (mDrawingState.sidebandStream != nullptr) {
         mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
     }
+
     if (mHadClonedChild) {
         mFlinger->mNumClones--;
     }
+
+    for (auto const& child : mCurrentChildren) {
+        if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
+        if (child->mDrawingParent == this) {
+            child->mDrawingParent = nullptr;
+        }
+    }
+    for (auto const& child : mDrawingChildren) {
+        if (child->mCurrentParent == this) child->mCurrentParent = nullptr;
+        if (child->mDrawingParent == this) {
+            child->mDrawingParent = nullptr;
+        }
+    }
 }
 
 LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, sp<Client> client, std::string name,
@@ -237,7 +251,7 @@
 }
 
 sp<Layer> Layer::getRootLayer() {
-    sp<Layer> parent = getParent();
+    auto parent = getParent();
     if (parent == nullptr) {
         return this;
     }
@@ -426,20 +440,6 @@
 
 void Layer::prepareGeometryCompositionState() {
     const auto& drawingState{getDrawingState()};
-
-    int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
-    int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0);
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent.get()) {
-        auto& parentState = parent->getDrawingState();
-        const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
-        const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0);
-        if (parentType > 0 && parentAppId > 0) {
-            type = parentType;
-            appId = parentAppId;
-        }
-    }
-
     auto* compositionState = editCompositionState();
 
     compositionState->geomBufferSize = getBufferSize(drawingState);
@@ -676,7 +676,7 @@
         return true;
     }
 
-    const auto p = mDrawingParent.promote();
+    const auto p = mDrawingParent;
     return (p != nullptr) ? p->isSecure() : false;
 }
 
@@ -859,7 +859,7 @@
     if (getDrawingState().isTrustedOverlay) {
         return true;
     }
-    const auto& p = mDrawingParent.promote();
+    const auto p = mDrawingParent;
     return (p != nullptr) && p->isTrustedOverlay();
 }
 
@@ -1039,7 +1039,7 @@
         return mDrawingState.frameRateSelectionPriority;
     }
     // If not, search whether its parents have it set.
-    sp<Layer> parent = getParent();
+    auto parent = getParent();
     if (parent != nullptr) {
         return parent->getFrameRateSelectionPriority();
     }
@@ -1052,10 +1052,11 @@
 };
 
 ui::LayerStack Layer::getLayerStack() const {
-    if (const auto parent = mDrawingParent.promote()) {
-        return parent->getLayerStack();
+    auto p = mDrawingParent;
+    if (p == nullptr) {
+        return getDrawingState().layerStack;
     }
-    return getDrawingState().layerStack;
+    return mDrawingParent->getLayerStack();
 }
 
 bool Layer::setShadowRadius(float shadowRadius) {
@@ -1100,7 +1101,7 @@
         return mDrawingState.stretchEffect;
     }
 
-    sp<Layer> parent = getParent();
+    auto parent = mDrawingParent;
     if (parent != nullptr) {
         auto effect = parent->getStretchEffect();
         if (effect.hasEffect()) {
@@ -1315,7 +1316,7 @@
 
 bool Layer::isHiddenByPolicy() const {
     const State& s(mDrawingState);
-    const auto& parent = mDrawingParent.promote();
+    auto parent = mDrawingParent;
     if (parent != nullptr && parent->isHiddenByPolicy()) {
         return true;
     }
@@ -1362,7 +1363,7 @@
     LayerDebugInfo info;
     const State& ds = getDrawingState();
     info.mName = getName();
-    sp<Layer> parent = mDrawingParent.promote();
+    auto parent = mDrawingParent;
     info.mParentName = parent ? parent->getName() : "none"s;
     info.mType = getType();
     info.mTransparentRegion = ds.activeTransparentRegion_legacy;
@@ -1594,7 +1595,7 @@
 
 void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
     for (const sp<Layer>& child : mDrawingChildren) {
-        child->mDrawingParent = newParent;
+        child->mDrawingParent = newParent.get();
         child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
                              newParent->mEffectiveShadowRadius);
     }
@@ -1614,7 +1615,7 @@
         }
     }
 
-    sp<Layer> parent = getParent();
+    auto parent = getParent();
     if (parent != nullptr) {
         parent->removeChild(this);
     }
@@ -1649,7 +1650,7 @@
 
 mat4 Layer::getColorTransform() const {
     mat4 colorTransform = mat4(getDrawingState().colorTransform);
-    if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
+    if (auto parent = mDrawingParent; parent != nullptr) {
         colorTransform = parent->getColorTransform() * colorTransform;
     }
     return colorTransform;
@@ -1657,7 +1658,7 @@
 
 bool Layer::hasColorTransform() const {
     bool hasColorTransform = getDrawingState().hasColorTransform;
-    if (sp<Layer> parent = mDrawingParent.promote(); parent != nullptr) {
+    if (auto parent = mDrawingParent; parent != nullptr) {
         hasColorTransform = hasColorTransform || parent->hasColorTransform();
     }
     return hasColorTransform;
@@ -1671,7 +1672,7 @@
 }
 
 void Layer::setParent(const sp<Layer>& layer) {
-    mCurrentParent = layer;
+    mCurrentParent = layer.get();
 }
 
 int32_t Layer::getZ(LayerVector::StateSet) const {
@@ -1875,7 +1876,7 @@
 }
 
 half Layer::getAlpha() const {
-    const auto& p = mDrawingParent.promote();
+    auto p = mDrawingParent;
 
     half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
     return parentAlpha * getDrawingState().color.a;
@@ -1886,7 +1887,7 @@
     if (fixedTransformHint != ui::Transform::ROT_INVALID) {
         return fixedTransformHint;
     }
-    const auto& p = mCurrentParent.promote();
+    auto p = mCurrentParent;
     if (!p) return fixedTransformHint;
     return p->getFixedTransformHint();
 }
@@ -1897,7 +1898,7 @@
 }
 
 int32_t Layer::getBackgroundBlurRadius() const {
-    const auto& p = mDrawingParent.promote();
+    auto p = mDrawingParent;
 
     half parentAlpha = (p != nullptr) ? p->getAlpha() : 1.0_hf;
     return parentAlpha * getDrawingState().backgroundBlurRadius;
@@ -1915,9 +1916,8 @@
 Layer::RoundedCornerState Layer::getRoundedCornerState() const {
     // Get parent settings
     RoundedCornerState parentSettings;
-    const auto& parent = mDrawingParent.promote();
-    if (parent != nullptr) {
-        parentSettings = parent->getRoundedCornerState();
+    if (mDrawingParent != nullptr) {
+        parentSettings = mDrawingParent->getRoundedCornerState();
         if (parentSettings.radius > 0) {
             ui::Transform t = getActiveTransform(getDrawingState());
             t = t.inverse();
@@ -1936,8 +1936,9 @@
     Rect layerCropRect = getCroppedBufferSize(getDrawingState());
     const float radius = getDrawingState().cornerRadius;
     RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+    const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid();
 
-    if (layerSettings.radius > 0 && parentSettings.radius > 0) {
+    if (layerSettingsValid && parentSettings.radius > 0) {
         // If the parent and the layer have rounded corner settings, use the parent settings if the
         // parent crop is entirely inside the layer crop.
         // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
@@ -1949,7 +1950,7 @@
         } else {
             return layerSettings;
         }
-    } else if (layerSettings.radius > 0) {
+    } else if (layerSettingsValid) {
         return layerSettings;
     } else if (parentSettings.radius > 0) {
         return parentSettings;
@@ -2132,7 +2133,7 @@
         LayerProtoHelper::writeToProtoDeprecated(requestedTransform,
                                                  layerInfo->mutable_requested_transform());
 
-        auto parent = useDrawing ? mDrawingParent.promote() : mCurrentParent.promote();
+        auto parent = useDrawing ? mDrawingParent : mCurrentParent;
         if (parent != nullptr) {
             layerInfo->set_parent(parent->sequence);
         } else {
@@ -2279,9 +2280,9 @@
 }
 
 void Layer::fillTouchOcclusionMode(WindowInfo& info) {
-    sp<Layer> p = this;
+    Layer* p = this;
     while (p != nullptr && !p->hasInputInfo()) {
-        p = p->mDrawingParent.promote();
+        p = p->mDrawingParent;
     }
     if (p != nullptr) {
         info.touchOcclusionMode = p->mDrawingState.inputInfo.touchOcclusionMode;
@@ -2293,9 +2294,8 @@
     if (mode == gui::DropInputMode::ALL) {
         return mode;
     }
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent) {
-        gui::DropInputMode parentMode = parent->getDropInputMode();
+    if (mDrawingParent) {
+        gui::DropInputMode parentMode = mDrawingParent->getDropInputMode();
         if (parentMode != gui::DropInputMode::NONE) {
             return parentMode;
         }
@@ -2322,8 +2322,7 @@
     }
 
     // Check if the parent has set an alpha on the layer
-    sp<Layer> parent = mDrawingParent.promote();
-    if (parent && parent->getAlpha() != 1.0_hf) {
+    if (mDrawingParent && mDrawingParent->getAlpha() != 1.0_hf) {
         info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
         ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
               static_cast<float>(getAlpha()));
@@ -2421,10 +2420,10 @@
     if (mClonedChild != nullptr) {
         return this;
     }
-    if (mDrawingParent == nullptr || mDrawingParent.promote() == nullptr) {
+    if (mDrawingParent == nullptr) {
         return nullptr;
     }
-    return mDrawingParent.promote()->getClonedRoot();
+    return mDrawingParent->getClonedRoot();
 }
 
 bool Layer::hasInputInfo() const {
@@ -2611,8 +2610,7 @@
         return true;
     }
 
-    sp<Layer> parent = mDrawingParent.promote();
-    return parent && parent->isInternalDisplayOverlay();
+    return mDrawingParent && mDrawingParent->isInternalDisplayOverlay();
 }
 
 void Layer::setClonedChild(const sp<Layer>& clonedChild) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d17c05b..07b2eb5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -525,12 +525,10 @@
      * called after composition.
      * returns true if the layer latched a new buffer this frame.
      */
-    virtual bool onPostComposition(const DisplayDevice*,
+    virtual void onPostComposition(const DisplayDevice*,
                                    const std::shared_ptr<FenceTime>& /*glDoneFence*/,
                                    const std::shared_ptr<FenceTime>& /*presentFence*/,
-                                   const CompositorTiming&) {
-        return false;
-    }
+                                   const CompositorTiming&) {}
 
     // If a buffer was replaced this frame, release the former buffer
     virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
@@ -591,10 +589,6 @@
     }
     virtual FrameRate getFrameRateForLayerTree() const;
 
-    virtual std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool /*forceFlush*/) {
-        return {};
-    }
-
     virtual bool getTransformToDisplayInverse() const { return false; }
 
     // Returns how rounded corners should be drawn for this layer.
@@ -801,12 +795,12 @@
     // Returns index if removed, or negative value otherwise
     // for symmetry with Vector::remove
     ssize_t removeChild(const sp<Layer>& layer);
-    sp<Layer> getParent() const { return mCurrentParent.promote(); }
 
     // Should be called with the surfaceflinger statelock held
     bool isAtRoot() const { return mIsAtRoot; }
     void setIsAtRoot(bool isAtRoot) { mIsAtRoot = isAtRoot; }
 
+    Layer* getParent() const { return mCurrentParent; }
     bool hasParent() const { return getParent() != nullptr; }
     Rect getScreenBounds(bool reduceTransparentRegion = true) const;
     bool setChildLayer(const sp<Layer>& childLayer, int32_t z);
@@ -1013,8 +1007,8 @@
     LayerVector mCurrentChildren{LayerVector::StateSet::Current};
     LayerVector mDrawingChildren{LayerVector::StateSet::Drawing};
 
-    wp<Layer> mCurrentParent;
-    wp<Layer> mDrawingParent;
+    Layer* mCurrentParent = nullptr;
+    Layer* mDrawingParent = nullptr;
 
     // Window types from WindowManager.LayoutParams
     const gui::WindowInfo::Type mWindowType;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e90af3a..acb81dc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2308,13 +2308,9 @@
     }
 
     for (const auto& layer: mLayersWithQueuedFrames) {
-        const bool frameLatched =
-                layer->onPostComposition(display, glCompositionDoneFenceTime,
-                                         mPreviousPresentFences[0].fenceTime, compositorTiming);
+        layer->onPostComposition(display, glCompositionDoneFenceTime,
+                                 mPreviousPresentFences[0].fenceTime, compositorTiming);
         layer->releasePendingBuffer(/*dequeueReadyTime*/ now);
-        if (frameLatched) {
-            recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
-        }
     }
 
     std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>>
@@ -3244,8 +3240,6 @@
     if (!mLayersPendingRemoval.isEmpty()) {
         // Notify removed layers now that they can't be drawn from
         for (const auto& l : mLayersPendingRemoval) {
-            recordBufferingStats(l->getName(), l->getOccupancyHistory(true));
-
             // Ensure any buffers set to display on any children are released.
             if (l->isRemovedFromCurrentState()) {
                 l->latchAndReleaseBuffer();
@@ -3418,6 +3412,7 @@
     states.add(composerState);
 
     lbc->updateTransformHint(mActiveDisplayTransformHint);
+
     if (outTransformHint) {
         *outTransformHint = mActiveDisplayTransformHint;
     }
@@ -3962,7 +3957,7 @@
     }
     if (what & layer_state_t::eLayerChanged) {
         // NOTE: index needs to be calculated before we update the state
-        const auto& p = layer->getParent();
+        auto p = layer->getParent();
         if (p == nullptr) {
             ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
             if (layer->setLayer(s.z) && idx >= 0) {
@@ -3980,7 +3975,7 @@
     }
     if (what & layer_state_t::eRelativeLayerChanged) {
         // NOTE: index needs to be calculated before we update the state
-        const auto& p = layer->getParent();
+        auto p = layer->getParent();
         const auto& relativeHandle = s.relativeLayerSurfaceControl ?
                 s.relativeLayerSurfaceControl->getHandle() : nullptr;
         if (p == nullptr) {
@@ -4814,24 +4809,6 @@
                   bucketTimeSec, percent);
 }
 
-void SurfaceFlinger::recordBufferingStats(const std::string& layerName,
-                                          std::vector<OccupancyTracker::Segment>&& history) {
-    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
-    auto& stats = getBE().mBufferingStats[layerName];
-    for (const auto& segment : history) {
-        if (!segment.usedThirdBuffer) {
-            stats.twoBufferTime += segment.totalTime;
-        }
-        if (segment.occupancyAverage < 1.0f) {
-            stats.doubleBufferedTime += segment.totalTime;
-        } else if (segment.occupancyAverage < 2.0f) {
-            stats.tripleBufferedTime += segment.totalTime;
-        }
-        ++stats.numSegments;
-        stats.totalTime += segment.totalTime;
-    }
-}
-
 void SurfaceFlinger::dumpFrameEventsLocked(std::string& result) {
     result.append("Layer frame timestamps:\n");
     // Traverse all layers to dump frame-events for each layer
@@ -4839,38 +4816,6 @@
         [&] (Layer* layer) { layer->dumpFrameEvents(result); });
 }
 
-void SurfaceFlinger::dumpBufferingStats(std::string& result) const {
-    result.append("Buffering stats:\n");
-    result.append("  [Layer name] <Active time> <Two buffer> "
-            "<Double buffered> <Triple buffered>\n");
-    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
-    typedef std::tuple<std::string, float, float, float> BufferTuple;
-    std::map<float, BufferTuple, std::greater<float>> sorted;
-    for (const auto& statsPair : getBE().mBufferingStats) {
-        const char* name = statsPair.first.c_str();
-        const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
-        if (stats.numSegments == 0) {
-            continue;
-        }
-        float activeTime = ns2ms(stats.totalTime) / 1000.0f;
-        float twoBufferRatio = static_cast<float>(stats.twoBufferTime) /
-                stats.totalTime;
-        float doubleBufferRatio = static_cast<float>(
-                stats.doubleBufferedTime) / stats.totalTime;
-        float tripleBufferRatio = static_cast<float>(
-                stats.tripleBufferedTime) / stats.totalTime;
-        sorted.insert({activeTime, {name, twoBufferRatio,
-                doubleBufferRatio, tripleBufferRatio}});
-    }
-    for (const auto& sortedPair : sorted) {
-        float activeTime = sortedPair.first;
-        const BufferTuple& values = sortedPair.second;
-        StringAppendF(&result, "  [%s] %.2f %.3f %.3f %.3f\n", std::get<0>(values).c_str(),
-                      activeTime, std::get<1>(values), std::get<2>(values), std::get<3>(values));
-    }
-    result.append("\n");
-}
-
 void SurfaceFlinger::dumpDisplayIdentificationData(std::string& result) const {
     for (const auto& [token, display] : mDisplays) {
         const auto displayId = PhysicalDisplayId::tryCast(display->getId());
@@ -5062,8 +5007,6 @@
     StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
     StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
 
-    dumpBufferingStats(result);
-
     /*
      * Dump the visible layer list
      */
@@ -6183,7 +6126,7 @@
                 return;
             }
 
-            sp<Layer> p = layer;
+            auto p = layer;
             while (p != nullptr) {
                 if (excludeLayers.count(p) != 0) {
                     return;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1217d63..1f0e42d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -32,7 +32,6 @@
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/ITransactionCompletedListener.h>
 #include <gui/LayerState.h>
-#include <gui/OccupancyTracker.h>
 #include <layerproto/LayerProtoHeader.h>
 #include <math/mat4.h>
 #include <renderengine/LayerSettings.h>
@@ -155,22 +154,6 @@
     nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
     nsecs_t mTotalTime = 0;
     std::atomic<nsecs_t> mLastSwapTime = 0;
-
-    // Double- vs. triple-buffering stats
-    struct BufferingStats {
-        size_t numSegments = 0;
-        nsecs_t totalTime = 0;
-
-        // "Two buffer" means that a third buffer was never used, whereas
-        // "double-buffered" means that on average the segment only used two
-        // buffers (though it may have used a third for some part of the
-        // segment)
-        nsecs_t twoBufferTime = 0;
-        nsecs_t doubleBufferedTime = 0;
-        nsecs_t tripleBufferedTime = 0;
-    };
-    mutable Mutex mBufferingStatsMutex;
-    std::unordered_map<std::string, BufferingStats> mBufferingStats;
 };
 
 class SurfaceFlinger : public BnSurfaceComposer,
@@ -1158,10 +1141,6 @@
     void dumpStaticScreenStats(std::string& result) const;
     // Not const because each Layer needs to query Fences and cache timestamps.
     void dumpFrameEventsLocked(std::string& result);
-
-    void recordBufferingStats(const std::string& layerName,
-                              std::vector<OccupancyTracker::Segment>&& history);
-    void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
     void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
     void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 7c1f21f..bf2038b 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -564,7 +564,7 @@
         layerRecords += record.second.stats.size();
     }
 
-    return mTimeStats.stats.size() < MAX_NUM_LAYER_STATS;
+    return layerRecords < MAX_NUM_LAYER_STATS;
 }
 
 void TimeStats::setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index e5872c1..9cb617a 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -208,6 +208,37 @@
     }
 }
 
+// b/200781179 - don't round a layer without a valid crop
+// This behaviour should be fixed since we treat buffer layers differently than
+// effect or container layers.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusInvalidCrop) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint8_t size = 64;
+    const uint8_t testArea = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::GREEN, size, size));
+    ASSERT_NO_FATAL_FAILURE(child = createColorLayer("child", Color::RED));
+
+    Transaction().setCornerRadius(child, cornerRadius).reparent(child, parent).show(child).apply();
+    {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
+        auto shot = getScreenCapture();
+        std::this_thread::sleep_for(std::chrono::seconds(5));
+        // Solid corners since we don't round a layer without a valid crop
+        shot->expectColor(Rect(0, 0, testArea, testArea), Color::RED);
+        shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::RED);
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::RED);
+        shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::RED);
+        // Solid center
+        shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+                               size / 2 + testArea / 2, size / 2 + testArea / 2),
+                          Color::RED);
+    }
+}
+
 TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
     sp<SurfaceControl> parent;
     sp<SurfaceControl> child;
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 3847a51..e50c2fc 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -31,7 +31,7 @@
 public:
     static void function(void* callbackContext, ReleaseCallbackId callbackId,
                          const sp<Fence>& releaseFence,
-                         uint32_t /*currentMaxAcquiredBufferCount*/) {
+                         std::optional<uint32_t> /*currentMaxAcquiredBufferCount*/) {
         if (!callbackContext) {
             FAIL() << "failed to get callback context";
         }
@@ -385,4 +385,84 @@
     ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
 }
 
+TEST_F(ReleaseBufferCallbackTest, DISABLED_SetBuffer_OverwriteBuffers) {
+    sp<SurfaceControl> layer = createBufferStateLayer();
+    ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+    sp<GraphicBuffer> firstBuffer = getBuffer();
+    ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+    // Create transaction with a buffer.
+    Transaction transaction;
+    transaction.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+                          firstBufferCallbackId, releaseCallback->getCallback());
+
+    sp<GraphicBuffer> secondBuffer = getBuffer();
+    ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+    // Call setBuffer on the same transaction with a different buffer.
+    transaction.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+                          secondBufferCallbackId, releaseCallback->getCallback());
+
+    ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Transactions_OverwriteBuffers) {
+    sp<SurfaceControl> layer = createBufferStateLayer();
+    ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+    sp<GraphicBuffer> firstBuffer = getBuffer();
+    ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+    // Create transaction with a buffer.
+    Transaction transaction1;
+    transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+                           firstBufferCallbackId, releaseCallback->getCallback());
+
+    sp<GraphicBuffer> secondBuffer = getBuffer();
+    ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+    // Create a second transaction with a new buffer for the same layer.
+    Transaction transaction2;
+    transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+                           secondBufferCallbackId, releaseCallback->getCallback());
+
+    // merge transaction1 into transaction2 so ensure we get a proper buffer release callback.
+    transaction1.merge(std::move(transaction2));
+    ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
+TEST_F(ReleaseBufferCallbackTest, DISABLED_MergeBuffers_Different_Processes) {
+    sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+    sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+    TransactionCompletedListener::setInstance(firstCompletedListener);
+
+    sp<SurfaceControl> layer = createBufferStateLayer();
+    ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+    sp<GraphicBuffer> firstBuffer = getBuffer();
+    ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+    Transaction transaction1;
+    transaction1.setBuffer(layer, firstBuffer, std::nullopt, firstBufferCallbackId.framenumber,
+                           firstBufferCallbackId, releaseCallback->getCallback());
+
+    // Sent a second buffer to allow the first buffer to get released.
+    sp<GraphicBuffer> secondBuffer = getBuffer();
+    ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+    Transaction transaction2;
+    transaction2.setBuffer(layer, secondBuffer, std::nullopt, secondBufferCallbackId.framenumber,
+                           secondBufferCallbackId, releaseCallback->getCallback());
+
+    // Set a different TransactionCompletedListener to mimic a second process
+    TransactionCompletedListener::setInstance(secondCompletedListener);
+    Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+    // Make sure we can still get the release callback even though the merge happened in a different
+    // process.
+    ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 7072439..db3b572 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,7 +289,7 @@
     }
 
     static void setLayerDrawingParent(const sp<Layer>& layer, const sp<Layer>& drawingParent) {
-        layer->mDrawingParent = drawingParent;
+        layer->mDrawingParent = drawingParent.get();
     }
 
     /* ------------------------------------------------------------------------