CE: Snapshot layer metadata

Adds LayerMetadata to LayerSnapshots. LayerMetadata is only populated
when CE enables the new feature flag and the feature flag will only be
enabled in ARC++'s CE.

This change is necessary to split LayerFE from the Layer class as
ARC++'s LayerFE subclass accesses LayerMetadata.

Bug: 238781169
Test: go/wm-smoke
Test: presubmit

Change-Id: Iae405707897eedf5af9025fe628c1cd60b596e10
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 3faa068..6832ae1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -18,9 +18,10 @@
 
 #include <TimeStats/TimeStats.h>
 #include <utils/Timers.h>
-
 #include <memory>
 
+#include "Feature.h"
+
 namespace android {
 
 class HWComposer;
@@ -72,6 +73,8 @@
     // TODO(b/121291683): These will become private/internal
     virtual void preComposition(CompositionRefreshArgs&) = 0;
 
+    virtual FeatureFlags getFeatureFlags() const = 0;
+
     // Debugging
     virtual void dump(std::string&) const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
new file mode 100644
index 0000000..ee8000a
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Feature.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/flags.h>
+#include <cstdint>
+
+namespace android::compositionengine {
+
+enum class Feature : int32_t {
+    kSnapshotLayerMetadata = 1 << 0,
+};
+
+using FeatureFlags = ftl::Flags<Feature>;
+
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index a738da0..fe8cad5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -39,6 +39,10 @@
 
 class Fence;
 
+namespace gui {
+struct LayerMetadata;
+}
+
 namespace compositionengine {
 
 struct LayerFECompositionState;
@@ -144,6 +148,8 @@
     // Whether the layer should be rendered with rounded corners.
     virtual bool hasRoundedCorners() const = 0;
     virtual void setWasClientComposed(const sp<Fence>&) {}
+    virtual const gui::LayerMetadata* getMetadata() const = 0;
+    virtual const gui::LayerMetadata* getRelativeMetadata() const = 0;
 };
 
 // TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index 0907926..dd4dbe9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -48,6 +48,8 @@
 
     void preComposition(CompositionRefreshArgs&) override;
 
+    FeatureFlags getFeatureFlags() const override;
+
     // Debugging
     void dump(std::string&) const override;
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index f953d0b..a48cc6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -53,6 +53,8 @@
 
     MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
 
+    MOCK_CONST_METHOD0(getFeatureFlags, FeatureFlags());
+
     MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index be0dbce..14922a4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -53,6 +53,8 @@
     MOCK_CONST_METHOD0(getDebugName, const char*());
     MOCK_CONST_METHOD0(getSequence, int32_t());
     MOCK_CONST_METHOD0(hasRoundedCorners, bool());
+    MOCK_CONST_METHOD0(getMetadata, gui::LayerMetadata*());
+    MOCK_CONST_METHOD0(getRelativeMetadata, gui::LayerMetadata*());
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 855507e..a4e1fff 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -140,6 +140,10 @@
     mNeedsAnotherUpdate = needsAnotherUpdate;
 }
 
+FeatureFlags CompositionEngine::getFeatureFlags() const {
+    return {};
+}
+
 void CompositionEngine::dump(std::string&) const {
     // The base class has no state to dump, but derived classes might.
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 13437a4..55a32ab 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -4241,6 +4241,38 @@
     preparePerFrameCompositionState();
 }
 
+void Layer::updateMetadataSnapshot(const LayerMetadata& parentMetadata) {
+    mSnapshot->layerMetadata = parentMetadata;
+    mSnapshot->layerMetadata.merge(mDrawingState.metadata);
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->updateMetadataSnapshot(mSnapshot->layerMetadata);
+    }
+}
+
+void Layer::updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
+                                           std::unordered_set<Layer*>& visited) {
+    if (visited.find(this) != visited.end()) {
+        ALOGW("Cycle containing layer %s detected in z-order relatives", getDebugName());
+        return;
+    }
+    visited.insert(this);
+
+    mSnapshot->relativeLayerMetadata = relativeLayerMetadata;
+
+    if (mDrawingState.zOrderRelatives.empty()) {
+        return;
+    }
+    LayerMetadata childRelativeLayerMetadata = mSnapshot->relativeLayerMetadata;
+    childRelativeLayerMetadata.merge(mSnapshot->layerMetadata);
+    for (wp<Layer> weakRelative : mDrawingState.zOrderRelatives) {
+        sp<Layer> relative = weakRelative.promote();
+        if (!relative) {
+            continue;
+        }
+        relative->updateRelativeMetadataSnapshot(childRelativeLayerMetadata, visited);
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4079d16..4ff86e5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -166,6 +166,8 @@
         ui::Transform transform;
         Rect bufferSize;
         std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+        LayerMetadata layerMetadata;
+        LayerMetadata relativeLayerMetadata;
     };
 
     using FrameRate = scheduler::LayerInfo::FrameRate;
@@ -611,6 +613,12 @@
         mClearClientCompositionFenceOnLayerDisplayed = false;
     }
 
