Merge changes Ida17429b,I3debc83d,If68332d6 into main

* changes:
  InputVerifier: make action_button a field of the action enum
  InputVerifier: use `let ... else` when converting flags and buttons
  InputVerifier: put parameters into a struct
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index 6d14d56..277300d 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -772,8 +772,8 @@
             break;
 
             case 'i':
-                displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg));
-                if (!displayId) {
+                displayId = PhysicalDisplayId::fromValue(atoll(optarg));
+                if (std::find(ids.begin(), ids.end(), displayId) == ids.end()) {
                     fprintf(stderr, "Invalid display ID: %s.\n", optarg);
                     exit(4);
                 }
diff --git a/include/ftl/small_map.h b/include/ftl/small_map.h
index 83d5967..96d35cd 100644
--- a/include/ftl/small_map.h
+++ b/include/ftl/small_map.h
@@ -234,6 +234,12 @@
   //
   bool erase(const key_type& key) { return erase(key, begin()); }
 
+  // Removes a mapping.
+  //
+  // The last() and end() iterators, as well as those to the erased mapping, are invalidated.
+  //
+  void erase(iterator it) { map_.unstable_erase(it); }
+
   // Removes all mappings.
   //
   // All iterators are invalidated.
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 152c815..83f4719 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -147,9 +147,11 @@
          data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
          data.writeInt32(uid);
          data.writeString16(callingPackage);
-         remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
+         status_t err = remote()->transact(IS_UID_ACTIVE_TRANSACTION, data, &reply);
          // fail on exception
-         if (reply.readExceptionCode() != 0) return false;
+         if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+             return false;
+         }
          return reply.readInt32() == 1;
     }
 
@@ -159,9 +161,9 @@
         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
         data.writeInt32(uid);
         data.writeString16(callingPackage);
-        remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply);
+        status_t err = remote()->transact(GET_UID_PROCESS_STATE_TRANSACTION, data, &reply);
         // fail on exception
-        if (reply.readExceptionCode() != 0) {
+        if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
             return ActivityManager::PROCESS_STATE_UNKNOWN;
         }
         return reply.readInt32();
@@ -192,7 +194,7 @@
         data.writeInt32(appPid);
         status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply,
                                           IBinder::FLAG_ONEWAY);
-        if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+        if (err != NO_ERROR) {
             ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
             return err;
         }
@@ -207,7 +209,7 @@
         data.writeInt32(appPid);
         status_t err =
                 remote()->transact(LOG_FGS_API_END_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
-        if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+        if (err != NO_ERROR) {
             ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
             return err;
         }
@@ -224,7 +226,7 @@
         data.writeInt32(appPid);
         status_t err = remote()->transact(LOG_FGS_API_STATE_CHANGED_TRANSACTION, data, &reply,
                                           IBinder::FLAG_ONEWAY);
-        if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
+        if (err != NO_ERROR) {
             ALOGD("%s: FGS Logger Transaction failed, %d", __func__, err);
             return err;
         }
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index bb45ad2..993ad82 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -263,7 +263,6 @@
         "android.utils.IMemory",
         "android.utils.IMemoryHeap",
         "com.android.car.procfsinspector.IProcfsInspector",
-        "com.android.internal.app.IAppOpsCallback",
         "com.android.internal.app.IAppOpsService",
         "com.android.internal.app.IBatteryStats",
         "com.android.internal.os.IResultReceiver",
diff --git a/libs/binder/rust/rpcbinder/Android.bp b/libs/binder/rust/rpcbinder/Android.bp
index 4036551..46651ce 100644
--- a/libs/binder/rust/rpcbinder/Android.bp
+++ b/libs/binder/rust/rpcbinder/Android.bp
@@ -26,6 +26,7 @@
     ],
     visibility: [
         "//device/google/cuttlefish/shared/minidroid/sample",
+        "//hardware/interfaces/security/see:__subpackages__",
         "//packages/modules/Virtualization:__subpackages__",
     ],
     apex_available: [
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index c0c0aae..339ce4b 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -22,17 +22,33 @@
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
 #include <cutils/trace.h>
+#include <gtest/gtest-spi.h>
 #include <gtest/gtest.h>
 #include <utils/CallStack.h>
 
 #include <malloc.h>
+#include <atomic>
 #include <functional>
+#include <numeric>
 #include <vector>
 
 using namespace android::binder::impl;
 
 static android::String8 gEmpty(""); // make sure first allocation from optimization runs
 
+struct State {
+    State(std::vector<size_t>&& expectedMallocs) : expectedMallocs(std::move(expectedMallocs)) {}
+    ~State() {
+        size_t num = numMallocs.load();
+        if (expectedMallocs.size() != num) {
+            ADD_FAILURE() << "Expected " << expectedMallocs.size() << " allocations, but got "
+                          << num;
+        }
+    }
+    const std::vector<size_t> expectedMallocs;
+    std::atomic<size_t> numMallocs;
+};
+
 struct DestructionAction {
     DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
     ~DestructionAction() { mF(); };
@@ -95,8 +111,7 @@
 
 // Action to execute when malloc is hit. Supports nesting. Malloc is not
 // restricted when the allocation hook is being processed.
-__attribute__((warn_unused_result))
-DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
+__attribute__((warn_unused_result)) DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
     MallocHooks before = MallocHooks::save();
     LambdaHooks::lambdas.emplace_back(std::move(f));
     LambdaHooks::lambda_malloc_hooks.overwrite();
@@ -106,6 +121,22 @@
     });
 }
 
+DestructionAction setExpectedMallocs(std::vector<size_t>&& expected) {
+    auto state = std::make_shared<State>(std::move(expected));
+    return OnMalloc([state = state](size_t bytes) {
+        size_t num = state->numMallocs.fetch_add(1);
+        if (num >= state->expectedMallocs.size() || state->expectedMallocs[num] != bytes) {
+            ADD_FAILURE() << "Unexpected allocation number " << num << " of size " << bytes
+                          << " bytes" << std::endl
+                          << android::CallStack::stackToString("UNEXPECTED ALLOCATION",
+                                                               android::CallStack::getCurrent(
+                                                                       4 /*ignoreDepth*/)
+                                                                       .get())
+                          << std::endl;
+        }
+    });
+}
+
 // exported symbol, to force compiler not to optimize away pointers we set here
 const void* imaginary_use;
 
@@ -119,16 +150,53 @@
 
         imaginary_use = new int[10];
     }
+    delete[] reinterpret_cast<const int*>(imaginary_use);
     EXPECT_EQ(mallocs, 1u);
 }
 
+TEST(TestTheTest, OnMallocWithExpectedMallocs) {
+    std::vector<size_t> expectedMallocs = {
+            4,
+            16,
+            8,
+    };
+    {
+        const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs));
+        imaginary_use = new int32_t[1];
+        delete[] reinterpret_cast<const int*>(imaginary_use);
+        imaginary_use = new int32_t[4];
+        delete[] reinterpret_cast<const int*>(imaginary_use);
+        imaginary_use = new int32_t[2];
+        delete[] reinterpret_cast<const int*>(imaginary_use);
+    }
+}
+
+TEST(TestTheTest, OnMallocWithExpectedMallocsWrongSize) {
+    std::vector<size_t> expectedMallocs = {
+            4,
+            16,
+            100000,
+    };
+    EXPECT_NONFATAL_FAILURE(
+            {
+                const auto on_malloc = setExpectedMallocs(std::move(expectedMallocs));
+                imaginary_use = new int32_t[1];
+                delete[] reinterpret_cast<const int*>(imaginary_use);
+                imaginary_use = new int32_t[4];
+                delete[] reinterpret_cast<const int*>(imaginary_use);
+                imaginary_use = new int32_t[2];
+                delete[] reinterpret_cast<const int*>(imaginary_use);
+            },
+            "Unexpected allocation number 2 of size 8 bytes");
+}
 
 __attribute__((warn_unused_result))
 DestructionAction ScopeDisallowMalloc() {
     return OnMalloc([&](size_t bytes) {
-        ADD_FAILURE() << "Unexpected allocation: " << bytes;
+        FAIL() << "Unexpected allocation: " << bytes;
         using android::CallStack;
-        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
+        std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION",
+                                              CallStack::getCurrent(4 /*ignoreDepth*/).get())
                   << std::endl;
     });
 }
@@ -224,6 +292,51 @@
     EXPECT_EQ(mallocs, 1u);
 }
 
+TEST(BinderAccessorAllocation, AddAccessorCheckService) {
+    // Need to call defaultServiceManager() before checking malloc because it
+    // will allocate an instance in the call_once
+    const auto sm = defaultServiceManager();
+    const std::string kInstanceName1 = "foo.bar.IFoo/default";
+    const std::string kInstanceName2 = "foo.bar.IFoo2/default";
+    const String16 kInstanceName16(kInstanceName1.c_str());
+    std::vector<size_t> expectedMallocs = {
+            // addAccessorProvider
+            112, // new AccessorProvider
+            16,  // new AccessorProviderEntry
+            // checkService
+            45,  // String8 from String16 in CppShim::checkService
+            128, // writeInterfaceToken
+            16,  // getInjectedAccessor, new AccessorProviderEntry
+            66,  // getInjectedAccessor, String16
+            45,  // String8 from String16 in AccessorProvider::provide
+    };
+    std::set<std::string> supportedInstances = {kInstanceName1, kInstanceName2};
+    auto onMalloc = setExpectedMallocs(std::move(expectedMallocs));
+
+    auto receipt =
+            android::addAccessorProvider(std::move(supportedInstances),
+                                         [&](const String16&) -> sp<IBinder> { return nullptr; });
+    EXPECT_FALSE(receipt.expired());
+
+    sp<IBinder> binder = sm->checkService(kInstanceName16);
+
+    status_t status = android::removeAccessorProvider(receipt);
+}
+
+TEST(BinderAccessorAllocation, AddAccessorEmpty) {
+    std::vector<size_t> expectedMallocs = {
+            48, // From ALOGE with empty set of instances
+    };
+    std::set<std::string> supportedInstances = {};
+    auto onMalloc = setExpectedMallocs(std::move(expectedMallocs));
+
+    auto receipt =
+            android::addAccessorProvider(std::move(supportedInstances),
+                                         [&](const String16&) -> sp<IBinder> { return nullptr; });
+
+    EXPECT_TRUE(receipt.expired());
+}
+
 TEST(RpcBinderAllocation, SetupRpcServer) {
     std::string tmp = getenv("TMPDIR") ?: "/tmp";
     std::string addr = tmp + "/binderRpcBenchmark";
@@ -255,6 +368,7 @@
 }
 
 int main(int argc, char** argv) {
+    LOG(INFO) << "Priming static log variables for binderAllocationLimits.";
     if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
         CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
         execv(argv[0], argv);
diff --git a/libs/binder/tests/binderStabilityIntegrationTest.cpp b/libs/binder/tests/binderStabilityIntegrationTest.cpp
index a3fc9cc..cbc4180 100644
--- a/libs/binder/tests/binderStabilityIntegrationTest.cpp
+++ b/libs/binder/tests/binderStabilityIntegrationTest.cpp
@@ -47,6 +47,7 @@
 
     Stability::Level level = Stability::Level::UNDECLARED;
     switch (partition) {
+        case Partition::PRODUCT:
         case Partition::SYSTEM:
         case Partition::SYSTEM_EXT:
             level = Stability::Level::SYSTEM;
diff --git a/libs/debugstore/rust/src/core.rs b/libs/debugstore/rust/src/core.rs
index a8acded..16147dd 100644
--- a/libs/debugstore/rust/src/core.rs
+++ b/libs/debugstore/rust/src/core.rs
@@ -48,7 +48,7 @@
     ///
     /// This constant is used as a part of the debug store's data format,
     /// allowing for version tracking and compatibility checks.
-    const ENCODE_VERSION: u32 = 2;
+    const ENCODE_VERSION: u32 = 3;
 
     /// Creates a new instance of `DebugStore` with specified event limit and maximum delay.
     fn new() -> Self {
@@ -123,9 +123,11 @@
 
 impl fmt::Display for DebugStore {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Write the debug store header information
         let uptime_now = uptimeMillis();
         write!(f, "{},{},{}::", Self::ENCODE_VERSION, self.event_store.len(), uptime_now)?;
 
+        // Join events with a separator
         write!(
             f,
             "{}",
@@ -136,7 +138,10 @@
                 acc.push_str(&event.to_string());
                 acc
             })
-        )
+        )?;
+
+        // Write the debug store footer
+        write!(f, ";;")
     }
 }
 
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 0848fac..c770db9 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -415,14 +415,12 @@
                                                     stat.frameEventStats.dequeueReadyTime);
                 }
                 auto currFrameNumber = stat.frameEventStats.frameNumber;
-                std::vector<ReleaseCallbackId> staleReleases;
-                for (const auto& [key, value]: mSubmitted) {
-                    if (currFrameNumber > key.framenumber) {
-                        staleReleases.push_back(key);
+                // Release stale buffers.
+                for (const auto& [key, _] : mSubmitted) {
+                    if (currFrameNumber <= key.framenumber) {
+                        continue; // not stale.
                     }
-                }
-                for (const auto& staleRelease : staleReleases) {
-                    releaseBufferCallbackLocked(staleRelease,
+                    releaseBufferCallbackLocked(key,
                                                 stat.previousReleaseFence
                                                         ? stat.previousReleaseFence
                                                         : Fence::NO_FENCE,
@@ -618,7 +616,7 @@
     mNumAcquired++;
     mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
     ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
-    mSubmitted[releaseCallbackId] = bufferItem;
+    mSubmitted.emplace_or_replace(releaseCallbackId, bufferItem);
 
     bool needsDisconnect = false;
     mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
@@ -851,7 +849,7 @@
 
 void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) {
     std::lock_guard _lock{mTimestampMutex};
-    mDequeueTimestamps[bufferId] = systemTime();
+    mDequeueTimestamps.emplace_or_replace(bufferId, systemTime());
 };
 
 void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) {
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index ba50bf8..ab747b9 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -238,7 +238,7 @@
         // socket should be atomic across processes.
         DisplayEventReceiver::Event event;
         event.header =
-                DisplayEventReceiver::Event::Header{DisplayEventReceiver::DISPLAY_EVENT_NULL,
+                DisplayEventReceiver::Event::Header{DisplayEventType::DISPLAY_EVENT_NULL,
                                                     PhysicalDisplayId::fromPort(0), systemTime()};
         injectEvent(event);
     }
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 68f10f4..6f23885 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -167,7 +167,7 @@
         for (ssize_t i = 0; i < n; i++) {
             const DisplayEventReceiver::Event& ev = buf[i];
             switch (ev.header.type) {
-                case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+                case DisplayEventType::DISPLAY_EVENT_VSYNC:
                     // Later vsync events will just overwrite the info from earlier
                     // ones. That's fine, we only care about the most recent.
                     gotVsync = true;
@@ -183,7 +183,7 @@
                         ATRACE_INT("RenderRate", fps);
                     }
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+                case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
                     if (ev.hotplug.connectionError == 0) {
                         dispatchHotplug(ev.header.timestamp, ev.header.displayId,
                                         ev.hotplug.connected);
@@ -192,31 +192,28 @@
                                                        ev.hotplug.connectionError);
                     }
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+                case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE:
                     dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
                                         ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_NULL:
+                case DisplayEventType::DISPLAY_EVENT_NULL:
                     dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+                case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
                     mFrameRateOverrides.emplace_back(ev.frameRateOverride);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+                case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
                     dispatchFrameRateOverrides(ev.header.timestamp, ev.header.displayId,
                                                std::move(mFrameRateOverrides));
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+                case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
                     dispatchHdcpLevelsChanged(ev.header.displayId,
                                               ev.hdcpLevelsChange.connectedLevel,
                                               ev.hdcpLevelsChange.maxLevel);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
+                case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
                     dispatchModeRejected(ev.header.displayId, ev.modeRejection.modeId);
                     break;
-                default:
-                    ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
-                    break;
             }
         }
     }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 44aac9b..ebfc62f 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -67,7 +67,6 @@
         reserved(0),
         cornerRadius(0.0f),
         clientDrawnCornerRadius(0.0f),
-        clientDrawnShadowRadius(0.0f),
         backgroundBlurRadius(0),
         color(0),
         bufferTransform(0),
@@ -143,7 +142,6 @@
     SAFE_PARCEL(output.write, colorTransform.asArray(), 16 * sizeof(float));
     SAFE_PARCEL(output.writeFloat, cornerRadius);
     SAFE_PARCEL(output.writeFloat, clientDrawnCornerRadius);
-    SAFE_PARCEL(output.writeFloat, clientDrawnShadowRadius);
     SAFE_PARCEL(output.writeUint32, backgroundBlurRadius);
     SAFE_PARCEL(output.writeParcelable, metadata);
     SAFE_PARCEL(output.writeFloat, bgColor.r);
@@ -279,7 +277,6 @@
     SAFE_PARCEL(input.read, &colorTransform, 16 * sizeof(float));
     SAFE_PARCEL(input.readFloat, &cornerRadius);
     SAFE_PARCEL(input.readFloat, &clientDrawnCornerRadius);
-    SAFE_PARCEL(input.readFloat, &clientDrawnShadowRadius);
     SAFE_PARCEL(input.readUint32, &backgroundBlurRadius);
     SAFE_PARCEL(input.readParcelable, &metadata);
 
@@ -606,10 +603,6 @@
         what |= eClientDrawnCornerRadiusChanged;
         clientDrawnCornerRadius = other.clientDrawnCornerRadius;
     }
-    if (other.what & eClientDrawnShadowsChanged) {
-        what |= eClientDrawnShadowsChanged;
-        clientDrawnShadowRadius = other.clientDrawnShadowRadius;
-    }
     if (other.what & eBackgroundBlurRadiusChanged) {
         what |= eBackgroundBlurRadiusChanged;
         backgroundBlurRadius = other.backgroundBlurRadius;
@@ -824,7 +817,6 @@
     CHECK_DIFF(diff, eLayerStackChanged, other, layerStack);
     CHECK_DIFF(diff, eCornerRadiusChanged, other, cornerRadius);
     CHECK_DIFF(diff, eClientDrawnCornerRadiusChanged, other, clientDrawnCornerRadius);
-    CHECK_DIFF(diff, eClientDrawnShadowsChanged, other, clientDrawnShadowRadius);
     CHECK_DIFF(diff, eBackgroundBlurRadiusChanged, other, backgroundBlurRadius);
     if (other.what & eBlurRegionsChanged) diff |= eBlurRegionsChanged;
     if (other.what & eRelativeLayerChanged) {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 852885b..37ed23b 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1415,9 +1415,8 @@
             ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds);
     if (status.isOk()) {
         physicalDisplayIds.reserve(displayIds.size());
-        for (auto item : displayIds) {
-            auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(item));
-            physicalDisplayIds.push_back(*id);
+        for (auto id : displayIds) {
+            physicalDisplayIds.push_back(PhysicalDisplayId::fromValue(static_cast<uint64_t>(id)));
         }
     }
     return physicalDisplayIds;
@@ -1688,17 +1687,6 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setClientDrawnShadowRadius(
-        const sp<SurfaceControl>& sc, float clientDrawnShadowRadius) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
-    }
-    s->what |= layer_state_t::eClientDrawnShadowsChanged;
-    s->clientDrawnShadowRadius = clientDrawnShadowRadius;
-    return *this;
-}
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
         const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
     layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index b97a496..cdc2150 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -20,6 +20,7 @@
 #include <optional>
 #include <queue>
 
+#include <ftl/small_map.h>
 #include <gui/BufferItem.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/IGraphicBufferConsumer.h>
@@ -36,6 +37,10 @@
 
 namespace android {
 
+// Sizes determined empirically to avoid allocations during common activity.
+constexpr size_t kSubmittedBuffersMapSizeHint = 8;
+constexpr size_t kDequeueTimestampsMapSizeHint = 32;
+
 class BLASTBufferQueue;
 class BufferItemConsumer;
 
@@ -206,7 +211,7 @@
 
     // Keep a reference to the submitted buffers so we can release when surfaceflinger drops the
     // buffer or the buffer has been presented and a new buffer is ready to be presented.
-    std::unordered_map<ReleaseCallbackId, BufferItem, ReleaseBufferCallbackIdHash> mSubmitted
+    ftl::SmallMap<ReleaseCallbackId, BufferItem, kSubmittedBuffersMapSizeHint> mSubmitted
             GUARDED_BY(mMutex);
 
     // Keep a queue of the released buffers instead of immediately releasing
@@ -291,8 +296,8 @@
     std::mutex mTimestampMutex;
     // Tracks buffer dequeue times by the client. This info is sent to SurfaceFlinger which uses
     // it for debugging purposes.
-    std::unordered_map<uint64_t /* bufferId */, nsecs_t> mDequeueTimestamps
-            GUARDED_BY(mTimestampMutex);
+    ftl::SmallMap<uint64_t /* bufferId */, nsecs_t, kDequeueTimestampsMapSizeHint>
+            mDequeueTimestamps GUARDED_BY(mTimestampMutex);
 
     // Keep track of SurfaceControls that have submitted a transaction and BBQ is waiting on a
     // callback for them.
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index ab6a6b7..f51390a 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -55,20 +55,20 @@
         static_cast<uint32_t>(c4);
 }
 
+enum class DisplayEventType : uint32_t {
+    DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
+    DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
+    DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
+    DISPLAY_EVENT_MODE_REJECTION = fourcc('r', 'e', 'j', 'e'),
+    DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
+    DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
+    DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
+    DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'),
+};
+
 // ----------------------------------------------------------------------------
 class DisplayEventReceiver {
 public:
-    enum {
-        DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
-        DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
-        DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
-        DISPLAY_EVENT_MODE_REJECTION = fourcc('r', 'e', 'j', 'e'),
-        DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
-        DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
-        DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
-        DISPLAY_EVENT_HDCP_LEVELS_CHANGE = fourcc('h', 'd', 'c', 'p'),
-    };
-
     struct Event {
         // We add __attribute__((aligned(8))) for nsecs_t fields because
         // we need to make sure all fields are aligned the same with x86
@@ -77,7 +77,7 @@
         // https://en.wikipedia.org/wiki/Data_structure_alignment
 
         struct Header {
-            uint32_t type;
+            DisplayEventType type;
             PhysicalDisplayId displayId __attribute__((aligned(8)));
             nsecs_t timestamp __attribute__((aligned(8)));
         };
diff --git a/libs/gui/include/gui/InputTransferToken.h b/libs/gui/include/gui/InputTransferToken.h
index 6530b50..fb4aaa7 100644
--- a/libs/gui/include/gui/InputTransferToken.h
+++ b/libs/gui/include/gui/InputTransferToken.h
@@ -25,7 +25,7 @@
 namespace android {
 struct InputTransferToken : public RefBase, Parcelable {
 public:
-    InputTransferToken() { mToken = new BBinder(); }
+    InputTransferToken() { mToken = sp<BBinder>::make(); }
 
     InputTransferToken(const sp<IBinder>& token) { mToken = token; }
 
@@ -50,4 +50,4 @@
     return token1->mToken == token2->mToken;
 }
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 1002614..d04b861 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -232,7 +232,6 @@
         ePictureProfileHandleChanged = 0x80000'00000000,
         eAppContentPriorityChanged = 0x100000'00000000,
         eClientDrawnCornerRadiusChanged = 0x200000'00000000,
-        eClientDrawnShadowsChanged = 0x400000'00000000,
     };
 
     layer_state_t();
@@ -276,7 +275,7 @@
             layer_state_t::eColorSpaceAgnosticChanged | layer_state_t::eColorTransformChanged |
             layer_state_t::eCornerRadiusChanged | layer_state_t::eDimmingEnabledChanged |
             layer_state_t::eHdrMetadataChanged | layer_state_t::eShadowRadiusChanged |
-            layer_state_t::eClientDrawnShadowsChanged | layer_state_t::eStretchChanged |
+            layer_state_t::eStretchChanged |
             layer_state_t::ePictureProfileHandleChanged | layer_state_t::eAppContentPriorityChanged;
 
     // Changes which invalidates the layer's visible region in CE.
@@ -336,7 +335,6 @@
     matrix22_t matrix;
     float cornerRadius;
     float clientDrawnCornerRadius;
-    float clientDrawnShadowRadius;
     uint32_t backgroundBlurRadius;
 
     sp<SurfaceControl> relativeLayerSurfaceControl;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index d30a830..10225cc 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -569,10 +569,6 @@
         // radius is drawn by the client and not SurfaceFlinger.
         Transaction& setClientDrawnCornerRadius(const sp<SurfaceControl>& sc,
                                                 float clientDrawnCornerRadius);
-        // Sets the client drawn shadow radius for the layer. This indicates that the shadows
-        // are drawn by the client and not SurfaceFlinger.
-        Transaction& setClientDrawnShadowRadius(const sp<SurfaceControl>& sc,
-                                                float clientDrawnShadowRadius);
         Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
                                              int backgroundBlurRadius);
         Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index a0d8c53..c35efe2 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -40,7 +40,7 @@
         std::unique_lock<decltype(mutex_)> lk(mutex_);
 
         auto check_event = [](auto const& ev) -> bool {
-            return ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+            return ev.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC;
         };
         DisplayEventReceiver::Event ev_;
         int evs = receiver_.getEvents(&ev_, 1);
diff --git a/libs/permission/Android.bp b/libs/permission/Android.bp
index 0eeca54..929f067 100644
--- a/libs/permission/Android.bp
+++ b/libs/permission/Android.bp
@@ -16,6 +16,7 @@
     double_loadable: true,
     srcs: [
         "aidl/android/content/AttributionSourceState.aidl",
+        "aidl/com/android/internal/app/IAppOpsCallback.aidl",
         "aidl/android/permission/IPermissionChecker.aidl",
     ],
 }
@@ -36,7 +37,6 @@
     ],
     srcs: [
         "AppOpsManager.cpp",
-        "IAppOpsCallback.cpp",
         "IAppOpsService.cpp",
         "android/permission/PermissionChecker.cpp",
     ],
