Merge "Remove libhostgraphics from libinput" into udc-qpr-dev
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index a6f503e..62e5f89 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -270,9 +270,9 @@
             layer_state_t::eFrameRateChanged | layer_state_t::eFixedTransformHintChanged;
 
     // Changes affecting data sent to input.
-    static constexpr uint64_t INPUT_CHANGES = layer_state_t::GEOMETRY_CHANGES |
-            layer_state_t::HIERARCHY_CHANGES | layer_state_t::eInputInfoChanged |
-            layer_state_t::eDropInputModeChanged | layer_state_t::eTrustedOverlayChanged;
+    static constexpr uint64_t INPUT_CHANGES = layer_state_t::eInputInfoChanged |
+            layer_state_t::eDropInputModeChanged | layer_state_t::eTrustedOverlayChanged |
+            layer_state_t::eLayerStackChanged;
 
     // Changes that affect the visible region on a display.
     static constexpr uint64_t VISIBLE_REGION_CHANGES =
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 0aa1bcb..545f6c2 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -61,7 +61,7 @@
 // For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED (4 * 1024)
 
-#define SENSOR_REGISTRATIONS_BUF_SIZE 200
+#define SENSOR_REGISTRATIONS_BUF_SIZE 500
 
 // Apps that targets S+ and do not have HIGH_SAMPLING_RATE_SENSORS permission will be capped
 // at 200 Hz. The cap also applies to all requests when the mic toggle is flipped to on, regardless
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index f7049b9..c0eb36d 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -20,6 +20,7 @@
 
 #include "AidlComposerHal.h"
 
+#include <SurfaceFlingerProperties.h>
 #include <android-base/file.h>
 #include <android/binder_ibinder_platform.h>
 #include <android/binder_manager.h>
@@ -249,15 +250,18 @@
         ALOGE("getInterfaceVersion for AidlComposer constructor failed %s",
               status.getDescription().c_str());
     }
-    if (version == 1) {
-        mClearSlotBuffer = sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBX_8888,
-                                                   GraphicBuffer::USAGE_HW_COMPOSER |
-                                                           GraphicBuffer::USAGE_SW_READ_OFTEN |
-                                                           GraphicBuffer::USAGE_SW_WRITE_OFTEN,
-                                                   "AidlComposer");
-        if (!mClearSlotBuffer || mClearSlotBuffer->initCheck() != ::android::OK) {
-            LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots");
-            return;
+    mSupportsBufferSlotsToClear = version > 1;
+    if (!mSupportsBufferSlotsToClear) {
+        if (sysprop::clear_slots_with_set_layer_buffer(false)) {
+            mClearSlotBuffer = sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBX_8888,
+                                                       GraphicBuffer::USAGE_HW_COMPOSER |
+                                                               GraphicBuffer::USAGE_SW_READ_OFTEN |
+                                                               GraphicBuffer::USAGE_SW_WRITE_OFTEN,
+                                                       "AidlComposer");
+            if (!mClearSlotBuffer || mClearSlotBuffer->initCheck() != ::android::OK) {
+                LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots");
+                return;
+            }
         }
     }
 
@@ -844,12 +848,12 @@
     Error error = Error::NONE;
     mMutex.lock_shared();
     if (auto writer = getWriter(display)) {
-        // Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder
-        // buffer, using the slot that needs to cleared... tricky.
-        if (mClearSlotBuffer == nullptr) {
+        if (mSupportsBufferSlotsToClear) {
             writer->get().setLayerBufferSlotsToClear(translate<int64_t>(display),
                                                      translate<int64_t>(layer), slotsToClear);
-        } else {
+            // Backwards compatible way of clearing buffer slots is to set the layer buffer with a
+            // placeholder buffer, using the slot that needs to cleared... tricky.
+        } else if (mClearSlotBuffer != nullptr) {
             for (uint32_t slot : slotsToClear) {
                 // Don't clear the active buffer slot because we need to restore the active buffer
                 // after clearing the requested buffer slots with a placeholder buffer.
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index ded91be..8d21b49 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -285,6 +285,8 @@
     // threading annotations.
     ftl::SharedMutex mMutex;
 
+    // Whether or not explicitly clearing buffer slots is supported.
+    bool mSupportsBufferSlotsToClear;
     // Buffer slots for layers are cleared by setting the slot buffer to this buffer.
     sp<GraphicBuffer> mClearSlotBuffer;
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index e0f6c45..9b41da5 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -24,12 +24,14 @@
 
 #include "HidlComposerHal.h"
 
+#include <SurfaceFlingerProperties.h>
 #include <android/binder_manager.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/HidlTransportUtils.h>
 #include <log/log.h>
 #include <utils/Trace.h>
+
 #include "HWC2.h"
 #include "Hal.h"
 
@@ -189,6 +191,9 @@
 }
 
 sp<GraphicBuffer> allocateClearSlotBuffer() {
+    if (!sysprop::clear_slots_with_set_layer_buffer(false)) {
+        return nullptr;
+    }
     sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBX_8888,
                                                        GraphicBuffer::USAGE_HW_COMPOSER |
                                                                GraphicBuffer::USAGE_SW_READ_OFTEN |
@@ -246,7 +251,7 @@
         LOG_ALWAYS_FATAL("failed to create composer client");
     }
 
-    if (!mClearSlotBuffer) {
+    if (!mClearSlotBuffer && sysprop::clear_slots_with_set_layer_buffer(false)) {
         LOG_ALWAYS_FATAL("Failed to allocate a buffer for clearing layer buffer slots");
         return;
     }
@@ -716,7 +721,11 @@
     if (slotsToClear.empty()) {
         return Error::NONE;
     }
-    // Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder
+    // This can be null when the HAL hasn't explicitly enabled this feature.
+    if (mClearSlotBuffer == nullptr) {
+        return Error::NONE;
+    }
+    //  Backwards compatible way of clearing buffer is to set the layer buffer with a placeholder
     // buffer, using the slot that needs to cleared... tricky.
     for (uint32_t slot : slotsToClear) {
         // Don't clear the active buffer slot because we need to restore the active buffer after
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 5913d4b..163d345 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -16,7 +16,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
-#define LOG_TAG "LayerHierarchy"
+#define LOG_TAG "SurfaceFlinger"
 
 #include "LayerHierarchy.h"
 #include "LayerLog.h"
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
index b25b731..5389ada 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h
@@ -42,10 +42,10 @@
 class LayerHierarchy {
 public:
     enum Variant : uint32_t {
-        Attached,
-        Detached,
-        Relative,
-        Mirror,
+        Attached, // child of the parent
+        Detached, // child of the parent but currently relative parented to another layer
+        Relative, // relative child of the parent
+        Mirror,   // mirrored from another layer
         ftl_first = Attached,
         ftl_last = Mirror,
     };
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index c9eb9c4..1712137 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -17,7 +17,7 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #undef LOG_TAG
-#define LOG_TAG "LayerLifecycleManager"
+#define LOG_TAG "SurfaceFlinger"
 
 #include "LayerLifecycleManager.h"
 #include "Client.h" // temporarily needed for LayerCreationArgs
@@ -51,6 +51,7 @@
                              it->second.owner.getDebugString().c_str());
         }
         mAddedLayers.push_back(newLayer.get());
+        mChangedLayers.push_back(newLayer.get());
         layer.parentId = linkLayer(layer.parentId, layer.id);
         layer.relativeParentId = linkLayer(layer.relativeParentId, layer.id);
         if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
@@ -202,6 +203,10 @@
                 continue;
             }
 
+            if (layer->changes.get() == 0) {
+                mChangedLayers.push_back(layer);
+            }
+
             if (transaction.flags & ISurfaceComposer::eAnimation) {
                 layer->changes |= RequestedLayerState::Changes::Animation;
             }
@@ -244,6 +249,7 @@
                     bgColorLayer->what |= layer_state_t::eColorChanged |
                             layer_state_t::eDataspaceChanged | layer_state_t::eAlphaChanged;
                     bgColorLayer->changes |= RequestedLayerState::Changes::Content;
+                    mChangedLayers.push_back(bgColorLayer);
                     mGlobalChanges |= RequestedLayerState::Changes::Content;
                 }
             }
@@ -290,6 +296,7 @@
         }
     }
     mDestroyedLayers.clear();