+    const LayerMetadata* getMetadata() const override { return &mSnapshot->layerMetadata; }
+
+    const LayerMetadata* getRelativeMetadata() const override {
+        return &mSnapshot->relativeLayerMetadata;
+    }
+
     const char* getDebugName() const override;
 
     bool setShadowRadius(float shadowRadius);
@@ -901,6 +909,9 @@
     // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
     // CompositionEngine to create a single path for composing layers.
     void updateSnapshot(bool updateGeometry);
+    void updateMetadataSnapshot(const LayerMetadata& parentMetadata);
+    void updateRelativeMetadataSnapshot(const LayerMetadata& relativeLayerMetadata,
+                                        std::unordered_set<Layer*>& visited);
 
 protected:
     friend class impl::SurfaceInterceptor;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e27c713..07e7e3a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2211,6 +2211,13 @@
     }
     mPowerAdvisor->setDisplays(displayIds);
 
+    const bool updateTaskMetadata = mCompositionEngine->getFeatureFlags().test(
+            compositionengine::Feature::kSnapshotLayerMetadata);
+    if (updateTaskMetadata && (mVisibleRegionsDirty || mLayerMetadataSnapshotNeeded)) {
+        updateLayerMetadataSnapshot();
+        mLayerMetadataSnapshotNeeded = false;
+    }
+
     if (DOES_CONTAIN_BORDER) {
         refreshArgs.borderInfoList.clear();
         mDrawingState.traverse([&refreshArgs](Layer* layer) {
@@ -4445,7 +4452,10 @@
             layer->setGameModeForTree(static_cast<GameMode>(gameMode));
         }
 
-        if (layer->setMetadata(s.metadata)) flags |= eTraversalNeeded;
+        if (layer->setMetadata(s.metadata)) {
+            flags |= eTraversalNeeded;
+            mLayerMetadataSnapshotNeeded = true;
+        }
     }
     if (what & layer_state_t::eColorSpaceAgnosticChanged) {
         if (layer->setColorSpaceAgnostic(s.colorSpaceAgnostic)) {
@@ -7240,6 +7250,31 @@
     return true;
 }
 
+void SurfaceFlinger::updateLayerMetadataSnapshot() {
+    LayerMetadata parentMetadata;
+    for (const auto& layer : mDrawingState.layersSortedByZ) {
+        layer->updateMetadataSnapshot(parentMetadata);
+    }
+
+    std::unordered_set<Layer*> visited;
+    mDrawingState.traverse([&visited](Layer* layer) {
+        if (visited.find(layer) != visited.end()) {
+            return;
+        }
+
+        // If the layer isRelativeOf, then either it's relative metadata will be set
+        // recursively when updateRelativeMetadataSnapshot is called on its relative parent or
+        // it's relative parent has been deleted. Clear the layer's relativeLayerMetadata to ensure
+        // that layers with deleted relative parents don't hold stale relativeLayerMetadata.
+        if (layer->getDrawingState().isRelativeOf) {
+            layer->editLayerSnapshot()->relativeLayerMetadata = {};
+            return;
+        }
+
+        layer->updateRelativeMetadataSnapshot({}, visited);
+    });
+}
+
 // gui::ISurfaceComposer
 
 binder::Status SurfaceComposerAIDL::bootFinished() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3c92d56..0c60137 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -699,6 +699,7 @@
     bool latchBuffers();
 
     void updateLayerGeometry();
+    void updateLayerMetadataSnapshot();
 
     void updateInputFlinger();
     void persistDisplayBrightness(bool needsComposite) REQUIRES(kMainThreadContext);
@@ -1176,6 +1177,9 @@
     bool mSomeDataspaceChanged = false;
     bool mForceTransactionDisplayChange = false;
 
+    // Set if LayerMetadata has changed since the last LayerMetadata snapshot.
+    bool mLayerMetadataSnapshotNeeded = false;
+
     // Tracks layers that have pending frames which are candidates for being
     // latched.
     std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index dec14d0..4469df0 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -109,6 +109,7 @@
         "SurfaceFlinger_SetDisplayStateTest.cpp",
         "SurfaceFlinger_SetPowerModeInternalTest.cpp",
         "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
+        "SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp",
         "SchedulerTest.cpp",
         "SetFrameRateTest.cpp",
         "RefreshRateConfigsTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
new file mode 100644
index 0000000..0cf3bdf
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_UpdateLayerMetadataSnapshotTest.cpp
@@ -0,0 +1,212 @@
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class SurfaceFlingerUpdateLayerMetadataSnapshotTest : public testing::Test {
+public:
+    SurfaceFlingerUpdateLayerMetadataSnapshotTest() { setupScheduler(); }
+
+protected:
+    void setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(sp<EventThreadConnection>::make(eventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(sp<EventThreadConnection>::make(sfEventThread.get(),
+                                                                 mock::EventThread::kCallingUid,
+                                                                 ResyncCallback())));
+
+        auto vsyncController = std::make_unique<mock::VsyncController>();
+        auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*vsyncTracker, currentPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    sp<Layer> createLayer(const char* name, LayerMetadata layerMetadata) {
+        return sp<Layer>::make(
+                LayerCreationArgs{mFlinger.flinger(), nullptr, name, 0, layerMetadata});
+    }
+
+    TestableSurfaceFlinger mFlinger;
+};
+
+class LayerMetadataBuilder {
+public:
+    LayerMetadataBuilder(LayerMetadata layerMetadata = {}) : mLayerMetadata(layerMetadata) {}
+
+    LayerMetadataBuilder& setInt32(uint32_t key, int32_t value) {
+        mLayerMetadata.setInt32(key, value);
+        return *this;
+    }
+
+    LayerMetadata build() { return mLayerMetadata; }
+
+private:
+    LayerMetadata mLayerMetadata;
+};
+
+bool operator==(const LayerMetadata& lhs, const LayerMetadata& rhs) {
+    return lhs.mMap == rhs.mMap;
+}
+
+std::ostream& operator<<(std::ostream& stream, const LayerMetadata& layerMetadata) {
+    stream << "LayerMetadata{";
+    for (auto it = layerMetadata.mMap.cbegin(); it != layerMetadata.mMap.cend(); it++) {
+        if (it != layerMetadata.mMap.cbegin()) {
+            stream << ", ";
+        }
+        stream << layerMetadata.itemToString(it->first, ":");
+    }
+    return stream << "}";
+}
+
+// Test that the snapshot's layer metadata is set.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesSnapshotMetadata) {
+    auto layerMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build();
+    auto layer = createLayer("layer", layerMetadata);
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+
+    mFlinger.updateLayerMetadataSnapshot();
+
+    ASSERT_EQ(layer->getLayerSnapshot()->layerMetadata, layerMetadata);
+}
+
+// Test that snapshot layer metadata is set by merging the child's metadata on top of its
+// parent's metadata.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, mergesSnapshotMetadata) {
+    auto layerAMetadata = LayerMetadataBuilder()
+                                  .setInt32(METADATA_OWNER_UID, 1)
+                                  .setInt32(METADATA_TASK_ID, 2)
+                                  .build();
+    auto layerA = createLayer("parent", layerAMetadata);
+    auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 3).build();
+    auto layerB = createLayer("child", layerBMetadata);
+    layerA->addChild(layerB);
+    layerA->commitChildList();
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+
+    mFlinger.updateLayerMetadataSnapshot();
+
+    ASSERT_EQ(layerA->getLayerSnapshot()->layerMetadata, layerAMetadata);
+    auto expectedChildMetadata =
+            LayerMetadataBuilder(layerAMetadata).setInt32(METADATA_TASK_ID, 3).build();
+    ASSERT_EQ(layerB->getLayerSnapshot()->layerMetadata, expectedChildMetadata);
+}
+
+// Test that snapshot relative layer metadata is set to the parent's layer metadata merged on top of
+// that parent's relative layer metadata.
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadata) {
+    auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 1).build();
+    auto layerA = createLayer("relative-parent", layerAMetadata);
+    auto layerAHandle = layerA->getHandle();
+    auto layerBMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 2).build();
+    auto layerB = createLayer("relative-child", layerBMetadata);
+    layerB->setRelativeLayer(layerAHandle, 1);
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerB);
+
+    mFlinger.updateLayerMetadataSnapshot();
+
+    ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{});
+    ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+}
+
+// Test that snapshot relative layer metadata is set correctly when a layer is interleaved within
+// two other layers.
+//
+// Layer
+//      A
+//     / \
+//    B   D
+//   /
+//  C
+//
+// Z-order Relatives
+//    B <- D <- C
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest, updatesRelativeMetadataInterleaved) {
+    auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build();
+    auto layerA = createLayer("layer-a", layerAMetadata);
+    auto layerBMetadata = LayerMetadataBuilder()
+                                  .setInt32(METADATA_TASK_ID, 2)
+                                  .setInt32(METADATA_OWNER_PID, 3)
+                                  .build();
+    auto layerB = createLayer("layer-b", layerBMetadata);
+    auto layerBHandle = layerB->getHandle();
+    auto layerC = createLayer("layer-c", {});
+    auto layerDMetadata = LayerMetadataBuilder().setInt32(METADATA_TASK_ID, 4).build();
+    auto layerD = createLayer("layer-d", layerDMetadata);
+    auto layerDHandle = layerD->getHandle();
+    layerB->addChild(layerC);
+    layerA->addChild(layerB);
+    layerA->addChild(layerD);
+    layerC->setRelativeLayer(layerDHandle, 1);
+    layerD->setRelativeLayer(layerBHandle, 1);
+    layerA->commitChildList();
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+
+    mFlinger.updateLayerMetadataSnapshot();
+
+    auto expectedLayerDRelativeMetadata = LayerMetadataBuilder()
+                                                  // From layer A, parent of relative parent
+                                                  .setInt32(METADATA_OWNER_UID, 1)
+                                                  // From layer B, relative parent
+                                                  .setInt32(METADATA_TASK_ID, 2)
+                                                  .setInt32(METADATA_OWNER_PID, 3)
+                                                  .build();
+    ASSERT_EQ(layerD->getLayerSnapshot()->relativeLayerMetadata, expectedLayerDRelativeMetadata);
+    auto expectedLayerCRelativeMetadata =
+            LayerMetadataBuilder()
+                    // From layer A, parent of relative parent
+                    .setInt32(METADATA_OWNER_UID, 1)
+                    // From layer B, relative parent of relative parent
+                    .setInt32(METADATA_OWNER_PID, 3)
+                    // From layer D, relative parent
+                    .setInt32(METADATA_TASK_ID, 4)
+                    .build();
+    ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, expectedLayerCRelativeMetadata);
+}
+
+TEST_F(SurfaceFlingerUpdateLayerMetadataSnapshotTest,
+       updatesRelativeMetadataMultipleRelativeChildren) {
+    auto layerAMetadata = LayerMetadataBuilder().setInt32(METADATA_OWNER_UID, 1).build();
+    auto layerA = createLayer("layer-a", layerAMetadata);
+    auto layerAHandle = layerA->getHandle();
+    auto layerB = createLayer("layer-b", {});
+    auto layerC = createLayer("layer-c", {});
+    layerB->setRelativeLayer(layerAHandle, 1);
+    layerC->setRelativeLayer(layerAHandle, 2);
+    layerA->commitChildList();
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerA);
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerB);
+    mFlinger.mutableDrawingState().layersSortedByZ.add(layerC);
+
+    mFlinger.updateLayerMetadataSnapshot();
+
+    ASSERT_EQ(layerA->getLayerSnapshot()->relativeLayerMetadata, LayerMetadata{});
+    ASSERT_EQ(layerB->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+    ASSERT_EQ(layerC->getLayerSnapshot()->relativeLayerMetadata, layerAMetadata);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2c9c451..13389a1 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -477,6 +477,8 @@
         return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
     }
 
+    void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */