SF: Introduce LayerSnapshot and LayerSnapshotBuilder
Create a builder that walks through the layer hierarchy
to build an ordered list of LayerSnapshots that can be
passed on to CompositionEngine.
This builder does a minimum amount of work to update
an existing set of snapshots based on hierarchy changes
and RequestedLayerState changes.
The builder also introduces a fast path to update
snapshots when there are only buffer updates.
Additionally, pull out LayerSnapshot class from LayerFE
and move it to frontend package.
Bug: 238781169
Test: presubmit
Change-Id: I3fbd6d60968950df2ee97d975c72f9e0aa31b007
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7bccfa7..c46806c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -95,6 +95,7 @@
"LayerMetadataTest.cpp",
"LayerHierarchyTest.cpp",
"LayerLifecycleManagerTest.cpp",
+ "LayerSnapshotTest.cpp",
"LayerTest.cpp",
"LayerTestUtils.cpp",
"MessageQueueTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 8560902..33c9440 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -21,6 +21,7 @@
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
#include "Layer.h"
+#include "LayerHierarchyTest.h"
#include "gui/SurfaceComposerClient.h"
#define UPDATE_AND_VERIFY(HIERARCHY) \
@@ -31,16 +32,6 @@
namespace android::surfaceflinger::frontend {
-namespace {
-LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent, wp<IBinder> mirror) {
- LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
- args.addToRoot = canBeRoot;
- args.parentHandle = parent;
- args.mirrorLayerHandle = mirror;
- return args;
-}
-} // namespace
-
// To run test:
/**
mp :libsurfaceflinger_unittest && adb sync; adb shell \
@@ -50,163 +41,9 @@
--gtest_brief=1
*/
-class LayerHierarchyTest : public testing::Test {
+class LayerHierarchyTest : public LayerHierarchyTestBase {
protected:
- LayerHierarchyTest() {
- // tree with 3 levels of children
- // ROOT
- // ├── 1
- // │ ├── 11
- // │ │ └── 111
- // │ ├── 12
- // │ │ ├── 121
- // │ │ └── 122
- // │ │ └── 1221
- // │ └── 13
- // └── 2
-
- createRootLayer(1);
- createRootLayer(2);
- createLayer(11, 1);
- createLayer(12, 1);
- createLayer(13, 1);
- createLayer(111, 11);
- createLayer(121, 12);
- createLayer(122, 12);
- createLayer(1221, 122);
- mLifecycleManager.commitChanges();
- }
- std::vector<uint32_t> getTraversalPath(const LayerHierarchy& hierarchy) const {
- std::vector<uint32_t> layerIds;
- hierarchy.traverse([&layerIds = layerIds](const LayerHierarchy& hierarchy,
- const LayerHierarchy::TraversalPath&) -> bool {
- layerIds.emplace_back(hierarchy.getLayer()->id);
- return true;
- });
- return layerIds;
- }
-
- std::vector<uint32_t> getTraversalPathInZOrder(const LayerHierarchy& hierarchy) const {
- std::vector<uint32_t> layerIds;
- hierarchy.traverseInZOrder(
- [&layerIds = layerIds](const LayerHierarchy& hierarchy,
- const LayerHierarchy::TraversalPath&) -> bool {
- layerIds.emplace_back(hierarchy.getLayer()->id);
- return true;
- });
- return layerIds;
- }
-
- void createRootLayer(uint32_t id) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- void createLayer(uint32_t id, uint32_t parentId) {
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/mHandles[parentId],
- /*mirror=*/nullptr)));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- void reparentLayer(uint32_t id, uint32_t newParentId) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- if (newParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.parentSurfaceControlForChild = nullptr;
- } else {
- auto parentHandle = mHandles[newParentId];
- transactions.back().states.front().state.parentSurfaceControlForChild =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(newParentId), "Test");
- }
- transactions.back().states.front().state.what = layer_state_t::eReparent;
- transactions.back().states.front().state.surface = mHandles[id];
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- if (relativeParentId == UNASSIGNED_LAYER_ID) {
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- } else {
- auto parentHandle = mHandles[relativeParentId];
- transactions.back().states.front().state.relativeLayerSurfaceControl =
- sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
- static_cast<int32_t>(relativeParentId), "test");
- transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
- }
- transactions.back().states.front().state.surface = mHandles[id];
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) {
- auto parentHandle = (parent == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[parent];
- auto mirrorHandle =
- (layerToMirror == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[layerToMirror];
-
- sp<LayerHandle> handle = sp<LayerHandle>::make(id);
- mHandles[id] = handle;
- std::vector<std::unique_ptr<RequestedLayerState>> layers;
- layers.emplace_back(std::make_unique<RequestedLayerState>(
- createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentHandle,
- /*mirror=*/mHandles[layerToMirror])));
- mLifecycleManager.addLayers(std::move(layers));
- }
-
- void updateBackgroundColor(uint32_t id, half alpha) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
- transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
- transactions.back().states.front().state.bgColorAlpha = alpha;
- transactions.back().states.front().state.surface = mHandles[id];
- mLifecycleManager.applyTransactions(transactions);
- }
-
- void destroyLayerHandle(uint32_t id) { mLifecycleManager.onHandlesDestroyed({id}); }
-
- void updateAndVerify(LayerHierarchyBuilder& hierarchyBuilder) {
- if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
- hierarchyBuilder.update(mLifecycleManager.getLayers(),
- mLifecycleManager.getDestroyedLayers());
- }
- mLifecycleManager.commitChanges();
-
- // rebuild layer hierarchy from scratch and verify that it matches the updated state.
- LayerHierarchyBuilder newBuilder(mLifecycleManager.getLayers());
- EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()),
- getTraversalPath(newBuilder.getHierarchy()));
- EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()),
- getTraversalPathInZOrder(newBuilder.getHierarchy()));
- EXPECT_FALSE(
- mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
- }
-
- void setZ(uint32_t id, int32_t z) {
- std::vector<TransactionState> transactions;
- transactions.emplace_back();
- transactions.back().states.push_back({});
-
- transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
- transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
- transactions.back().states.front().state.z = z;
- mLifecycleManager.applyTransactions(transactions);
- }
- LayerLifecycleManager mLifecycleManager;
- std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
+ LayerHierarchyTest() : LayerHierarchyTestBase() { mLifecycleManager.commitChanges(); }
};
// reparenting tests
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
new file mode 100644
index 0000000..08727f2
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "FrontEnd/LayerHandle.h"
+#include "FrontEnd/LayerHierarchy.h"
+#include "FrontEnd/LayerLifecycleManager.h"
+#include "Layer.h"
+#include "gui/SurfaceComposerClient.h"
+
+namespace android::surfaceflinger::frontend {
+
+class LayerHierarchyTestBase : public testing::Test {
+protected:
+ LayerHierarchyTestBase() {
+ // tree with 3 levels of children
+ // ROOT
+ // ├── 1
+ // │ ├── 11
+ // │ │ └── 111
+ // │ ├── 12
+ // │ │ ├── 121
+ // │ │ └── 122
+ // │ │ └── 1221
+ // │ └── 13
+ // └── 2
+
+ createRootLayer(1);
+ createRootLayer(2);
+ createLayer(11, 1);
+ createLayer(12, 1);
+ createLayer(13, 1);
+ createLayer(111, 11);
+ createLayer(121, 12);
+ createLayer(122, 12);
+ createLayer(1221, 122);
+ }
+
+ LayerCreationArgs createArgs(uint32_t id, bool canBeRoot, wp<IBinder> parent,
+ wp<IBinder> mirror) {
+ LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ args.addToRoot = canBeRoot;
+ args.parentHandle = parent;
+ args.mirrorLayerHandle = mirror;
+ return args;
+ }
+
+ std::vector<uint32_t> getTraversalPath(const LayerHierarchy& hierarchy) const {
+ std::vector<uint32_t> layerIds;
+ hierarchy.traverse([&layerIds = layerIds](const LayerHierarchy& hierarchy,
+ const LayerHierarchy::TraversalPath&) -> bool {
+ layerIds.emplace_back(hierarchy.getLayer()->id);
+ return true;
+ });
+ return layerIds;
+ }
+
+ std::vector<uint32_t> getTraversalPathInZOrder(const LayerHierarchy& hierarchy) const {
+ std::vector<uint32_t> layerIds;
+ hierarchy.traverseInZOrder(
+ [&layerIds = layerIds](const LayerHierarchy& hierarchy,
+ const LayerHierarchy::TraversalPath&) -> bool {
+ layerIds.emplace_back(hierarchy.getLayer()->id);
+ return true;
+ });
+ return layerIds;
+ }
+
+ virtual void createRootLayer(uint32_t id) {
+ sp<LayerHandle> handle = sp<LayerHandle>::make(id);
+ mHandles[id] = handle;
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/nullptr, /*mirror=*/nullptr)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ virtual void createLayer(uint32_t id, uint32_t parentId) {
+ sp<LayerHandle> handle = sp<LayerHandle>::make(id);
+ mHandles[id] = handle;
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/mHandles[parentId],
+ /*mirror=*/nullptr)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ void reparentLayer(uint32_t id, uint32_t newParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ if (newParentId == UNASSIGNED_LAYER_ID) {
+ transactions.back().states.front().state.parentSurfaceControlForChild = nullptr;
+ } else {
+ auto parentHandle = mHandles[newParentId];
+ transactions.back().states.front().state.parentSurfaceControlForChild =
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
+ static_cast<int32_t>(newParentId), "Test");
+ }
+ transactions.back().states.front().state.what = layer_state_t::eReparent;
+ transactions.back().states.front().state.surface = mHandles[id];
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void reparentRelativeLayer(uint32_t id, uint32_t relativeParentId) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ if (relativeParentId == UNASSIGNED_LAYER_ID) {
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ } else {
+ auto parentHandle = mHandles[relativeParentId];
+ transactions.back().states.front().state.relativeLayerSurfaceControl =
+ sp<SurfaceControl>::make(SurfaceComposerClient::getDefault(), parentHandle,
+ static_cast<int32_t>(relativeParentId), "test");
+ transactions.back().states.front().state.what = layer_state_t::eRelativeLayerChanged;
+ }
+ transactions.back().states.front().state.surface = mHandles[id];
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ virtual void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) {
+ auto parentHandle = (parent == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[parent];
+ auto mirrorHandle =
+ (layerToMirror == UNASSIGNED_LAYER_ID) ? nullptr : mHandles[layerToMirror];
+
+ sp<LayerHandle> handle = sp<LayerHandle>::make(id);
+ mHandles[id] = handle;
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createArgs(/*id=*/id, /*canBeRoot=*/false, /*parent=*/parentHandle,
+ /*mirror=*/mHandles[layerToMirror])));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
+ void updateBackgroundColor(uint32_t id, half alpha) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eBackgroundColorChanged;
+ transactions.back().states.front().state.bgColorAlpha = alpha;
+ transactions.back().states.front().state.surface = mHandles[id];
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void destroyLayerHandle(uint32_t id) { mLifecycleManager.onHandlesDestroyed({id}); }
+
+ void updateAndVerify(LayerHierarchyBuilder& hierarchyBuilder) {
+ if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
+ hierarchyBuilder.update(mLifecycleManager.getLayers(),
+ mLifecycleManager.getDestroyedLayers());
+ }
+ mLifecycleManager.commitChanges();
+
+ // rebuild layer hierarchy from scratch and verify that it matches the updated state.
+ LayerHierarchyBuilder newBuilder(mLifecycleManager.getLayers());
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()),
+ getTraversalPath(newBuilder.getHierarchy()));
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()),
+ getTraversalPathInZOrder(newBuilder.getHierarchy()));
+ EXPECT_FALSE(
+ mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
+ }
+
+ void setZ(uint32_t id, int32_t z) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eLayerChanged;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().state.z = z;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setCrop(uint32_t id, const Rect& crop) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eCropChanged;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().state.crop = crop;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setFlags(uint32_t id, uint32_t mask, uint32_t flags) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFlagsChanged;
+ transactions.back().states.front().state.flags = flags;
+ transactions.back().states.front().state.mask = mask;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void setAlpha(uint32_t id, float alpha) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eAlphaChanged;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ transactions.back().states.front().state.color.a = static_cast<half>(alpha);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ void hideLayer(uint32_t id) {
+ setFlags(id, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden);
+ }
+
+ void showLayer(uint32_t id) { setFlags(id, layer_state_t::eLayerHidden, 0); }
+
+ void setColor(uint32_t id, half3 rgb = half3(1._hf, 1._hf, 1._hf)) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+ transactions.back().states.front().state.what = layer_state_t::eColorChanged;
+ transactions.back().states.front().state.color.rgb = rgb;
+ transactions.back().states.front().state.surface = mHandles[id];
+ transactions.back().states.front().state.layerId = static_cast<int32_t>(id);
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
+ LayerLifecycleManager mLifecycleManager;
+ std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
+};
+
+} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
new file mode 100644
index 0000000..2441c06
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "FrontEnd/LayerHandle.h"
+#include "FrontEnd/LayerHierarchy.h"
+#include "FrontEnd/LayerLifecycleManager.h"
+#include "FrontEnd/LayerSnapshotBuilder.h"
+#include "Layer.h"
+#include "LayerHierarchyTest.h"
+
+#define UPDATE_AND_VERIFY(BUILDER, ...) \
+ ({ \
+ SCOPED_TRACE(""); \
+ updateAndVerify((BUILDER), /*displayChanges=*/false, __VA_ARGS__); \
+ })
+
+#define UPDATE_AND_VERIFY_WITH_DISPLAY_CHANGES(BUILDER, ...) \
+ ({ \
+ SCOPED_TRACE(""); \
+ updateAndVerify((BUILDER), /*displayChanges=*/true, __VA_ARGS__); \
+ })
+
+namespace android::surfaceflinger::frontend {
+
+// To run test:
+/**
+ mp :libsurfaceflinger_unittest && adb sync; adb shell \
+ /data/nativetest/libsurfaceflinger_unittest/libsurfaceflinger_unittest \
+ --gtest_filter="LayerSnapshotTest.*" --gtest_brief=1
+*/
+
+class LayerSnapshotTest : public LayerHierarchyTestBase {
+protected:
+ LayerSnapshotTest() : LayerHierarchyTestBase() {
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ }
+
+ void createRootLayer(uint32_t id) override {
+ LayerHierarchyTestBase::createRootLayer(id);
+ setColor(id);
+ }
+
+ void createLayer(uint32_t id, uint32_t parentId) override {
+ LayerHierarchyTestBase::createLayer(id, parentId);
+ setColor(parentId);
+ }
+
+ void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override {
+ LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror);
+ setColor(id);
+ }
+
+ void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges,
+ const std::vector<uint32_t> expectedVisibleLayerIdsInZOrder) {
+ if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
+ mHierarchyBuilder.update(mLifecycleManager.getLayers(),
+ mLifecycleManager.getDestroyedLayers());
+ }
+ LayerSnapshotBuilder::Args args{
+ .root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .displayChanges = hasDisplayChanges,
+ .globalShadowSettings = globalShadowSettings,
+ };
+ actualBuilder.update(args);
+
+ // rebuild layer snapshots from scratch and verify that it matches the updated state.
+ LayerSnapshotBuilder expectedBuilder(args);
+ mLifecycleManager.commitChanges();
+ ASSERT_TRUE(expectedBuilder.getSnapshots().size() > 0);
+ ASSERT_TRUE(actualBuilder.getSnapshots().size() > 0);
+
+ std::vector<std::unique_ptr<LayerSnapshot>>& snapshots = actualBuilder.getSnapshots();
+ std::vector<uint32_t> actualVisibleLayerIdsInZOrder;
+ for (auto& snapshot : snapshots) {
+ if (!snapshot->isVisible) {
+ break;
+ }
+ actualVisibleLayerIdsInZOrder.push_back(snapshot->path.id);
+ }
+ EXPECT_EQ(expectedVisibleLayerIdsInZOrder, actualVisibleLayerIdsInZOrder);
+ }
+
+ LayerSnapshot* getSnapshot(uint32_t layerId) { return mSnapshotBuilder.getSnapshot(layerId); }
+
+ LayerHierarchyBuilder mHierarchyBuilder{{}};
+ LayerSnapshotBuilder mSnapshotBuilder;
+ std::unordered_map<uint32_t, sp<LayerHandle>> mHandles;
+ display::DisplayMap<ui::LayerStack, frontend::DisplayInfo> mFrontEndDisplayInfos;
+ renderengine::ShadowSettings globalShadowSettings;
+ static const std::vector<uint32_t> STARTING_ZORDER;
+};
+const std::vector<uint32_t> LayerSnapshotTest::STARTING_ZORDER = {1, 11, 111, 12, 121,
+ 122, 1221, 13, 2};
+
+TEST_F(LayerSnapshotTest, buildSnapshot) {
+ LayerSnapshotBuilder::Args args{
+ .root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .globalShadowSettings = globalShadowSettings,
+ };
+ LayerSnapshotBuilder builder(args);
+}
+
+TEST_F(LayerSnapshotTest, updateSnapshot) {
+ LayerSnapshotBuilder::Args args{
+ .root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .globalShadowSettings = globalShadowSettings,
+ };
+
+ LayerSnapshotBuilder builder;
+ builder.update(args);
+}
+
+// update using parent snapshot data
+TEST_F(LayerSnapshotTest, croppedByParent) {
+ /// MAKE ALL LAYERS VISIBLE BY DEFAULT
+ DisplayInfo info;
+ info.info.logicalHeight = 100;
+ info.info.logicalWidth = 200;
+ mFrontEndDisplayInfos.emplace_or_replace(ui::LayerStack::fromValue(1), info);
+ Rect layerCrop(0, 0, 10, 20);
+ setCrop(11, layerCrop);
+ EXPECT_TRUE(mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Geometry));
+ UPDATE_AND_VERIFY_WITH_DISPLAY_CHANGES(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(11)->geomCrop, layerCrop);
+ EXPECT_EQ(getSnapshot(111)->geomLayerBounds, layerCrop.toFloatRect());
+ float maxHeight = static_cast<float>(info.info.logicalHeight * 10);
+ float maxWidth = static_cast<float>(info.info.logicalWidth * 10);
+
+ FloatRect maxDisplaySize(-maxWidth, -maxHeight, maxWidth, maxHeight);
+ EXPECT_EQ(getSnapshot(1)->geomLayerBounds, maxDisplaySize);
+}
+
+// visibility tests
+TEST_F(LayerSnapshotTest, newLayerHiddenByPolicy) {
+ createLayer(112, 11);
+ hideLayer(112);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ showLayer(112);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 11, 111, 112, 12, 121, 122, 1221, 13, 2});
+}
+
+TEST_F(LayerSnapshotTest, hiddenByParent) {
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+}
+
+TEST_F(LayerSnapshotTest, reparentShowsChild) {
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+
+ showLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+}
+
+TEST_F(LayerSnapshotTest, reparentHidesChild) {
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+
+ reparentLayer(121, 11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 122, 1221, 13, 2});
+}
+
+TEST_F(LayerSnapshotTest, unHidingUpdatesSnapshot) {
+ hideLayer(11);
+ Rect crop(1, 2, 3, 4);
+ setCrop(111, crop);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+
+ showLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(111)->geomLayerBounds, crop.toFloatRect());
+}
+
+TEST_F(LayerSnapshotTest, childBehindParentCanBeHiddenByParent) {
+ setZ(111, -1);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 111, 11, 12, 121, 122, 1221, 13, 2});
+
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+}
+
+// relative tests
+TEST_F(LayerSnapshotTest, RelativeParentCanHideChild) {
+ reparentRelativeLayer(13, 11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 11, 13, 111, 12, 121, 122, 1221, 2});
+
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 2});
+}
+
+TEST_F(LayerSnapshotTest, ReparentingToHiddenRelativeParentHidesChild) {
+ hideLayer(11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 13, 2});
+ reparentRelativeLayer(13, 11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 12, 121, 122, 1221, 2});
+}
+
+TEST_F(LayerSnapshotTest, AlphaInheritedByChildren) {
+ setAlpha(1, 0.5);
+ setAlpha(122, 0.5);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(12)->alpha, 0.5f);
+ EXPECT_EQ(getSnapshot(1221)->alpha, 0.25f);
+}
+
+// Change states
+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);
+ 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);
+}
+
+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);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_TRUE(getSnapshot(11)->changes.get() == 0);
+}
+
+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);
+}
+
+} // namespace android::surfaceflinger::frontend