+    mChangedLayers.clear();
     mGlobalChanges.clear();
 }
 
@@ -310,10 +317,25 @@
     return mDestroyedLayers;
 }
 
+const std::vector<RequestedLayerState*>& LayerLifecycleManager::getChangedLayers() const {
+    return mChangedLayers;
+}
+
 const ftl::Flags<RequestedLayerState::Changes> LayerLifecycleManager::getGlobalChanges() const {
     return mGlobalChanges;
 }
 
+const RequestedLayerState* LayerLifecycleManager::getLayerFromId(uint32_t id) const {
+    if (id == UNASSIGNED_LAYER_ID) {
+        return nullptr;
+    }
+    auto it = mIdToLayer.find(id);
+    if (it == mIdToLayer.end()) {
+        return nullptr;
+    }
+    return &it->second.owner;
+}
+
 RequestedLayerState* LayerLifecycleManager::getLayerFromId(uint32_t id) {
     if (id == UNASSIGNED_LAYER_ID) {
         return nullptr;
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index f0d2c22..48571bf 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -76,7 +76,9 @@
     void removeLifecycleListener(std::shared_ptr<ILifecycleListener>);
     const std::vector<std::unique_ptr<RequestedLayerState>>& getLayers() const;
     const std::vector<std::unique_ptr<RequestedLayerState>>& getDestroyedLayers() const;
+    const std::vector<RequestedLayerState*>& getChangedLayers() const;
     const ftl::Flags<RequestedLayerState::Changes> getGlobalChanges() const;
+    const RequestedLayerState* getLayerFromId(uint32_t) const;
 
 private:
     friend class LayerLifecycleManagerTest;
@@ -111,6 +113,8 @@
     // Keeps track of all the layers that were added in order. Changes will be cleared once
     // committed.
     std::vector<RequestedLayerState*> mAddedLayers;
+    // Keeps track of new and layers with states changes since last commit.
+    std::vector<RequestedLayerState*> mChangedLayers;
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 3caeebe..f0826c6 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -16,7 +16,7 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
-#define LOG_TAG "LayerSnapshot"
+#define LOG_TAG "SurfaceFlinger"
 
 #include "LayerSnapshot.h"
 
@@ -24,6 +24,23 @@
 
 using namespace ftl::flag_operators;
 
+namespace {
+
+void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFrame,
+                         bool forceFullDamage, Region& outSurfaceDamageRegion) {
+    if (!hasReadyFrame) {
+        outSurfaceDamageRegion.clear();
+        return;
+    }
+    if (forceFullDamage) {
+        outSurfaceDamageRegion = Region::INVALID_REGION;
+    } else {
+        outSurfaceDamageRegion = requested.surfaceDamageRegion;
+    }
+}
+
+} // namespace
+
 LayerSnapshot::LayerSnapshot(const RequestedLayerState& state,
                              const LayerHierarchy::TraversalPath& path)
       : path(path) {
@@ -51,9 +68,11 @@
     uid = state.ownerUid;
     pid = state.ownerPid;
     changes = RequestedLayerState::Changes::Created;
+    clientChanges = 0;
     mirrorRootPath = path.variant == LayerHierarchy::Variant::Mirror
             ? path
             : LayerHierarchy::TraversalPath::ROOT;
+    reachablilty = LayerSnapshot::Reachablilty::Unreachable;
 }
 
 // As documented in libhardware header, formats in the range
@@ -131,6 +150,10 @@
 }
 
 bool LayerSnapshot::getIsVisible() const {
+    if (reachablilty != LayerSnapshot::Reachablilty::Reachable) {
+        return false;
+    }
+
     if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) {
         return false;
     }
@@ -148,12 +171,16 @@
 
 std::string LayerSnapshot::getIsVisibleReason() const {
     // not visible
-    if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) return "eLayerSkipScreenshot";
-    if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
-    if (invalidTransform) return "invalidTransform";
+    if (reachablilty == LayerSnapshot::Reachablilty::Unreachable)
+        return "layer not reachable from root";
+    if (reachablilty == LayerSnapshot::Reachablilty::ReachableByRelativeParent)
+        return "layer only reachable via relative parent";
     if (isHiddenByPolicyFromParent) return "hidden by parent or layer flag";
     if (isHiddenByPolicyFromRelativeParent) return "hidden by relative parent";
+    if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) return "eLayerSkipScreenshot";
+    if (invalidTransform) return "invalidTransform";
     if (color.a == 0.0f && !hasBlur()) return "alpha = 0 and no blur";
+    if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
 
     // visible
     std::stringstream reason;
@@ -177,8 +204,9 @@
 }
 
 bool LayerSnapshot::hasInputInfo() const {
-    return inputInfo.token != nullptr ||
-            inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL);
+    return (inputInfo.token != nullptr ||
+            inputInfo.inputConfig.test(gui::WindowInfo::InputConfig::NO_INPUT_CHANNEL)) &&
+            reachablilty == Reachablilty::Reachable;
 }
 
 std::string LayerSnapshot::getDebugString() const {
@@ -191,8 +219,16 @@
           << " geomLayerTransform={tx=" << geomLayerTransform.tx()
           << ",ty=" << geomLayerTransform.ty() << "}"
           << "}";
-    debug << " input{ touchCropId=" << touchCropId
-          << " replaceTouchableRegionWithCrop=" << inputInfo.replaceTouchableRegionWithCrop << "}";
+    if (hasInputInfo()) {
+        debug << " input{"
+              << "(" << inputInfo.inputConfig.string() << ")";
+        if (touchCropId != UNASSIGNED_LAYER_ID) debug << " touchCropId=" << touchCropId;
+        if (inputInfo.replaceTouchableRegionWithCrop) debug << " replaceTouchableRegionWithCrop";
+        auto touchableRegion = inputInfo.touchableRegion.getBounds();
+        debug << " touchableRegion={" << touchableRegion.left << "," << touchableRegion.top << ","
+              << touchableRegion.bottom << "," << touchableRegion.right << "}"
+              << "}";
+    }
     return debug.str();
 }
 
@@ -203,4 +239,172 @@
     return geomBufferSize.toFloatRect();
 }
 