diff --git a/libs/permission/IAppOpsCallback.cpp b/libs/permission/IAppOpsCallback.cpp
deleted file mode 100644
index 2b3f462..0000000
--- a/libs/permission/IAppOpsCallback.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AppOpsCallback"
-
-#include <binder/IAppOpsCallback.h>
-
-#include <utils/Log.h>
-#include <binder/Parcel.h>
-#include <utils/String8.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class BpAppOpsCallback : public BpInterface<IAppOpsCallback>
-{
-public:
-    explicit BpAppOpsCallback(const sp<IBinder>& impl)
-        : BpInterface<IAppOpsCallback>(impl)
-    {
-    }
-
-    virtual void opChanged(int32_t op, const String16& packageName) {
-        Parcel data, reply;
-        data.writeInterfaceToken(IAppOpsCallback::getInterfaceDescriptor());
-        data.writeInt32(op);
-        data.writeString16(packageName);
-        remote()->transact(OP_CHANGED_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(AppOpsCallback, "com.android.internal.app.IAppOpsCallback")
-
-// ----------------------------------------------------------------------
-
-// NOLINTNEXTLINE(google-default-arguments)
-status_t BnAppOpsCallback::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    switch(code) {
-        case OP_CHANGED_TRANSACTION: {
-            CHECK_INTERFACE(IAppOpsCallback, data, reply);
-            int32_t op = data.readInt32();
-            String16 packageName;
-            (void)data.readString16(&packageName);
-            opChanged(op, packageName);
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/RenderArea.cpp b/libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl
similarity index 61%
rename from services/surfaceflinger/RenderArea.cpp
rename to libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl
index 5fea521..36b19df 100644
--- a/services/surfaceflinger/RenderArea.cpp
+++ b/libs/permission/aidl/com/android/internal/app/IAppOpsCallback.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,18 +14,8 @@
  * limitations under the License.
  */
 
-#include "RenderArea.h"
+package com.android.internal.app;
 
-namespace android {
-
-float RenderArea::getCaptureFillValue(CaptureFill captureFill) {
-    switch(captureFill) {
-        case CaptureFill::CLEAR:
-            return 0.0f;
-        case CaptureFill::OPAQUE:
-        default:
-            return 1.0f;
-    }
+oneway interface IAppOpsCallback {
+    void opChanged(int op, int uid, String packageName, String persistentDeviceId);
 }
-
-} // namespace android
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index 7e179d6..a22c975 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -180,10 +180,10 @@
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage,
             const std::optional<String16>& attributionTag);
     void startWatchingMode(int32_t op, const String16& packageName,
-            const sp<IAppOpsCallback>& callback);
+            const sp<com::android::internal::app::IAppOpsCallback>& callback);
     void startWatchingMode(int32_t op, const String16& packageName, int32_t flags,
-            const sp<IAppOpsCallback>& callback);
-    void stopWatchingMode(const sp<IAppOpsCallback>& callback);
+            const sp<com::android::internal::app::IAppOpsCallback>& callback);
+    void stopWatchingMode(const sp<com::android::internal::app::IAppOpsCallback>& callback);
     int32_t permissionToOpCode(const String16& permission);
     void setCameraAudioRestriction(int32_t mode);
 
diff --git a/libs/permission/include/binder/IAppOpsCallback.h b/libs/permission/include/binder/IAppOpsCallback.h
deleted file mode 100644
index eb76f57..0000000
--- a/libs/permission/include/binder/IAppOpsCallback.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef __ANDROID_VNDK__
-
-#include <binder/IInterface.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------
-
-class IAppOpsCallback : public IInterface
-{
-public:
-    DECLARE_META_INTERFACE(AppOpsCallback)
-
-    virtual void opChanged(int32_t op, const String16& packageName) = 0;
-
-    enum {
-        OP_CHANGED_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
-    };
-};
-
-// ----------------------------------------------------------------------
-
-class BnAppOpsCallback : public BnInterface<IAppOpsCallback>
-{
-public:
-    // NOLINTNEXTLINE(google-default-arguments)
-    virtual status_t    onTransact( uint32_t code,
-                                    const Parcel& data,
-                                    Parcel* reply,
-                                    uint32_t flags = 0);
-};
-
-// ----------------------------------------------------------------------
-
-} // namespace android
-
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
diff --git a/libs/permission/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
index 918fcdb..1468fd9 100644
--- a/libs/permission/include/binder/IAppOpsService.h
+++ b/libs/permission/include/binder/IAppOpsService.h
@@ -16,7 +16,8 @@
 
 #pragma once
 
-#include <binder/IAppOpsCallback.h>
+#include <com/android/internal/app/IAppOpsCallback.h>
+#include <com/android/internal/app/BnAppOpsCallback.h>
 #include <binder/IInterface.h>
 
 #include <optional>
@@ -27,6 +28,8 @@
 
 namespace android {
 
+using IAppOpsCallback = ::com::android::internal::app::IAppOpsCallback;
+
 // ----------------------------------------------------------------------
 
 class IAppOpsService : public IInterface
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index 17ab29f..e296283 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -7,4 +7,3 @@
 lpy@google.com
 nscobie@google.com
 sallyqi@google.com
-scroggo@google.com
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
index 897f5cf..ff96b08 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.cpp
@@ -39,12 +39,36 @@
 namespace skia {
 
 KawaseBlurDualFilter::KawaseBlurDualFilter() : BlurFilter() {
-    // A shader to sample each vertex of a unit regular heptagon
-    // plus the original fragment coordinate.
-    SkString blurString(R"(
+    // A shader to sample each vertex of a square, plus the original fragment coordinate,
+    // using a total of 5 samples.
+    SkString lowSampleBlurString(R"(
         uniform shader child;
         uniform float in_blurOffset;
         uniform float in_crossFade;
+        uniform float in_weightedCrossFade;
+
+        const float2 STEP_0 = float2( 0.707106781, 0.707106781);
+        const float2 STEP_1 = float2( 0.707106781, -0.707106781);
+        const float2 STEP_2 = float2(-0.707106781, -0.707106781);
+        const float2 STEP_3 = float2(-0.707106781, 0.707106781);
+
+        half4 main(float2 xy) {
+            half3 c = child.eval(xy).rgb;
+
+            c += child.eval(xy + STEP_0 * in_blurOffset).rgb;
+            c += child.eval(xy + STEP_1 * in_blurOffset).rgb;
+            c += child.eval(xy + STEP_2 * in_blurOffset).rgb;
+            c += child.eval(xy + STEP_3 * in_blurOffset).rgb;
+
+            return half4(c * in_weightedCrossFade, in_crossFade);
+        }
+    )");
+
+    // A shader to sample each vertex of a unit regular heptagon, plus the original fragment
+    // coordinate, using a total of 8 samples.
+    SkString highSampleBlurString(R"(
+        uniform shader child;
+        uniform float in_blurOffset;
 
         const float2 STEP_0 = float2( 1.0, 0.0);
         const float2 STEP_1 = float2( 0.623489802,  0.781831482);
@@ -65,39 +89,46 @@
             c += child.eval(xy + STEP_5 * in_blurOffset).rgb;
             c += child.eval(xy + STEP_6 * in_blurOffset).rgb;
 
-            return half4(c * 0.125 * in_crossFade, in_crossFade);
+            return half4(c * 0.125, 1.0);
         }
     )");
 
-    auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
-    LOG_ALWAYS_FATAL_IF(!blurEffect, "RuntimeShader error: %s", error.c_str());
-    mBlurEffect = std::move(blurEffect);
+    auto [lowSampleBlurEffect, error] = SkRuntimeEffect::MakeForShader(lowSampleBlurString);
+    auto [highSampleBlurEffect, error2] = SkRuntimeEffect::MakeForShader(highSampleBlurString);
+    LOG_ALWAYS_FATAL_IF(!lowSampleBlurEffect, "RuntimeShader error: %s", error.c_str());
+    LOG_ALWAYS_FATAL_IF(!highSampleBlurEffect, "RuntimeShader error: %s", error2.c_str());
+    mLowSampleBlurEffect = std::move(lowSampleBlurEffect);
+    mHighSampleBlurEffect = std::move(highSampleBlurEffect);
 }
 
 void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface,
                                     const sk_sp<SkImage>& readImage, const float radius,
-                                    const float alpha) const {
+                                    const float alpha,
+                                    const sk_sp<SkRuntimeEffect>& blurEffect) const {
     const float scale = static_cast<float>(drawSurface->width()) / readImage->width();
     SkMatrix blurMatrix = SkMatrix::Scale(scale, scale);
     blurInto(drawSurface,
              readImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                    SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
                                    blurMatrix),
-             readImage->width() / static_cast<float>(drawSurface->width()), radius, alpha);
+             radius, alpha, blurEffect);
 }
 
 void KawaseBlurDualFilter::blurInto(const sk_sp<SkSurface>& drawSurface, sk_sp<SkShader> input,
-                                    const float inverseScale, const float radius,
-                                    const float alpha) const {
+                                    const float radius, const float alpha,
+                                    const sk_sp<SkRuntimeEffect>& blurEffect) const {
     SkPaint paint;
     if (radius == 0) {
         paint.setShader(std::move(input));
         paint.setAlphaf(alpha);
     } else {
-        SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
+        SkRuntimeShaderBuilder blurBuilder(blurEffect);
         blurBuilder.child("child") = std::move(input);
+        if (blurEffect == mLowSampleBlurEffect) {
+            blurBuilder.uniform("in_crossFade") = alpha;
+            blurBuilder.uniform("in_weightedCrossFade") = alpha * 0.2f;
+        }
         blurBuilder.uniform("in_blurOffset") = radius;
-        blurBuilder.uniform("in_crossFade") = alpha;
         paint.setShader(blurBuilder.makeShader(nullptr));
     }
     paint.setBlendMode(alpha == 1.0f ? SkBlendMode::kSrc : SkBlendMode::kSrcOver);
@@ -163,16 +194,19 @@
                 input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
                                   SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
                                   blurMatrix);
-        blurInto(surfaces[0], std::move(sourceShader), kInputScale, kWeights[0] * step, 1.0f);
+        blurInto(surfaces[0], std::move(sourceShader), kWeights[0] * step, 1.0f,
+                 mLowSampleBlurEffect);
     }
     // Next the remaining downscale blur passes.
     for (int i = 0; i < filterPasses; i++) {
-        blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f);
+        // Blur with the higher sample effect into the smaller buffers, for better visual quality.
+        blurInto(surfaces[i + 1], surfaces[i]->makeTemporaryImage(), kWeights[1 + i] * step, 1.0f,
+                 i == 0 ? mLowSampleBlurEffect : mHighSampleBlurEffect);
     }
     // Finally blur+upscale back to our original size.
     for (int i = filterPasses - 1; i >= 0; i--) {
         blurInto(surfaces[i], surfaces[i + 1]->makeTemporaryImage(), kWeights[4 - i] * step,
-                 std::min(1.0f, filterDepth - i));
+                 std::min(1.0f, filterDepth - i), mLowSampleBlurEffect);
     }
     return surfaces[0]->makeTemporaryImage();
 }
diff --git a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
index 6f4adbf..5efda35 100644
--- a/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
+++ b/libs/renderengine/skia/filters/KawaseBlurDualFilter.h
@@ -41,13 +41,14 @@
                             const sk_sp<SkImage> blurInput, const SkRect& blurRect) const override;
 
 private:
-    sk_sp<SkRuntimeEffect> mBlurEffect;
+    sk_sp<SkRuntimeEffect> mLowSampleBlurEffect;
+    sk_sp<SkRuntimeEffect> mHighSampleBlurEffect;
 
     void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkImage>& readImage,
-                  const float radius, const float alpha) const;
+                  const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
 
     void blurInto(const sk_sp<SkSurface>& drawSurface, const sk_sp<SkShader> input,
-                  const float inverseScale, const float radius, const float alpha) const;
+                  const float radius, const float alpha, const sk_sp<SkRuntimeEffect>&) const;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp
index 10218bb..f262158 100644
--- a/libs/renderengine/skia/filters/LutShader.cpp
+++ b/libs/renderengine/skia/filters/LutShader.cpp
@@ -182,8 +182,8 @@
      * (R1, G1, B1, 0)
      * ...
      */
-    SkImageInfo info = SkImageInfo::Make(length /* the number of rgba */ * 4, 1,
-                                         kRGBA_F16_SkColorType, kPremul_SkAlphaType);
+    SkImageInfo info = SkImageInfo::Make(length /* the number of rgba */, 1, kRGBA_F16_SkColorType,
+                                         kPremul_SkAlphaType);
     SkBitmap bitmap;
     bitmap.allocPixels(info);
     if (!bitmap.installPixels(info, buffer.data(), info.minRowBytes())) {
diff --git a/libs/shaders/OWNERS b/libs/shaders/OWNERS
index 6d91da3..6977a49 100644
--- a/libs/shaders/OWNERS
+++ b/libs/shaders/OWNERS
@@ -1,4 +1,3 @@
 alecmouri@google.com
 jreck@google.com
 sallyqi@google.com
-scroggo@google.com
\ No newline at end of file
diff --git a/libs/tonemap/OWNERS b/libs/tonemap/OWNERS
index 6d91da3..6977a49 100644
--- a/libs/tonemap/OWNERS
+++ b/libs/tonemap/OWNERS
@@ -1,4 +1,3 @@
 alecmouri@google.com
 jreck@google.com
 sallyqi@google.com
-scroggo@google.com
\ No newline at end of file
diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp
index b7ef9b3..78e84fc 100644
--- a/libs/ui/DisplayIdentification.cpp
+++ b/libs/ui/DisplayIdentification.cpp
@@ -444,7 +444,7 @@
             (edid.hashedBlockZeroSerialNumberOpt.value_or(0) >> 11) ^
             (edid.hashedDescriptorBlockSerialNumberOpt.value_or(0) << 23);
 
-    return PhysicalDisplayId::fromEdidHash(id);
+    return PhysicalDisplayId::fromValue(id);
 }
 
 } // namespace android
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index a0b5fe7..2a85a4b 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -2,6 +2,5 @@
 alecmouri@google.com
 chrisforbes@google.com
 jreck@google.com
-lpy@google.com
 mathias@google.com
 romainguy@google.com
diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h
index 13ed754..937e3f1 100644
--- a/libs/ui/include/ui/DisplayId.h
+++ b/libs/ui/include/ui/DisplayId.h
@@ -30,27 +30,16 @@
     // Flag indicating that the display is virtual.
     static constexpr uint64_t FLAG_VIRTUAL = 1ULL << 63;
 
-    // TODO(b/162612135) Remove default constructor
+    // TODO: b/162612135 - Remove default constructor.
     DisplayId() = default;
     constexpr DisplayId(const DisplayId&) = default;
     DisplayId& operator=(const DisplayId&) = default;
 
+    static constexpr DisplayId fromValue(uint64_t value) { return DisplayId(value); }
     constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; }
 
     uint64_t value;
 
-    // For deserialization.
-    static constexpr std::optional<DisplayId> fromValue(uint64_t);
-
-    // As above, but also upcast to Id.
-    template <typename Id>
-    static constexpr std::optional<Id> fromValue(uint64_t value) {
-        if (const auto id = Id::tryCast(DisplayId(value))) {
-            return id;
-        }
-        return {};
-    }
-
 protected:
     explicit constexpr DisplayId(uint64_t id) : value(id) {}
 };
@@ -74,6 +63,9 @@
 
 // DisplayId of a physical display, such as the internal display or externally connected display.
 struct PhysicalDisplayId : DisplayId {
+    // TODO: b/162612135 - Remove default constructor.
+    PhysicalDisplayId() = default;
+
     static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) {
         if (id.isVirtual()) {
             return std::nullopt;
@@ -87,11 +79,6 @@
         return PhysicalDisplayId(FLAG_STABLE, port, manufacturerId, modelHash);
     }
 
-    // Returns a stable and consistent ID based exclusively on EDID information.
-    static constexpr PhysicalDisplayId fromEdidHash(uint64_t hashedEdid) {
-        return PhysicalDisplayId(hashedEdid);
-    }
-
     // Returns an unstable ID. If EDID is available using "fromEdid" is preferred.
     static constexpr PhysicalDisplayId fromPort(uint8_t port) {
         constexpr uint16_t kManufacturerId = 0;
@@ -99,8 +86,9 @@
         return PhysicalDisplayId(0, port, kManufacturerId, kModelHash);
     }
 
-    // TODO(b/162612135) Remove default constructor
-    PhysicalDisplayId() = default;
+    static constexpr PhysicalDisplayId fromValue(uint64_t value) {
+        return PhysicalDisplayId(value);
+    }
 
     constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); }
 
@@ -131,8 +119,15 @@
         return std::nullopt;
     }
 
+    static constexpr VirtualDisplayId fromValue(uint64_t value) {
+        return VirtualDisplayId(SkipVirtualFlag{}, value);
+    }
+
 protected:
+    struct SkipVirtualFlag {};
+    constexpr VirtualDisplayId(SkipVirtualFlag, uint64_t value) : DisplayId(value) {}
     explicit constexpr VirtualDisplayId(uint64_t value) : DisplayId(FLAG_VIRTUAL | value) {}
+
     explicit constexpr VirtualDisplayId(DisplayId other) : DisplayId(other) {}
 };
 
@@ -146,8 +141,12 @@
         return std::nullopt;
     }
 
+    static constexpr HalVirtualDisplayId fromValue(uint64_t value) {
+        return HalVirtualDisplayId(SkipVirtualFlag{}, value);
+    }
+
 private:
-    explicit constexpr HalVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {}
+    using VirtualDisplayId::VirtualDisplayId;
 };
 
 struct GpuVirtualDisplayId : VirtualDisplayId {
@@ -160,8 +159,12 @@
         return std::nullopt;
     }
 
+    static constexpr GpuVirtualDisplayId fromValue(uint64_t value) {
+        return GpuVirtualDisplayId(SkipVirtualFlag{}, value);
+    }
+
 private:
-    explicit constexpr GpuVirtualDisplayId(DisplayId other) : VirtualDisplayId(other) {}
+    using VirtualDisplayId::VirtualDisplayId;
 };
 
 // HalDisplayId is the ID of a display which is managed by HWC.
@@ -177,20 +180,13 @@
         return HalDisplayId(id);
     }
 
+    static constexpr HalDisplayId fromValue(uint64_t value) { return HalDisplayId(value); }
+
 private:
+    using DisplayId::DisplayId;
     explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {}
 };
 
-constexpr std::optional<DisplayId> DisplayId::fromValue(uint64_t value) {
-    if (const auto id = fromValue<PhysicalDisplayId>(value)) {
-        return id;
-    }
-    if (const auto id = fromValue<VirtualDisplayId>(value)) {
-        return id;
-    }
-    return {};
-}
-
 static_assert(sizeof(DisplayId) == sizeof(uint64_t));
 static_assert(sizeof(HalDisplayId) == sizeof(uint64_t));
 static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t));
diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h
index 06be6db..c0b83b8 100644
--- a/libs/ui/include/ui/ShadowSettings.h
+++ b/libs/ui/include/ui/ShadowSettings.h
@@ -46,9 +46,6 @@
     // Length of the cast shadow. If length is <= 0.f no shadows will be drawn.
     float length = 0.f;
 
-    // Length of the cast shadow that is drawn by the client.
-    float clientDrawnLength = 0.f;
-
     // If true fill in the casting layer is translucent and the shadow needs to fill the bounds.
     // Otherwise the shadow will only be drawn around the edges of the casting layer.
     bool casterIsTranslucent = false;
@@ -58,7 +55,6 @@
     return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor &&
             lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos &&
             lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length &&
-            lhs.clientDrawnLength == rhs.clientDrawnLength &&
             lhs.casterIsTranslucent == rhs.casterIsTranslucent;
 }
 
diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp
index 090d2ee..209acba 100644
--- a/libs/ui/tests/DisplayId_test.cpp
+++ b/libs/ui/tests/DisplayId_test.cpp
@@ -33,7 +33,7 @@
     EXPECT_TRUE(HalDisplayId::tryCast(id));
 
     EXPECT_EQ(id, DisplayId::fromValue(id.value));
-    EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
+    EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value));
 }
 
 TEST(DisplayIdTest, createPhysicalIdFromPort) {
@@ -47,7 +47,7 @@
     EXPECT_TRUE(HalDisplayId::tryCast(id));
 
     EXPECT_EQ(id, DisplayId::fromValue(id.value));
-    EXPECT_EQ(id, DisplayId::fromValue<PhysicalDisplayId>(id.value));
+    EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value));
 }
 
 TEST(DisplayIdTest, createGpuVirtualId) {
@@ -59,7 +59,7 @@
     EXPECT_FALSE(HalDisplayId::tryCast(id));
 
     EXPECT_EQ(id, DisplayId::fromValue(id.value));
-    EXPECT_EQ(id, DisplayId::fromValue<GpuVirtualDisplayId>(id.value));
+    EXPECT_EQ(id, GpuVirtualDisplayId::fromValue(id.value));
 }
 
 TEST(DisplayIdTest, createVirtualIdFromGpuVirtualId) {
@@ -83,7 +83,7 @@
     EXPECT_TRUE(HalDisplayId::tryCast(id));
 
     EXPECT_EQ(id, DisplayId::fromValue(id.value));
-    EXPECT_EQ(id, DisplayId::fromValue<HalVirtualDisplayId>(id.value));
+    EXPECT_EQ(id, HalVirtualDisplayId::fromValue(id.value));
 }
 
 TEST(DisplayIdTest, createVirtualIdFromHalVirtualId) {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 5fe9484..0dd9f19 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -134,6 +134,11 @@
 
     if (cnx->egl.eglGetPlatformDisplay) {
         std::vector<EGLAttrib> attrs;
+        // These must have the same lifetime as |attrs|, because |attrs| contains pointers to these
+        // variables.
+        std::vector<const char*> enabled;  // ANGLE features to enable
+        std::vector<const char*> disabled; // ANGLE features to disable
+
         if (attrib_list) {
             for (const EGLAttrib* attr = attrib_list; *attr != EGL_NONE; attr += 2) {
                 attrs.push_back(attr[0]);
@@ -142,9 +147,6 @@
         }
 
         if (graphicsenv_flags::feature_overrides()) {
-            std::vector<const char*> enabled;  // ANGLE features to enable
-            std::vector<const char*> disabled; // ANGLE features to disable
-
             // Get the list of ANGLE features to enable from Global.Settings.
             const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
             for (const std::string& eglFeature : eglFeatures) {
@@ -154,25 +156,24 @@
             // Get the list of ANGLE features to enable/disable from gpuservice.
             GraphicsEnv::getInstance().getAngleFeatureOverrides(enabled, disabled);
             if (!enabled.empty()) {
-                enabled.push_back(0);
+                enabled.push_back(nullptr);
                 attrs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
                 attrs.push_back(reinterpret_cast<EGLAttrib>(enabled.data()));
             }
             if (!disabled.empty()) {
-                disabled.push_back(0);
+                disabled.push_back(nullptr);
                 attrs.push_back(EGL_FEATURE_OVERRIDES_DISABLED_ANGLE);
                 attrs.push_back(reinterpret_cast<EGLAttrib>(disabled.data()));
             }
         } else {
             const auto& eglFeatures = GraphicsEnv::getInstance().getAngleEglFeatures();
-            std::vector<const char*> features;
-            if (eglFeatures.size() > 0) {
+            if (!eglFeatures.empty()) {
                 for (const std::string& eglFeature : eglFeatures) {
-                    features.push_back(eglFeature.c_str());
+                    enabled.push_back(eglFeature.c_str());
                 }
-                features.push_back(0);
+                enabled.push_back(nullptr);
                 attrs.push_back(EGL_FEATURE_OVERRIDES_ENABLED_ANGLE);
-                attrs.push_back(reinterpret_cast<EGLAttrib>(features.data()));
+                attrs.push_back(reinterpret_cast<EGLAttrib>(enabled.data()));
             }
         }
 
diff --git a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
index 7c255ed..5ba72af 100644
--- a/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglCreateWindowSurface.cpp
@@ -113,7 +113,7 @@
     if (producer == NULL)
         goto not_valid_surface;
 
-    window = new android::Surface(producer, true);
+    window = android::sp<android::Surface>::make(producer, true);
 
     if (window == NULL)
         goto not_valid_surface;
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index d205231..afa6233 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -34,10 +34,8 @@
     sp<IBinder> displayToken = nullptr;
     sp<SurfaceControl> surfaceControl = nullptr;
     if (it == mDisplays.end()) {
-        if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
-            displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
-        }
-
+        displayToken =
+                SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id));
         if (displayToken == nullptr) {
             ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
             return nullptr;
@@ -160,11 +158,8 @@
     HwDisplayConfig activeConfig;
     HwDisplayState  activeState;
 
-    sp<IBinder> displayToken;
-    if (const auto displayId = DisplayId::fromValue<PhysicalDisplayId>(id)) {
-        displayToken = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
-    }
-
+    sp<IBinder> displayToken =
+            SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId::fromValue(id));
     if (displayToken == nullptr) {
         ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
     } else {
@@ -197,4 +192,3 @@
 }  // namespace automotive
 }  // namespace frameworks
 }  // namespace android
-
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
index 5c7f344..e96b17a 100644
--- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -2,3 +2,4 @@
     class hal
     user graphics
     group automotive_evs
+    disabled
diff --git a/services/displayservice/DisplayEventReceiver.cpp b/services/displayservice/DisplayEventReceiver.cpp
index 2bb74c2..9927fb6 100644
--- a/services/displayservice/DisplayEventReceiver.cpp
+++ b/services/displayservice/DisplayEventReceiver.cpp
@@ -22,6 +22,7 @@
 #include <android/frameworks/displayservice/1.0/BpHwEventCallback.h>
 
 #include <thread>
+#include <ftl/enum.h>
 
 namespace android {
 namespace frameworks {
@@ -97,11 +98,11 @@
         for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
             const FwkReceiver::Event &event = buf[i];
 
-            uint32_t type = event.header.type;
+            android::DisplayEventType type = event.header.type;
             uint64_t timestamp = event.header.timestamp;
 
             switch(buf[i].header.type) {
-                case FwkReceiver::DISPLAY_EVENT_VSYNC: {
+                case DisplayEventType::DISPLAY_EVENT_VSYNC: {
                     auto ret = mCallback->onVsync(timestamp, event.vsync.count);
                     if (!ret.isOk()) {
                         LOG(ERROR) << "AttachedEvent handleEvent fails on onVsync callback"
@@ -109,7 +110,7 @@
                         return 0;  // remove the callback
                     }
                 } break;
-                case FwkReceiver::DISPLAY_EVENT_HOTPLUG: {
+                case DisplayEventType::DISPLAY_EVENT_HOTPLUG: {
                     auto ret = mCallback->onHotplug(timestamp, event.hotplug.connected);
                     if (!ret.isOk()) {
                         LOG(ERROR) << "AttachedEvent handleEvent fails on onHotplug callback"
@@ -118,7 +119,8 @@
                     }
                 } break;
                 default: {
-                    LOG(ERROR) << "AttachedEvent handleEvent unknown type: " << type;
+                    LOG(ERROR) << "AttachedEvent handleEvent unknown type: "
+                                << ftl::to_underlying(type);
                 }
             }
         }
diff --git a/services/displayservice/OWNERS b/services/displayservice/OWNERS
index 7a3e4c2..40164aa 100644
--- a/services/displayservice/OWNERS
+++ b/services/displayservice/OWNERS
@@ -1,2 +1 @@
 smoreland@google.com
-lpy@google.com
diff --git a/services/gpuservice/feature_override/Android.bp b/services/gpuservice/feature_override/Android.bp
index cda67f0..3b5407b 100644
--- a/services/gpuservice/feature_override/Android.bp
+++ b/services/gpuservice/feature_override/Android.bp
@@ -34,9 +34,7 @@
         "libbase",
         "libgraphicsenv",
         "liblog",
-    ],
-    static_libs: [
-        "libprotobuf-cpp-lite-ndk",
+        "libprotobuf-cpp-lite",
     ],
 }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index c1ddb6a..f42c368 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -798,20 +798,6 @@
     return !isFromSource(source, AINPUT_SOURCE_MOUSE);
 }
 
-/**
- * Return true if stylus is currently down anywhere on the specified display, and false otherwise.
- */
-bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId,
-                             const std::unordered_map<ui::LogicalDisplayId /*displayId*/,
-                                                      TouchState>& touchStatesByDisplay) {
-    const auto it = touchStatesByDisplay.find(displayId);
-    if (it == touchStatesByDisplay.end()) {
-        return false;
-    }
-    const TouchState& state = it->second;
-    return state.hasActiveStylus();
-}
-
 Result<void> validateWindowInfosUpdate(const gui::WindowInfosUpdate& update) {
     std::unordered_set<int32_t> windowIds;
     for (const WindowInfo& info : update.windowInfos) {
@@ -1155,9 +1141,7 @@
 
     // If dispatching is frozen, do not process timeouts or try to deliver any new events.
     if (mDispatchFrozen) {
-        if (DEBUG_FOCUS) {
-            ALOGD("Dispatch frozen.  Waiting some more.");
-        }
+        LOG_IF(DEBUG, DEBUG_FOCUS) << "Dispatch frozen.  Waiting some more.";
         return;
     }
 
@@ -1350,9 +1334,8 @@
 
         // Alternatively, maybe there's a spy window that could handle this event.
         const std::vector<sp<WindowInfoHandle>> touchedSpies =
-                mWindowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus,
-                                                     motionEntry.deviceId,
-                                                     mTouchStates.mTouchStatesByDisplay);
+                findTouchedSpyWindowsAt(displayId, x, y, isStylus, motionEntry.deviceId,
+                                        mWindowInfos);
         for (const auto& windowHandle : touchedSpies) {
             const std::shared_ptr<Connection> connection =
                     mConnectionManager.getConnection(windowHandle->getToken());
@@ -1510,16 +1493,16 @@
     return outsideTargets;
 }
 
-std::vector<sp<WindowInfoHandle>> InputDispatcher::DispatcherWindowInfo::findTouchedSpyWindowsAt(
+std::vector<sp<WindowInfoHandle>> InputDispatcher::findTouchedSpyWindowsAt(
         ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
-        const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) const {
+        const DispatcherWindowInfo& windowInfos) {
     // Traverse windows from front to back and gather the touched spy windows.
     std::vector<sp<WindowInfoHandle>> spyWindows;
-    const auto& windowHandles = getWindowHandlesForDisplay(displayId);
+    const ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId);
+    const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId);
     for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
         const WindowInfo& info = *windowHandle->getInfo();
-        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus,
-                                  getDisplayTransform(displayId))) {
+        if (!windowAcceptsTouchAt(info, displayId, x, y, isStylus, displayTransform)) {
             // Skip if the pointer is outside of the window.
             continue;
         }
@@ -1536,9 +1519,8 @@
     const char* reason;
     switch (dropReason) {
         case DropReason::POLICY:
-            if (debugInboundEventDetails()) {
-                ALOGD("Dropped event because policy consumed it.");
-            }
+            LOG_IF(DEBUG, debugInboundEventDetails())
+                    << "Dropped event because policy consumed it.";
             reason = "inbound event was dropped because the policy consumed it";
             break;
         case DropReason::DISABLED:
@@ -1652,9 +1634,7 @@
 void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<const EventEntry> entry) {
     const std::shared_ptr<InjectionState>& injectionState = entry->injectionState;
     if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
-        if (DEBUG_DISPATCH_CYCLE) {
-            ALOGD("Injected inbound event was dropped.");
-        }
+        LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE) << "Injected inbound event was dropped.";
         setInjectionResult(*entry, InputEventInjectionResult::FAILED);
     }
     if (entry == mNextUnblockedEvent) {
@@ -1694,10 +1674,9 @@
 
 bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
                                                 const DeviceResetEntry& entry) {
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
-              entry.deviceId);
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << "dispatchDeviceReset - eventTime=" << entry.eventTime
+            << ", deviceId=" << entry.deviceId;
 
     // Reset key repeating in case a keyboard device was disabled or enabled.
     if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->deviceId == entry.deviceId) {
@@ -1889,9 +1868,8 @@
         } else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
                    mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
             // The key on device 'deviceId' is still down, do not stop key repeat
