SF: Support display mirroring with new frontend
Bug: 238781169
Test: presubmit
Change-Id: I569822bd1dd70e2b0b660042329abb27f263dc66
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
index 7b5a157..9d2aaab 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -18,10 +18,12 @@
#include <binder/Binder.h>
#include <gui/LayerMetadata.h>
+#include <ui/LayerStack.h>
#include <utils/StrongPointer.h>
#include <cstdint>
#include <limits>
#include <optional>
+
constexpr uint32_t UNASSIGNED_LAYER_ID = std::numeric_limits<uint32_t>::max();
namespace android {
@@ -51,6 +53,7 @@
bool addToRoot = true;
wp<IBinder> parentHandle = nullptr;
wp<IBinder> mirrorLayerHandle = nullptr;
+ ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
};
} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 678d36b..a4fac1c 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -252,8 +252,8 @@
attachToParent(hierarchy);
attachToRelativeParent(hierarchy);
- if (layer->mirrorId != UNASSIGNED_LAYER_ID) {
- LayerHierarchy* mirror = getHierarchyFromId(layer->mirrorId);
+ for (uint32_t mirrorId : layer->mirrorIds) {
+ LayerHierarchy* mirror = getHierarchyFromId(mirrorId);
hierarchy->addChild(mirror, LayerHierarchy::Variant::Mirror);
}
}
@@ -292,14 +292,14 @@
auto it = hierarchy->mChildren.begin();
while (it != hierarchy->mChildren.end()) {
if (it->second == LayerHierarchy::Variant::Mirror) {
- hierarchy->mChildren.erase(it);
- break;
+ it = hierarchy->mChildren.erase(it);
+ } else {
+ it++;
}
- it++;
}
- if (layer->mirrorId != UNASSIGNED_LAYER_ID) {
- hierarchy->addChild(getHierarchyFromId(layer->mirrorId), LayerHierarchy::Variant::Mirror);
+ for (uint32_t mirrorId : layer->mirrorIds) {
+ hierarchy->addChild(getHierarchyFromId(mirrorId), LayerHierarchy::Variant::Mirror);
}
}
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 5514c06..547a852 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -44,9 +44,28 @@
layer.parentId = linkLayer(layer.parentId, layer.id);
layer.relativeParentId = linkLayer(layer.relativeParentId, layer.id);
- layer.mirrorId = linkLayer(layer.mirrorId, layer.id);
+ if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
+ // if this layer is mirroring a display, then walk though all the existing root layers
+ // for the layer stack and add them as children to be mirrored.
+ mDisplayMirroringLayers.emplace_back(layer.id);
+ for (auto& rootLayer : mLayers) {
+ if (rootLayer->isRoot() && rootLayer->layerStack == layer.layerStackToMirror) {
+ layer.mirrorIds.emplace_back(rootLayer->id);
+ linkLayer(rootLayer->id, layer.id);
+ }
+ }
+ } else {
+ // Check if we are mirroring a single layer, and if so add it to the list of children
+ // to be mirrored.
+ layer.layerIdToMirror = linkLayer(layer.layerIdToMirror, layer.id);
+ if (layer.layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ layer.mirrorIds.emplace_back(layer.layerIdToMirror);
+ }
+ }
layer.touchCropId = linkLayer(layer.touchCropId, layer.id);
-
+ if (layer.isRoot()) {
+ updateDisplayMirrorLayers(layer);
+ }
mLayers.emplace_back(std::move(newLayer));
}
}
@@ -85,7 +104,14 @@
layer.parentId = unlinkLayer(layer.parentId, layer.id);
layer.relativeParentId = unlinkLayer(layer.relativeParentId, layer.id);
- layer.mirrorId = unlinkLayer(layer.mirrorId, layer.id);
+ if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
+ layer.mirrorIds = unlinkLayers(layer.mirrorIds, layer.id);
+ swapErase(mDisplayMirroringLayers, layer.id);
+ } else {
+ layer.layerIdToMirror = unlinkLayer(layer.layerIdToMirror, layer.id);
+ layer.mirrorIds.clear();
+ }
+
layer.touchCropId = unlinkLayer(layer.touchCropId, layer.id);
auto& references = it->second.references;
@@ -106,8 +132,8 @@
if (linkedLayer->relativeParentId == layer.id) {
linkedLayer->relativeParentId = UNASSIGNED_LAYER_ID;
}
- if (linkedLayer->mirrorId == layer.id) {
- linkedLayer->mirrorId = UNASSIGNED_LAYER_ID;
+ if (swapErase(linkedLayer->mirrorIds, layer.id)) {
+ linkedLayer->changes |= RequestedLayerState::Changes::Mirror;
}
if (linkedLayer->touchCropId == layer.id) {
linkedLayer->touchCropId = UNASSIGNED_LAYER_ID;
@@ -200,6 +226,12 @@
if (oldParentId != layer->parentId) {
unlinkLayer(oldParentId, layer->id);
layer->parentId = linkLayer(layer->parentId, layer->id);
+ if (oldParentId == UNASSIGNED_LAYER_ID) {
+ updateDisplayMirrorLayers(*layer);
+ }
+ }
+ if (layer->what & layer_state_t::eLayerStackChanged && layer->isRoot()) {
+ updateDisplayMirrorLayers(*layer);
}
if (oldRelativeParentId != layer->relativeParentId) {
unlinkLayer(oldRelativeParentId, layer->id);
@@ -308,6 +340,14 @@
return UNASSIGNED_LAYER_ID;
}
+std::vector<uint32_t> LayerLifecycleManager::unlinkLayers(const std::vector<uint32_t>& layerIds,
+ uint32_t linkedLayer) {
+ for (uint32_t layerId : layerIds) {
+ unlinkLayer(layerId, linkedLayer);
+ }
+ return {};
+}
+
std::string LayerLifecycleManager::References::getDebugString() const {
std::string debugInfo = owner.name + "[" + std::to_string(owner.id) + "] refs:";
std::for_each(references.begin(), references.end(),
@@ -329,4 +369,30 @@
mGlobalChanges |= RequestedLayerState::Changes::Hierarchy;
}
+// Some layers mirror the entire display stack. Since we don't have a single root layer per display
+// we have to track all these layers and update what they mirror when the list of root layers
+// on a display changes. This function walks through the list of display mirroring layers
+// and updates its list of layers that its mirroring. This function should be called when a new
+// root layer is added, removed or moved to another display.
+void LayerLifecycleManager::updateDisplayMirrorLayers(RequestedLayerState& rootLayer) {
+ for (uint32_t mirrorLayerId : mDisplayMirroringLayers) {
+ RequestedLayerState* mirrorLayer = getLayerFromId(mirrorLayerId);
+ bool canBeMirrored =
+ rootLayer.isRoot() && rootLayer.layerStack == mirrorLayer->layerStackToMirror;
+ bool currentlyMirrored =
+ std::find(mirrorLayer->mirrorIds.begin(), mirrorLayer->mirrorIds.end(),
+ rootLayer.id) != mirrorLayer->mirrorIds.end();
+
+ if (canBeMirrored && !currentlyMirrored) {
+ mirrorLayer->mirrorIds.emplace_back(rootLayer.id);
+ linkLayer(rootLayer.id, mirrorLayer->id);
+ mirrorLayer->changes |= RequestedLayerState::Changes::Mirror;
+ } else if (!canBeMirrored && currentlyMirrored) {
+ swapErase(mirrorLayer->mirrorIds, rootLayer.id);
+ unlinkLayer(rootLayer.id, mirrorLayer->id);
+ mirrorLayer->changes |= RequestedLayerState::Changes::Mirror;
+ }
+ }
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index 63a7afc..25d27ee 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -80,6 +80,9 @@
std::vector<uint32_t>* getLinkedLayersFromId(uint32_t);
uint32_t linkLayer(uint32_t layerId, uint32_t layerToLink);
uint32_t unlinkLayer(uint32_t layerId, uint32_t linkedLayer);
+ std::vector<uint32_t> unlinkLayers(const std::vector<uint32_t>& layerIds, uint32_t linkedLayer);
+
+ void updateDisplayMirrorLayers(RequestedLayerState& rootLayer);
struct References {
// Lifetime tied to mLayers
@@ -90,6 +93,8 @@
std::unordered_map<uint32_t, References> mIdToLayer;
// Listeners are invoked once changes are committed.
std::vector<std::shared_ptr<ILifecycleListener>> mListeners;
+ // Layers that mirror a display stack (see updateDisplayMirrorLayers)
+ std::vector<uint32_t> mDisplayMirroringLayers;
// Aggregation of changes since last commit.
ftl::Flags<RequestedLayerState::Changes> mGlobalChanges;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 3a0540c..4e69565 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -112,6 +112,10 @@
}
bool LayerSnapshot::getIsVisible() const {
+ if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) {
+ return false;
+ }
+
if (!hasSomethingToDraw()) {
return false;
}
@@ -125,6 +129,7 @@
std::string LayerSnapshot::getIsVisibleReason() const {
// not visible
+ if (handleSkipScreenshotFlag & outputFilter.toInternalDisplay) return "eLayerSkipScreenshot";
if (!hasSomethingToDraw()) return "!hasSomethingToDraw";
if (invalidTransform) return "invalidTransform";
if (isHiddenByPolicyFromParent) return "hidden by parent or layer flag";
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 4512ade..159410f 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -84,6 +84,7 @@
gui::GameMode gameMode;
scheduler::LayerInfo::FrameRate frameRate;
ui::Transform::RotationFlags fixedTransformHint;
+ bool handleSkipScreenshotFlag = false;
ChildState childState;
static bool isOpaqueFormat(PixelFormat format);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index cc26591..d0ffe61 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -714,6 +714,10 @@
snapshot.fixedTransformHint = requested.fixedTransformHint != ui::Transform::ROT_INVALID
? requested.fixedTransformHint
: parentSnapshot.fixedTransformHint;
+ // 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 || requested.changes.get() != 0) {
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index b7fa4f0..d63b126 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -45,6 +45,16 @@
return layerId == UNASSIGNED_LAYER_ID ? "none" : std::to_string(layerId);
}
+std::string layerIdsToString(const std::vector<uint32_t>& layerIds) {
+ std::stringstream stream;
+ stream << "{";
+ for (auto layerId : layerIds) {
+ stream << layerId << ",";
+ }
+ stream << "}";
+ return stream.str();
+}
+
} // namespace
RequestedLayerState::RequestedLayerState(const LayerCreationArgs& args)
@@ -64,8 +74,11 @@
if (args.parentHandle != nullptr) {
canBeRoot = false;
}
- mirrorId = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
- if (mirrorId != UNASSIGNED_LAYER_ID) {
+ layerIdToMirror = LayerHandle::getLayerId(args.mirrorLayerHandle.promote());
+ if (layerIdToMirror != UNASSIGNED_LAYER_ID) {
+ changes |= RequestedLayerState::Changes::Mirror;
+ } else if (args.layerStackToMirror != ui::INVALID_LAYER_STACK) {
+ layerStackToMirror = args.layerStackToMirror;
changes |= RequestedLayerState::Changes::Mirror;
}
@@ -309,7 +322,7 @@
return "[" + std::to_string(id) + "]" + name + ",parent=" + layerIdToString(parentId) +
",relativeParent=" + layerIdToString(relativeParentId) +
",isRelativeOf=" + std::to_string(isRelativeOf) +
- ",mirrorId=" + layerIdToString(mirrorId) +
+ ",mirrorIds=" + layerIdsToString(mirrorIds) +
",handleAlive=" + std::to_string(handleAlive) + ",z=" + std::to_string(z);
}
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.h b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
index 3a16531..6317b95 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.h
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.h
@@ -97,13 +97,15 @@
std::shared_ptr<renderengine::ExternalTexture> externalTexture;
gui::GameMode gameMode;
scheduler::LayerInfo::FrameRate requestedFrameRate;
+ ui::LayerStack layerStackToMirror = ui::INVALID_LAYER_STACK;
+ uint32_t layerIdToMirror = UNASSIGNED_LAYER_ID;
// book keeping states
bool handleAlive = true;
bool isRelativeOf = false;
uint32_t parentId = UNASSIGNED_LAYER_ID;
uint32_t relativeParentId = UNASSIGNED_LAYER_ID;
- uint32_t mirrorId = UNASSIGNED_LAYER_ID;
+ std::vector<uint32_t> mirrorIds{};
uint32_t touchCropId = UNASSIGNED_LAYER_ID;
uint32_t bgColorLayerId = UNASSIGNED_LAYER_ID;
ftl::Flags<RequestedLayerState::Changes> changes;
diff --git a/services/surfaceflinger/FrontEnd/SwapErase.h b/services/surfaceflinger/FrontEnd/SwapErase.h
index f672f99..0061c53 100644
--- a/services/surfaceflinger/FrontEnd/SwapErase.h
+++ b/services/surfaceflinger/FrontEnd/SwapErase.h
@@ -23,12 +23,15 @@
// remove an element from a vector that avoids relocating all the elements after the one
// that is erased.
template <typename T>
-void swapErase(std::vector<T>& vec, const T& value) {
+bool swapErase(std::vector<T>& vec, const T& value) {
+ bool found = false;
auto it = std::find(vec.begin(), vec.end(), value);
if (it != vec.end()) {
std::iter_swap(it, vec.end() - 1);
vec.erase(vec.end() - 1);
+ found = true;
}
+ return found;
}
// Similar to swapErase(std::vector<T>& vec, const T& value) but erases the first element
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 783df28..763426a 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -641,4 +641,69 @@
EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
}
+TEST_F(LayerHierarchyTest, canMirrorDisplay) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot);
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expected = {3, 1, 11, 111, 12, 121, 122, 1221, 13, 2,
+ 1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expected);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expected);
+ expected = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
+}
+
+TEST_F(LayerHierarchyTest, mirrorNonExistingDisplay) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot);
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(5));
+ setLayerStack(3, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expected = {3, 1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expected);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expected);
+ expected = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
+}
+
+TEST_F(LayerHierarchyTest, newRootLayerIsMirrored) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot);
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ createRootLayer(4);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expected = {3, 1, 11, 111, 12, 121, 122, 1221, 13, 2, 4,
+ 1, 11, 111, 12, 121, 122, 1221, 13, 2, 4};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expected);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expected);
+ expected = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
+}
+
+TEST_F(LayerHierarchyTest, removedRootLayerIsNoLongerMirrored) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot);
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ reparentLayer(1, UNASSIGNED_LAYER_ID);
+ destroyLayerHandle(1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expected = {3, 2, 2};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expected);
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expected);
+ expected = {11, 111, 12, 121, 122, 1221, 13};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expected);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 1a82232..852cb91 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -60,6 +60,14 @@
return args;
}
+ LayerCreationArgs createDisplayMirrorArgs(uint32_t id, ui::LayerStack layerStack) {
+ LayerCreationArgs args(nullptr, nullptr, "testlayer", 0, {}, std::make_optional(id));
+ args.addToRoot = true;
+ args.parentHandle.clear();
+ args.layerStackToMirror = layerStack;
+ return args;
+ }
+
std::vector<uint32_t> getTraversalPath(const LayerHierarchy& hierarchy) const {
std::vector<uint32_t> layerIds;
hierarchy.traverse([&layerIds = layerIds](const LayerHierarchy& hierarchy,
@@ -90,6 +98,15 @@
mLifecycleManager.addLayers(std::move(layers));
}
+ void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
+ sp<LayerHandle> handle = sp<LayerHandle>::make(id);
+ mHandles[id] = handle;
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ layers.emplace_back(std::make_unique<RequestedLayerState>(
+ createDisplayMirrorArgs(/*id=*/id, layerStack)));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
virtual void createLayer(uint32_t id, uint32_t parentId) {
sp<LayerHandle> handle = sp<LayerHandle>::make(id);
mHandles[id] = handle;
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index e124342..aa6a14e 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -306,4 +306,27 @@
EXPECT_EQ(getSnapshot(1)->frameRate.type, scheduler::LayerInfo::FrameRateCompatibility::NoVote);
}
+// Display Mirroring Tests
+// tree with 3 levels of children
+// ROOT (DISPLAY 0)
+// ├── 1
+// │ ├── 11
+// │ │ └── 111
+// │ ├── 12 (has skip screenshot flag)
+// │ │ ├── 121
+// │ │ └── 122
+// │ │ └── 1221
+// │ └── 13
+// └── 2
+// ROOT (DISPLAY 1)
+// └── 3 (mirrors display 0)
+TEST_F(LayerSnapshotTest, displayMirrorRespects) {
+ setFlags(12, layer_state_t::eLayerSkipScreenshot, layer_state_t::eLayerSkipScreenshot);
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+
+ std::vector<uint32_t> expected = {3, 1, 11, 111, 13, 2, 1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+}
+
} // namespace android::surfaceflinger::frontend