+Hwc2::IComposerClient::BlendMode LayerSnapshot::getBlendMode(
+        const RequestedLayerState& requested) const {
+    auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
+    if (alpha != 1.0f || !contentOpaque) {
+        blendMode = requested.premultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
+                                                 : Hwc2::IComposerClient::BlendMode::COVERAGE;
+    }
+    return blendMode;
+}
+
+void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate,
+                          bool displayChanges, bool forceFullDamage,
+                          uint32_t displayRotationFlags) {
+    clientChanges = requested.what;
+    changes = requested.changes;
+    contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
+    // TODO(b/238781169) scope down the changes to only buffer updates.
+    hasReadyFrame = requested.hasReadyFrame();
+    sidebandStreamHasFrame = requested.hasSidebandStreamFrame();
+    updateSurfaceDamage(requested, hasReadyFrame, forceFullDamage, surfaceDamage);
+
+    if (forceUpdate || requested.what & layer_state_t::eTransparentRegionChanged) {
+        transparentRegionHint = requested.transparentRegion;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eFlagsChanged) {
+        layerOpaqueFlagSet =
+                (requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eBufferTransformChanged) {
+        geomBufferTransform = requested.bufferTransform;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eTransformToDisplayInverseChanged) {
+        geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eDataspaceChanged) {
+        dataspace = requested.dataspace;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eExtendedRangeBrightnessChanged) {
+        currentHdrSdrRatio = requested.currentHdrSdrRatio;
+        desiredHdrSdrRatio = requested.desiredHdrSdrRatio;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eCachingHintChanged) {
+        cachingHint = requested.cachingHint;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eHdrMetadataChanged) {
+        hdrMetadata = requested.hdrMetadata;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eSidebandStreamChanged) {
+        sidebandStream = requested.sidebandStream;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) {
+        shadowRadius = requested.shadowRadius;
+        shadowSettings.length = requested.shadowRadius;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) {
+        frameRateSelectionPriority = requested.frameRateSelectionPriority;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eColorSpaceAgnosticChanged) {
+        isColorspaceAgnostic = requested.colorSpaceAgnostic;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eDimmingEnabledChanged) {
+        dimmingEnabled = requested.dimmingEnabled;
+    }
+    if (forceUpdate || requested.what & layer_state_t::eCropChanged) {
+        geomCrop = requested.crop;
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eFlagsChanged | layer_state_t::eBufferChanged |
+                 layer_state_t::eSidebandStreamChanged)) {
+        compositionType = requested.getCompositionType();
+    }
+
+    if (forceUpdate || requested.what & layer_state_t::eInputInfoChanged) {
+        if (requested.windowInfoHandle) {
+            inputInfo = *requested.windowInfoHandle->getInfo();
+        } else {
+            inputInfo = {};
+            // b/271132344 revisit this and see if we can always use the layers uid/pid
+            inputInfo.name = requested.name;
+            inputInfo.ownerUid = requested.ownerUid;
+            inputInfo.ownerPid = requested.ownerPid;
+        }
+        inputInfo.id = static_cast<int32_t>(uniqueSequence);
+        touchCropId = requested.touchCropId;
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eColorChanged | layer_state_t::eBufferChanged |
+                 layer_state_t::eSidebandStreamChanged)) {
+        color.rgb = requested.getColor().rgb;
+    }
+
+    if (forceUpdate || requested.what & layer_state_t::eBufferChanged) {
+        acquireFence =
+                (requested.externalTexture &&
+                 requested.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged))
+                ? requested.bufferData->acquireFence
+                : Fence::NO_FENCE;
+        buffer = requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
+        externalTexture = requested.externalTexture;
+        frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
+        hasProtectedContent = requested.externalTexture &&
+                requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
+        geomUsesSourceCrop = hasBufferOrSidebandStream();
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eCropChanged | layer_state_t::eBufferCropChanged |
+                 layer_state_t::eBufferTransformChanged |
+                 layer_state_t::eTransformToDisplayInverseChanged) ||
+        requested.changes.test(RequestedLayerState::Changes::BufferSize) || displayChanges) {
+        bufferSize = requested.getBufferSize(displayRotationFlags);
+        geomBufferSize = bufferSize;
+        croppedBufferSize = requested.getCroppedBufferSize(bufferSize);
+        geomContentCrop = requested.getBufferCrop();
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eFlagsChanged | layer_state_t::eDestinationFrameChanged |
+                 layer_state_t::ePositionChanged | layer_state_t::eMatrixChanged |
+                 layer_state_t::eBufferTransformChanged |
+                 layer_state_t::eTransformToDisplayInverseChanged) ||
+        requested.changes.test(RequestedLayerState::Changes::BufferSize) || displayChanges) {
+        localTransform = requested.getTransform(displayRotationFlags);
+        localTransformInverse = localTransform.inverse();
+    }
+
+    if (forceUpdate || requested.what & (layer_state_t::eColorChanged) ||
+        requested.changes.test(RequestedLayerState::Changes::BufferSize)) {
+        color.rgb = requested.getColor().rgb;
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
+                 layer_state_t::eApiChanged)) {
+        isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
+                requested.api == NATIVE_WINDOW_API_MEDIA &&
+                requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
+                 layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged |
+                 layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) {
+        forceClientComposition = isHdrY410 || shadowSettings.length > 0 ||
+                requested.blurRegions.size() > 0 || stretchEffect.hasEffect();
+    }
+
+    if (forceUpdate ||
+        requested.what &
+                (layer_state_t::eColorChanged | layer_state_t::eShadowRadiusChanged |
+                 layer_state_t::eBlurRegionsChanged | layer_state_t::eBackgroundBlurRadiusChanged |
+                 layer_state_t::eCornerRadiusChanged | layer_state_t::eAlphaChanged |
+                 layer_state_t::eFlagsChanged | layer_state_t::eBufferChanged |
+                 layer_state_t::eSidebandStreamChanged)) {
+        contentOpaque = isContentOpaque();
+        isOpaque = contentOpaque && !roundedCorner.hasRoundedCorners() && color.a == 1.f;
+        blendMode = getBlendMode(requested);
+    }
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index b167d3e..2f45d52 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/LayerFECompositionState.h>
 #include <renderengine/LayerSettings.h>
+#include "DisplayHardware/ComposerHal.h"
 #include "LayerHierarchy.h"
 #include "RequestedLayerState.h"
 #include "Scheduler/LayerInfo.h"
@@ -57,6 +58,7 @@
     bool isHiddenByPolicyFromParent = false;
     bool isHiddenByPolicyFromRelativeParent = false;
     ftl::Flags<RequestedLayerState::Changes> changes;
+    uint64_t clientChanges = 0;
     // Some consumers of this snapshot (input, layer traces) rely on each snapshot to be unique.
     // For mirrored layers, snapshots will have the same sequence so this unique id provides
     // an alternative identifier when needed.
@@ -93,11 +95,37 @@
     bool handleSkipScreenshotFlag = false;
     int32_t frameRateSelectionPriority;
     LayerHierarchy::TraversalPath mirrorRootPath;
-    bool unreachable = true;
     uint32_t touchCropId;
-    uid_t uid;
-    pid_t pid;
+    gui::Uid uid = gui::Uid::INVALID;
+    gui::Pid pid = gui::Pid::INVALID;
     ChildState childState;
+    enum class Reachablilty : uint32_t {
+        // Can traverse the hierarchy from a root node and reach this snapshot
+        Reachable,
+        // Cannot traverse the hierarchy from a root node and reach this snapshot
+        Unreachable,
+        // Can only reach this node from a relative parent. This means the nodes parents are
+        // not reachable.
+        // See example scenario:
+        // ROOT
+        // ├── 1
+        // │   ├── 11
+        // │   │   └── 111
+        // │   ├── 12
+        // │   │   └ - 111 (relative)
+        // │   ├── 13
+        // │   └── 14
+        // │       └ * 12 (mirroring)
+        // └── 2
+        // 111 will create two snapshots, first when visited from 1 -> 12 or 1 -> 11 and the
+        // second when visited from 1 -> 14 -> 12. Because its parent 11 doesn't exist in the
+        // mirrored hierarchy, the second snapshot will be marked as ReachableByRelativeParent.
+        // This snapshot doesn't have any valid properties because it cannot inherit from its
+        // parent. Therefore, snapshots that are not reachable will be ignored for composition
+        // and input.
+        ReachableByRelativeParent
+    };
+    Reachablilty reachablilty;
 
     static bool isOpaqueFormat(PixelFormat format);
     static bool isTransformValid(const ui::Transform& t);
@@ -116,6 +144,10 @@
     std::string getIsVisibleReason() const;
     bool hasInputInfo() const;
     FloatRect sourceBounds() const;