-            if (debugInboundEventDetails()) {
-                ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
-            }
+            LOG_IF(DEBUG, debugInboundEventDetails())
+                    << "deviceId=" << entry->deviceId << " got KEY_UP as stale";
         } else if (!entry->syntheticRepeat) {
             resetKeyRepeatLocked();
         }
@@ -1988,25 +1966,24 @@
 }
 
 void InputDispatcher::logOutboundKeyDetails(const char* prefix, const KeyEntry& entry) {
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%s, "
-              "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
-              "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
-              prefix, entry.eventTime, entry.deviceId, entry.source,
-              entry.displayId.toString().c_str(), entry.policyFlags, entry.action, entry.flags,
-              entry.keyCode, entry.scanCode, entry.metaState, entry.repeatCount, entry.downTime);
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << prefix << "eventTime=" << entry.eventTime << ", deviceId=" << entry.deviceId
+            << ", source=0x" << std::hex << entry.source
+            << ", displayId=" << entry.displayId.toString() << ", policyFlags=0x"
+            << entry.policyFlags << ", action=0x" << entry.action << ", flags=0x" << entry.flags
+            << ", keyCode=0x" << entry.keyCode << ", scanCode=0x" << entry.scanCode
+            << ", metaState=0x" << entry.metaState << ", repeatCount=" << std::dec
+            << entry.repeatCount << ", downTime=" << entry.downTime;
 }
 
 void InputDispatcher::dispatchSensorLocked(nsecs_t currentTime,
                                            const std::shared_ptr<const SensorEntry>& entry,
                                            DropReason* dropReason, nsecs_t& nextWakeupTime) {
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("notifySensorEvent eventTime=%" PRId64 ", hwTimestamp=%" PRId64 ", deviceId=%d, "
-              "source=0x%x, sensorType=%s",
-              entry->eventTime, entry->hwTimestamp, entry->deviceId, entry->source,
-              ftl::enum_string(entry->sensorType).c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << "notifySensorEvent eventTime=" << entry->eventTime
+            << ", hwTimestamp=" << entry->hwTimestamp << ", deviceId=" << entry->deviceId
+            << ", source=0x" << std::hex << entry->source << std::dec
+            << ", sensorType=" << ftl::enum_string(entry->sensorType);
     auto command = [this, entry]() REQUIRES(mLock) {
         scoped_unlock unlock(mLock);
 
@@ -2020,10 +1997,9 @@
 }
 
 bool InputDispatcher::flushSensor(int deviceId, InputDeviceSensorType sensorType) {
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("flushSensor deviceId=%d, sensorType=%s", deviceId,
-              ftl::enum_string(sensorType).c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << "flushSensor deviceId=" << deviceId
+            << ", sensorType=" << ftl::enum_string(sensorType).c_str();
     { // acquire lock
         std::scoped_lock _l(mLock);
 
@@ -2193,9 +2169,7 @@
                                           std::shared_ptr<const EventEntry> eventEntry,
                                           const std::vector<InputTarget>& inputTargets) {
     ATRACE_CALL();
-    if (DEBUG_DISPATCH_CYCLE) {
-        ALOGD("dispatchEventToCurrentInputTargets");
-    }
+    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE) << "dispatchEventToCurrentInputTargets";
 
     processInteractionsLocked(*eventEntry, inputTargets);
 
@@ -2238,9 +2212,7 @@
 }
 
 void InputDispatcher::resetNoFocusedWindowTimeoutLocked() {
-    if (DEBUG_FOCUS) {
-        ALOGD("Resetting ANR timeouts.");
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "Resetting ANR timeouts.";
 
     // Reset input target wait timeout.
     mNoFocusedWindowTimeoutTime = std::nullopt;
@@ -2480,8 +2452,7 @@
         }
 
         std::vector<sp<WindowInfoHandle>> newTouchedWindows =
-                windowInfos.findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId,
-                                                    mTouchStatesByDisplay);
+                findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, windowInfos);
         if (newTouchedWindowHandle != nullptr) {
             // Process the foreground window first so that it is the first to receive the event.
             newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
@@ -2494,8 +2465,7 @@
         }
 
         for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
-            if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos,
-                                        mTouchStatesByDisplay)) {
+            if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos)) {
                 continue;
             }
 
@@ -2576,11 +2546,10 @@
         // If the pointer is not currently down, then ignore the event.
         if (!tempTouchState.isDown(entry.deviceId) &&
             maskedAction != AMOTION_EVENT_ACTION_HOVER_EXIT) {
-            if (DEBUG_DROPPED_EVENTS_VERBOSE) {
-                LOG(INFO) << "Dropping event because the pointer for device " << entry.deviceId
-                          << " is not down or we previously dropped the pointer down event in "
-                          << "display " << displayId << ": " << entry.getDescription();
-            }
+            LOG_IF(INFO, DEBUG_DROPPED_EVENTS_VERBOSE)
+                    << "Dropping event because the pointer for device " << entry.deviceId
+                    << " is not down or we previously dropped the pointer down event in display "
+                    << displayId << ": " << entry.getDescription();
             return injectionError(InputEventInjectionResult::FAILED);
         }
 
@@ -2618,8 +2587,7 @@
 
             // Do not slide events to the window which can not receive motion event
             if (newTouchedWindowHandle != nullptr &&
-                !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos,
-                                        mTouchStatesByDisplay)) {
+                !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos)) {
                 newTouchedWindowHandle = nullptr;
             }
 
@@ -3261,10 +3229,9 @@
                 return;
             }
             if (windowDisablingUserActivityInfo != nullptr) {
-                if (DEBUG_DISPATCH_CYCLE) {
-                    ALOGD("Not poking user activity: disabled by window '%s'.",
-                          windowDisablingUserActivityInfo->name.c_str());
-                }
+                LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+                        << "Not poking user activity: disabled by window '"
+                        << windowDisablingUserActivityInfo->name << "'.";
                 return;
             }
             break;
@@ -3278,10 +3245,9 @@
             // the apps, like system shortcuts
             if (windowDisablingUserActivityInfo != nullptr &&
                 keyEntry.interceptKeyResult != KeyEntry::InterceptKeyResult::SKIP) {
-                if (DEBUG_DISPATCH_CYCLE) {
-                    ALOGD("Not poking user activity: disabled by window '%s'.",
-                          windowDisablingUserActivityInfo->name.c_str());
-                }
+                LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+                        << "Not poking user activity: disabled by window '"
+                        << windowDisablingUserActivityInfo->name << "'.";
                 return;
             }
             break;
@@ -3309,22 +3275,19 @@
     ATRACE_NAME_IF(ATRACE_ENABLED(),
                    StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
                                 connection->getInputChannelName().c_str(), eventEntry->id));
-    if (DEBUG_DISPATCH_CYCLE) {
-        ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
-              "globalScaleFactor=%f, pointerIds=%s %s",
-              connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
-              inputTarget.globalScaleFactor, bitsetToString(inputTarget.getPointerIds()).c_str(),
-              inputTarget.getPointerInfoString().c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+            << "channel '" << connection->getInputChannelName()
+            << "' ~ prepareDispatchCycle - flags=" << inputTarget.flags.string()
+            << ", globalScaleFactor=" << inputTarget.globalScaleFactor
+            << ", pointerIds=" << bitsetToString(inputTarget.getPointerIds()) << " "
+            << inputTarget.getPointerInfoString();
 
     // Skip this event if the connection status is not normal.
     // We don't want to enqueue additional outbound events if the connection is broken.
     if (connection->status != Connection::Status::NORMAL) {
-        if (DEBUG_DISPATCH_CYCLE) {
-            ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
-                  connection->getInputChannelName().c_str(),
-                  ftl::enum_string(connection->status).c_str());
-        }
+        LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE) << "channel '" << connection->getInputChannelName()
+                                            << "' ~ Dropping event because the channel status is "
+                                            << ftl::enum_string(connection->status);
         return;
     }
 
@@ -3443,11 +3406,10 @@
                 if (resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE &&
                     !connection->inputState.isHovering(motionEntry.deviceId, motionEntry.source,
                                                        motionEntry.displayId)) {
-                    if (DEBUG_DISPATCH_CYCLE) {
-                        LOG(DEBUG) << "channel '" << connection->getInputChannelName().c_str()
-                                   << "' ~ enqueueDispatchEntryLocked: filling in missing hover "
-                                      "enter event";
-                    }
+                    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+                            << "channel '" << connection->getInputChannelName().c_str()
+                            << "' ~ enqueueDispatchEntryLocked: filling in missing hover enter "
+                               "event";
                     resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
                 }
 
@@ -3741,9 +3703,8 @@
     ATRACE_NAME_IF(ATRACE_ENABLED(),
                    StringPrintf("startDispatchCycleLocked(inputChannel=%s)",
                                 connection->getInputChannelName().c_str()));
-    if (DEBUG_DISPATCH_CYCLE) {
-        ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+            << "channel '" << connection->getInputChannelName() << "' ~ startDispatchCycle";
 
     while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
         std::unique_ptr<DispatchEntry>& dispatchEntry = connection->outboundQueue.front();
@@ -3758,10 +3719,9 @@
             case EventEntry::Type::KEY: {
                 const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
                 std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
-                if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                    LOG(INFO) << "Publishing " << *dispatchEntry << " to "
-                              << connection->getInputChannelName();
-                }
+                LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+                        << "Publishing " << *dispatchEntry << " to "
+                        << connection->getInputChannelName();
 
                 // Publish the key event.
                 status = connection->inputPublisher
@@ -3780,10 +3740,9 @@
             }
 
             case EventEntry::Type::MOTION: {
-                if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                    LOG(INFO) << "Publishing " << *dispatchEntry << " to "
-                              << connection->getInputChannelName();
-                }
+                LOG_IF(INFO, DEBUG_OUTBOUND_EVENT_DETAILS)
+                        << "Publishing " << *dispatchEntry << " to "
+                        << connection->getInputChannelName();
                 const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
                 status = publishMotionEvent(*connection, *dispatchEntry);
                 if (status == BAD_VALUE) {
@@ -3856,11 +3815,10 @@
                 } else {
                     // Pipe is full and we are waiting for the app to finish process some events
                     // before sending more events to it.
-                    if (DEBUG_DISPATCH_CYCLE) {
-                        ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
-                              "waiting for the application to catch up",
-                              connection->getInputChannelName().c_str());
-                    }
+                    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+                            << "channel '" << connection->getInputChannelName()
+                            << "' ~ Could not publish event because the pipe is full, waiting for "
+                               "the application to catch up";
                 }
             } else {
                 ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
@@ -3926,10 +3884,9 @@
 void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                 const std::shared_ptr<Connection>& connection,
                                                 uint32_t seq, bool handled, nsecs_t consumeTime) {
-    if (DEBUG_DISPATCH_CYCLE) {
-        ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
-              connection->getInputChannelName().c_str(), seq, toString(handled));
-    }
+    LOG_IF(DEBUG, DEBUG_DISPATCH_CYCLE)
+            << "channel '" << connection->getInputChannelName()
+            << "' ~ finishDispatchCycle - seq=" << seq << ", handled=" << toString(handled);
 
     if (connection->status != Connection::Status::NORMAL) {
         return;
@@ -3944,10 +3901,8 @@
 
 void InputDispatcher::abortBrokenDispatchCycleLocked(const std::shared_ptr<Connection>& connection,
                                                      bool notify) {
-    if (DEBUG_DISPATCH_CYCLE) {
-        LOG(INFO) << "channel '" << connection->getInputChannelName() << "'~ " << __func__
-                  << " - notify=" << toString(notify);
-    }
+    LOG_IF(INFO, DEBUG_DISPATCH_CYCLE) << "channel '" << connection->getInputChannelName() << "'~ "
+                                       << __func__ << " - notify=" << toString(notify);
 
     // Clear the dispatch queues.
     drainDispatchQueue(connection->outboundQueue);
@@ -4072,13 +4027,17 @@
     // Generate cancellations for touched windows first. This is to avoid generating cancellations
     // through a non-touched window if there are more than one window for an input channel.
     if (cancelPointers) {
-        for (const auto& [displayId, touchState] : mTouchStates.mTouchStatesByDisplay) {
-            if (options.displayId.has_value() && options.displayId != displayId) {
-                continue;
-            }
-            for (const auto& touchedWindow : touchState.windows) {
-                synthesizeCancelationEventsForWindowLocked(touchedWindow.windowHandle, options);
-            }
+        if (options.displayId.has_value()) {
+            mTouchStates.forAllTouchedWindowsOnDisplay(
+                    options.displayId.value(), [&](const sp<gui::WindowInfoHandle>& windowHandle) {
+                        base::ScopedLockAssertion assumeLocked(mLock);
+                        synthesizeCancelationEventsForWindowLocked(windowHandle, options);
+                    });
+        } else {
+            mTouchStates.forAllTouchedWindows([&](const sp<gui::WindowInfoHandle>& windowHandle) {
+                base::ScopedLockAssertion assumeLocked(mLock);
+                synthesizeCancelationEventsForWindowLocked(windowHandle, options);
+            });
         }
     }
     // Follow up by generating cancellations for all windows, because we don't explicitly track
@@ -4149,12 +4108,11 @@
         return;
     }
 
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync "
-              "with reality: %s, mode=%s.",
-              connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,
-              ftl::enum_string(options.mode).c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << "channel '" << connection->getInputChannelName() << "' ~ Synthesized "
+            << cancelationEvents.size()
+            << " cancelation events to bring channel back in sync with reality: " << options.reason
+            << ", mode=" << ftl::enum_string(options.mode) << ".";
 
     std::string reason = std::string("reason=").append(options.reason);
     android_log_event_list(LOGTAG_INPUT_CANCEL)
@@ -4271,18 +4229,17 @@
         return;
     }
 
-    if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-        ALOGD("channel '%s' ~ Synthesized %zu down events to ensure consistent event stream.",
-              connection->getInputChannelName().c_str(), downEvents.size());
-    }
+    LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+            << "channel '" << connection->getInputChannelName() << "' ~ Synthesized "
+            << downEvents.size() << " down events to ensure consistent event stream.";
 
-    const auto [_, touchedWindowState, displayId] =
-            findTouchStateWindowAndDisplay(connection->getToken(),
-                                           mTouchStates.mTouchStatesByDisplay);
-    if (touchedWindowState == nullptr) {
+    auto touchedWindowHandleAndDisplay =
+            mTouchStates.findTouchedWindowHandleAndDisplay(connection->getToken());
+    if (!touchedWindowHandleAndDisplay.has_value()) {
         LOG(FATAL) << __func__ << ": Touch state is out of sync: No touched window for token";
     }
-    const auto& windowHandle = touchedWindowState->windowHandle;
+
+    const auto [windowHandle, displayId] = touchedWindowHandleAndDisplay.value();
 
     const bool wasEmpty = connection->outboundQueue.empty();
     for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
@@ -4414,15 +4371,15 @@
 }
 
 void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {
-    ALOGD_IF(debugInboundEventDetails(),
-             "notifyKey - id=%" PRIx32 ", eventTime=%" PRId64
-             ", deviceId=%d, source=%s, displayId=%s, policyFlags=0x%x, action=%s, flags=0x%x, "
-             "keyCode=%s, scanCode=0x%x, metaState=0x%x, "
-             "downTime=%" PRId64,
-             args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),
-             args.displayId.toString().c_str(), args.policyFlags,
-             KeyEvent::actionToString(args.action), args.flags, KeyEvent::getLabel(args.keyCode),
-             args.scanCode, args.metaState, args.downTime);
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifyKey - id=" << args.id << ", eventTime=" << args.eventTime
+            << ", deviceId=" << args.deviceId
+            << ", source=" << inputEventSourceToString(args.source)
+            << ", displayId=" << args.displayId.toString() << ", policyFlags=0x" << std::hex
+            << args.policyFlags << ", action=" << KeyEvent::actionToString(args.action)
+            << ", flags=0x" << args.flags << ", keyCode=" << KeyEvent::getLabel(args.keyCode)
+            << ", scanCode=0x" << args.scanCode << ", metaState=0x" << args.metaState
+            << ", downTime=" << std::dec << args.downTime;
     Result<void> keyCheck = validateKeyEvent(args.action);
     if (!keyCheck.ok()) {
         LOG(ERROR) << "invalid key event: " << keyCheck.error();
@@ -4632,12 +4589,10 @@
 }
 
 void InputDispatcher::notifySensor(const NotifySensorArgs& args) {
-    if (debugInboundEventDetails()) {
-        ALOGD("notifySensor - id=%" PRIx32 " eventTime=%" PRId64 ", deviceId=%d, source=0x%x, "
-              " sensorType=%s",
-              args.id, args.eventTime, args.deviceId, args.source,
-              ftl::enum_string(args.sensorType).c_str());
-    }
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifySensor - id=" << args.id << " eventTime=" << args.eventTime
+            << ", deviceId=" << args.deviceId << ", source=0x" << std::hex << args.source
+            << std::dec << ", sensorType=" << ftl::enum_string(args.sensorType);
 
     bool needWake = false;
     { // acquire lock
@@ -4659,10 +4614,9 @@
 }
 
 void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs& args) {
-    if (debugInboundEventDetails()) {
-        ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d,  isOn=%d", args.eventTime,
-              args.deviceId, args.isOn);
-    }
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifyVibratorState - eventTime=" << args.eventTime << ", device=" << args.deviceId
+            << ", isOn=" << args.isOn;
     mPolicy.notifyVibratorState(args.deviceId, args.isOn);
 }
 
@@ -4671,11 +4625,10 @@
 }
 
 void InputDispatcher::notifySwitch(const NotifySwitchArgs& args) {
-    if (debugInboundEventDetails()) {
-        ALOGD("notifySwitch - eventTime=%" PRId64 ", policyFlags=0x%x, switchValues=0x%08x, "
-              "switchMask=0x%08x",
-              args.eventTime, args.policyFlags, args.switchValues, args.switchMask);
-    }
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifySwitch - eventTime=" << args.eventTime << ", policyFlags=0x" << std::hex
+            << args.policyFlags << ", switchValues=0x" << std::setfill('0') << std::setw(8)
+            << args.switchValues << ", switchMask=0x" << std::setw(8) << args.switchMask;
 
     uint32_t policyFlags = args.policyFlags;
     policyFlags |= POLICY_FLAG_TRUSTED;
@@ -4684,10 +4637,8 @@
 
 void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) {
     // TODO(b/308677868) Remove device reset from the InputListener interface
-    if (debugInboundEventDetails()) {
-        ALOGD("notifyDeviceReset - eventTime=%" PRId64 ", deviceId=%d", args.eventTime,
-              args.deviceId);
-    }
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifyDeviceReset - eventTime=" << args.eventTime << ", deviceId=" << args.deviceId;
 
     bool needWake = false;
     { // acquire lock
@@ -4708,10 +4659,9 @@
 }
 
 void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) {
-    if (debugInboundEventDetails()) {
-        ALOGD("notifyPointerCaptureChanged - eventTime=%" PRId64 ", enabled=%s", args.eventTime,
-              args.request.isEnable() ? "true" : "false");
-    }
+    LOG_IF(DEBUG, debugInboundEventDetails())
+            << "notifyPointerCaptureChanged - eventTime=%" << args.eventTime
+            << ", enabled=" << toString(args.request.isEnable());
 
     bool needWake = false;
     { // acquire lock
@@ -4771,12 +4721,10 @@
         return InputEventInjectionResult::FAILED;
     }
 
-    if (debugInboundEventDetails()) {
-        LOG(INFO) << __func__ << ": targetUid=" << toString(targetUid, &uidString)
-                  << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
-                  << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec
-                  << ", event=" << *event;
-    }
+    LOG_IF(INFO, debugInboundEventDetails())
+            << __func__ << ": targetUid=" << toString(targetUid, &uidString)
+            << ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
+            << "ms, policyFlags=0x" << std::hex << policyFlags << std::dec << ", event=" << *event;
     nsecs_t endTime = now() + std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count();
 
     policyFlags |= POLICY_FLAG_INJECTED | POLICY_FLAG_TRUSTED;
@@ -4953,9 +4901,7 @@
 
     bool needWake = false;
     while (!injectedEntries.empty()) {
-        if (DEBUG_INJECTION) {
-            LOG(INFO) << "Injecting " << injectedEntries.front()->getDescription();
-        }
+        LOG_IF(INFO, DEBUG_INJECTION) << "Injecting " << injectedEntries.front()->getDescription();
         needWake |= enqueueInboundEventLocked(std::move(injectedEntries.front()));
         injectedEntries.pop();
     }
@@ -4981,10 +4927,8 @@
 
                 nsecs_t remainingTimeout = endTime - now();
                 if (remainingTimeout <= 0) {
-                    if (DEBUG_INJECTION) {
-                        ALOGD("injectInputEvent - Timed out waiting for injection result "
-                              "to become available.");
-                    }
+                    LOG_IF(DEBUG, DEBUG_INJECTION) << "injectInputEvent - Timed out waiting for "
+                                                      "injection result to become available.";
                     injectionResult = InputEventInjectionResult::TIMED_OUT;
                     break;
                 }
@@ -4995,16 +4939,14 @@
             if (injectionResult == InputEventInjectionResult::SUCCEEDED &&
                 syncMode == InputEventInjectionSync::WAIT_FOR_FINISHED) {
                 while (injectionState->pendingForegroundDispatches != 0) {
-                    if (DEBUG_INJECTION) {
-                        ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.",
-                              injectionState->pendingForegroundDispatches);
-                    }
+                    LOG_IF(DEBUG, DEBUG_INJECTION) << "injectInputEvent - Waiting for "
+                                                   << injectionState->pendingForegroundDispatches
+                                                   << " pending foreground dispatches.";
                     nsecs_t remainingTimeout = endTime - now();
                     if (remainingTimeout <= 0) {
-                        if (DEBUG_INJECTION) {
-                            ALOGD("injectInputEvent - Timed out waiting for pending foreground "
-                                  "dispatches to finish.");
-                        }
+                        LOG_IF(DEBUG, DEBUG_INJECTION)
+                                << "injectInputEvent - Timed out waiting for pending foreground "
+                                   "dispatches to finish.";
                         injectionResult = InputEventInjectionResult::TIMED_OUT;
                         break;
                     }
@@ -5015,10 +4957,8 @@
         }
     } // release lock
 
-    if (DEBUG_INJECTION) {
-        LOG(INFO) << "injectInputEvent - Finished with result "
-                  << ftl::enum_string(injectionResult);
-    }
+    LOG_IF(INFO, DEBUG_INJECTION) << "injectInputEvent - Finished with result "
+                                  << ftl::enum_string(injectionResult);
 
     return injectionResult;
 }
@@ -5064,10 +5004,8 @@
     }
 
     InjectionState& injectionState = *entry.injectionState;