+    Hwc2::IComposerClient::BlendMode getBlendMode(const RequestedLayerState& requested) const;
+
+    void merge(const RequestedLayerState& requested, bool forceUpdate, bool displayChanges,
+               bool forceFullDamage, uint32_t displayRotationFlags);
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index a266493..21f0a67 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -17,13 +17,14 @@
 // #define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
-#define LOG_TAG "LayerSnapshotBuilder"
+#define LOG_TAG "SurfaceFlinger"
 
 #include <numeric>
 #include <optional>
 
 #include <ftl/small_map.h>
 #include <gui/TraceUtils.h>
+#include <ui/DisplayMap.h>
 #include <ui/FloatRect.h>
 
 #include "DisplayHardware/HWC2.h"
@@ -257,19 +258,6 @@
     return blendMode;
 }
 
-void updateSurfaceDamage(const RequestedLayerState& requested, bool hasReadyFrame,
-                         bool forceFullDamage, Region& outSurfaceDamageRegion) {
-    if (!hasReadyFrame) {
-        outSurfaceDamageRegion.clear();
-        return;
-    }
-    if (forceFullDamage) {
-        outSurfaceDamageRegion = Region::INVALID_REGION;
-    } else {
-        outSurfaceDamageRegion = requested.surfaceDamageRegion;
-    }
-}
-
 void updateVisibility(LayerSnapshot& snapshot, bool visible) {
     snapshot.isVisible = visible;
 
@@ -287,6 +275,8 @@
     const bool visibleForInput =
             snapshot.hasInputInfo() ? snapshot.canReceiveInput() : snapshot.isVisible;
     snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visibleForInput);
+    LLOGV(snapshot.sequence, "updating visibility %s %s", visible ? "true" : "false",
+          snapshot.getDebugString().c_str());
 }
 
 bool needsInputInfo(const LayerSnapshot& snapshot, const RequestedLayerState& requested) {
@@ -329,18 +319,31 @@
 
 void clearChanges(LayerSnapshot& snapshot) {
     snapshot.changes.clear();
+    snapshot.clientChanges = 0;
     snapshot.contentDirty = false;
     snapshot.hasReadyFrame = false;
     snapshot.sidebandStreamHasFrame = false;
     snapshot.surfaceDamage.clear();
 }
 
+// TODO (b/259407931): Remove.
+uint32_t getPrimaryDisplayRotationFlags(
+        const ui::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displays) {
+    for (auto& [_, display] : displays) {
+        if (display.isPrimary) {
+            return display.rotationFlags;
+        }
+    }
+    return 0;
+}
+
 } // namespace
 
 LayerSnapshot LayerSnapshotBuilder::getRootSnapshot() {
     LayerSnapshot snapshot;
     snapshot.path = LayerHierarchy::TraversalPath::ROOT;
     snapshot.changes = ftl::Flags<RequestedLayerState::Changes>();
+    snapshot.clientChanges = 0;
     snapshot.isHiddenByPolicyFromParent = false;
     snapshot.isHiddenByPolicyFromRelativeParent = false;
     snapshot.parentTransform.reset();
@@ -374,43 +377,44 @@
 }
 
 bool LayerSnapshotBuilder::tryFastUpdate(const Args& args) {
-    if (args.forceUpdate != ForceUpdateFlags::NONE || args.displayChanges) {
-        // force update requested, or we have display changes, so skip the fast path
-        return false;
-    }
+    const bool forceUpdate = args.forceUpdate != ForceUpdateFlags::NONE;
 
-    if (args.layerLifecycleManager.getGlobalChanges().get() == 0) {
+    if (args.layerLifecycleManager.getGlobalChanges().get() == 0 && !forceUpdate &&
+        !args.displayChanges) {
         return true;
     }
 
-    if (args.layerLifecycleManager.getGlobalChanges() != RequestedLayerState::Changes::Content) {
-        // We have changes that require us to walk the hierarchy and update child layers.
-        // No fast path for you.
-        return false;
-    }
-
     // There are only content changes which do not require any child layer snapshots to be updated.
     ALOGV("%s", __func__);
     ATRACE_NAME("FastPath");
 
-    // Collect layers with changes
-    ftl::SmallMap<uint32_t, RequestedLayerState*, 10> layersWithChanges;
-    for (auto& layer : args.layerLifecycleManager.getLayers()) {
-        if (layer->changes.test(RequestedLayerState::Changes::Content)) {
-            layersWithChanges.emplace_or_replace(layer->id, layer.get());
+    uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
+    if (forceUpdate || args.displayChanges) {
+        for (auto& snapshot : mSnapshots) {
+            const RequestedLayerState* requested =
+                    args.layerLifecycleManager.getLayerFromId(snapshot->path.id);
+            if (!requested) continue;
+            snapshot->merge(*requested, forceUpdate, args.displayChanges, args.forceFullDamage,
+                            primaryDisplayRotationFlags);
+        }
+        return false;
+    }
+
+    // Walk through all the updated requested layer states and update the corresponding snapshots.
+    for (const RequestedLayerState* requested : args.layerLifecycleManager.getChangedLayers()) {
+        auto range = mIdToSnapshots.equal_range(requested->id);
+        for (auto it = range.first; it != range.second; it++) {
+            it->second->merge(*requested, forceUpdate, args.displayChanges, args.forceFullDamage,
+                              primaryDisplayRotationFlags);
         }
     }
 
-    // Walk through the snapshots, clearing previous change flags and updating the snapshots
-    // if needed.
-    for (auto& snapshot : mSnapshots) {
-        auto it = layersWithChanges.find(snapshot->path.id);
-        if (it != layersWithChanges.end()) {
-            ALOGV("%s fast path snapshot changes = %s", __func__,
-                  mRootSnapshot.changes.string().c_str());
-            LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
-            updateSnapshot(*snapshot, args, *it->second, mRootSnapshot, root);
-        }
+    if ((args.layerLifecycleManager.getGlobalChanges().get() &
+         ~(RequestedLayerState::Changes::Content | RequestedLayerState::Changes::Buffer).get()) !=
+        0) {
+        // We have changes that require us to walk the hierarchy and update child layers.
+        // No fast path for you.
+        return false;
     }
     return true;
 }
@@ -429,7 +433,15 @@
     if (args.forceUpdate == ForceUpdateFlags::HIERARCHY) {
         mRootSnapshot.changes |=
                 RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility;
+        mRootSnapshot.clientChanges |= layer_state_t::eReparent;
     }
+
+    for (auto& snapshot : mSnapshots) {
+        if (snapshot->reachablilty == LayerSnapshot::Reachablilty::Reachable) {
+            snapshot->reachablilty = LayerSnapshot::Reachablilty::Unreachable;
+        }
+    }
+
     LayerHierarchy::TraversalPath root = LayerHierarchy::TraversalPath::ROOT;
     if (args.root.getLayer()) {
         // The hierarchy can have a root layer when used for screenshots otherwise, it will have
@@ -468,13 +480,26 @@
     auto it = mSnapshots.begin();
     while (it < mSnapshots.end()) {
         auto& traversalPath = it->get()->path;
-        if (!it->get()->unreachable &&
-            destroyedLayerIds.find(traversalPath.id) == destroyedLayerIds.end()) {
+        const bool unreachable =
+                it->get()->reachablilty == LayerSnapshot::Reachablilty::Unreachable;
+        const bool isClone = traversalPath.isClone();
+        const bool layerIsDestroyed =
+                destroyedLayerIds.find(traversalPath.id) != destroyedLayerIds.end();
+        const bool destroySnapshot = (unreachable && isClone) || layerIsDestroyed;
+
+        if (!destroySnapshot) {
             it++;
             continue;
         }
 
-        mIdToSnapshot.erase(traversalPath);
+        mPathToSnapshot.erase(traversalPath);
+
+        auto range = mIdToSnapshots.equal_range(traversalPath.id);
+        auto matchingSnapshot =
+                std::find_if(range.first, range.second, [&traversalPath](auto& snapshotWithId) {
+                    return snapshotWithId.second->path == traversalPath;
+                });
+        mIdToSnapshots.erase(matchingSnapshot);
         mNeedsTouchableRegionCrop.erase(traversalPath);
         mSnapshots.back()->globalZ = it->get()->globalZ;
         std::iter_swap(it, mSnapshots.end() - 1);
@@ -507,8 +532,12 @@
     const RequestedLayerState* layer = hierarchy.getLayer();
     LayerSnapshot* snapshot = getSnapshot(traversalPath);
     const bool newSnapshot = snapshot == nullptr;
+    uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
     if (newSnapshot) {
         snapshot = createSnapshot(traversalPath, *layer, parentSnapshot);
+        snapshot->merge(*layer, /*forceUpdate=*/true, /*displayChanges=*/true, args.forceFullDamage,
+                        primaryDisplayRotationFlags);
+        snapshot->changes |= RequestedLayerState::Changes::Created;
     }
     scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate;
     if (traversalPath.isRelative()) {
@@ -546,8 +575,8 @@
 }
 
 LayerSnapshot* LayerSnapshotBuilder::getSnapshot(const LayerHierarchy::TraversalPath& id) const {
-    auto it = mIdToSnapshot.find(id);
-    return it == mIdToSnapshot.end() ? nullptr : it->second;
+    auto it = mPathToSnapshot.find(id);
+    return it == mPathToSnapshot.end() ? nullptr : it->second;
 }
 
 LayerSnapshot* LayerSnapshotBuilder::createSnapshot(const LayerHierarchy::TraversalPath& path,
@@ -559,7 +588,9 @@
     if (path.isClone() && path.variant != LayerHierarchy::Variant::Mirror) {
         snapshot->mirrorRootPath = parentSnapshot.mirrorRootPath;
     }
-    mIdToSnapshot[path] = snapshot;
+    mPathToSnapshot[path] = snapshot;
+
+    mIdToSnapshots.emplace(path.id, snapshot);
     return snapshot;
 }
 
@@ -574,20 +605,15 @@
     }
     mResortSnapshots = false;
 
-    for (auto& snapshot : mSnapshots) {
-        snapshot->unreachable = snapshot->path.isClone();
-    }
-
     size_t globalZ = 0;
     args.root.traverseInZOrder(
             [this, &globalZ](const LayerHierarchy&,
                              const LayerHierarchy::TraversalPath& traversalPath) -> bool {
                 LayerSnapshot* snapshot = getSnapshot(traversalPath);
                 if (!snapshot) {
-                    return false;
+                    return true;
                 }
 
-                snapshot->unreachable = false;
                 if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
                     updateVisibility(*snapshot, snapshot->getIsVisible());
                     size_t oldZ = snapshot->globalZ;
@@ -610,7 +636,7 @@
         mSnapshots[globalZ]->globalZ = globalZ;
         /* mark unreachable snapshots as explicitly invisible */
         updateVisibility(*mSnapshots[globalZ], false);
-        if (mSnapshots[globalZ]->unreachable) {
+        if (mSnapshots[globalZ]->reachablilty == LayerSnapshot::Reachablilty::Unreachable) {
             hasUnreachableSnapshots = true;
         }
         globalZ++;
@@ -634,7 +660,9 @@
             snapshot.relativeLayerMetadata = parentSnapshot.relativeLayerMetadata;
         }
     }
-    snapshot.isVisible = snapshot.getIsVisible();
+    if (snapshot.reachablilty == LayerSnapshot::Reachablilty::Unreachable) {
+        snapshot.reachablilty = LayerSnapshot::Reachablilty::ReachableByRelativeParent;
+    }
 }
 
 void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
@@ -675,16 +703,6 @@
     snapshot.relativeLayerMetadata.mMap.clear();
 }
 
-// TODO (b/259407931): Remove.
-uint32_t getPrimaryDisplayRotationFlags(const DisplayInfos& displays) {
-    for (auto& [_, display] : displays) {
-        if (display.isPrimary) {
-            return display.rotationFlags;
-        }
-    }
-    return 0;
-}
-
 void LayerSnapshotBuilder::updateSnapshot(LayerSnapshot& snapshot, const Args& args,
                                           const RequestedLayerState& requested,
                                           const LayerSnapshot& parentSnapshot,
@@ -694,82 +712,69 @@
             (RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Geometry |
              RequestedLayerState::Changes::Visibility | RequestedLayerState::Changes::Metadata |
              RequestedLayerState::Changes::AffectsChildren |
-             RequestedLayerState::Changes::FrameRate);
-    snapshot.changes |= parentChanges | requested.changes;
+             RequestedLayerState::Changes::FrameRate | RequestedLayerState::Changes::GameMode);
+    snapshot.changes |= parentChanges;
+    if (args.displayChanges) snapshot.changes |= RequestedLayerState::Changes::Geometry;
+    snapshot.reachablilty = LayerSnapshot::Reachablilty::Reachable;
+    snapshot.clientChanges |= (parentSnapshot.clientChanges & layer_state_t::AFFECTS_CHILDREN);
     snapshot.isHiddenByPolicyFromParent = parentSnapshot.isHiddenByPolicyFromParent ||
             parentSnapshot.invalidTransform || requested.isHiddenByPolicy() ||
             (args.excludeLayerIds.find(path.id) != args.excludeLayerIds.end());
-    snapshot.contentDirty = requested.what & layer_state_t::CONTENT_DIRTY;
-    // TODO(b/238781169) scope down the changes to only buffer updates.
-    snapshot.hasReadyFrame = requested.hasReadyFrame();
-    snapshot.sidebandStreamHasFrame = requested.hasSidebandStreamFrame();
-    updateSurfaceDamage(requested, snapshot.hasReadyFrame, args.forceFullDamage,
-                        snapshot.surfaceDamage);
-    snapshot.outputFilter.layerStack = parentSnapshot.path == LayerHierarchy::TraversalPath::ROOT
-            ? requested.layerStack
-            : parentSnapshot.outputFilter.layerStack;
 
-    uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
     const bool forceUpdate = args.forceUpdate == ForceUpdateFlags::ALL ||
+            snapshot.clientChanges & layer_state_t::eReparent ||
             snapshot.changes.any(RequestedLayerState::Changes::Visibility |
                                  RequestedLayerState::Changes::Created);
 
-    // always update the buffer regardless of visibility
-    if (forceUpdate || requested.what & layer_state_t::BUFFER_CHANGES || args.displayChanges) {
-        snapshot.acquireFence =
-                (requested.externalTexture &&
-                 requested.bufferData->flags.test(BufferData::BufferDataChange::fenceChanged))
-                ? requested.bufferData->acquireFence
-                : Fence::NO_FENCE;
-        snapshot.buffer =
-                requested.externalTexture ? requested.externalTexture->getBuffer() : nullptr;
-        snapshot.bufferSize = requested.getBufferSize(primaryDisplayRotationFlags);
-        snapshot.geomBufferSize = snapshot.bufferSize;
-        snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
-        snapshot.dataspace = requested.dataspace;
-        snapshot.externalTexture = requested.externalTexture;
-        snapshot.frameNumber = (requested.bufferData) ? requested.bufferData->frameNumber : 0;
-        snapshot.geomBufferTransform = requested.bufferTransform;
-        snapshot.geomBufferUsesDisplayInverseTransform = requested.transformToDisplayInverse;
-        snapshot.geomContentCrop = requested.getBufferCrop();
-        snapshot.geomUsesSourceCrop = snapshot.hasBufferOrSidebandStream();
-        snapshot.hasProtectedContent = requested.externalTexture &&
-                requested.externalTexture->getUsage() & GRALLOC_USAGE_PROTECTED;
-        snapshot.isHdrY410 = requested.dataspace == ui::Dataspace::BT2020_ITU_PQ &&
-                requested.api == NATIVE_WINDOW_API_MEDIA &&
-                requested.bufferData->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102;
-        snapshot.sidebandStream = requested.sidebandStream;
-        snapshot.transparentRegionHint = requested.transparentRegion;
-        snapshot.color.rgb = requested.getColor().rgb;
-        snapshot.currentHdrSdrRatio = requested.currentHdrSdrRatio;
-        snapshot.desiredHdrSdrRatio = requested.desiredHdrSdrRatio;
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eLayerStackChanged) {
+        // If root layer, use the layer stack otherwise get the parent's layer stack.
+        snapshot.outputFilter.layerStack =
+                parentSnapshot.path == LayerHierarchy::TraversalPath::ROOT
+                ? requested.layerStack
+                : parentSnapshot.outputFilter.layerStack;
     }
 
     if (snapshot.isHiddenByPolicyFromParent &&
         !snapshot.changes.test(RequestedLayerState::Changes::Created)) {
         if (forceUpdate ||
-            snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
-                                 RequestedLayerState::Changes::Geometry |
+            snapshot.changes.any(RequestedLayerState::Changes::Geometry |
                                  RequestedLayerState::Changes::Input)) {
             updateInput(snapshot, requested, parentSnapshot, path, args);
         }
         return;
     }
 
-    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
-        // If root layer, use the layer stack otherwise get the parent's layer stack.
+    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Mirror)) {
+        // Display mirrors are always placed in a VirtualDisplay so we never want to capture layers
+        // marked as skip capture
+        snapshot.handleSkipScreenshotFlag = parentSnapshot.handleSkipScreenshotFlag ||
+                (requested.layerStackToMirror != ui::INVALID_LAYER_STACK);
+    }
+
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eAlphaChanged) {
         snapshot.color.a = parentSnapshot.color.a * requested.color.a;
         snapshot.alpha = snapshot.color.a;
         snapshot.inputInfo.alpha = snapshot.color.a;
+    }
 
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eFlagsChanged) {
         snapshot.isSecure =
                 parentSnapshot.isSecure || (requested.flags & layer_state_t::eLayerSecure);
-        snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay;
         snapshot.outputFilter.toInternalDisplay = parentSnapshot.outputFilter.toInternalDisplay ||
                 (requested.flags & layer_state_t::eLayerSkipScreenshot);
+    }
+
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eTrustedOverlayChanged) {
+        snapshot.isTrustedOverlay = parentSnapshot.isTrustedOverlay || requested.isTrustedOverlay;
+    }
+
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eStretchChanged) {
         snapshot.stretchEffect = (requested.stretchEffect.hasEffect())
                 ? requested.stretchEffect
                 : parentSnapshot.stretchEffect;
+    }
+
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eColorTransformChanged) {
         if (!parentSnapshot.colorTransformIsIdentity) {
             snapshot.colorTransform = parentSnapshot.colorTransform * requested.colorTransform;
             snapshot.colorTransformIsIdentity = false;
@@ -777,16 +782,20 @@
             snapshot.colorTransform = requested.colorTransform;
             snapshot.colorTransformIsIdentity = !requested.hasColorTransform;
         }
+    }
+
+    if (forceUpdate || snapshot.changes.test(RequestedLayerState::Changes::GameMode)) {
         snapshot.gameMode = requested.metadata.has(gui::METADATA_GAME_MODE)
                 ? requested.gameMode
                 : parentSnapshot.gameMode;
-        // Display mirrors are always placed in a VirtualDisplay so we never want to capture layers
-        // marked as skip capture
-        snapshot.handleSkipScreenshotFlag = parentSnapshot.handleSkipScreenshotFlag ||
-                (requested.layerStackToMirror != ui::INVALID_LAYER_STACK);
+        updateMetadata(snapshot, requested, args);
+        if (args.includeMetadata) {
+            snapshot.layerMetadata = parentSnapshot.layerMetadata;
+            snapshot.layerMetadata.merge(requested.metadata);
+        }
     }
 