-    if (DEBUG_INJECTION) {
-        LOG(INFO) << "Setting input event injection result to "
-                  << ftl::enum_string(injectionResult);
-    }
+    LOG_IF(INFO, DEBUG_INJECTION) << "Setting input event injection result to "
+                                  << ftl::enum_string(injectionResult);
 
     if (injectionState.injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
         // Log the outcome since the injector did not wait for the injection result.
@@ -5273,11 +5211,10 @@
     return dump;
 }
 
-bool InputDispatcher::canWindowReceiveMotion(
+bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion(
         const sp<android::gui::WindowInfoHandle>& window,
         const android::inputdispatcher::MotionEntry& motionEntry,
-        const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
-        const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates) {
+        const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos) const {
     const WindowInfo& info = *window->getInfo();
 
     // Skip spy window targets that are not valid for targeted injection.
@@ -5331,7 +5268,7 @@
 
     // Ignore touches if stylus is down anywhere on screen
     if (info.inputConfig.test(WindowInfo::InputConfig::GLOBAL_STYLUS_BLOCKS_TOUCH) &&
-        isStylusActiveInDisplay(info.displayId, touchStates)) {
+        isStylusActiveInDisplay(info.displayId)) {
         LOG(INFO) << "Dropping touch from " << window->getName() << " because stylus is active";
         return false;
     }
@@ -5495,9 +5432,7 @@
     // which might not happen until the next GC.
     for (const sp<WindowInfoHandle>& oldWindowHandle : oldWindowHandles) {
         if (!mWindowInfos.isWindowPresent(oldWindowHandle)) {
-            if (DEBUG_FOCUS) {
-                ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
-            }
+            LOG_IF(DEBUG, DEBUG_FOCUS) << "Window went away: " << oldWindowHandle->getName();
             oldWindowHandle->releaseChannel();
         }
     }
@@ -5530,7 +5465,7 @@
         LOG(INFO) << "Touched window was removed: " << touchedWindow.windowHandle->getName()
                   << " in display %" << displayId;
         cancellations.emplace_back(touchedWindow.windowHandle,
-                                   CancelationOptions::Mode::CANCEL_POINTER_EVENTS, std::nullopt);
+                                   CancelationOptions::Mode::CANCEL_POINTER_EVENTS);
         // Since we are about to drop the touch, cancel the events for the wallpaper as well.
         if (touchedWindow.targetFlags.test(InputTarget::Flags::FOREGROUND) &&
             touchedWindow.windowHandle->getInfo()->inputConfig.test(
@@ -5576,10 +5511,9 @@
 void InputDispatcher::setFocusedApplication(
         ui::LogicalDisplayId displayId,
         const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
-    if (DEBUG_FOCUS) {
-        ALOGD("setFocusedApplication displayId=%s %s", displayId.toString().c_str(),
-              inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "setFocusedApplication displayId=" << displayId.toString() << " "
+                               << (inputApplicationHandle ? inputApplicationHandle->getName()
+                                                          : "<nullptr>");
     { // acquire lock
         std::scoped_lock _l(mLock);
         setFocusedApplicationLocked(displayId, inputApplicationHandle);
@@ -5629,9 +5563,7 @@
  * display. The display-specified events won't be affected.
  */
 void InputDispatcher::setFocusedDisplay(ui::LogicalDisplayId displayId) {
-    if (DEBUG_FOCUS) {
-        ALOGD("setFocusedDisplay displayId=%s", displayId.toString().c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "setFocusedDisplay displayId=" << displayId.toString();
     { // acquire lock
         std::scoped_lock _l(mLock);
         ScopedSyntheticEventTracer traceContext(mTracer);
@@ -5685,9 +5617,8 @@
 }
 
 void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
-    if (DEBUG_FOCUS) {
-        ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "setInputDispatchMode: enabled=" << enabled
+                               << ", frozen=" << frozen;
 
     bool changed;
     { // acquire lock
@@ -5717,9 +5648,7 @@
 }
 
 void InputDispatcher::setInputFilterEnabled(bool enabled) {
-    if (DEBUG_FOCUS) {
-        ALOGD("setInputFilterEnabled: enabled=%d", enabled);
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "setInputFilterEnabled: enabled=" << enabled;
 
     { // acquire lock
         std::scoped_lock _l(mLock);
@@ -5741,14 +5670,16 @@
     bool needWake = false;
     {
         std::scoped_lock lock(mLock);
-        ALOGD_IF(DEBUG_TOUCH_MODE,
-                 "Request to change touch mode to %s (calling pid=%s, uid=%s, "
-                 "hasPermission=%s, target displayId=%s, mTouchModePerDisplay[displayId]=%s)",
-                 toString(inTouchMode), pid.toString().c_str(), uid.toString().c_str(),
-                 toString(hasPermission), displayId.toString().c_str(),
-                 mTouchModePerDisplay.count(displayId) == 0
-                         ? "not set"
-                         : std::to_string(mTouchModePerDisplay[displayId]).c_str());
+        LOG_IF(DEBUG, DEBUG_TOUCH_MODE)
+                << "Request to change touch mode to " << toString(inTouchMode)
+                << " (calling pid=" << pid.toString() << ", uid=" << uid.toString()
+                << ", hasPermission=" << toString(hasPermission)
+                << ", target displayId=" << displayId.toString()
+                << ", mTouchModePerDisplay[displayId]="
+                << (mTouchModePerDisplay.count(displayId) == 0
+                            ? "not set"
+                            : std::to_string(mTouchModePerDisplay[displayId]))
+                << ")";
 
         auto touchModeIt = mTouchModePerDisplay.find(displayId);
         if (touchModeIt != mTouchModePerDisplay.end() && touchModeIt->second == inTouchMode) {
@@ -5798,92 +5729,43 @@
     mWindowInfos.setMaximumObscuringOpacityForTouch(opacity);
 }
 
-std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId>
-InputDispatcher::findTouchStateWindowAndDisplay(
-        const sp<IBinder>& token,
-        const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) {
-    for (auto& [displayId, state] : touchStatesByDisplay) {
-        for (const TouchedWindow& w : state.windows) {
-            if (w.windowHandle->getToken() == token) {
-                return std::make_tuple(&state, &w, displayId);
-            }
-        }
-    }
-    return std::make_tuple(nullptr, nullptr, ui::LogicalDisplayId::DEFAULT);
-}
-
-std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId>
-InputDispatcher::findTouchStateWindowAndDisplay(
-        const sp<IBinder>& token,
-        std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay) {
-    auto [constTouchState, constTouchedWindow, displayId] = InputDispatcher::
-            findTouchStateWindowAndDisplay(token,
-                                           const_cast<const std::unordered_map<ui::LogicalDisplayId,
-                                                                               TouchState>&>(
-                                                   touchStatesByDisplay));
-
-    return std::make_tuple(const_cast<TouchState*>(constTouchState),
-                           const_cast<TouchedWindow*>(constTouchedWindow), displayId);
-}
-
 bool InputDispatcher::transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
                                            bool isDragDrop) {
     if (fromToken == toToken) {
-        if (DEBUG_FOCUS) {
-            ALOGD("Trivial transfer to same window.");
-        }
+        LOG_IF(DEBUG, DEBUG_FOCUS) << "Trivial transfer to same window.";
         return true;
     }
 
     { // acquire lock
         std::scoped_lock _l(mLock);
 
-        // Find the target touch state and touched window by fromToken.
-        auto [state, touchedWindow, displayId] =
-                findTouchStateWindowAndDisplay(fromToken, mTouchStates.mTouchStatesByDisplay);
+        ScopedSyntheticEventTracer traceContext(mTracer);
+        CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+                                   "transferring touch from this window to another window",
+                                   traceContext.getTracker());
 
-        if (state == nullptr || touchedWindow == nullptr) {
-            ALOGD("Touch transfer failed because from window is not being touched.");
-            return false;
-        }
-        std::set<DeviceId> deviceIds = touchedWindow->getTouchingDeviceIds();
-        if (deviceIds.size() != 1) {
-            LOG(INFO) << "Can't transfer touch. Currently touching devices: "
-                      << dumpContainer(deviceIds) << " for window: " << touchedWindow->dump();
-            return false;
-        }
-        const DeviceId deviceId = *deviceIds.begin();
-
-        const sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
-        const sp<WindowInfoHandle> toWindowHandle =
-                mWindowInfos.findWindowHandle(toToken, displayId);
-        if (!toWindowHandle) {
-            ALOGW("Cannot transfer touch because the transfer target window was not found.");
+        auto result = mTouchStates.transferTouchGesture(fromToken, toToken, mWindowInfos,
+                                                        mConnectionManager);
+        if (!result.has_value()) {
             return false;
         }
 
-        if (DEBUG_FOCUS) {
-            ALOGD("%s: fromWindowHandle=%s, toWindowHandle=%s", __func__,
-                  touchedWindow->windowHandle->getName().c_str(),
-                  toWindowHandle->getName().c_str());
+        const auto& [toWindowHandle, deviceId, pointers, cancellations, pointerDowns] =
+                result.value();
+
+        for (const auto& cancellationArgs : cancellations) {
+            LOG_ALWAYS_FATAL_IF(cancellationArgs.mode !=
+                                CancelationOptions::Mode::CANCEL_POINTER_EVENTS);
+            LOG_ALWAYS_FATAL_IF(cancellationArgs.deviceId.has_value());
+            synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, options);
         }
 
-        // Erase old window.
-        ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
-        std::vector<PointerProperties> pointers = touchedWindow->getTouchingPointers(deviceId);
-        state->removeWindowByToken(fromToken);
-
-        // Add new window.
-        nsecs_t downTimeInTarget = now();
-        ftl::Flags<InputTarget::Flags> newTargetFlags =
-                oldTargetFlags & (InputTarget::Flags::SPLIT);
-        if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
-            newTargetFlags |= InputTarget::Flags::FOREGROUND;
+        for (const auto& pointerDownArgs : pointerDowns) {
+            synthesizePointerDownEventsForConnectionLocked(pointerDownArgs.downTimeInTarget,
+                                                           pointerDownArgs.connection,
+                                                           pointerDownArgs.targetFlags,
+                                                           traceContext.getTracker());
         }
-        // Transferring touch focus using this API should not effect the focused window.
-        newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE;
-        state->addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags,
-                                 deviceId, pointers, downTimeInTarget);
 
         // Store the dragging window.
         if (isDragDrop) {
@@ -5896,30 +5778,6 @@
             const size_t id = pointers.begin()->id;
             mDragState = std::make_unique<DragState>(toWindowHandle, deviceId, id);
         }
-
-        // Synthesize cancel for old window and down for new window.
-        ScopedSyntheticEventTracer traceContext(mTracer);
-        std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken);
-        std::shared_ptr<Connection> toConnection = mConnectionManager.getConnection(toToken);
-        if (fromConnection != nullptr && toConnection != nullptr) {
-            fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
-            CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
-                                       "transferring touch from this window to another window",
-                                       traceContext.getTracker());
-            synthesizeCancelationEventsForWindowLocked(fromWindowHandle, options, fromConnection);
-
-            // Check if the wallpaper window should deliver the corresponding event.
-            transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
-                                   *state, deviceId, pointers, traceContext.getTracker());
-
-            // Because new window may have a wallpaper window, it will merge input state from it
-            // parent window, after this the firstNewPointerIdx in input state will be reset, then
-            // it will cause new move event be thought inconsistent, so we should synthesize the
-            // down event after it reset.
-            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
-                                                           newTargetFlags,
-                                                           traceContext.getTracker());
-        }
     } // release lock
 
     // Wake up poll loop since it may need to make new input dispatching choices.
@@ -5927,6 +5785,83 @@
     return true;
 }
 
+std::optional<std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>,
+                         std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>,
+                         std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>>
+InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken,
+                                                            const sp<android::IBinder>& toToken,
+                                                            const DispatcherWindowInfo& windowInfos,
+                                                            const ConnectionManager& connections) {
+    // Find the target touch state and touched window by fromToken.
+    auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken);
+    if (!touchStateWindowAndDisplay.has_value()) {
+        ALOGD("Touch transfer failed because from window is not being touched.");
+        return std::nullopt;
+    }
+
+    auto [state, touchedWindow, displayId] = touchStateWindowAndDisplay.value();
+    std::set<DeviceId> deviceIds = touchedWindow.getTouchingDeviceIds();
+    if (deviceIds.size() != 1) {
+        LOG(INFO) << "Can't transfer touch. Currently touching devices: "
+                  << dumpContainer(deviceIds) << " for window: " << touchedWindow.dump();
+        return std::nullopt;
+    }
+    const DeviceId deviceId = *deviceIds.begin();
+
+    const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle;
+    const sp<WindowInfoHandle> toWindowHandle = windowInfos.findWindowHandle(toToken, displayId);
+    if (!toWindowHandle) {
+        ALOGW("Cannot transfer touch because the transfer target window was not found.");
+        return std::nullopt;
+    }
+
+    LOG_IF(DEBUG, DEBUG_FOCUS) << __func__ << ": fromWindowHandle=" << fromWindowHandle->getName()
+                               << ", toWindowHandle=" << toWindowHandle->getName();
+
+    // Erase old window.
+    ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow.targetFlags;
+    std::vector<PointerProperties> pointers = touchedWindow.getTouchingPointers(deviceId);
+    state.removeWindowByToken(fromToken);
+
+    // Add new window.
+    nsecs_t downTimeInTarget = now();
+    ftl::Flags<InputTarget::Flags> newTargetFlags = oldTargetFlags & (InputTarget::Flags::SPLIT);
+    if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
+        newTargetFlags |= InputTarget::Flags::FOREGROUND;
+    }
+    // Transferring touch focus using this API should not effect the focused window.
+    newTargetFlags |= InputTarget::Flags::NO_FOCUS_CHANGE;
+    state.addOrUpdateWindow(toWindowHandle, InputTarget::DispatchMode::AS_IS, newTargetFlags,
+                            deviceId, pointers, downTimeInTarget);
+
+    // Synthesize cancel for old window and down for new window.
+    std::shared_ptr<Connection> fromConnection = connections.getConnection(fromToken);
+    std::shared_ptr<Connection> toConnection = connections.getConnection(toToken);
+    std::list<CancellationArgs> cancellations;
+    std::list<PointerDownArgs> pointerDowns;
+    if (fromConnection != nullptr && toConnection != nullptr) {
+        fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
+        cancellations.emplace_back(fromWindowHandle,
+                                   CancelationOptions::Mode::CANCEL_POINTER_EVENTS);
+
+        // Check if the wallpaper window should deliver the corresponding event.
+        auto [wallpaperCancellations, wallpaperPointerDowns] =
+                transferWallpaperTouch(fromWindowHandle, toWindowHandle, state, deviceId, pointers,
+                                       oldTargetFlags, newTargetFlags, windowInfos, connections);
+
+        cancellations.splice(cancellations.end(), wallpaperCancellations);
+        pointerDowns.splice(pointerDowns.end(), wallpaperPointerDowns);
+
+        // Because new window may have a wallpaper window, it will merge input state from it
+        // parent window, after this the firstNewPointerIdx in input state will be reset, then
+        // it will cause new move event be thought inconsistent, so we should synthesize the
+        // down event after it reset.
+        pointerDowns.emplace_back(downTimeInTarget, toConnection, newTargetFlags);
+    }
+
+    return std::make_tuple(toWindowHandle, deviceId, pointers, cancellations, pointerDowns);
+}
+
 /**
  * Get the touched foreground window on the given display.
  * Return null if there are no windows touched on that display, or if more than one foreground
@@ -5984,9 +5919,7 @@
 }
 
 void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
-    if (DEBUG_FOCUS) {
-        ALOGD("Resetting and dropping all events (%s).", reason);
-    }
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "Resetting and dropping all events (" << reason << ").";
 
     ScopedSyntheticEventTracer traceContext(mTracer);
     CancelationOptions options(CancelationOptions::Mode::CANCEL_ALL_EVENTS, reason,
@@ -6141,9 +6074,7 @@
 };
 
 Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
-    if (DEBUG_CHANNEL_CREATION) {
-        ALOGD("channel '%s' ~ createInputChannel", name.c_str());
-    }
+    LOG_IF(DEBUG, DEBUG_CHANNEL_CREATION) << "channel '" << name << "' ~ createInputChannel";
 
     std::unique_ptr<InputChannel> serverChannel;
     std::unique_ptr<InputChannel> clientChannel;
@@ -6259,43 +6190,62 @@
         return BAD_VALUE;
     }
 
-    auto [statePtr, windowPtr, displayId] =
-            findTouchStateWindowAndDisplay(token, mTouchStates.mTouchStatesByDisplay);
-    if (statePtr == nullptr || windowPtr == nullptr) {
-        LOG(WARNING)
-                << "Attempted to pilfer points from a channel without any on-going pointer streams."
-                   " Ignoring.";
-        return BAD_VALUE;
-    }
-    std::set<int32_t> deviceIds = windowPtr->getTouchingDeviceIds();
-    if (deviceIds.empty()) {
-        LOG(WARNING) << "Can't pilfer: no touching devices in window: " << windowPtr->dump();
-        return BAD_VALUE;
+    const auto result = mTouchStates.pilferPointers(token, *requestingConnection);
+    if (!result.ok()) {
+        return result.error().code();
     }
 
     ScopedSyntheticEventTracer traceContext(mTracer);
+    CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+                               "input channel stole pointer stream", traceContext.getTracker());
+    const auto cancellations = *result;
+    for (const auto& cancellationArgs : cancellations) {
+        LOG_ALWAYS_FATAL_IF(cancellationArgs.mode !=
+                            CancelationOptions::Mode::CANCEL_POINTER_EVENTS);
+        options.displayId = cancellationArgs.displayId;
+        options.deviceId = cancellationArgs.deviceId;
+        options.pointerIds = cancellationArgs.pointerIds;
+        synthesizeCancelationEventsForWindowLocked(cancellationArgs.windowHandle, options);
+    }
+    return OK;
+}
+
+base::Result<std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>, status_t>
+InputDispatcher::DispatcherTouchState::pilferPointers(const sp<IBinder>& token,
+                                                      const Connection& requestingConnection) {
+    auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(token);
+    if (!touchStateWindowAndDisplay.has_value()) {
+        LOG(WARNING)
+                << "Attempted to pilfer points from a channel without any on-going pointer streams."
+                   " Ignoring.";
+        return Error(BAD_VALUE);
+    }
+
+    auto [state, window, displayId] = touchStateWindowAndDisplay.value();
+
+    std::set<int32_t> deviceIds = window.getTouchingDeviceIds();
+    if (deviceIds.empty()) {
+        LOG(WARNING) << "Can't pilfer: no touching devices in window: " << window.dump();
+        return Error(BAD_VALUE);
+    }
+
+    std::list<CancellationArgs> cancellations;
     for (const DeviceId deviceId : deviceIds) {
-        TouchState& state = *statePtr;
-        TouchedWindow& window = *windowPtr;
         // Send cancel events to all the input channels we're stealing from.
-        CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
-                                   "input channel stole pointer stream", traceContext.getTracker());
-        options.deviceId = deviceId;
-        options.displayId = displayId;
         std::vector<PointerProperties> pointers = window.getTouchingPointers(deviceId);
         std::bitset<MAX_POINTER_ID + 1> pointerIds = getPointerIds(pointers);
-        options.pointerIds = pointerIds;
-
         std::string canceledWindows;
         for (const TouchedWindow& w : state.windows) {
             if (w.windowHandle->getToken() != token) {
-                synthesizeCancelationEventsForWindowLocked(w.windowHandle, options);
+                cancellations.emplace_back(w.windowHandle,
+                                           CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+                                           deviceId, displayId, pointerIds);
                 canceledWindows += canceledWindows.empty() ? "[" : ", ";
                 canceledWindows += w.windowHandle->getName();
             }
         }
         canceledWindows += canceledWindows.empty() ? "[]" : "]";
-        LOG(INFO) << "Channel " << requestingConnection->getInputChannelName()
+        LOG(INFO) << "Channel " << requestingConnection.getInputChannelName()
                   << " is stealing input gesture for device " << deviceId << " from "
                   << canceledWindows;
 
@@ -6305,7 +6255,7 @@
 
         state.cancelPointersForWindowsExcept(deviceId, pointerIds, token);
     }
-    return OK;
+    return cancellations;
 }
 
 void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) {
@@ -6675,12 +6625,11 @@
         // then cancel the associated fallback key, if any.
         if (fallbackKeyCode) {
             // Dispatch the unhandled key to the policy with the cancel flag.
-            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                ALOGD("Unhandled key event: Asking policy to cancel fallback action.  "
-                      "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                      keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount,
-                      keyEntry.policyFlags);
-            }
+            LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+                    << "Unhandled key event: Asking policy to cancel fallback action.  keyCode="
+                    << keyEntry.keyCode << ", action=" << keyEntry.action
+                    << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+                    << keyEntry.policyFlags;
             KeyEvent event = createKeyEvent(keyEntry);
             event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
 
@@ -6717,21 +6666,22 @@
         // Then ask the policy what to do with it.
         bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
         if (!fallbackKeyCode && !initialDown) {
-            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                ALOGD("Unhandled key event: Skipping unhandled key event processing "
-                      "since this is not an initial down.  "
-                      "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                      originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-            }
+            LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+                    << "Unhandled key event: Skipping unhandled key event processing since this is "
+                       "not an initial down.  keyCode="
+                    << originalKeyCode << ", action=" << keyEntry.action
+                    << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+                    << keyEntry.policyFlags;
             return {};
         }
 
         // Dispatch the unhandled key to the policy.
-        if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-            ALOGD("Unhandled key event: Asking policy to perform fallback action.  "
-                  "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                  keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
-        }
+        LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+                << "Unhandled key event: Asking policy to perform fallback action.  keyCode="
+                << keyEntry.keyCode << ", action=" << keyEntry.action
+                << ", repeatCount=" << keyEntry.repeatCount << ", policyFlags=0x" << std::hex
+                << keyEntry.policyFlags;
+        ;
         KeyEvent event = createKeyEvent(keyEntry);
 
         mLock.unlock();
@@ -6828,16 +6778,13 @@
                 newEntry->traceTracker =
                         mTracer->traceDerivedEvent(*newEntry, *keyEntry.traceTracker);
             }
-            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                ALOGD("Unhandled key event: Dispatching fallback key.  "
-                      "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
-                      originalKeyCode, *fallbackKeyCode, keyEntry.metaState);
-            }
+            LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS)
+                    << "Unhandled key event: Dispatching fallback key.  originalKeyCode="
+                    << originalKeyCode << ", fallbackKeyCode=" << *fallbackKeyCode
+                    << ", fallbackMetaState=0x" << std::hex << keyEntry.metaState;
             return newEntry;
         } else {
-            if (DEBUG_OUTBOUND_EVENT_DETAILS) {
-                ALOGD("Unhandled key event: No fallback key.");
-            }
+            LOG_IF(DEBUG, DEBUG_OUTBOUND_EVENT_DETAILS) << "Unhandled key event: No fallback key.";
 
             // Report the key as unhandled, since there is no fallback key.
             mReporter->reportUnhandledKey(keyEntry.id);
@@ -6978,7 +6925,7 @@
         return;
     }
 
-    ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus.");
+    LOG_IF(DEBUG, DEBUG_FOCUS) << "Disabling Pointer Capture because the window lost focus.";
 
     if (mCurrentPointerCaptureRequest.isEnable()) {
         setPointerCaptureLocked(nullptr);
@@ -7158,12 +7105,15 @@
     }
 }
 
-void InputDispatcher::transferWallpaperTouch(
+std::pair<std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>,
+          std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>
+InputDispatcher::DispatcherTouchState::transferWallpaperTouch(
+        const sp<gui::WindowInfoHandle> fromWindowHandle,
+        const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state,
+        android::DeviceId deviceId, const std::vector<PointerProperties>& pointers,
         ftl::Flags<InputTarget::Flags> oldTargetFlags,
-        ftl::Flags<InputTarget::Flags> newTargetFlags, const sp<WindowInfoHandle> fromWindowHandle,
-        const sp<WindowInfoHandle> toWindowHandle, TouchState& state, DeviceId deviceId,
-        const std::vector<PointerProperties>& pointers,
-        const std::unique_ptr<trace::EventTrackerInterface>& traceTracker) {
+        ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos,
+        const ConnectionManager& connections) {
     const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
             fromWindowHandle->getInfo()->inputConfig.test(
                     gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
@@ -7174,16 +7124,16 @@
     const sp<WindowInfoHandle> oldWallpaper =
             oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr;
     const sp<WindowInfoHandle> newWallpaper =
-            newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr;
+            newHasWallpaper ? windowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr;
     if (oldWallpaper == newWallpaper) {
-        return;
+        return {};
     }
 
+    std::list<CancellationArgs> cancellations;
+    std::list<PointerDownArgs> pointerDowns;
     if (oldWallpaper != nullptr) {
-        CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
-                                   "transferring touch focus to another window", traceTracker);
         state.removeWindowByToken(oldWallpaper->getToken());
-        synthesizeCancelationEventsForWindowLocked(oldWallpaper, options);
+        cancellations.emplace_back(oldWallpaper, CancelationOptions::Mode::CANCEL_POINTER_EVENTS);
     }
 
     if (newWallpaper != nullptr) {
@@ -7195,15 +7145,16 @@
         state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags,
                                 deviceId, pointers, downTimeInTarget);
         std::shared_ptr<Connection> wallpaperConnection =
-                mConnectionManager.getConnection(newWallpaper->getToken());
+                connections.getConnection(newWallpaper->getToken());
         if (wallpaperConnection != nullptr) {
             std::shared_ptr<Connection> toConnection =
-                    mConnectionManager.getConnection(toWindowHandle->getToken());
+                    connections.getConnection(toWindowHandle->getToken());
             toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
-            synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, wallpaperConnection,
-                                                           wallpaperFlags, traceTracker);
+            pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags);
         }
+        pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags);
     }
+    return {cancellations, pointerDowns};
 }
 
 sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWallpaperWindowBelow(
@@ -7251,6 +7202,12 @@
     }
 }
 
+void InputDispatcher::setDisplayTopology(
+        const android::DisplayTopologyGraph& displayTopologyGraph) {
+    std::scoped_lock _l(mLock);
+    mWindowInfos.setDisplayTopology(displayTopologyGraph);
+}
+
 InputDispatcher::ConnectionManager::ConnectionManager(const sp<android::Looper>& looper)
       : mLooper(looper) {}
 
@@ -7386,6 +7343,11 @@
     mMaximumObscuringOpacityForTouch = opacity;
 }
 
+void InputDispatcher::DispatcherWindowInfo::setDisplayTopology(
+        const DisplayTopologyGraph& displayTopologyGraph) {
+    mTopology = displayTopologyGraph;
+}
+
 ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetFlags(
         const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit,
         const DispatcherWindowInfo& windowInfos) {
@@ -7433,6 +7395,40 @@
     return false;
 }
 
+std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
+InputDispatcher::DispatcherTouchState::findTouchedWindowHandleAndDisplay(
+        const sp<android::IBinder>& token) const {
+    for (const auto& [displayId, state] : mTouchStatesByDisplay) {
+        for (const TouchedWindow& w : state.windows) {
+            if (w.windowHandle->getToken() == token) {
+                return std::make_tuple(std::ref(w.windowHandle), displayId);
+            }
+        }
+    }
+    return std::nullopt;
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchedWindows(
+        std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
+    for (const auto& [_, state] : mTouchStatesByDisplay) {
+        for (const TouchedWindow& window : state.windows) {
+            f(window.windowHandle);
+        }
+    }
+}
+
+void InputDispatcher::DispatcherTouchState::forAllTouchedWindowsOnDisplay(
+        ui::LogicalDisplayId displayId,
+        std::function<void(const sp<gui::WindowInfoHandle>&)> f) const {
+    const auto touchStateIt = mTouchStatesByDisplay.find(displayId);
+    if (touchStateIt == mTouchStatesByDisplay.end()) {
+        return;
+    }
+    for (const TouchedWindow& window : touchStateIt->second.windows) {
+        f(window.windowHandle);
+    }
+}
+
 std::string InputDispatcher::DispatcherTouchState::dump() const {
     std::string dump;
     if (!mTouchStatesByDisplay.empty()) {
@@ -7457,4 +7453,27 @@
     mTouchStatesByDisplay.clear();
 }
 
+std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
+InputDispatcher::DispatcherTouchState::findTouchStateWindowAndDisplay(
+        const sp<android::IBinder>& token) {
+    for (auto& [displayId, state] : mTouchStatesByDisplay) {
+        for (TouchedWindow& w : state.windows) {
+            if (w.windowHandle->getToken() == token) {
+                return std::make_tuple(std::ref(state), std::ref(w), displayId);
+            }
+        }
+    }
+    return std::nullopt;
+}
+
+bool InputDispatcher::DispatcherTouchState::isStylusActiveInDisplay(
+        ui::LogicalDisplayId displayId) const {
+    const auto it = mTouchStatesByDisplay.find(displayId);
+    if (it == mTouchStatesByDisplay.end()) {
+        return false;
+    }
+    const TouchState& state = it->second;
+    return state.hasActiveStylus();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f590806..e76bd89 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -164,6 +164,8 @@
 
     void setInputMethodConnectionIsActive(bool isActive) override;
 
+    void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) override;
+
 private:
     enum class DropReason {
         NOT_DROPPED,
@@ -291,6 +293,8 @@
 
         void setMaximumObscuringOpacityForTouch(float opacity);
 
+        void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph);
+
         // Get a reference to window handles by display, return an empty vector if not found.
         const std::vector<sp<android::gui::WindowInfoHandle>>& getWindowHandlesForDisplay(
                 ui::LogicalDisplayId displayId) const;
@@ -319,11 +323,6 @@
                 ui::LogicalDisplayId displayId, float x, float y, bool isStylus = false,
                 const sp<android::gui::WindowInfoHandle> ignoreWindow = nullptr) const;
 
-        std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt(
-                ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
-                const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay)
-                const;
-
         TouchOcclusionInfo computeTouchOcclusionInfo(
                 const sp<android::gui::WindowInfoHandle>& windowHandle, float x, float y) const;
 
@@ -346,6 +345,11 @@
         std::unordered_map<ui::LogicalDisplayId /*displayId*/, android::gui::DisplayInfo>
                 mDisplayInfos;
         float mMaximumObscuringOpacityForTouch{1.0f};
+
+        // Topology is initialized with default-constructed value, which is an empty topology until
+        // we receive setDisplayTopology call. Meanwhile we will treat every display as an
+        // independent display.
+        DisplayTopologyGraph mTopology;
     };
 
     DispatcherWindowInfo mWindowInfos GUARDED_BY(mLock);
@@ -355,7 +359,15 @@
         struct CancellationArgs {
             const sp<gui::WindowInfoHandle> windowHandle;
             CancelationOptions::Mode mode;
-            std::optional<DeviceId> deviceId;
+            std::optional<DeviceId> deviceId{std::nullopt};
+            ui::LogicalDisplayId displayId{ui::LogicalDisplayId::INVALID};
+            std::bitset<MAX_POINTER_ID + 1> pointerIds{};
+        };
+
+        struct PointerDownArgs {
+            const nsecs_t downTimeInTarget;
+            const std::shared_ptr<Connection> connection;
+            const ftl::Flags<InputTarget::Flags> targetFlags;
         };
 
         static void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle,
@@ -384,20 +396,62 @@
         bool isPointerInWindow(const sp<android::IBinder>& token, ui::LogicalDisplayId displayId,
                                DeviceId deviceId, int32_t pointerId) const;
 
+        // Find touched windowHandle and display by token.
+        std::optional<std::tuple<const sp<gui::WindowInfoHandle>&, ui::LogicalDisplayId>>
+        findTouchedWindowHandleAndDisplay(const sp<IBinder>& token) const;
+
+        void forAllTouchedWindows(std::function<void(const sp<gui::WindowInfoHandle>&)> f) const;
+
+        void forAllTouchedWindowsOnDisplay(
+                ui::LogicalDisplayId displayId,
+                std::function<void(const sp<gui::WindowInfoHandle>&)> f) const;
+
         std::string dump() const;
 
         // Updates the touchState for display from WindowInfo,
-        // return vector of CancellationArgs for every cancelled touch
+        // returns list of CancellationArgs for every cancelled touch
         std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId,
                                                          const DispatcherWindowInfo& windowInfos);
 
         void removeAllPointersForDevice(DeviceId deviceId);
 
+        // transfer touch between provided tokens, returns destination WindowHandle, deviceId,
+        // pointers, list of cancelled windows and pointers on successful transfer.
+        std::optional<
+                std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>,
+                           std::list<CancellationArgs>, std::list<PointerDownArgs>>>
+        transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
+                             const DispatcherWindowInfo& windowInfos,
+                             const ConnectionManager& connections);
+
+        base::Result<std::list<CancellationArgs>, status_t> pilferPointers(
+                const sp<IBinder>& token, const Connection& requestingConnection);
+
         void clear();
 
+    private:
         std::unordered_map<ui::LogicalDisplayId, TouchState> mTouchStatesByDisplay;
 
-    private:
+        std::optional<std::tuple<TouchState&, TouchedWindow&, ui::LogicalDisplayId>>
+        findTouchStateWindowAndDisplay(const sp<IBinder>& token);
+
+        std::pair<std::list<CancellationArgs>, std::list<PointerDownArgs>> transferWallpaperTouch(
+                const sp<gui::WindowInfoHandle> fromWindowHandle,
+                const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state,
+                DeviceId deviceId, const std::vector<PointerProperties>& pointers,
+                ftl::Flags<InputTarget::Flags> oldTargetFlags,
+                ftl::Flags<InputTarget::Flags> newTargetFlags,
+                const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections);
+
+        bool canWindowReceiveMotion(const sp<android::gui::WindowInfoHandle>& window,
+                                    const MotionEntry& motionEntry,
+                                    const ConnectionManager& connections,
+                                    const DispatcherWindowInfo& windowInfos) const;
+
+        // Return true if stylus is currently down anywhere on the specified display,
+        // and false otherwise.
+        bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId) const;
+
         static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo(
                 TouchState& state, ui::LogicalDisplayId displayId,
                 const DispatcherWindowInfo& windowInfos);
@@ -553,11 +607,6 @@
     sp<android::gui::WindowInfoHandle> getFocusedWindowHandleLocked(
             ui::LogicalDisplayId displayId) const REQUIRES(mLock);
 
-    static bool canWindowReceiveMotion(
-            const sp<android::gui::WindowInfoHandle>& window, const MotionEntry& motionEntry,
-            const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos,
-            const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStates);
-
     // Returns all the input targets (with their respective input channels) from the window handles
     // passed as argument.
     std::vector<InputTarget> getInputTargetsFromWindowHandlesLocked(
@@ -727,6 +776,10 @@
     std::string getApplicationWindowLabel(const InputApplicationHandle* applicationHandle,
                                           const sp<android::gui::WindowInfoHandle>& windowHandle);
 
+    static std::vector<sp<android::gui::WindowInfoHandle>> findTouchedSpyWindowsAt(
+            ui::LogicalDisplayId displayId, float x, float y, bool isStylus, DeviceId deviceId,
+            const DispatcherWindowInfo& windowInfos);
+
     static bool shouldDropInput(const EventEntry& entry,
                                 const sp<android::gui::WindowInfoHandle>& windowHandle,
                                 const DispatcherWindowInfo& windowInfo);
@@ -824,17 +877,6 @@
             const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry,
             bool handled) REQUIRES(mLock);
 
-    // Find touched state and touched window by token.
-    static std::tuple<TouchState*, TouchedWindow*, ui::LogicalDisplayId>
-    findTouchStateWindowAndDisplay(
-            const sp<IBinder>& token,
-            std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
-
-    static std::tuple<const TouchState*, const TouchedWindow*, ui::LogicalDisplayId>
-    findTouchStateWindowAndDisplay(
-            const sp<IBinder>& token,
-            const std::unordered_map<ui::LogicalDisplayId, TouchState>& touchStatesByDisplay);
-
     // Statistics gathering.
     nsecs_t mLastStatisticPushTime = 0;
     std::unique_ptr<InputEventTimelineProcessor> mInputEventTimelineProcessor GUARDED_BY(mLock);
@@ -849,15 +891,6 @@
 
     sp<InputReporterInterface> mReporter;
 
-    void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
-                                ftl::Flags<InputTarget::Flags> newTargetFlags,
-                                const sp<android::gui::WindowInfoHandle> fromWindowHandle,
-                                const sp<android::gui::WindowInfoHandle> toWindowHandle,
-                                TouchState& state, DeviceId deviceId,
-                                const std::vector<PointerProperties>& pointers,
-                                const std::unique_ptr<trace::EventTrackerInterface>& traceTracker)
-            REQUIRES(mLock);
-
     /** Stores the value of the input flag for per device input latency metrics. */
     const bool mPerDeviceInputLatencyMetricsFlag =
             com::android::input::flags::enable_per_device_input_latency_metrics();
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 463a952..ab039c3 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -24,6 +24,7 @@
 #include <android/os/InputEventInjectionSync.h>
 #include <gui/InputApplication.h>
 #include <gui/WindowInfo.h>
+#include <input/DisplayTopologyGraph.h>
 #include <input/InputDevice.h>
 #include <input/InputTransport.h>
 #include <unordered_map>
@@ -243,6 +244,11 @@
      * Notify the dispatcher that the state of the input method connection changed.
      */
     virtual void setInputMethodConnectionIsActive(bool isActive) = 0;
+
+    /*
+     * Notify the dispatcher of the latest DisplayTopology.
+     */
+    virtual void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 013ef86..3c8b6f5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1620,41 +1620,43 @@
 
     const auto& path = *sysfsRootPathOpt;
 
-    std::shared_ptr<const AssociatedDevice> associatedDevice = std::make_shared<AssociatedDevice>(
-            AssociatedDevice{.sysfsRootPath = path,
-                             .batteryInfos = readBatteryConfiguration(path),
-                             .lightInfos = readLightsConfiguration(path),
-                             .layoutInfo = readLayoutConfiguration(path)});
-
-    bool associatedDeviceChanged = false;
+    std::shared_ptr<const AssociatedDevice> associatedDevice;
     for (const auto& [id, dev] : mDevices) {
-        if (dev->associatedDevice && dev->associatedDevice->sysfsRootPath == path) {
-            if (*associatedDevice != *dev->associatedDevice) {
-                associatedDeviceChanged = true;
-                dev->associatedDevice = associatedDevice;
-            }
-            associatedDevice = dev->associatedDevice;
+        if (!dev->associatedDevice || dev->associatedDevice->sysfsRootPath != path) {
+            continue;
         }
+        if (!associatedDevice) {
+            // Found matching associated device for the first time.
+            associatedDevice = dev->associatedDevice;
+            // Reload this associated device if needed.
+            const auto reloadedDevice = AssociatedDevice(path);
+            if (reloadedDevice != *dev->associatedDevice) {
+                ALOGI("The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
+                      path.c_str(), associatedDevice->dump().c_str());
+                associatedDevice = std::make_shared<AssociatedDevice>(std::move(reloadedDevice));
+            }
+        }
+        // Update the associatedDevice.
+        dev->associatedDevice = associatedDevice;
     }
-    ALOGI_IF(associatedDeviceChanged,
-             "The AssociatedDevice changed for path '%s'. Using new AssociatedDevice: %s",
-             path.c_str(), associatedDevice->dump().c_str());
+
+    if (!associatedDevice) {
+        // No existing associated device found for this path, so create a new one.
+        associatedDevice = std::make_shared<AssociatedDevice>(path);
+    }
 
     return associatedDevice;
 }
 
-bool EventHub::AssociatedDevice::isChanged() const {
-    std::unordered_map<int32_t, RawBatteryInfo> newBatteryInfos =
-            readBatteryConfiguration(sysfsRootPath);
-    std::unordered_map<int32_t, RawLightInfo> newLightInfos =
-            readLightsConfiguration(sysfsRootPath);
-    std::optional<RawLayoutInfo> newLayoutInfo = readLayoutConfiguration(sysfsRootPath);
+EventHub::AssociatedDevice::AssociatedDevice(const std::filesystem::path& sysfsRootPath)
+      : sysfsRootPath(sysfsRootPath),
+        batteryInfos(readBatteryConfiguration(sysfsRootPath)),
+        lightInfos(readLightsConfiguration(sysfsRootPath)),
+        layoutInfo(readLayoutConfiguration(sysfsRootPath)) {}
 
-    if (newBatteryInfos == batteryInfos && newLightInfos == lightInfos &&
-        newLayoutInfo == layoutInfo) {
-        return false;
-    }
-    return true;
+std::string EventHub::AssociatedDevice::dump() const {
+    return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
+                        batteryInfos.size(), lightInfos.size());
 }
 
 void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
@@ -2646,33 +2648,56 @@
 void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) {
     std::scoped_lock _l(mLock);
 
-    // Check in opening devices
-    for (auto it = mOpeningDevices.begin(); it != mOpeningDevices.end(); it++) {
-        std::unique_ptr<Device>& device = *it;
-        if (device->associatedDevice &&
-            sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
-                    std::string::npos &&
-            device->associatedDevice->isChanged()) {
-            it = mOpeningDevices.erase(it);
-            openDeviceLocked(device->path);
+    // Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid
+    // testing the same node multiple times.
+    std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices;
+    auto isAssociatedDeviceChanged = [&testedDevices, &sysfsNodePath](const Device& dev) {
+        if (!dev.associatedDevice) {
+            return false;
+        }
+        if (auto testedIt = testedDevices.find(dev.associatedDevice);
+            testedIt != testedDevices.end()) {
+            return testedIt->second;
+        }
+        // Cache miss
+        if (sysfsNodePath.find(dev.associatedDevice->sysfsRootPath.string()) == std::string::npos) {
+            testedDevices.emplace(dev.associatedDevice, false);
+            return false;
+        }
+        auto reloadedDevice = AssociatedDevice(dev.associatedDevice->sysfsRootPath);
+        const bool changed = *dev.associatedDevice != reloadedDevice;
+        testedDevices.emplace(dev.associatedDevice, changed);
+        return changed;
+    };
+
+    std::set<Device*> devicesToClose;
+    std::set<std::string /*path*/> devicesToOpen;
+
+    // Check in opening devices. If its associated device changed,
+    // the device should be removed from mOpeningDevices and needs to be opened again.
+    std::erase_if(mOpeningDevices, [&](const auto& dev) {
+        if (isAssociatedDeviceChanged(*dev)) {
+            devicesToOpen.emplace(dev->path);
+            return true;
+        }
+        return false;
+    });
+
+    // Check in already added device. If its associated device changed,
+    // the device needs to be re-opened.
+    for (const auto& [id, dev] : mDevices) {
+        if (isAssociatedDeviceChanged(*dev)) {
+            devicesToOpen.emplace(dev->path);
+            devicesToClose.emplace(dev.get());
         }
     }
 
-    // Check in already added device
-    std::vector<Device*> devicesToReopen;
-    for (const auto& [id, device] : mDevices) {
-        if (device->associatedDevice &&
-            sysfsNodePath.find(device->associatedDevice->sysfsRootPath.string()) !=
-                    std::string::npos &&
-            device->associatedDevice->isChanged()) {
-            devicesToReopen.push_back(device.get());
-        }
-    }
-    for (const auto& device : devicesToReopen) {
+    for (auto* device : devicesToClose) {
         closeDeviceLocked(*device);
-        openDeviceLocked(device->path);
     }
-    devicesToReopen.clear();
+    for (const auto& path : devicesToOpen) {
+        openDeviceLocked(path);
+    }
 }
 
 void EventHub::createVirtualKeyboardLocked() {
@@ -2972,9 +2997,4 @@
     std::unique_lock<std::mutex> lock(mLock);
 }
 
-std::string EventHub::AssociatedDevice::dump() const {
-    return StringPrintf("path=%s, numBatteries=%zu, numLight=%zu", sysfsRootPath.c_str(),
-                        batteryInfos.size(), lightInfos.size());
-}
-
 } // namespace android
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 5839b4c..31ac63f 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -619,13 +619,13 @@
 private:
     // Holds information about the sysfs device associated with the Device.
     struct AssociatedDevice {
+        AssociatedDevice(const std::filesystem::path& sysfsRootPath);
         // The sysfs root path of the misc device.
         std::filesystem::path sysfsRootPath;
         std::unordered_map<int32_t /*batteryId*/, RawBatteryInfo> batteryInfos;
         std::unordered_map<int32_t /*lightId*/, RawLightInfo> lightInfos;
         std::optional<RawLayoutInfo> layoutInfo;
 
-        bool isChanged() const;
         bool operator==(const AssociatedDevice&) const = default;
         bool operator!=(const AssociatedDevice&) const = default;
         std::string dump() const;
diff --git a/services/sensorservice/aidl/fuzzer/Android.bp b/services/sensorservice/aidl/fuzzer/Android.bp
index 880df08..f38cf5a 100644
--- a/services/sensorservice/aidl/fuzzer/Android.bp
+++ b/services/sensorservice/aidl/fuzzer/Android.bp
@@ -22,6 +22,7 @@
         "android.hardware.sensors-V1-convert",
         "android.hardware.sensors-V3-ndk",
         "android.hardware.common-V2-ndk",
+        "framework-permission-aidl-cpp",
         "libsensor",
         "libfakeservicemanager",
         "libcutils",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ea7d6d7..9aa1ffa 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -93,7 +93,6 @@
         "iinputflinger_aidl_lib_static",
         "libaidlcommonsupport",
         "libcompositionengine",
-        "libframetimeline",
         "libgui_aidl_static",
         "libperfetto_client_experimental",
         "librenderengine",
@@ -206,9 +205,9 @@
         "Display/DisplayModeController.cpp",
         "Display/DisplaySnapshot.cpp",
         "DisplayDevice.cpp",
-        "DisplayRenderArea.cpp",
         "Effects/Daltonizer.cpp",
         "FpsReporter.cpp",
+        "FrameTimeline/FrameTimeline.cpp",
         "FrameTracer/FrameTracer.cpp",
         "FrameTracker.cpp",
         "FrontEnd/LayerCreationArgs.cpp",
@@ -225,12 +224,10 @@
         "Layer.cpp",
         "LayerFE.cpp",
         "LayerProtoHelper.cpp",
-        "LayerRenderArea.cpp",
         "LayerVector.cpp",
         "NativeWindowSurface.cpp",
         "RefreshRateOverlay.cpp",
         "RegionSamplingThread.cpp",
-        "RenderArea.cpp",
         "Scheduler/EventThread.cpp",
         "Scheduler/FrameRateOverrideMappings.cpp",
         "Scheduler/LayerHistory.cpp",
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 77bf145..6088e25 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -110,8 +110,8 @@
     LayerCreationArgs args(mFlinger.get(), sp<Client>::fromExisting(this),
                            "MirrorRoot-" + std::to_string(displayId), 0 /* flags */,
                            gui::LayerMetadata());
-    std::optional<DisplayId> id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
-    status_t status = mFlinger->mirrorDisplay(*id, args, *outResult);
+    const DisplayId id = DisplayId::fromValue(static_cast<uint64_t>(displayId));
+    status_t status = mFlinger->mirrorDisplay(id, args, *outResult);
     return binderStatusFromStatusT(status);
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index e876693..780758e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -19,6 +19,7 @@
 #include <optional>
 #include <ostream>
 #include <unordered_set>
+#include "aidl/android/hardware/graphics/composer3/Composition.h"
 #include "ui/LayerStack.h"
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -36,10 +37,6 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
-namespace aidl::android::hardware::graphics::composer3 {
-enum class Composition;
-}
-
 namespace android {
 
 class Fence;
@@ -182,10 +179,27 @@
     // Whether the layer should be rendered with rounded corners.
     virtual bool hasRoundedCorners() const = 0;
     virtual void setWasClientComposed(const sp<Fence>&) {}
-    virtual void setHwcCompositionType(
-            aidl::android::hardware::graphics::composer3::Composition) = 0;
-    virtual aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
-            const = 0;
+
+    // These fields are all copied from the last written HWC state.
+    // This state is only used for debugging purposes.
+    struct HwcLayerDebugState {
+        aidl::android::hardware::graphics::composer3::Composition lastCompositionType =
+                aidl::android::hardware::graphics::composer3::Composition::INVALID;
+        // Corresponds to passing an alpha of 0 to HWC2::Layer::setPlaneAlpha.
+        bool wasSkipped = false;
+
+        // Indicates whether the compositionengine::OutputLayer had properties overwritten.
+        // Not directly passed to HWC.
+        bool wasOverridden = false;
+
+        // Corresponds to the GraphicBuffer ID of the buffer passed to HWC2::Layer::setBuffer.
+        // This buffer corresponds to a CachedSet that the LayerFE was flattened to.
+        uint64_t overrideBufferId = 0;
+    };
+
+    // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+    virtual void setLastHwcState(const LayerFE::HwcLayerDebugState &hwcState) = 0;
+    virtual const HwcLayerDebugState &getLastHwcState() const = 0;
 
     virtual const gui::LayerMetadata* getMetadata() const = 0;
     virtual const gui::LayerMetadata* getRelativeMetadata() const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 7744b8b..d2a5a20 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -59,9 +59,9 @@
     MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*());
     MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*());
     MOCK_METHOD0(onPictureProfileCommitted, void());
-    MOCK_METHOD(void, setHwcCompositionType,
-                (aidl::android::hardware::graphics::composer3::Composition), (override));
-    MOCK_METHOD(aidl::android::hardware::graphics::composer3::Composition, getHwcCompositionType,
+    MOCK_METHOD(void, setLastHwcState,
+                (const HwcLayerDebugState&), (override));
+    MOCK_METHOD(const HwcLayerDebugState&, getLastHwcState,
                 (), (const, override));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 9b66f01..9d67122 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -502,6 +502,15 @@
 
     editState().hwc->stateOverridden = isOverridden;
     editState().hwc->layerSkipped = skipLayer;
+
+
+    // Save the final HWC state for debugging purposes, e.g. perfetto tracing, dumpsys.
+    getLayerFE().setLastHwcState({.lastCompositionType = editState().hwc->hwcCompositionType,
+                                  .wasSkipped = skipLayer,
+                                  .wasOverridden = isOverridden,
+                                  .overrideBufferId = editState().overrideInfo.buffer
+                                          ? editState().overrideInfo.buffer.get()->getId()
+                                          : 0});
 }
 
 void OutputLayer::writeOutputDependentGeometryStateToHWC(HWC2::Layer* hwcLayer,
@@ -867,7 +876,6 @@
     if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType ||
         (outputDependentState.hwc->layerSkipped && !skipLayer)) {
         outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
-        getLayerFE().setHwcCompositionType(requestedCompositionType);
 
         if (auto error = hwcLayer->setCompositionType(requestedCompositionType);
             error != hal::Error::NONE) {
@@ -965,7 +973,13 @@
     }
 
     hwcState.hwcCompositionType = compositionType;
-    getLayerFE().setHwcCompositionType(compositionType);
+
+    getLayerFE().setLastHwcState({.lastCompositionType = hwcState.hwcCompositionType,
+                                  .wasSkipped = hwcState.layerSkipped,
+                                  .wasOverridden = hwcState.stateOverridden,
+                                  .overrideBufferId = state.overrideInfo.buffer
+                                          ? state.overrideInfo.buffer.get()->getId()
+                                          : 0});
 }
 
 void OutputLayer::prepareForDeviceLayerRequests() {
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
deleted file mode 100644
index c63c738..0000000
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "DisplayRenderArea.h"
-#include "DisplayDevice.h"
-
-namespace android {
-
-std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak,
-                                                      const Rect& sourceCrop, ui::Size reqSize,
-                                                      ui::Dataspace reqDataSpace,
-                                                      ftl::Flags<Options> options) {
-    if (auto display = displayWeak.promote()) {
-        // Using new to access a private constructor.
-        return std::unique_ptr<DisplayRenderArea>(new DisplayRenderArea(std::move(display),
-                                                                        sourceCrop, reqSize,
-                                                                        reqDataSpace, options));
-    }
-    return nullptr;
-}
-
-DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
-                                     ui::Size reqSize, ui::Dataspace reqDataSpace,
-                                     ftl::Flags<Options> options)
-      : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, options),
-        mDisplay(std::move(display)),
-        mSourceCrop(sourceCrop) {}
-
-const ui::Transform& DisplayRenderArea::getTransform() const {
-    return mTransform;
-}
-
-bool DisplayRenderArea::isSecure() const {
-    return mOptions.test(Options::CAPTURE_SECURE_LAYERS) && mDisplay->isSecure();
-}
-
-sp<const DisplayDevice> DisplayRenderArea::getDisplayDevice() const {
-    return mDisplay;
-}
-
-Rect DisplayRenderArea::getSourceCrop() const {
-    // use the projected display viewport by default.
-    if (mSourceCrop.isEmpty()) {
-        return mDisplay->getLayerStackSpaceRect();
-    }
-    return mSourceCrop;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
deleted file mode 100644
index 677d019..0000000
--- a/services/surfaceflinger/DisplayRenderArea.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <ui/GraphicTypes.h>
-#include <ui/Transform.h>
-
-#include "RenderArea.h"
-
-namespace android {
-
-class DisplayDevice;
-
-class DisplayRenderArea : public RenderArea {
-public:
-    static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
-                                              ui::Size reqSize, ui::Dataspace,
-                                              ftl::Flags<Options> options);
-
-    const ui::Transform& getTransform() const override;
-    bool isSecure() const override;
-    sp<const DisplayDevice> getDisplayDevice() const override;
-    Rect getSourceCrop() const override;
-
-private:
-    DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
-                      ui::Dataspace, ftl::Flags<Options> options);
-
-    const sp<const DisplayDevice> mDisplay;
-    const Rect mSourceCrop;
-    const ui::Transform mTransform;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/FrameTimeline/Android.bp b/services/surfaceflinger/FrameTimeline/Android.bp
deleted file mode 100644
index 8e28cc3..0000000
--- a/services/surfaceflinger/FrameTimeline/Android.bp
+++ /dev/null
@@ -1,35 +0,0 @@
-package {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_native_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_native_license"],
-    default_team: "trendy_team_android_core_graphics_stack",
-}
-
-cc_library_static {
-    name: "libframetimeline",
-    defaults: ["surfaceflinger_defaults"],
-    srcs: [
-        "FrameTimeline.cpp",
-    ],
-    header_libs: [
-        "libscheduler_headers",
-    ],
-    shared_libs: [
-        "android.hardware.graphics.composer@2.4",
-        "libbase",
-        "libcutils",
-        "liblog",
-        "libgui",
-        "libtimestats",
-        "libui",
-        "libutils",
-    ],
-    static_libs: [
-        "libperfetto_client_experimental",
-        "libsurfaceflinger_common",
-    ],
-    export_include_dirs: ["."],
-}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 523ef7b..839bd79 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -403,11 +403,8 @@
     if (forceUpdate || requested.what & layer_state_t::eSidebandStreamChanged) {
         sidebandStream = requested.sidebandStream;
     }
-    if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged ||
-        requested.what & layer_state_t::eClientDrawnShadowsChanged) {
-        shadowSettings.length =
-                requested.clientDrawnShadowRadius > 0 ? 0.f : requested.shadowRadius;
-        shadowSettings.clientDrawnLength = requested.clientDrawnShadowRadius;
+    if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) {
+        shadowSettings.length = requested.shadowRadius;
     }
 
     if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) {
@@ -537,12 +534,13 @@
     }
 }
 