-    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren) ||
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eFixedTransformHintChanged ||
         args.displayChanges) {
         snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
                 ? requested.fixedTransformHint
@@ -802,9 +811,7 @@
         }
     }
 
-    if (forceUpdate ||
-        snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
-                             RequestedLayerState::Changes::Hierarchy)) {
+    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) {
         snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
                               (requested.requestedFrameRate.type ==
                                scheduler::LayerInfo::FrameRateCompatibility::NoVote))
@@ -812,23 +819,10 @@
                 : parentSnapshot.frameRate;
     }
 
-    if (forceUpdate || requested.what & layer_state_t::eMetadataChanged) {
-        updateMetadata(snapshot, requested, args);
-    }
-
-    if (forceUpdate || requested.changes.get() != 0) {
-        snapshot.compositionType = requested.getCompositionType();
-        snapshot.dimmingEnabled = requested.dimmingEnabled;
-        snapshot.layerOpaqueFlagSet =
-                (requested.flags & layer_state_t::eLayerOpaque) == layer_state_t::eLayerOpaque;
-        snapshot.cachingHint = requested.cachingHint;
-        snapshot.frameRateSelectionPriority = requested.frameRateSelectionPriority;
-    }
-
-    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Content) ||
-        snapshot.changes.any(RequestedLayerState::Changes::AffectsChildren)) {
-        snapshot.color.rgb = requested.getColor().rgb;
-        snapshot.isColorspaceAgnostic = requested.colorSpaceAgnostic;
+    if (forceUpdate ||
+        snapshot.clientChanges &
+                (layer_state_t::eBackgroundBlurRadiusChanged | layer_state_t::eBlurRegionsChanged |
+                 layer_state_t::eAlphaChanged)) {
         snapshot.backgroundBlurRadius = args.supportsBlur
                 ? static_cast<int>(parentSnapshot.color.a * (float)requested.backgroundBlurRadius)
                 : 0;
@@ -836,29 +830,30 @@
         for (auto& region : snapshot.blurRegions) {
             region.alpha = region.alpha * snapshot.color.a;
         }
-        snapshot.hdrMetadata = requested.hdrMetadata;
     }
 
-    if (forceUpdate ||
-        snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
-                             RequestedLayerState::Changes::Geometry)) {
+    if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
+        uint32_t primaryDisplayRotationFlags = getPrimaryDisplayRotationFlags(args.displays);
         updateLayerBounds(snapshot, requested, parentSnapshot, primaryDisplayRotationFlags);
+    }
+
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged ||
+        snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
         updateRoundedCorner(snapshot, requested, parentSnapshot);
     }
 