-char LayerSnapshot::classifyCompositionForDebug(Composition compositionType) const {
+char LayerSnapshot::classifyCompositionForDebug(
+        const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const {
     if (!isVisible) {
         return '.';
     }
 
-    switch (compositionType) {
+    switch (hwcState.lastCompositionType) {
         case Composition::INVALID:
             return 'i';
         case Composition::SOLID_COLOR:
@@ -561,21 +559,21 @@
     }
 
     char code = '.'; // Default to invisible
-    if (hasBufferOrSidebandStream()) {
-        code = 'b';
-    } else if (fillsColor()) {
-        code = 'c'; // Solid color
-    } else if (hasBlur()) {
+    if (hasBlur()) {
         code = 'l'; // Blur
     } else if (hasProtectedContent) {
         code = 'p'; // Protected content
-    } else if (drawShadows()) {
-        code = 's'; // Shadow
     } else if (roundedCorner.hasRoundedCorners()) {
         code = 'r'; // Rounded corners
+    } else if (drawShadows()) {
+        code = 's'; // Shadow
+    } else if (fillsColor()) {
+        code = 'c'; // Solid color
+    } else if (hasBufferOrSidebandStream()) {
+        code = 'b';
     }
 
-    if (compositionType == Composition::CLIENT) {
+    if (hwcState.lastCompositionType == Composition::CLIENT) {
         return static_cast<char>(std::toupper(code));
     } else {
         return code;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 04b9f3b..69120bd 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -24,6 +24,7 @@
 #include "RequestedLayerState.h"
 #include "Scheduler/LayerInfo.h"
 #include "android-base/stringprintf.h"
+#include "compositionengine/LayerFE.h"
 
 namespace android::surfaceflinger::frontend {
 
@@ -163,7 +164,7 @@
     // Returns a char summarizing the composition request
     // This function tries to maintain parity with planner::Plan chars.
     char classifyCompositionForDebug(
-            aidl::android::hardware::graphics::composer3::Composition compositionType) const;
+            const compositionengine::LayerFE::HwcLayerDebugState& hwcState) const;
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 1d53e71..58c235e 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -108,7 +108,6 @@
     surfaceDamageRegion = Region::INVALID_REGION;
     cornerRadius = 0.0f;
     clientDrawnCornerRadius = 0.0f;
-    clientDrawnShadowRadius = 0.0f;
     backgroundBlurRadius = 0;
     api = -1;
     hasColorTransform = false;
@@ -355,11 +354,6 @@
         clientDrawnCornerRadius = clientState.clientDrawnCornerRadius;
         changes |= RequestedLayerState::Changes::Geometry;
     }
-
-    if (clientState.what & layer_state_t::eClientDrawnShadowsChanged) {
-        clientDrawnShadowRadius = clientState.clientDrawnShadowRadius;
-        changes |= RequestedLayerState::Changes::Geometry;
-    }
 }
 
 ui::Size RequestedLayerState::getUnrotatedBufferSize(uint32_t displayRotationFlags) const {
@@ -646,7 +640,6 @@
             layer_state_t::eColorTransformChanged | layer_state_t::eBackgroundColorChanged |
             layer_state_t::eMatrixChanged | layer_state_t::eCornerRadiusChanged |
             layer_state_t::eClientDrawnCornerRadiusChanged |
-            layer_state_t::eClientDrawnShadowsChanged |
             layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBufferTransformChanged |
             layer_state_t::eTransformToDisplayInverseChanged | layer_state_t::eCropChanged |
             layer_state_t::eDataspaceChanged | layer_state_t::eHdrMetadataChanged |
diff --git a/services/surfaceflinger/Jank/JankTracker.cpp b/services/surfaceflinger/Jank/JankTracker.cpp
index 8e0e084..5e6267d 100644
--- a/services/surfaceflinger/Jank/JankTracker.cpp
+++ b/services/surfaceflinger/Jank/JankTracker.cpp
@@ -88,7 +88,8 @@
 }
 
 void JankTracker::addJankListenerLocked(int32_t layerId, sp<IBinder> listener) {
-    for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+    auto range = mJankListeners.equal_range(layerId);
+    for (auto it = range.first; it != range.second; it++) {
         if (it->second.mListener == listener) {
             // Undo the duplicate increment in addJankListener.
             sListenerCount--;
@@ -106,7 +107,8 @@
     std::vector<sp<IBinder>> toSend;
 
     mLock.lock();
-    for (auto it = mJankListeners.find(layerId); it != mJankListeners.end();) {
+    auto range = mJankListeners.equal_range(layerId);
+    for (auto it = range.first; it != range.second;) {
         if (!jankData.empty()) {
             toSend.emplace_back(it->second.mListener);
         }
@@ -133,7 +135,8 @@
 
 void JankTracker::markJankListenerForRemovalLocked(int32_t layerId, sp<IBinder> listener,
                                                    int64_t afterVysnc) {
-    for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+    auto range = mJankListeners.equal_range(layerId);
+    for (auto it = range.first; it != range.second; it++) {
         if (it->second.mListener == listener) {
             it->second.mRemoveAfter = std::max(static_cast<int64_t>(0), afterVysnc);
             return;
@@ -156,7 +159,8 @@
 
 void JankTracker::dropJankListener(int32_t layerId, sp<IBinder> listener) {
     const std::lock_guard<std::mutex> _l(mLock);
-    for (auto it = mJankListeners.find(layerId); it != mJankListeners.end(); it++) {
+    auto range = mJankListeners.equal_range(layerId);
+    for (auto it = range.first; it != range.second; it++) {
         if (it->second.mListener == listener) {
             mJankListeners.erase(it);
             sListenerCount--;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 195461f..e1bba44 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -64,7 +64,7 @@
 
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWComposer.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
 #include "FrameTracer/FrameTracer.h"
 #include "FrontEnd/LayerCreationArgs.h"
 #include "FrontEnd/LayerHandle.h"
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index 725a782..b619268 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -428,13 +428,12 @@
     return mReleaseFencePromiseStatus;
 }
 
-void LayerFE::setHwcCompositionType(
-        aidl::android::hardware::graphics::composer3::Composition type) {
-    mLastHwcCompositionType = type;
+void LayerFE::setLastHwcState(const LayerFE::HwcLayerDebugState &state) {
+    mLastHwcState = state;
 }
 
-aidl::android::hardware::graphics::composer3::Composition LayerFE::getHwcCompositionType() const {
-    return mLastHwcCompositionType;
-}
+const LayerFE::HwcLayerDebugState& LayerFE::getLastHwcState() const {
+    return mLastHwcState;
+};
 
 } // namespace android
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
index 64ec278..a537456 100644
--- a/services/surfaceflinger/LayerFE.h
+++ b/services/surfaceflinger/LayerFE.h
@@ -59,9 +59,10 @@
     void setReleaseFence(const FenceResult& releaseFence) override;
     LayerFE::ReleaseFencePromiseStatus getReleaseFencePromiseStatus() override;
     void onPictureProfileCommitted() override;
-    void setHwcCompositionType(aidl::android::hardware::graphics::composer3::Composition) override;
-    aidl::android::hardware::graphics::composer3::Composition getHwcCompositionType()
-            const override;
+
+    // Used for debugging purposes, e.g. perfetto tracing, dumpsys.
+    void setLastHwcState(const HwcLayerDebugState &state) override;
+    const HwcLayerDebugState &getLastHwcState() const override;
 
     std::unique_ptr<surfaceflinger::frontend::LayerSnapshot> mSnapshot;
 
@@ -93,8 +94,7 @@
     std::string mName;
     std::promise<FenceResult> mReleaseFence;
     ReleaseFencePromiseStatus mReleaseFencePromiseStatus = ReleaseFencePromiseStatus::UNINITIALIZED;
-    aidl::android::hardware::graphics::composer3::Composition mLastHwcCompositionType =
-            aidl::android::hardware::graphics::composer3::Composition::INVALID;
+    HwcLayerDebugState mLastHwcState;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
deleted file mode 100644
index bfe6d2a..0000000
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ui/GraphicTypes.h>
-#include <ui/Transform.h>
-
-#include "DisplayDevice.h"
-#include "FrontEnd/LayerCreationArgs.h"
-#include "Layer.h"
-#include "LayerRenderArea.h"
-#include "SurfaceFlinger.h"
-
-namespace android {
-
-LayerRenderArea::LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot,
-                                 const Rect& crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
-                                 const ui::Transform& layerTransform, const Rect& layerBufferSize,
-                                 ftl::Flags<RenderArea::Options> options)
-      : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, options),
-        mLayer(std::move(layer)),
-        mLayerSnapshot(std::move(layerSnapshot)),
-        mLayerBufferSize(layerBufferSize),
-        mCrop(crop),
-        mTransform(layerTransform) {}
-
-const ui::Transform& LayerRenderArea::getTransform() const {
-    return mTransform;
-}
-
-bool LayerRenderArea::isSecure() const {
-    return mOptions.test(Options::CAPTURE_SECURE_LAYERS);
-}
-
-sp<const DisplayDevice> LayerRenderArea::getDisplayDevice() const {
-    return nullptr;
-}
-
-Rect LayerRenderArea::getSourceCrop() const {
-    if (mCrop.isEmpty()) {
-        // TODO this should probably be mBounds instead of just buffer bounds
-        return mLayerBufferSize;
-    } else {
-        return mCrop;
-    }
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
deleted file mode 100644
index f72c7c7..0000000
--- a/services/surfaceflinger/LayerRenderArea.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include <ui/GraphicTypes.h>
-#include <ui/Transform.h>
-#include <utils/StrongPointer.h>
-
-#include "RenderArea.h"
-
-namespace android {
-
-class DisplayDevice;
-class Layer;
-class SurfaceFlinger;
-
-class LayerRenderArea : public RenderArea {
-public:
-    LayerRenderArea(sp<Layer> layer, frontend::LayerSnapshot layerSnapshot, const Rect& crop,
-                    ui::Size reqSize, ui::Dataspace reqDataSpace,
-                    const ui::Transform& layerTransform, const Rect& layerBufferSize,
-                    ftl::Flags<RenderArea::Options> options);
-
-    const ui::Transform& getTransform() const override;
-    bool isSecure() const override;
-    sp<const DisplayDevice> getDisplayDevice() const override;
-    Rect getSourceCrop() const override;
-
-    sp<Layer> getParentLayer() const override { return mLayer; }
-    const frontend::LayerSnapshot* getLayerSnapshot() const override { return &mLayerSnapshot; }
-
-private:
-    const sp<Layer> mLayer;
-    const frontend::LayerSnapshot mLayerSnapshot;
-    const Rect mLayerBufferSize;
-    const Rect mCrop;
-
-    ui::Transform mTransform;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index fa0ecee..13edd16 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -12,6 +12,5 @@
 ramindani@google.com
 rnlee@google.com
 sallyqi@google.com
-scroggo@google.com
 vishnun@google.com
 xwxw@google.com
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index d3483b0..1c4a11a 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -39,11 +39,8 @@
 #include <string>
 
 #include "DisplayDevice.h"
-#include "DisplayRenderArea.h"
 #include "FrontEnd/LayerCreationArgs.h"
 #include "Layer.h"
-#include "RenderAreaBuilder.h"
-#include "Scheduler/VsyncController.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
@@ -259,6 +256,7 @@
     ui::LayerStack layerStack;
     ui::Transform::RotationFlags orientation;
     ui::Size displaySize;
+    Rect layerStackSpaceRect;
 
     {
         // TODO(b/159112860): Don't keep sp<DisplayDevice> outside of SF main thread
@@ -267,6 +265,7 @@
         layerStack = display->getLayerStack();
         orientation = ui::Transform::toRotationFlags(display->getOrientation());
         displaySize = display->getSize();
+        layerStackSpaceRect = display->getLayerStackSpaceRect();
     }
 
     std::vector<RegionSamplingThread::Descriptor> descriptors;
@@ -347,16 +346,20 @@
     constexpr bool kGrayscale = false;
     constexpr bool kIsProtected = false;
 
-    SurfaceFlinger::RenderAreaBuilderVariant
-            renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds,
-                              sampledBounds.getSize(), ui::Dataspace::V0_SRGB, displayWeak,
-                              RenderArea::Options::CAPTURE_SECURE_LAYERS);
+    SurfaceFlinger::ScreenshotArgs screenshotArgs;
+    screenshotArgs.captureTypeVariant = displayWeak;
+    screenshotArgs.displayId = std::nullopt;
+    screenshotArgs.sourceCrop = sampledBounds.isEmpty() ? layerStackSpaceRect : sampledBounds;
+    screenshotArgs.reqSize = sampledBounds.getSize();
+    screenshotArgs.dataspace = ui::Dataspace::V0_SRGB;
+    screenshotArgs.isSecure = true;
+    screenshotArgs.seamlessTransition = false;
 
     std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
     auto displayState =
-            mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers);
+            mFlinger.getSnapshotsFromMainThread(screenshotArgs, getLayerSnapshotsFn, layers);
     FenceResult fenceResult =
-            mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale,
+            mFlinger.captureScreenshot(screenshotArgs, buffer, kRegionSampling, kGrayscale,
                                        kIsProtected, nullptr, displayState, layers)
                     .get();
     if (fenceResult.ok()) {
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
deleted file mode 100644
index aa66ccf..0000000
--- a/services/surfaceflinger/RenderArea.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#pragma once
-
-#include <ui/GraphicTypes.h>
-#include <ui/Transform.h>
-
-#include <functional>
-
-#include "FrontEnd/LayerSnapshot.h"
-#include "Layer.h"
-
-namespace android {
-
-class DisplayDevice;
-
-// RenderArea describes a rectangular area that layers can be rendered to.
-//
-// There is a logical render area and a physical render area.  When a layer is
-// rendered to the render area, it is first transformed and clipped to the logical
-// render area.  The transformed and clipped layer is then projected onto the
-// physical render area.
-class RenderArea {
-public:
-    enum class CaptureFill {CLEAR, OPAQUE};
-    enum class Options {
-        // If not set, the secure layer would be blacked out or skipped
-        // when rendered to an insecure render area
-        CAPTURE_SECURE_LAYERS = 1 << 0,
-
-        // If set, the render result may be used for system animations
-        // that must preserve the exact colors of the display
-        HINT_FOR_SEAMLESS_TRANSITION = 1 << 1,
-    };
-    static float getCaptureFillValue(CaptureFill captureFill);
-
-    RenderArea(ui::Size reqSize, CaptureFill captureFill, ui::Dataspace reqDataSpace,
-               ftl::Flags<Options> options)
-          : mOptions(options),
-            mReqSize(reqSize),
-            mReqDataSpace(reqDataSpace),
-            mCaptureFill(captureFill) {}
-
-    virtual ~RenderArea() = default;
-
-    // Returns true if the render area is secure.  A secure layer should be
-    // blacked out / skipped when rendered to an insecure render area.
-    virtual bool isSecure() const = 0;
-
-    // Returns the transform to be applied on layers to transform them into
-    // the logical render area.
-    virtual const ui::Transform& getTransform() const = 0;
-
-    // Returns the source crop of the render area.  The source crop defines
-    // how layers are projected from the logical render area onto the physical
-    // render area.  It can be larger than the logical render area.  It can
-    // also be optionally rotated.
-    //
-    // The source crop is specified in layer space (when rendering a layer and
-    // its children), or in layer-stack space (when rendering all layers visible
-    // on the display).
-    virtual Rect getSourceCrop() const = 0;
-
-    // Returns the size of the physical render area.
-    int getReqWidth() const { return mReqSize.width; }
-    int getReqHeight() const { return mReqSize.height; }
-
-    // Returns the composition data space of the render area.
-    ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
-
-    // Returns the fill color of the physical render area.  Regions not
-    // covered by any rendered layer should be filled with this color.
-    CaptureFill getCaptureFill() const { return mCaptureFill; }
-
-    virtual sp<const DisplayDevice> getDisplayDevice() const = 0;
-
-    // If this is a LayerRenderArea, return the root layer of the
-    // capture operation.
-    virtual sp<Layer> getParentLayer() const { return nullptr; }
-
-    // If this is a LayerRenderArea, return the layer snapshot
-    // of the root layer of the capture operation
-    virtual const frontend::LayerSnapshot* getLayerSnapshot() const { return nullptr; }
-
-    // Returns whether the render result may be used for system animations that
-    // must preserve the exact colors of the display.
-    bool getHintForSeamlessTransition() const {
-        return mOptions.test(Options::HINT_FOR_SEAMLESS_TRANSITION);
-    }
-
-protected:
-    ftl::Flags<Options> mOptions;
-
-private:
-    const ui::Size mReqSize;
-    const ui::Dataspace mReqDataSpace;
-    const CaptureFill mCaptureFill;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/RenderAreaBuilder.h b/services/surfaceflinger/RenderAreaBuilder.h
deleted file mode 100644
index 599fa7e..0000000
--- a/services/surfaceflinger/RenderAreaBuilder.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "DisplayDevice.h"
-#include "DisplayRenderArea.h"
-#include "LayerRenderArea.h"
-#include "ui/Size.h"
-#include "ui/Transform.h"
-
-namespace android {
-/**
- * A parameter object for creating a render area
- */
-struct RenderAreaBuilder {
-    // Source crop of the render area
-    Rect crop;
-
-    // Size of the physical render area
-    ui::Size reqSize;
-
-    // Composition data space of the render area
-    ui::Dataspace reqDataSpace;
-
-    ftl::Flags<RenderArea::Options> options;
-    virtual std::unique_ptr<RenderArea> build() const = 0;
-
-    RenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
-                      ftl::Flags<RenderArea::Options> options)
-          : crop(crop), reqSize(reqSize), reqDataSpace(reqDataSpace), options(options) {}
-
-    virtual ~RenderAreaBuilder() = default;
-};
-
-struct DisplayRenderAreaBuilder : RenderAreaBuilder {
-    DisplayRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace,
-                             wp<const DisplayDevice> displayWeak,
-                             ftl::Flags<RenderArea::Options> options)
-          : RenderAreaBuilder(crop, reqSize, reqDataSpace, options), displayWeak(displayWeak) {}
-
-    // Display that render area will be on
-    wp<const DisplayDevice> displayWeak;
-
-    std::unique_ptr<RenderArea> build() const override {
-        return DisplayRenderArea::create(displayWeak, crop, reqSize, reqDataSpace, options);
-    }
-};
-
-struct LayerRenderAreaBuilder : RenderAreaBuilder {
-    LayerRenderAreaBuilder(Rect crop, ui::Size reqSize, ui::Dataspace reqDataSpace, sp<Layer> layer,
-                           bool childrenOnly, ftl::Flags<RenderArea::Options> options)
-          : RenderAreaBuilder(crop, reqSize, reqDataSpace, options),
-            layer(layer),
-            childrenOnly(childrenOnly) {}
-
-    // Root layer of the render area
-    sp<Layer> layer;
-
-    // Layer snapshot of the root layer
-    frontend::LayerSnapshot layerSnapshot;
-
-    // Transform to be applied on the layers to transform them
-    // into the logical render area
-    ui::Transform layerTransform{ui::Transform()};
-
-    // Buffer bounds
-    Rect layerBufferSize{Rect()};
-
-    // If false, transform is inverted from the parent snapshot
-    bool childrenOnly;
-
-    // Uses parent snapshot to determine layer transform and buffer size
-    void setLayerSnapshot(const frontend::LayerSnapshot& parentSnapshot) {
-        layerSnapshot = parentSnapshot;
-        if (!childrenOnly) {
-            layerTransform = parentSnapshot.localTransform.inverse();
-        }
-        layerBufferSize = parentSnapshot.bufferSize;
-    }
-
-    std::unique_ptr<RenderArea> build() const override {
-        return std::make_unique<LayerRenderArea>(layer, std::move(layerSnapshot), crop, reqSize,
-                                                 reqDataSpace, layerTransform, layerBufferSize,
-                                                 options);
-    }
-};
-
-} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 0efc396..c37b965 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -45,7 +45,7 @@
 #include <common/FlagManager.h>
 #include <scheduler/FrameRateMode.h>
 #include <scheduler/VsyncConfig.h>
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
 #include "VSyncDispatch.h"
 
 #include "EventThread.h"
@@ -86,36 +86,43 @@
 
 std::string toString(const DisplayEventReceiver::Event& event) {
     switch (event.header.type) {
-        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+        case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
             return StringPrintf("Hotplug{displayId=%s, %s}",
                                 to_string(event.header.displayId).c_str(),
                                 event.hotplug.connected ? "connected" : "disconnected");
-        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+        case DisplayEventType::DISPLAY_EVENT_VSYNC:
             return StringPrintf("VSync{displayId=%s, count=%u, expectedPresentationTime=%" PRId64
                                 "}",
                                 to_string(event.header.displayId).c_str(), event.vsync.count,
                                 event.vsync.vsyncData.preferredExpectedPresentationTime());
-        case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+        case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE:
             return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
                                 to_string(event.header.displayId).c_str(), event.modeChange.modeId);
-        case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+        case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
             return StringPrintf("HdcpLevelsChange{displayId=%s, connectedLevel=%d, maxLevel=%d}",
                                 to_string(event.header.displayId).c_str(),
                                 event.hdcpLevelsChange.connectedLevel,
                                 event.hdcpLevelsChange.maxLevel);
-        case DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION:
+        case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
             return StringPrintf("ModeRejected{displayId=%s, modeId=%u}",
                                 to_string(event.header.displayId).c_str(),
                                 event.modeRejection.modeId);
-        default:
-            return "Event{}";
+        case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+            return StringPrintf("FrameRateOverride{displayId=%s, frameRateHz=%f}",
+                                to_string(event.header.displayId).c_str(),
+                                event.frameRateOverride.frameRateHz);
+        case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+            return StringPrintf("FrameRateOverrideFlush{displayId=%s}",
+                                to_string(event.header.displayId).c_str());
+        case DisplayEventType::DISPLAY_EVENT_NULL:
+            return "NULL";
     }
 }
 
 DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp,
                                         bool connected) {
     DisplayEventReceiver::Event event;
-    event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
+    event.header = {DisplayEventType::DISPLAY_EVENT_HOTPLUG, displayId, timestamp};
     event.hotplug.connected = connected;
     return event;
 }
@@ -123,7 +130,7 @@
 DisplayEventReceiver::Event makeHotplugError(nsecs_t timestamp, int32_t connectionError) {
     DisplayEventReceiver::Event event;
     PhysicalDisplayId unusedDisplayId;
-    event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, unusedDisplayId, timestamp};
+    event.header = {DisplayEventType::DISPLAY_EVENT_HOTPLUG, unusedDisplayId, timestamp};
     event.hotplug.connected = false;
     event.hotplug.connectionError = connectionError;
     return event;
@@ -133,7 +140,7 @@
                                       uint32_t count, nsecs_t expectedPresentationTime,
                                       nsecs_t deadlineTimestamp) {
     DisplayEventReceiver::Event event;
-    event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp};
+    event.header = {DisplayEventType::DISPLAY_EVENT_VSYNC, displayId, timestamp};
     event.vsync.count = count;
     event.vsync.vsyncData.preferredFrameTimelineIndex = 0;
     // Temporarily store the current vsync information in frameTimelines[0], marked as
@@ -148,7 +155,7 @@
 
 DisplayEventReceiver::Event makeModeChanged(const scheduler::FrameRateMode& mode) {
     DisplayEventReceiver::Event event;
-    event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
+    event.header = {DisplayEventType::DISPLAY_EVENT_MODE_CHANGE,
                     mode.modePtr->getPhysicalDisplayId(), systemTime()};
     event.modeChange.modeId = ftl::to_underlying(mode.modePtr->getId());
     event.modeChange.vsyncPeriod = mode.fps.getPeriodNsecs();
@@ -160,7 +167,7 @@
     return DisplayEventReceiver::Event{
             .header =
                     DisplayEventReceiver::Event::Header{
-                            .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
+                            .type = DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE,
                             .displayId = displayId,
                             .timestamp = systemTime(),
                     },
@@ -171,7 +178,7 @@
 DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId displayId) {
     return DisplayEventReceiver::Event{
             .header = DisplayEventReceiver::Event::Header{
-                    .type = DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
+                    .type = DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH,
                     .displayId = displayId,
                     .timestamp = systemTime(),
             }};
@@ -182,7 +189,7 @@
     return DisplayEventReceiver::Event{
             .header =
                     DisplayEventReceiver::Event::Header{
-                            .type = DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE,
+                            .type = DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE,
                             .displayId = displayId,
                             .timestamp = systemTime(),
                     },
@@ -195,7 +202,7 @@
     return DisplayEventReceiver::Event{
             .header =
                     DisplayEventReceiver::Event::Header{
-                            .type = DisplayEventReceiver::DISPLAY_EVENT_MODE_REJECTION,
+                            .type = DisplayEventType::DISPLAY_EVENT_MODE_REJECTION,
                             .displayId = displayId,
                             .timestamp = systemTime(),
                     },
@@ -263,10 +270,10 @@
         return size < 0 ? status_t(size) : status_t(NO_ERROR);
     };
 
-    if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE ||
-        event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
+    if (event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE ||
+        event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH) {
         mPendingEvents.emplace_back(event);
-        if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
+        if (event.header.type == DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE) {
             return status_t(NO_ERROR);
         }
 
@@ -524,7 +531,7 @@
             event = mPendingEvents.front();
             mPendingEvents.pop_front();
 
-            if (event->header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
+            if (event->header.type == DisplayEventType::DISPLAY_EVENT_HOTPLUG) {
                 if (event->hotplug.connectionError == 0) {
                     if (event->hotplug.connected && !mVSyncState) {
                         mVSyncState.emplace();
@@ -636,18 +643,21 @@
     };
 
     switch (event.header.type) {
-        case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
+        case DisplayEventType::DISPLAY_EVENT_HOTPLUG:
             return true;
 
-        case DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
+        case DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE:
             return true;
 
-        case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
+        case DisplayEventType::DISPLAY_EVENT_MODE_CHANGE: {
             return connection->mEventRegistration.test(
                     gui::ISurfaceComposer::EventRegistration::modeChanged);
         }
 
-        case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+        case DisplayEventType::DISPLAY_EVENT_MODE_REJECTION:
+            return true;
+
+        case DisplayEventType::DISPLAY_EVENT_VSYNC:
             switch (connection->vsyncRequest) {
                 case VSyncRequest::None:
                     return false;
@@ -673,13 +683,12 @@
                     return event.vsync.count % vsyncPeriod(connection->vsyncRequest) == 0;
             }
 
-        case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
+        case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE:
             [[fallthrough]];
-        case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
+        case DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH:
             return connection->mEventRegistration.test(
                     gui::ISurfaceComposer::EventRegistration::frameRateOverride);
-
-        default:
+        case DisplayEventType::DISPLAY_EVENT_NULL:
             return false;
     }
 }
@@ -758,7 +767,7 @@
     ftl::SmallVector<uid_t, 10> uidsPostedQueuedBuffers;
     for (const auto& consumer : consumers) {
         DisplayEventReceiver::Event copy = event;
-        if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+        if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
             const Period frameInterval = mCallback.getVsyncPeriod(consumer->mOwnerUid);
             copy.vsync.vsyncData.frameInterval = frameInterval.ns();
             generateFrameTimeline(copy.vsync.vsyncData, frameInterval.ns(), copy.header.timestamp,
@@ -793,7 +802,7 @@
     for (auto uid : uidsPostedQueuedBuffers) {
         mBufferStuffedUids.erase(uid);
     }
-    if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC &&
+    if (event.header.type == DisplayEventType::DISPLAY_EVENT_VSYNC &&
         FlagManager::getInstance().vrr_config()) {
         mLastCommittedVsyncTime =
                 TimePoint::fromNs(event.vsync.vsyncData.preferredExpectedPresentationTime());
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 2e1f938..91a798e 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -24,7 +24,7 @@
 #include <scheduler/interface/ICompositor.h>
 
 #include "EventThread.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
 #include "MessageQueue.h"
 
 namespace android::impl {
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 5f71b88..7123905 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -29,11 +29,15 @@
 
 std::shared_ptr<ScreenCaptureOutput> createScreenCaptureOutput(ScreenCaptureOutputArgs args) {
     std::shared_ptr<ScreenCaptureOutput> output = compositionengine::impl::createOutputTemplated<
-            ScreenCaptureOutput, compositionengine::CompositionEngine, const RenderArea&,
+            ScreenCaptureOutput, compositionengine::CompositionEngine,
+            /* sourceCrop */ const Rect, std::optional<DisplayId>,
             const compositionengine::Output::ColorProfile&,
-            bool>(args.compositionEngine, args.renderArea, args.colorProfile, args.regionSampling,
-                  args.dimInGammaSpaceForEnhancedScreenshots, args.enableLocalTonemapping);
-    output->editState().isSecure = args.renderArea.isSecure();
+            /* layerAlpha */ float,
+            /* regionSampling */ bool>(args.compositionEngine, args.sourceCrop, args.displayId,
+                                       args.colorProfile, args.layerAlpha, args.regionSampling,
+                                       args.dimInGammaSpaceForEnhancedScreenshots,
+                                       args.enableLocalTonemapping);
+    output->editState().isSecure = args.isSecure;
     output->editState().isProtected = args.isProtected;
     output->setCompositionEnabled(true);
     output->setLayerFilter({args.layerStack});
@@ -47,16 +51,16 @@
                     .setHasWideColorGamut(true)
                     .Build()));
 
-    const Rect& sourceCrop = args.renderArea.getSourceCrop();
+    const Rect& sourceCrop = args.sourceCrop;
     const ui::Rotation orientation = ui::ROTATION_0;
     output->setDisplaySize({sourceCrop.getWidth(), sourceCrop.getHeight()});
     output->setProjection(orientation, sourceCrop,
-                          {args.renderArea.getReqWidth(), args.renderArea.getReqHeight()});
+                          {args.reqBufferSize.width, args.reqBufferSize.height});
 
     {
         std::string name = args.regionSampling ? "RegionSampling" : "ScreenCaptureOutput";
-        if (auto displayDevice = args.renderArea.getDisplayDevice()) {
-            base::StringAppendF(&name, " for %" PRIu64, displayDevice->getId().value);
+        if (args.displayId) {
+            base::StringAppendF(&name, " for %" PRIu64, args.displayId.value().value);
         }
         output->setName(name);
     }
@@ -64,11 +68,14 @@
 }
 
 ScreenCaptureOutput::ScreenCaptureOutput(
-        const RenderArea& renderArea, const compositionengine::Output::ColorProfile& colorProfile,
+        const Rect sourceCrop, std::optional<DisplayId> displayId,
+        const compositionengine::Output::ColorProfile& colorProfile, float layerAlpha,
         bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots,
         bool enableLocalTonemapping)
-      : mRenderArea(renderArea),
+      : mSourceCrop(sourceCrop),
+        mDisplayId(displayId),
         mColorProfile(colorProfile),
+        mLayerAlpha(layerAlpha),
         mRegionSampling(regionSampling),
         mDimInGammaSpaceForEnhancedScreenshots(dimInGammaSpaceForEnhancedScreenshots),
         mEnableLocalTonemapping(enableLocalTonemapping) {}
@@ -83,7 +90,7 @@
         const std::shared_ptr<renderengine::ExternalTexture>& buffer) const {
     auto clientCompositionDisplay =
             compositionengine::impl::Output::generateClientCompositionDisplaySettings(buffer);
-    clientCompositionDisplay.clip = mRenderArea.getSourceCrop();
+    clientCompositionDisplay.clip = mSourceCrop;
 
     auto renderIntent = static_cast<ui::RenderIntent>(clientCompositionDisplay.renderIntent);
     if (mDimInGammaSpaceForEnhancedScreenshots && renderIntent != ui::RenderIntent::COLORIMETRIC &&
@@ -130,8 +137,8 @@
         }
 
         std::vector<aidl::android::hardware::graphics::composer3::Luts> luts;
-        if (auto displayDevice = mRenderArea.getDisplayDevice()) {
-            const auto id = PhysicalDisplayId::tryCast(displayDevice->getId());
+        if (mDisplayId) {
+            const auto id = PhysicalDisplayId::tryCast(mDisplayId.value());
             if (id) {
                 auto& hwc = getCompositionEngine().getHwComposer();
                 hwc.getLuts(*id, buffers, &luts);
@@ -201,14 +208,15 @@
         }
     }
 
-    Rect sourceCrop = mRenderArea.getSourceCrop();
     compositionengine::LayerFE::LayerSettings fillLayer;
     fillLayer.source.buffer.buffer = nullptr;
     fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f);
     fillLayer.geometry.boundaries =
-            FloatRect(static_cast<float>(sourceCrop.left), static_cast<float>(sourceCrop.top),
-                      static_cast<float>(sourceCrop.right), static_cast<float>(sourceCrop.bottom));
-    fillLayer.alpha = half(RenderArea::getCaptureFillValue(mRenderArea.getCaptureFill()));
+            FloatRect(static_cast<float>(mSourceCrop.left), static_cast<float>(mSourceCrop.top),
+                      static_cast<float>(mSourceCrop.right),
+                      static_cast<float>(mSourceCrop.bottom));
+
+    fillLayer.alpha = half(mLayerAlpha);
     clientCompositionLayers.insert(clientCompositionLayers.begin(), fillLayer);
 
     return clientCompositionLayers;
diff --git a/services/surfaceflinger/ScreenCaptureOutput.h b/services/surfaceflinger/ScreenCaptureOutput.h
index 444a28f..b3e98b1 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.h
+++ b/services/surfaceflinger/ScreenCaptureOutput.h
@@ -22,23 +22,25 @@
 #include <ui/Rect.h>
 #include <unordered_map>
 
-#include "RenderArea.h"
-
 namespace android {
 
 struct ScreenCaptureOutputArgs {
     const compositionengine::CompositionEngine& compositionEngine;
     const compositionengine::Output::ColorProfile& colorProfile;
-    const RenderArea& renderArea;
     ui::LayerStack layerStack;
+    Rect sourceCrop;
     std::shared_ptr<renderengine::ExternalTexture> buffer;
+    std::optional<DisplayId> displayId;
+    ui::Size reqBufferSize;
     float sdrWhitePointNits;
     float displayBrightnessNits;
     // Counterintuitively, when targetBrightness > 1.0 then dim the scene.
     float targetBrightness;
+    float layerAlpha;
     bool regionSampling;
     bool treat170mAsSrgb;
     bool dimInGammaSpaceForEnhancedScreenshots;
+    bool isSecure = false;
     bool isProtected = false;
     bool enableLocalTonemapping = false;
 };
@@ -49,10 +51,10 @@
 // SurfaceFlinger::captureLayers and SurfaceFlinger::captureDisplay.
 class ScreenCaptureOutput : public compositionengine::impl::Output {
 public:
-    ScreenCaptureOutput(const RenderArea& renderArea,
+    ScreenCaptureOutput(const Rect sourceCrop, std::optional<DisplayId> displayId,
                         const compositionengine::Output::ColorProfile& colorProfile,
-                        bool regionSampling, bool dimInGammaSpaceForEnhancedScreenshots,
-                        bool enableLocalTonemapping);
+                        float layerAlpha, bool regionSampling,
+                        bool dimInGammaSpaceForEnhancedScreenshots, bool enableLocalTonemapping);
 
     void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
 
@@ -67,8 +69,10 @@
 
 private:
     std::unordered_map<int32_t, aidl::android::hardware::graphics::composer3::Luts> generateLuts();
-    const RenderArea& mRenderArea;
+    const Rect mSourceCrop;
+    const std::optional<DisplayId> mDisplayId;
     const compositionengine::Output::ColorProfile& mColorProfile;
+    const float mLayerAlpha;
     const bool mRegionSampling;
     const bool mDimInGammaSpaceForEnhancedScreenshots;
     const bool mEnableLocalTonemapping;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index eecdd72..1163390 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -137,7 +137,6 @@
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/Hal.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
-#include "DisplayRenderArea.h"
 #include "Effects/Daltonizer.h"
 #include "FpsReporter.h"
 #include "FrameTimeline/FrameTimeline.h"
@@ -151,14 +150,12 @@
 #include "Jank/JankTracker.h"
 #include "Layer.h"
 #include "LayerProtoHelper.h"
-#include "LayerRenderArea.h"
 #include "LayerVector.h"
 #include "MutexUtils.h"
 #include "NativeWindowSurface.h"
 #include "PowerAdvisor/PowerAdvisor.h"
 #include "PowerAdvisor/Workload.h"
 #include "RegionSamplingThread.h"
-#include "RenderAreaBuilder.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/LayerHistory.h"
 #include "Scheduler/Scheduler.h"
@@ -1166,8 +1163,8 @@
     }
 
     Mutex::Autolock lock(mStateLock);
-    const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
-    const auto displayOpt = mPhysicalDisplays.get(*id).and_then(getDisplayDeviceAndSnapshot());
+    const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId));
+    const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot());
 
     if (!displayOpt) {
         return NAME_NOT_FOUND;
@@ -1289,9 +1286,9 @@
 
     Mutex::Autolock lock(mStateLock);
 
-    const auto id_ =
-            DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(physicalDisplayId));
-    const auto displayOpt = mPhysicalDisplays.get(*id_).and_then(getDisplayDeviceAndSnapshot());
+    const PhysicalDisplayId id =
+            PhysicalDisplayId::fromValue(static_cast<uint64_t>(physicalDisplayId));
+    const auto displayOpt = mPhysicalDisplays.get(id).and_then(getDisplayDeviceAndSnapshot());
 
     if (!displayOpt) {
         return NAME_NOT_FOUND;
@@ -2980,6 +2977,8 @@
     int index = 0;
     ftl::StaticVector<char, WorkloadTracer::COMPOSITION_SUMMARY_SIZE> compositionSummary;
     auto lastLayerStack = ui::INVALID_LAYER_STACK;
+
+    uint64_t prevOverrideBufferId = 0;
     for (auto& [layer, layerFE] : layers) {
         CompositionResult compositionResult{layerFE->stealCompositionResult()};
         if (lastLayerStack != layerFE->mSnapshot->outputFilter.layerStack) {
@@ -2989,8 +2988,37 @@
             }
             lastLayerStack = layerFE->mSnapshot->outputFilter.layerStack;
         }
+
+        // If there are N layers in a cached set they should all share the same buffer id.
+        // The first layer in the cached set will be not skipped and layers 1..N-1 will be skipped.
+        // We expect all layers in the cached set to be marked as composited by HWC.
+        // Here is a made up example of how it is visualized
+        //
+        //      [b:rrc][s:cc]
+        //
+        // This should be interpreted to mean that there are 2 cached sets.
+        // So there are only 2 non skipped layers -- b and s.
+        // The layers rrc and cc are flattened into layers b and s respectively.
+        const LayerFE::HwcLayerDebugState &hwcState = layerFE->getLastHwcState();
+        if (hwcState.overrideBufferId != prevOverrideBufferId) {
+            // End the existing run.
+            if (prevOverrideBufferId) {
+                compositionSummary.push_back(']');
+            }
+            // Start a new run.
+            if (hwcState.overrideBufferId) {
+                compositionSummary.push_back('[');
+            }
+        }
+
         compositionSummary.push_back(
-                layerFE->mSnapshot->classifyCompositionForDebug(layerFE->getHwcCompositionType()));
+                layerFE->mSnapshot->classifyCompositionForDebug(hwcState));
+
+        if (hwcState.overrideBufferId && !hwcState.wasSkipped) {
+                compositionSummary.push_back(':');
+        }
+        prevOverrideBufferId = hwcState.overrideBufferId;
+
         if (layerFE->mSnapshot->hasEffect()) {
             compositedWorkload |= adpf::Workload::EFFECTS;
         }
@@ -3002,6 +3030,10 @@
             mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult);
         }
     }
+    // End the last run.
+    if (prevOverrideBufferId) {
+        compositionSummary.push_back(']');
+    }
 
     // Concisely describe the layers composited this frame using single chars. GPU composited layers
     // are uppercase, DPU composited are lowercase. Special chars denote effects (blur, shadow,
@@ -6734,8 +6766,9 @@
                         return getDefaultDisplayDevice()->getDisplayToken().promote();
                     }
 
-                    if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(value)) {
-                        return getPhysicalDisplayToken(*id);
+                    if (const auto token =
+                                getPhysicalDisplayToken(PhysicalDisplayId::fromValue(value))) {
+                        return token;
                     }
 
                     ALOGE("Invalid physical display ID");
@@ -6833,10 +6866,10 @@
             case 1040: {
                 auto future = mScheduler->schedule([&] {
                     n = data.readInt32();
-                    std::optional<PhysicalDisplayId> inputId = std::nullopt;
+                    PhysicalDisplayId inputId;
                     if (uint64_t inputDisplayId; data.readUint64(&inputDisplayId) == NO_ERROR) {
-                        inputId = DisplayId::fromValue<PhysicalDisplayId>(inputDisplayId);
-                        if (!inputId || getPhysicalDisplayToken(*inputId)) {
+                        inputId = PhysicalDisplayId::fromValue(inputDisplayId);
+                        if (!getPhysicalDisplayToken(inputId)) {
                             ALOGE("No display with id: %" PRIu64, inputDisplayId);
                             return NAME_NOT_FOUND;
                         }
@@ -6845,7 +6878,7 @@
                         Mutex::Autolock lock(mStateLock);
                         mLayerCachingEnabled = n != 0;
                         for (const auto& [_, display] : mDisplays) {
-                            if (!inputId || *inputId == display->getPhysicalId()) {
+                            if (inputId == display->getPhysicalId()) {
                                 display->enableLayerCaching(mLayerCachingEnabled);
                             }
                         }
@@ -6928,11 +6961,10 @@
                         int64_t arg1 = data.readInt64();
                         int64_t arg2 = data.readInt64();
                         // Enable mirroring for one display
-                        const auto display1id = DisplayId::fromValue(arg1);
                         auto mirrorRoot = SurfaceComposerClient::getDefault()->mirrorDisplay(
-                                display1id.value());
-                        auto id2 = DisplayId::fromValue<PhysicalDisplayId>(arg2);
-                        const auto token2 = getPhysicalDisplayToken(*id2);
+                                DisplayId::fromValue(arg1));
+                        const auto token2 =
+                                getPhysicalDisplayToken(PhysicalDisplayId::fromValue(arg2));
                         ui::LayerStack layerStack;
                         {
                             Mutex::Autolock lock(mStateLock);
@@ -7220,9 +7252,13 @@
     }
 
     wp<const DisplayDevice> displayWeak;
+    DisplayId displayId;
     ui::LayerStack layerStack;
     ui::Size reqSize(args.width, args.height);
     std::unordered_set<uint32_t> excludeLayerIds;
+    Rect layerStackSpaceRect;
+    bool displayIsSecure;
+
     {
         Mutex::Autolock lock(mStateLock);
         sp<DisplayDevice> display = getDisplayDeviceLocked(args.displayToken);
@@ -7232,11 +7268,14 @@
             return;
         }
         displayWeak = display;
+        displayId = display->getId();
         layerStack = display->getLayerStack();
+        displayIsSecure = display->isSecure();
 
+        layerStackSpaceRect = display->getLayerStackSpaceRect();
         // set the requested width/height to the logical display layer stack rect size by default
         if (args.width == 0 || args.height == 0) {
-            reqSize = display->getLayerStackSpaceRect().getSize();
+            reqSize = layerStackSpaceRect.getSize();
         }
 
         for (const auto& handle : captureArgs.excludeHandles) {
@@ -7255,16 +7294,19 @@
             getLayerSnapshotsForScreenshots(layerStack, captureArgs.uid,
                                             std::move(excludeLayerIds));
 
-    ftl::Flags<RenderArea::Options> options;
-    if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS;
-    if (captureArgs.hintForSeamlessTransition)
-        options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
-    captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>,
-                                                 gui::aidl_utils::fromARect(captureArgs.sourceCrop),
-                                                 reqSize,
-                                                 static_cast<ui::Dataspace>(captureArgs.dataspace),
-                                                 displayWeak, options),
-                        getLayerSnapshotsFn, reqSize,
+    ScreenshotArgs screenshotArgs;
+    screenshotArgs.captureTypeVariant = displayWeak;
+    screenshotArgs.displayId = displayId;
+    screenshotArgs.sourceCrop = gui::aidl_utils::fromARect(captureArgs.sourceCrop);
+    if (screenshotArgs.sourceCrop.isEmpty()) {
+        screenshotArgs.sourceCrop = layerStackSpaceRect;
+    }
+    screenshotArgs.reqSize = reqSize;
+    screenshotArgs.dataspace = static_cast<ui::Dataspace>(captureArgs.dataspace);
+    screenshotArgs.isSecure = captureArgs.captureSecureLayers && displayIsSecure;
+    screenshotArgs.seamlessTransition = captureArgs.hintForSeamlessTransition;
+
+    captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, reqSize,
                         static_cast<ui::PixelFormat>(captureArgs.pixelFormat),
                         captureArgs.allowProtected, captureArgs.grayscale, captureListener);
 }
@@ -7274,6 +7316,9 @@
     ui::LayerStack layerStack;
     wp<const DisplayDevice> displayWeak;
     ui::Size size;
+    Rect layerStackSpaceRect;
+    bool displayIsSecure;
+
     {
         Mutex::Autolock lock(mStateLock);
 
@@ -7286,7 +7331,9 @@
 
         displayWeak = display;
         layerStack = display->getLayerStack();
+        layerStackSpaceRect = display->getLayerStackSpaceRect();
         size = display->getLayerStackSpaceRect().getSize();
+        displayIsSecure = display->isSecure();
     }
 
     size.width *= args.frameScaleX;
@@ -7315,15 +7362,18 @@
     constexpr bool kAllowProtected = false;
     constexpr bool kGrayscale = false;
 
-    ftl::Flags<RenderArea::Options> options;
-    if (args.hintForSeamlessTransition)
-        options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
-    captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<DisplayRenderAreaBuilder>,
-                                                 Rect(), size,
-                                                 static_cast<ui::Dataspace>(args.dataspace),
-                                                 displayWeak, options),
-                        getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat),
-                        kAllowProtected, kGrayscale, captureListener);
+    ScreenshotArgs screenshotArgs;
+    screenshotArgs.captureTypeVariant = displayWeak;
+    screenshotArgs.displayId = displayId;
+    screenshotArgs.sourceCrop = layerStackSpaceRect;
+    screenshotArgs.reqSize = size;
+    screenshotArgs.dataspace = static_cast<ui::Dataspace>(args.dataspace);
+    screenshotArgs.isSecure = args.captureSecureLayers && displayIsSecure;
+    screenshotArgs.seamlessTransition = args.hintForSeamlessTransition;
+
+    captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, size,
+                        static_cast<ui::PixelFormat>(args.pixelFormat), kAllowProtected, kGrayscale,
+                        captureListener);
 }
 
 ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) {
@@ -7425,14 +7475,16 @@
         return;
     }
 
-    ftl::Flags<RenderArea::Options> options;
-    if (captureArgs.captureSecureLayers) options |= RenderArea::Options::CAPTURE_SECURE_LAYERS;
-    if (captureArgs.hintForSeamlessTransition)
-        options |= RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION;
-    captureScreenCommon(RenderAreaBuilderVariant(std::in_place_type<LayerRenderAreaBuilder>, crop,
-                                                 reqSize, dataspace, parent, args.childrenOnly,
-                                                 options),
-                        getLayerSnapshotsFn, reqSize,
+    ScreenshotArgs screenshotArgs;
+    screenshotArgs.captureTypeVariant = parent->getSequence();
+    screenshotArgs.childrenOnly = args.childrenOnly;
+    screenshotArgs.sourceCrop = crop;
+    screenshotArgs.reqSize = reqSize;
+    screenshotArgs.dataspace = static_cast<ui::Dataspace>(captureArgs.dataspace);
+    screenshotArgs.isSecure = captureArgs.captureSecureLayers;
+    screenshotArgs.seamlessTransition = captureArgs.hintForSeamlessTransition;
+
+    captureScreenCommon(screenshotArgs, getLayerSnapshotsFn, reqSize,
                         static_cast<ui::PixelFormat>(captureArgs.pixelFormat),
                         captureArgs.allowProtected, captureArgs.grayscale, captureListener);
 }
@@ -7468,10 +7520,10 @@
 // is reduced when grabbed from the main thread, thus also reducing
 // risk of deadlocks.
 std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapshotsFromMainThread(
-        RenderAreaBuilderVariant& renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn,
+        ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn,
         std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
     return mScheduler
-            ->schedule([=, this, &renderAreaBuilder, &layers]() REQUIRES(kMainThreadContext) {
+            ->schedule([=, this, &args, &layers]() REQUIRES(kMainThreadContext) {
                 SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Screenshot");
                 mPowerAdvisor->setScreenshotWorkload();
                 SFTRACE_NAME("getSnapshotsFromMainThread");
@@ -7486,12 +7538,12 @@
                                                         ui::INVALID_LAYER_STACK);
                     }
                 }
-                return getDisplayStateFromRenderAreaBuilder(renderAreaBuilder);
+                return getDisplayStateOnMainThread(args);
             })
             .get();
 }
 
-void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder,
+void SurfaceFlinger::captureScreenCommon(ScreenshotArgs& args,
                                          GetLayerSnapshotsFunction getLayerSnapshotsFn,
                                          ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
                                          bool allowProtected, bool grayscale,
@@ -7507,7 +7559,11 @@
     }
 
     std::vector<std::pair<Layer*, sp<LayerFE>>> layers;
-    auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers);
+    auto displayState = getSnapshotsFromMainThread(args, getLayerSnapshotsFn, layers);
+    if (!displayState) {
+        ALOGD("Display state not found");
+        invokeScreenCaptureError(NO_MEMORY, captureListener);
+    }
 
     const bool hasHdrLayer = std::any_of(layers.cbegin(), layers.cend(), [this](const auto& layer) {
         return isHdrLayer(*(layer.second->mSnapshot.get()));
@@ -7545,12 +7601,8 @@
     std::shared_ptr<renderengine::impl::ExternalTexture> hdrTexture;
     std::shared_ptr<renderengine::impl::ExternalTexture> gainmapTexture;
 
-    bool hintForSeamless = std::visit(
-            [](auto&& arg) {
-                return arg.options.test(RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION);
-            },
-            renderAreaBuilder);
-    if (hasHdrLayer && !hintForSeamless && FlagManager::getInstance().true_hdr_screenshots()) {
+    if (hasHdrLayer && !args.seamlessTransition &&
+        FlagManager::getInstance().true_hdr_screenshots()) {
         const auto hdrBuffer =
                 getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(),
                                                  HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */,
@@ -7583,35 +7635,41 @@
         }
     }
 
-    auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */,
-                                         grayscale, isProtected, captureListener, displayState,
-                                         layers, hdrTexture, gainmapTexture);
+    auto futureFence =
+            captureScreenshot(args, texture, false /* regionSampling */, grayscale, isProtected,
+                              captureListener, displayState, layers, hdrTexture, gainmapTexture);
     futureFence.get();
 }
 
-std::optional<SurfaceFlinger::OutputCompositionState>
-SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& renderAreaBuilder) {
+std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getDisplayStateOnMainThread(
+        ScreenshotArgs& args) {
     sp<const DisplayDevice> display = nullptr;
     {
         Mutex::Autolock lock(mStateLock);
-        if (auto* layerRenderAreaBuilder =
-                    std::get_if<LayerRenderAreaBuilder>(&renderAreaBuilder)) {
+        // Screenshot initiated through captureLayers
+        if (auto* layerSequence = std::get_if<int32_t>(&args.captureTypeVariant)) {
             // LayerSnapshotBuilder should only be accessed from the main thread.
             const frontend::LayerSnapshot* snapshot =
-                    mLayerSnapshotBuilder.getSnapshot(layerRenderAreaBuilder->layer->getSequence());
+                    mLayerSnapshotBuilder.getSnapshot(*layerSequence);
             if (!snapshot) {
-                ALOGW("Couldn't find layer snapshot for %d",
-                      layerRenderAreaBuilder->layer->getSequence());
+                ALOGW("Couldn't find layer snapshot for %d", *layerSequence);
             } else {
-                layerRenderAreaBuilder->setLayerSnapshot(*snapshot);
+                if (!args.childrenOnly) {
+                    args.transform = snapshot->localTransform.inverse();
+                }
+                if (args.sourceCrop.isEmpty()) {
+                    args.sourceCrop = snapshot->bufferSize;
+                }
                 display = findDisplay(
                         [layerStack = snapshot->outputFilter.layerStack](const auto& display) {
                             return display.getLayerStack() == layerStack;
                         });
             }
-        } else if (auto* displayRenderAreaBuilder =
-                           std::get_if<DisplayRenderAreaBuilder>(&renderAreaBuilder)) {
-            display = displayRenderAreaBuilder->displayWeak.promote();
+
+            // Screenshot initiated through captureDisplay
+        } else if (auto* displayWeak =
+                           std::get_if<wp<const DisplayDevice>>(&args.captureTypeVariant)) {
+            display = displayWeak->promote();
         }
 
         if (display == nullptr) {
@@ -7626,9 +7684,9 @@
 }
 
 ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot(
-        const RenderAreaBuilderVariant& renderAreaBuilder,
-        const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
-        bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener,
+        const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+        bool regionSampling, bool grayscale, bool isProtected,
+        const sp<IScreenCaptureListener>& captureListener,
         const std::optional<OutputCompositionState>& displayState,
         const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers,
         const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer,
@@ -7636,18 +7694,6 @@
     SFTRACE_CALL();
 
     ScreenCaptureResults captureResults;
-    std::unique_ptr<const RenderArea> renderArea =
-            std::visit([](auto&& arg) -> std::unique_ptr<RenderArea> { return arg.build(); },
-                       renderAreaBuilder);
-
-    if (!renderArea) {
-        ALOGW("Skipping screen capture because of invalid render area.");
-        if (captureListener) {
-            captureResults.fenceResult = base::unexpected(NO_MEMORY);
-            captureListener->onScreenCaptureCompleted(captureResults);
-        }
-        return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share();
-    }
 
     float displayBrightnessNits = displayState.value().displayBrightnessNits;
     float sdrWhitePointNits = displayState.value().sdrWhitePointNits;
@@ -7656,8 +7702,8 @@
 
     if (hdrBuffer && gainmapBuffer) {
         ftl::SharedFuture<FenceResult> hdrRenderFuture =
-                renderScreenImpl(std::move(renderArea), hdrBuffer, regionSampling, grayscale,
-                                 isProtected, captureResults, displayState, layers);
+                renderScreenImpl(args, hdrBuffer, regionSampling, grayscale, isProtected,
+                                 captureResults, displayState, layers);
         captureResults.buffer = buffer->getBuffer();
         captureResults.optionalGainMap = gainmapBuffer->getBuffer();
 
@@ -7680,8 +7726,8 @@
                         })
                         .share();
     } else {
-        renderFuture = renderScreenImpl(std::move(renderArea), buffer, regionSampling, grayscale,
-                                        isProtected, captureResults, displayState, layers);
+        renderFuture = renderScreenImpl(args, buffer, regionSampling, grayscale, isProtected,
+                                        captureResults, displayState, layers);
     }
 
     if (captureListener) {
@@ -7701,8 +7747,7 @@
 }
 
 ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl(
-        std::unique_ptr<const RenderArea> renderArea,
-        const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+        const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>& buffer,
         bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults,
         const std::optional<OutputCompositionState>& displayState,
         const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) {
@@ -7713,29 +7758,27 @@
         captureResults.capturedSecureLayers |= (snapshot->isVisible && snapshot->isSecure);
         captureResults.capturedHdrLayers |= isHdrLayer(*snapshot);
         layerFE->mSnapshot->geomLayerTransform =
-                renderArea->getTransform() * layerFE->mSnapshot->geomLayerTransform;
+                args.transform * layerFE->mSnapshot->geomLayerTransform;
         layerFE->mSnapshot->geomInverseLayerTransform =
                 layerFE->mSnapshot->geomLayerTransform.inverse();
     }
 
     auto capturedBuffer = buffer;
 
-    auto requestedDataspace = renderArea->getReqDataSpace();
-    auto parent = renderArea->getParentLayer();
     auto renderIntent = RenderIntent::TONE_MAP_COLORIMETRIC;
     auto sdrWhitePointNits = DisplayDevice::sDefaultMaxLumiance;
     auto displayBrightnessNits = DisplayDevice::sDefaultMaxLumiance;
 
-    captureResults.capturedDataspace = requestedDataspace;
+    captureResults.capturedDataspace = args.dataspace;
 
-    const bool enableLocalTonemapping = FlagManager::getInstance().local_tonemap_screenshots() &&
-            !renderArea->getHintForSeamlessTransition();
+    const bool enableLocalTonemapping =
+            FlagManager::getInstance().local_tonemap_screenshots() && !args.seamlessTransition;
 
     if (displayState) {
         const auto& state = displayState.value();
         captureResults.capturedDataspace =
-                pickBestDataspace(requestedDataspace, state, captureResults.capturedHdrLayers,
-                                  renderArea->getHintForSeamlessTransition());
+                pickBestDataspace(args.dataspace, state, captureResults.capturedHdrLayers,
+                                  args.seamlessTransition);
         sdrWhitePointNits = state.sdrWhitePointNits;
 
         if (!captureResults.capturedHdrLayers) {
@@ -7747,7 +7790,7 @@
                 // Otherwise for seamless transitions it's important to match the current
                 // display state as the buffer will be shown under these same conditions, and we
                 // want to avoid any flickers
-                if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) {
+                if (sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
                     // Restrict the amount of HDR "headroom" in the screenshot to avoid
                     // over-dimming the SDR portion. 2.0 chosen by experimentation
                     constexpr float kMaxScreenshotHeadroom = 2.0f;
@@ -7758,8 +7801,7 @@
         }
 
         // Screenshots leaving the device should be colorimetric
-        if (requestedDataspace == ui::Dataspace::UNKNOWN &&
-            renderArea->getHintForSeamlessTransition()) {
+        if (args.dataspace == ui::Dataspace::UNKNOWN && args.seamlessTransition) {
             renderIntent = state.renderIntent;
         }
     }
@@ -7774,7 +7816,7 @@
 
     auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace,
                     sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, layers,
-                    layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent,
+                    layerStack, regionSampling, args, renderIntent,
                     enableLocalTonemapping]() -> FenceResult {
         std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
                 mFactory.createCompositionEngine();
@@ -7810,23 +7852,33 @@
             }
         }
 
+        // Capturing screenshots using layers have a clear capture fill (0 alpha).
+        // Capturing via display or displayId, which do not use args.layerSequence,
+        // has an opaque capture fill (1 alpha).
+        const float layerAlpha =
+                std::holds_alternative<int32_t>(args.captureTypeVariant) ? 0.0f : 1.0f;
+
         // Screenshots leaving the device must not dim in gamma space.
-        const bool dimInGammaSpaceForEnhancedScreenshots = mDimInGammaSpaceForEnhancedScreenshots &&
-                renderArea->getHintForSeamlessTransition();
+        const bool dimInGammaSpaceForEnhancedScreenshots =
+                mDimInGammaSpaceForEnhancedScreenshots && args.seamlessTransition;
 
         std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput(
                 ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine,
                                         .colorProfile = colorProfile,
-                                        .renderArea = *renderArea,
                                         .layerStack = layerStack,
+                                        .sourceCrop = args.sourceCrop,
                                         .buffer = std::move(buffer),
+                                        .displayId = args.displayId,
+                                        .reqBufferSize = args.reqSize,
                                         .sdrWhitePointNits = sdrWhitePointNits,
                                         .displayBrightnessNits = displayBrightnessNits,
                                         .targetBrightness = targetBrightness,
+                                        .layerAlpha = layerAlpha,
                                         .regionSampling = regionSampling,
                                         .treat170mAsSrgb = mTreat170mAsSrgb,
                                         .dimInGammaSpaceForEnhancedScreenshots =
                                                 dimInGammaSpaceForEnhancedScreenshots,
+                                        .isSecure = args.isSecure,
                                         .isProtected = isProtected,
                                         .enableLocalTonemapping = enableLocalTonemapping});
 
@@ -8697,8 +8749,8 @@
     if (status != OK) {
         return binderStatusFromStatusT(status);
     }
-    const auto id = DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId));
-    *outDisplay = mFlinger->getPhysicalDisplayToken(*id);
+    const PhysicalDisplayId id = PhysicalDisplayId::fromValue(static_cast<uint64_t>(displayId));
+    *outDisplay = mFlinger->getPhysicalDisplayToken(id);
     return binder::Status::ok();
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b3a3aad..935a2da 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -132,7 +132,6 @@
 class MessageBase;
 class RefreshRateOverlay;
 class RegionSamplingThread;
-class RenderArea;
 class TimeStats;
 class FrameTracer;
 class ScreenCapturer;
@@ -197,9 +196,6 @@
     Always,
 };
 
-struct DisplayRenderAreaBuilder;
-struct LayerRenderAreaBuilder;
-
 using DisplayColorSetting = compositionengine::OutputColorSetting;
 
 class SurfaceFlinger : public BnSurfaceComposer,
@@ -371,9 +367,7 @@
     friend class Layer;
     friend class RefreshRateOverlay;
     friend class RegionSamplingThread;
-    friend class LayerRenderArea;
     friend class SurfaceComposerAIDL;
-    friend class DisplayRenderArea;
 
     // For unit tests
     friend class TestableSurfaceFlinger;
@@ -382,7 +376,6 @@
 
     using TransactionSchedule = scheduler::TransactionSchedule;
     using GetLayerSnapshotsFunction = std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()>;
-    using RenderAreaBuilderVariant = std::variant<DisplayRenderAreaBuilder, LayerRenderAreaBuilder>;
     using DumpArgs = Vector<String16>;
     using Dumper = std::function<void(const DumpArgs&, bool asProto, std::string&)>;
 
@@ -868,20 +861,56 @@
 
     using OutputCompositionState = compositionengine::impl::OutputCompositionState;
 
+    /*
+     * Parameters used across screenshot methods.
+     */
+    struct ScreenshotArgs {
+        // Contains the sequence ID of the parent layer if the screenshot is
+        // initiated though captureLayers(), or the display that the render
+        // result will be on if initiated through captureDisplay()
+        std::variant<int32_t, wp<const DisplayDevice>> captureTypeVariant;
+
+        // Display ID of the display the result will be on
+        std::optional<DisplayId> displayId{std::nullopt};
+
+        // If true, transform is inverted from the parent layer snapshot
+        bool childrenOnly{false};
+
+        // Source crop of the render area
+        Rect sourceCrop;
+
+        // Transform to be applied on the layers to transform them
+        // into the logical render area
+        ui::Transform transform;
+
+        // Size of the physical render area
+        ui::Size reqSize;
+
+        // Composition dataspace of the render area
+        ui::Dataspace dataspace;
+
+        // If false, the secure layer is blacked out or skipped
+        // when rendered to an insecure render area
+        bool isSecure{false};
+
+        // If true, the render result may be used for system animations
+        // that must preserve the exact colors of the display
+        bool seamlessTransition{false};
+    };
+
     std::optional<OutputCompositionState> getSnapshotsFromMainThread(
-            RenderAreaBuilderVariant& renderAreaBuilder,
-            GetLayerSnapshotsFunction getLayerSnapshotsFn,
+            ScreenshotArgs& args, GetLayerSnapshotsFunction getLayerSnapshotsFn,
             std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
 
-    void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction,
-                             ui::Size bufferSize, ui::PixelFormat, bool allowProtected,
-                             bool grayscale, const sp<IScreenCaptureListener>&);
+    void captureScreenCommon(ScreenshotArgs& args, GetLayerSnapshotsFunction, ui::Size bufferSize,
+                             ui::PixelFormat, bool allowProtected, bool grayscale,
+                             const sp<IScreenCaptureListener>&);
 
-    std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder(
-            RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext);
+    std::optional<OutputCompositionState> getDisplayStateOnMainThread(ScreenshotArgs& args)
+            REQUIRES(kMainThreadContext);
 
     ftl::SharedFuture<FenceResult> captureScreenshot(
-            const RenderAreaBuilderVariant& renderAreaBuilder,
+            const ScreenshotArgs& args,
             const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling,
             bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener,
             const std::optional<OutputCompositionState>& displayState,
@@ -890,8 +919,7 @@
             const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr);
 
     ftl::SharedFuture<FenceResult> renderScreenImpl(
-            std::unique_ptr<const RenderArea> renderArea,
-            const std::shared_ptr<renderengine::ExternalTexture>&,
+            const ScreenshotArgs& args, const std::shared_ptr<renderengine::ExternalTexture>&,
             bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&,
             const std::optional<OutputCompositionState>& displayState,
             const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers);
diff --git a/services/surfaceflinger/common/include/common/WorkloadTracer.h b/services/surfaceflinger/common/include/common/WorkloadTracer.h
index 39b6fa1..c4074f7 100644
--- a/services/surfaceflinger/common/include/common/WorkloadTracer.h
+++ b/services/surfaceflinger/common/include/common/WorkloadTracer.h
@@ -23,7 +23,7 @@
 
 static constexpr int32_t COMPOSITION_TRACE_COOKIE = 1;
 static constexpr int32_t POST_COMPOSITION_TRACE_COOKIE = 2;
-static constexpr size_t COMPOSITION_SUMMARY_SIZE = 20;
+static constexpr size_t COMPOSITION_SUMMARY_SIZE = 64;
 static constexpr const char* TRACK_NAME = "CriticalWorkload";
 
 } // namespace android::WorkloadTracer
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
index b4496d3..5a82914 100644
--- a/services/surfaceflinger/tests/LayerCallback_test.cpp
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -147,7 +147,7 @@
                 << "Timeout waiting for vsync event";
         DisplayEventReceiver::Event event;
         while (mDisplayEventReceiver.getEvents(&event, 1) > 0) {
-            if (event.header.type != DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+            if (event.header.type != DisplayEventType::DISPLAY_EVENT_VSYNC) {
                 continue;
             }
 
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index ee5d919..7910e77 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -497,17 +497,6 @@
         mLifecycleManager.applyTransactions(transactions);
     }
 
-    void setClientDrawnShadowRadius(uint32_t id, float clientDrawnShadowRadius) {
-        std::vector<QueuedTransactionState> transactions;
-        transactions.emplace_back();
-        transactions.back().states.push_back({});
-
-        transactions.back().states.front().state.what = layer_state_t::eClientDrawnShadowsChanged;
-        transactions.back().states.front().layerId = id;
-        transactions.back().states.front().state.clientDrawnShadowRadius = clientDrawnShadowRadius;
-        mLifecycleManager.applyTransactions(transactions);
-    }
-
     void setShadowRadius(uint32_t id, float shadowRadius) {
         std::vector<QueuedTransactionState> transactions;
         transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 42259af..f1c1549 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -65,9 +65,9 @@
         "mock/MockFrameTracer.cpp",
         "mock/MockNativeWindowSurface.cpp",
         "mock/MockTimeStats.cpp",
-        "mock/MockVsyncController.cpp",
         "mock/MockVSyncDispatch.cpp",
         "mock/MockVSyncTracker.cpp",
+        "mock/MockVsyncController.cpp",
     ],
 }
 
@@ -87,10 +87,10 @@
     test_suites: ["device-tests"],
     header_libs: ["surfaceflinger_tests_common_headers"],
     srcs: [
+        "*.cpp",
         ":libsurfaceflinger_backend_mock_sources",
         ":libsurfaceflinger_mock_sources",
         ":libsurfaceflinger_sources",
-        "*.cpp",
     ],
 }
 
@@ -117,9 +117,8 @@
         "android.hardware.power@1.2",
         "android.hardware.power@1.3",
         "libaidlcommonsupport",
-        "libcompositionengine_mocks",
         "libcompositionengine",
-        "libframetimeline",
+        "libcompositionengine_mocks",
         "libgmock",
         "libgui_mocks",
         "libperfetto_client_experimental",
@@ -140,14 +139,15 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.common@1.2",
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libSurfaceFlingerProp",
         "libbase",
         "libbinder",
         "libbinder_ndk",
         "libcutils",
-        "libEGL",
         "libfmq",
-        "libGLESv1_CM",
-        "libGLESv2",
         "libgui",
         "libhidlbase",
         "libinput",
@@ -157,11 +157,10 @@
         "libprocessgroup",
         "libprotobuf-cpp-lite",
         "libstatslog_surfaceflinger",
-        "libSurfaceFlingerProp",
         "libsync",
+        "libtracing_perfetto",
         "libui",
         "libutils",
-        "libtracing_perfetto",
     ],
     header_libs: [
         "android.hardware.graphics.composer3-command-buffer",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 71cafbf..9ece312 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -36,7 +36,6 @@
 #include <system/window.h>
 #include <utils/String8.h>
 
-#include "DisplayRenderArea.h"
 #include "Layer.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
@@ -199,25 +198,21 @@
     const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
     constexpr bool regionSampling = false;
 
-    auto renderArea =
-            DisplayRenderArea::create(mDisplay, sourceCrop, sourceCrop.getSize(),
-                                      ui::Dataspace::V0_SRGB,
-                                      RenderArea::Options::CAPTURE_SECURE_LAYERS |
-                                              RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION);
-
     auto getLayerSnapshotsFn = mFlinger.getLayerSnapshotsForScreenshotsFn(mDisplay->getLayerStack(),
                                                                           CaptureArgs::UNSET_UID);
 
     const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
             GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
     mCaptureScreenBuffer =
-            std::make_shared<renderengine::mock::FakeExternalTexture>(renderArea->getReqWidth(),
-                                                                      renderArea->getReqHeight(),
+            std::make_shared<renderengine::mock::FakeExternalTexture>(sourceCrop.getSize().width,
+                                                                      sourceCrop.getSize().height,
                                                                       HAL_PIXEL_FORMAT_RGBA_8888, 1,
                                                                       usage);
 
-    auto future = mFlinger.renderScreenImpl(mDisplay, std::move(renderArea), getLayerSnapshotsFn,
-                                            mCaptureScreenBuffer, regionSampling);
+    auto future = mFlinger.renderScreenImpl(mDisplay, sourceCrop, ui::Dataspace::V0_SRGB,
+                                            getLayerSnapshotsFn, mCaptureScreenBuffer,
+                                            regionSampling, mDisplay->isSecure(),
+                                            /* seamlessTransition */ true);
     ASSERT_TRUE(future.valid());
     const auto fenceResult = future.get();
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 3fead93..81bfc97 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -193,7 +193,7 @@
     }
 };
 
-template <uint64_t displayId>
+template <VirtualDisplayId::BaseId displayId>
 struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
     static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
 };
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 268a6c4..6f15db8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -30,7 +30,7 @@
 
 #include "AsyncCallRecorder.h"
 #include "DisplayHardware/DisplayMode.h"
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
 #include "Scheduler/EventThread.h"
 #include "mock/MockVSyncDispatch.h"
 #include "mock/MockVSyncTracker.h"
@@ -270,7 +270,7 @@
     ASSERT_TRUE(args.has_value()) << name << " did not receive an event for timestamp "
                                   << expectedTimestamp;
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_VSYNC, event.header.type)
+    EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_VSYNC, event.header.type)
             << name << " did not get the correct event for timestamp " << expectedTimestamp;
     EXPECT_EQ(expectedTimestamp, event.header.timestamp)
             << name << " did not get the expected timestamp for timestamp " << expectedTimestamp;
@@ -344,7 +344,7 @@
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
+    EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_HOTPLUG, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
     EXPECT_EQ(expectedConnected, event.hotplug.connected);
 }
@@ -355,7 +355,7 @@
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, event.header.type);
+    EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_MODE_CHANGE, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
     EXPECT_EQ(expectedConfigId, event.modeChange.modeId);
     EXPECT_EQ(expectedVsyncPeriod, event.modeChange.vsyncPeriod);
@@ -367,7 +367,7 @@
         auto args = mConnectionEventCallRecorder.waitForCall();
         ASSERT_TRUE(args.has_value());
         const auto& event = std::get<0>(args.value());
-        EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, event.header.type);
+        EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE, event.header.type);
         EXPECT_EQ(expectedDisplayId, event.header.displayId);
         EXPECT_EQ(uid, event.frameRateOverride.uid);
         EXPECT_EQ(frameRateHz, event.frameRateOverride.frameRateHz);
@@ -376,7 +376,7 @@
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, event.header.type);
+    EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
 }
 
@@ -874,7 +874,7 @@
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, event.header.type);
+    EXPECT_EQ(DisplayEventType::DISPLAY_EVENT_HDCP_LEVELS_CHANGE, event.header.type);
     EXPECT_EQ(EXTERNAL_DISPLAY_ID, event.header.displayId);
     EXPECT_EQ(HDCP_V1, event.hdcpLevelsChange.connectedLevel);
     EXPECT_EQ(HDCP_V2, event.hdcpLevelsChange.maxLevel);
diff --git a/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp b/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
index 2941a14..0f16073 100644
--- a/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/JankTrackerTest.cpp
@@ -213,4 +213,33 @@
     EXPECT_EQ(listenerCount(), 0u);
 }
 
-} // namespace android
\ No newline at end of file
+TEST_F(JankTrackerTest, multipleLayersAreTrackedIndependently) {
+    size_t jankDataReceived = 0;
+    size_t numBatchesReceived = 0;
+
+    EXPECT_CALL(*mListener.get(), onJankData(_))
+            .WillRepeatedly([&](const std::vector<gui::JankData>& jankData) {
+                jankDataReceived += jankData.size();
+                numBatchesReceived++;
+                return binder::Status::ok();
+            });
+    addJankListener(123);
+    addJankListener(321);
+    addJankData(123, 1);
+    addJankData(123, 2);
+    addJankData(123, 3);
+    addJankData(321, 4);
+    addJankData(321, 5);
+
+    JankTracker::flushJankData(123);
+    flushBackgroundThread();
+    EXPECT_EQ(numBatchesReceived, 1u);
+    EXPECT_EQ(jankDataReceived, 3u);
+
+    JankTracker::flushJankData(321);
+    flushBackgroundThread();
+    EXPECT_EQ(numBatchesReceived, 2u);
+    EXPECT_EQ(jankDataReceived, 5u);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 453c053..7aad84b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -1505,14 +1505,6 @@
     EXPECT_EQ(getSnapshot({.id = 111})->roundedCorner.radius.x, RADIUS);
 }
 