+    if (forceUpdate || snapshot.clientChanges & layer_state_t::eShadowRadiusChanged ||
+        snapshot.changes.any(RequestedLayerState::Changes::Geometry)) {
+        updateShadows(snapshot, requested, args.globalShadowSettings);
+    }
+
     if (forceUpdate ||
-        snapshot.changes.any(RequestedLayerState::Changes::Hierarchy |
-                             RequestedLayerState::Changes::Geometry |
+        snapshot.changes.any(RequestedLayerState::Changes::Geometry |
                              RequestedLayerState::Changes::Input)) {
         updateInput(snapshot, requested, parentSnapshot, path, args);
     }
 
     // computed snapshot properties
-    updateShadows(snapshot, requested, args.globalShadowSettings);
-    if (args.includeMetadata) {
-        snapshot.layerMetadata = parentSnapshot.layerMetadata;
-        snapshot.layerMetadata.merge(requested.metadata);
-    }
     snapshot.forceClientComposition = snapshot.isHdrY410 || snapshot.shadowSettings.length > 0 ||
             requested.blurRegions.size() > 0 || snapshot.stretchEffect.hasEffect();
     snapshot.contentOpaque = snapshot.isContentOpaque();
@@ -914,10 +909,6 @@
                                              const RequestedLayerState& requested,
                                              const LayerSnapshot& parentSnapshot,
                                              uint32_t primaryDisplayRotationFlags) {
-    snapshot.croppedBufferSize = requested.getCroppedBufferSize(snapshot.bufferSize);
-    snapshot.geomCrop = requested.crop;
-    snapshot.localTransform = requested.getTransform(primaryDisplayRotationFlags);
-    snapshot.localTransformInverse = snapshot.localTransform.inverse();
     snapshot.geomLayerTransform = parentSnapshot.geomLayerTransform * snapshot.localTransform;
     const bool transformWasInvalid = snapshot.invalidTransform;
     snapshot.invalidTransform = !LayerSnapshot::isTransformValid(snapshot.geomLayerTransform);
@@ -974,11 +965,8 @@
     }
 }
 
-void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot,
-                                         const RequestedLayerState& requested,
+void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const RequestedLayerState&,
                                          const renderengine::ShadowSettings& globalShadowSettings) {
-    snapshot.shadowRadius = requested.shadowRadius;
-    snapshot.shadowSettings.length = requested.shadowRadius;
     if (snapshot.shadowRadius > 0.f) {
         snapshot.shadowSettings = globalShadowSettings;
 
@@ -1058,10 +1046,11 @@
         snapshot.inputInfo.inputConfig |= gui::WindowInfo::InputConfig::DROP_INPUT;
     }
 
-    auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
-    if (cropLayerSnapshot) {
+    if (requested.touchCropId != UNASSIGNED_LAYER_ID || path.isClone()) {
         mNeedsTouchableRegionCrop.insert(path);
-    } else if (snapshot.inputInfo.replaceTouchableRegionWithCrop) {
+    }
+    auto cropLayerSnapshot = getSnapshot(requested.touchCropId);
+    if (!cropLayerSnapshot && snapshot.inputInfo.replaceTouchableRegionWithCrop) {
         FloatRect inputBounds = getInputBounds(snapshot, /*fillParentBounds=*/true).first;
         Rect inputBoundsInDisplaySpace =
                 getInputBoundsInDisplaySpace(snapshot, inputBounds, displayInfo.transform);
@@ -1081,8 +1070,6 @@
         // Cloned layers shouldn't handle watch outside since their z order is not determined by
         // WM or the client.
         snapshot.inputInfo.inputConfig.clear(gui::WindowInfo::InputConfig::WATCH_OUTSIDE_TOUCH);
-
-        mNeedsTouchableRegionCrop.insert(path);
     }
 }
 
@@ -1139,7 +1126,7 @@
             RequestedLayerState::Changes::Input;
 
     if (args.forceUpdate != ForceUpdateFlags::ALL &&
-        !args.layerLifecycleManager.getGlobalChanges().any(AFFECTS_INPUT)) {
+        !args.layerLifecycleManager.getGlobalChanges().any(AFFECTS_INPUT) && !args.displayChanges) {
         return;
     }
 
@@ -1148,6 +1135,8 @@
         if (!snapshot) {
             continue;
         }
+        LLOGV(snapshot->sequence, "updateTouchableRegionCrop=%s",
+              snapshot->getDebugString().c_str());
         const std::optional<frontend::DisplayInfo> displayInfoOpt =
                 args.displays.get(snapshot->outputFilter.layerStack);
         static frontend::DisplayInfo sDefaultInfo = {.isSecure = false};
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 2e46dc6..c81a5d2 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -122,7 +122,9 @@
 
     std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
                        LayerHierarchy::TraversalPathHash>
-            mIdToSnapshot;
+            mPathToSnapshot;
+    std::multimap<uint32_t, LayerSnapshot*> mIdToSnapshots;
+
     // Track snapshots that needs touchable region crop from other snapshots
     std::unordered_set<LayerHierarchy::TraversalPath, LayerHierarchy::TraversalPathHash>
             mNeedsTouchableRegionCrop;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index bde2d05..5738262 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -13,10 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// #define LOG_NDEBUG 0
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 #undef LOG_TAG
-#define LOG_TAG "RequestedLayerState"
+#define LOG_TAG "SurfaceFlinger"
 
 #include <log/log.h>
 #include <private/android_filesystem_config.h>
@@ -132,12 +133,16 @@
     const half oldAlpha = color.a;
     const bool hadBuffer = externalTexture != nullptr;
     uint64_t oldFramenumber = hadBuffer ? bufferData->frameNumber : 0;
+    const ui::Size oldBufferSize = hadBuffer
+            ? ui::Size(externalTexture->getWidth(), externalTexture->getHeight())
+            : ui::Size();
     const bool hadSideStream = sidebandStream != nullptr;
     const layer_state_t& clientState = resolvedComposerState.state;
     const bool hadBlur = hasBlur();
     uint64_t clientChanges = what | layer_state_t::diff(clientState);
     layer_state_t::merge(clientState);
     what = clientChanges;
+    LLOGV(layerId, "requested=%" PRIu64 "flags=%" PRIu64, clientState.what, clientChanges);
 
     if (clientState.what & layer_state_t::eFlagsChanged) {
         if ((oldFlags ^ flags) & layer_state_t::eLayerHidden) {
@@ -154,6 +159,13 @@
         const bool hasBuffer = externalTexture != nullptr;
         if (hasBuffer || hasBuffer != hadBuffer) {
             changes |= RequestedLayerState::Changes::Buffer;
+            const ui::Size newBufferSize = hasBuffer
+                    ? ui::Size(externalTexture->getWidth(), externalTexture->getHeight())
+                    : ui::Size();
+            if (oldBufferSize != newBufferSize) {
+                changes |= RequestedLayerState::Changes::BufferSize;
+                changes |= RequestedLayerState::Changes::Geometry;
+            }
         }
 
         if (hasBuffer != hadBuffer) {
@@ -281,7 +293,7 @@
             // child layers.
             if (static_cast<int32_t>(gameMode) != requestedGameMode) {
                 gameMode = static_cast<gui::GameMode>(requestedGameMode);
-                changes |= RequestedLayerState::Changes::AffectsChildren;
+                changes |= RequestedLayerState::Changes::GameMode;
             }
         }
     }
@@ -372,7 +384,7 @@
     return (flags & layer_state_t::eLayerHidden) == layer_state_t::eLayerHidden;
 };
 half4 RequestedLayerState::getColor() const {
-    if ((sidebandStream != nullptr) || (externalTexture != nullptr)) {
+    if (sidebandStream || externalTexture) {
         return {0._hf, 0._hf, 0._hf, color.a};
     }
     return color;
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 0ef50bc..02e3bac 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -54,6 +54,8 @@
         Buffer = 1u << 15,
         SidebandStream = 1u << 16,
         Animation = 1u << 17,
+        BufferSize = 1u << 18,
+        GameMode = 1u << 19,
     };
     static Rect reduce(const Rect& win, const Region& exclude);
     RequestedLayerState(const LayerCreationArgs&);
@@ -91,10 +93,10 @@
     const uint32_t textureName;
     // The owner of the layer. If created from a non system process, it will be the calling uid.
     // If created from a system process, the value can be passed in.
-    const uid_t ownerUid;
+    const gui::Uid ownerUid;
     // The owner pid of the layer. If created from a non system process, it will be the calling pid.
     // If created from a system process, the value can be passed in.
-    const pid_t ownerPid;
+    const gui::Pid ownerPid;
     bool dataspaceRequested;
     bool hasColorTransform;
     bool premultipliedAlpha{true};
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index 9cbe0bb..fa8eb3c 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -16,7 +16,7 @@
 
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
-#define LOG_TAG "TransactionHandler"
+#define LOG_TAG "SurfaceFlinger"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <cutils/trace.h>
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 427a85c..1c7581b 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -428,7 +428,7 @@
 
     layerInfo->set_is_relative_of(requestedState.isRelativeOf);
 
-    layerInfo->set_owner_uid(requestedState.ownerUid);
+    layerInfo->set_owner_uid(requestedState.ownerUid.val());
 
     if ((traceFlags & LayerTracing::TRACE_INPUT) && snapshot.hasInputInfo()) {
         LayerProtoHelper::writeToProto(snapshot.inputInfo, {},
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9c3fb09..8ffc3c3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2172,6 +2172,7 @@
 bool SurfaceFlinger::updateLayerSnapshotsLegacy(VsyncId vsyncId, frontend::Update& update,
                                                 bool transactionsFlushed,
                                                 bool& outTransactionsAreEmpty) {
+    ATRACE_CALL();
     bool needsTraversal = false;
     if (transactionsFlushed) {
         needsTraversal |= commitMirrorDisplays(vsyncId);
@@ -2224,7 +2225,7 @@
 bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, frontend::Update& update,
                                           bool transactionsFlushed, bool& outTransactionsAreEmpty) {
     using Changes = frontend::RequestedLayerState::Changes;
-    ATRACE_NAME("updateLayerSnapshots");
+    ATRACE_CALL();
     {
         mLayerLifecycleManager.addLayers(std::move(update.newLayers));
         mLayerLifecycleManager.applyTransactions(update.transactions);
@@ -8164,7 +8165,7 @@
                     if (layerStack && snapshot->outputFilter.layerStack != *layerStack) {
                         return;
                     }
-                    if (uid != CaptureArgs::UNSET_UID && snapshot->uid != uid) {
+                    if (uid != CaptureArgs::UNSET_UID && snapshot->uid != gui::Uid(uid)) {
                         return;
                     }
                     if (!snapshot->hasSomethingToDraw()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 20fa091..96c8b54 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -375,5 +375,9 @@
     return SurfaceFlingerProperties::ignore_hdr_camera_layers().value_or(defaultValue);
 }
 
+bool clear_slots_with_set_layer_buffer(bool defaultValue) {
+    return SurfaceFlingerProperties::clear_slots_with_set_layer_buffer().value_or(defaultValue);
+}
+
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 080feee..951f8f8 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -102,6 +102,8 @@
 
 bool ignore_hdr_camera_layers(bool defaultValue);
 
+bool clear_slots_with_set_layer_buffer(bool defaultValue);
+
 } // namespace sysprop
 } // namespace android
 #endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index bcbe21a..689f51a 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -470,4 +470,18 @@
     scope: Public
     access: Readonly
     prop_name: "ro.surface_flinger.ignore_hdr_camera_layers"
-}
\ No newline at end of file
+}
+
+# When enabled, SurfaceFlinger will attempt to clear the per-layer HAL buffer cache slots for
+# buffers when they are evicted from the app cache by using additional setLayerBuffer commands.
+# Ideally, this behavior would always be enabled to reduce graphics memory consumption. However,
+# Some HAL implementations may not support the additional setLayerBuffer commands used to clear
+# the cache slots.
+prop {
+    api_name: "clear_slots_with_set_layer_buffer"
+    type: Boolean
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.clear_slots_with_set_layer_buffer"
+}
+
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index 348a462..9660ff3 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -1,6 +1,10 @@
 props {
   module: "android.sysprop.SurfaceFlingerProperties"
   prop {
+    api_name: "clear_slots_with_set_layer_buffer"
+    prop_name: "ro.surface_flinger.clear_slots_with_set_layer_buffer"
+  }
+  prop {
     api_name: "color_space_agnostic_dataspace"
     type: Long
     prop_name: "ro.surface_flinger.color_space_agnostic_dataspace"
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 12cf070..5da893e 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -228,6 +228,7 @@
     setAlpha(1, 0.5);
     setAlpha(122, 0.5);
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot(1)->alpha, 0.5f);
     EXPECT_EQ(getSnapshot(12)->alpha, 0.5f);
     EXPECT_EQ(getSnapshot(1221)->alpha, 0.25f);
 }
@@ -236,28 +237,30 @@
 TEST_F(LayerSnapshotTest, UpdateClearsPreviousChangeStates) {
     setCrop(1, Rect(1, 2, 3, 4));
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
-    EXPECT_TRUE(getSnapshot(1)->changes.get() != 0);
-    EXPECT_TRUE(getSnapshot(11)->changes.get() != 0);
+    EXPECT_TRUE(getSnapshot(1)->changes.test(RequestedLayerState::Changes::Geometry));
+    EXPECT_TRUE(getSnapshot(11)->changes.test(RequestedLayerState::Changes::Geometry));
     setCrop(2, Rect(1, 2, 3, 4));
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
-    EXPECT_TRUE(getSnapshot(2)->changes.get() != 0);
-    EXPECT_TRUE(getSnapshot(1)->changes.get() == 0);
-    EXPECT_TRUE(getSnapshot(11)->changes.get() == 0);
+    EXPECT_TRUE(getSnapshot(2)->changes.test(RequestedLayerState::Changes::Geometry));
+    EXPECT_FALSE(getSnapshot(1)->changes.test(RequestedLayerState::Changes::Geometry));
+    EXPECT_FALSE(getSnapshot(11)->changes.test(RequestedLayerState::Changes::Geometry));
 }
 
 TEST_F(LayerSnapshotTest, FastPathClearsPreviousChangeStates) {
     setColor(11, {1._hf, 0._hf, 0._hf});
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
-    EXPECT_TRUE(getSnapshot(11)->changes.get() != 0);
-    EXPECT_TRUE(getSnapshot(1)->changes.get() == 0);
+    EXPECT_EQ(getSnapshot(11)->changes, RequestedLayerState::Changes::Content);
+    EXPECT_EQ(getSnapshot(11)->clientChanges, layer_state_t::eColorChanged);
+    EXPECT_EQ(getSnapshot(1)->changes.get(), 0u);
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
-    EXPECT_TRUE(getSnapshot(11)->changes.get() == 0);
+    EXPECT_EQ(getSnapshot(11)->changes.get(), 0u);
 }
 
 TEST_F(LayerSnapshotTest, FastPathSetsChangeFlagToContent) {
     setColor(1, {1._hf, 0._hf, 0._hf});
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
     EXPECT_EQ(getSnapshot(1)->changes, RequestedLayerState::Changes::Content);
+    EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::eColorChanged);
 }
 
 TEST_F(LayerSnapshotTest, GameMode) {
@@ -270,7 +273,9 @@
     transactions.back().states.front().layerId = 1;
     transactions.back().states.front().state.layerId = static_cast<int32_t>(1);
     mLifecycleManager.applyTransactions(transactions);
+    EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::GameMode);
     UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+    EXPECT_EQ(getSnapshot(1)->clientChanges, layer_state_t::eMetadataChanged);
     EXPECT_EQ(static_cast<int32_t>(getSnapshot(1)->gameMode), 42);
     EXPECT_EQ(static_cast<int32_t>(getSnapshot(11)->gameMode), 42);
 }
@@ -309,7 +314,7 @@
     EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote);
 }
 
-TEST_F(LayerSnapshotTest, canCropTouchableRegion) {
+TEST_F(LayerSnapshotTest, CanCropTouchableRegion) {
     // ROOT
     // ├── 1
     // │   ├── 11