-TEST_F(LayerSnapshotTest, ignoreShadows) {
-    static constexpr float SHADOW_RADIUS = 123.f;
-    setClientDrawnShadowRadius(1, SHADOW_RADIUS);
-    setShadowRadius(1, SHADOW_RADIUS);
-    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
-    EXPECT_EQ(getSnapshot({.id = 1})->shadowSettings.length, 0.f);
-}
-
 TEST_F(LayerSnapshotTest, setShadowRadius) {
     static constexpr float SHADOW_RADIUS = 123.f;
     setShadowRadius(1, SHADOW_RADIUS);
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 908637a..e9b86b2 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -22,7 +22,7 @@
 
 #include <scheduler/interface/ICompositor.h>
 
-#include "FrameTimeline.h"
+#include "FrameTimeline/FrameTimeline.h"
 #include "Scheduler/MessageQueue.h"
 #include "mock/MockVSyncDispatch.h"
 #include "utils/Timers.h"
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
index 2d3ebb4..aadff76 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -27,7 +27,8 @@
 
 class CreateDisplayTest : public DisplayTransactionTest {
 public:
-    void createDisplayWithRequestedRefreshRate(const std::string& name, uint64_t displayId,
+    void createDisplayWithRequestedRefreshRate(const std::string& name,
+                                               VirtualDisplayId::BaseId baseId,
                                                float pacesetterDisplayRefreshRate,
                                                float requestedRefreshRate,
                                                float expectedAdjustedRefreshRate) {
@@ -49,12 +50,10 @@
         EXPECT_EQ(display.requestedRefreshRate, Fps::fromValue(requestedRefreshRate));
         EXPECT_EQ(name.c_str(), display.displayName);
 
-        std::optional<VirtualDisplayId> vid =
-                DisplayId::fromValue<VirtualDisplayId>(displayId | DisplayId::FLAG_VIRTUAL);
-        ASSERT_TRUE(vid.has_value());
-
+        const VirtualDisplayId vid = GpuVirtualDisplayId(baseId);
         sp<DisplayDevice> device =
-                mFlinger.createVirtualDisplayDevice(displayToken, *vid, requestedRefreshRate);
+                mFlinger.createVirtualDisplayDevice(displayToken, vid, requestedRefreshRate);
+
         EXPECT_TRUE(device->isVirtual());
         device->adjustRefreshRate(Fps::fromValue(pacesetterDisplayRefreshRate));
         // verifying desired value
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2353ef8..9a2e254 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -42,7 +42,6 @@
 #include "FrontEnd/RequestedLayerState.h"
 #include "Layer.h"
 #include "NativeWindowSurface.h"
-#include "RenderArea.h"
 #include "Scheduler/RefreshRateSelector.h"
 #include "Scheduler/VSyncTracker.h"
 #include "Scheduler/VsyncController.h"
@@ -461,11 +460,11 @@
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
-    auto renderScreenImpl(const sp<DisplayDevice> display,
-                          std::unique_ptr<const RenderArea> renderArea,
+    auto renderScreenImpl(const sp<DisplayDevice> display, const Rect sourceCrop,
+                          ui::Dataspace dataspace,
                           SurfaceFlinger::GetLayerSnapshotsFunction getLayerSnapshotsFn,
                           const std::shared_ptr<renderengine::ExternalTexture>& buffer,
-                          bool regionSampling) {
+                          bool regionSampling, bool isSecure, bool seamlessTransition) {
         Mutex::Autolock lock(mFlinger->mStateLock);
         ftl::FakeGuard guard(kMainThreadContext);
 
@@ -473,7 +472,16 @@
         auto displayState = std::optional{display->getCompositionDisplay()->getState()};
         auto layers = getLayerSnapshotsFn();
 
-        return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling,
+        SurfaceFlinger::ScreenshotArgs screenshotArgs;
+        screenshotArgs.captureTypeVariant = display;
+        screenshotArgs.displayId = std::nullopt;
+        screenshotArgs.sourceCrop = sourceCrop;
+        screenshotArgs.reqSize = sourceCrop.getSize();
+        screenshotArgs.dataspace = dataspace;
+        screenshotArgs.isSecure = isSecure;
+        screenshotArgs.seamlessTransition = seamlessTransition;
+
+        return mFlinger->renderScreenImpl(screenshotArgs, buffer, regionSampling,
                                           false /* grayscale */, false /* isProtected */,
                                           captureResults, displayState, layers);
     }
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index 8b4a6be..77a68d9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -41,7 +41,7 @@
 
     while ((n = q->getEvents(buffer, 1)) > 0) {
         for (int i=0 ; i<n ; i++) {
-            if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+            if (buffer[i].header.type == DisplayEventType::DISPLAY_EVENT_VSYNC) {
                 printf("event vsync: count=%d\t", buffer[i].vsync.count);
             }
             if (oldTimeStamp) {