[sf] destroy unreachable snapshots
Keep track of unreachable snapshots and destroy
them. This is a more robust way of cleaning up
snapshots rather than going through destroyed
layer handles. This way we will handle mirrored
snapshots when the original layer gets destroyed.
Test: presubmit
Bug: 238781169
Change-Id: Iddd5754ae71086719711ecaab218fc5f52e11ef5
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 9757640..07aa122 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -85,6 +85,7 @@
ui::Transform::RotationFlags fixedTransformHint;
bool handleSkipScreenshotFlag = false;
LayerHierarchy::TraversalPath mirrorRootPath;
+ bool unreachable = true;
ChildState childState;
static bool isOpaqueFormat(PixelFormat format);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 9ccf6dc..db6e716 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -435,22 +435,18 @@
}
}
- sortSnapshotsByZ(args);
+ const bool hasUnreachableSnapshots = sortSnapshotsByZ(args);
clearChanges(mRootSnapshot);
// Destroy unreachable snapshots
- if (args.layerLifecycleManager.getDestroyedLayers().empty()) {
+ if (!hasUnreachableSnapshots) {
return;
}
- std::unordered_set<uint32_t> destroyedLayerIds;
- for (auto& destroyedLayer : args.layerLifecycleManager.getDestroyedLayers()) {
- destroyedLayerIds.emplace(destroyedLayer->id);
- }
auto it = mSnapshots.begin();
while (it < mSnapshots.end()) {
auto& traversalPath = it->get()->path;
- if (destroyedLayerIds.find(traversalPath.id) == destroyedLayerIds.end()) {
+ if (!it->get()->unreachable) {
it++;
continue;
}
@@ -534,18 +530,21 @@
return snapshot;
}
-void LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
+bool LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE &&
!args.layerLifecycleManager.getGlobalChanges().any(
RequestedLayerState::Changes::Hierarchy |
RequestedLayerState::Changes::Visibility)) {
// We are not force updating and there are no hierarchy or visibility changes. Avoid sorting
// the snapshots.
- return;
+ return false;
}
-
mResortSnapshots = false;
+ for (auto& snapshot : mSnapshots) {
+ snapshot->unreachable = true;
+ }
+
size_t globalZ = 0;
args.root.traverseInZOrder(
[this, &globalZ](const LayerHierarchy&,
@@ -555,11 +554,7 @@
return false;
}
- if (snapshot->isHiddenByPolicy() &&
- !snapshot->changes.test(RequestedLayerState::Changes::Visibility)) {
- return false;
- }
-
+ snapshot->unreachable = false;
if (snapshot->getIsVisible() || snapshot->hasInputInfo()) {
updateVisibility(*snapshot, snapshot->getIsVisible());
size_t oldZ = snapshot->globalZ;
@@ -577,12 +572,17 @@
return true;
});
mNumInterestingSnapshots = (int)globalZ;
+ bool hasUnreachableSnapshots = false;
while (globalZ < mSnapshots.size()) {
mSnapshots[globalZ]->globalZ = globalZ;
/* mark unreachable snapshots as explicitly invisible */
updateVisibility(*mSnapshots[globalZ], false);
+ if (mSnapshots[globalZ]->unreachable) {
+ hasUnreachableSnapshots = true;
+ }
globalZ++;
}
+ return hasUnreachableSnapshots;
}
void LayerSnapshotBuilder::updateRelativeState(LayerSnapshot& snapshot,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 07b0d14..3997a0a 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -112,7 +112,8 @@
void updateInput(LayerSnapshot& snapshot, const RequestedLayerState& requested,
const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath& path,
const Args& args);
- void sortSnapshotsByZ(const Args& args);
+ // Return true if there are unreachable snapshots
+ bool sortSnapshotsByZ(const Args& args);
LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id,
const RequestedLayerState& layer,
const LayerSnapshot& parentSnapshot);
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 1916404..77dc868 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -263,6 +263,37 @@
EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
}
+TEST_F(LayerHierarchyTest, reparentRelativeLayer) {
+ LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
+ reparentRelativeLayer(11, 2);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+
+ std::vector<uint32_t> expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2, 11, 111};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {1, 12, 121, 122, 1221, 13, 2, 11, 111};
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+
+ reparentLayer(11, 1);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2, 11, 111};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {1, 12, 121, 122, 1221, 13, 2, 11, 111};
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+
+ setZ(11, 0);
+ UPDATE_AND_VERIFY(hierarchyBuilder);
+ expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ EXPECT_EQ(getTraversalPathInZOrder(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
+ expectedTraversalPath = {};
+ EXPECT_EQ(getTraversalPath(hierarchyBuilder.getOffscreenHierarchy()), expectedTraversalPath);
+}
+
// mirror tests
TEST_F(LayerHierarchyTest, canTraverseMirrorLayer) {
LayerHierarchyBuilder hierarchyBuilder(mLifecycleManager.getLayers());
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 14569ab..db0b907 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -391,4 +391,39 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
}
+TEST_F(LayerSnapshotTest, cleanUpUnreachableSnapshotsAfterMirroring) {
+ size_t startingNumSnapshots = mSnapshotBuilder.getSnapshots().size();
+ createDisplayMirrorLayer(3, ui::LayerStack::fromValue(0));
+ setLayerStack(3, 1);
+ std::vector<uint32_t> expected = {3, 1, 11, 111, 12, 121, 122, 1221, 13, 2,
+ 1, 11, 111, 12, 121, 122, 1221, 13, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+ destroyLayerHandle(3);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(startingNumSnapshots, mSnapshotBuilder.getSnapshots().size());
+}
+
+// Rel z doesn't create duplicate snapshots but this is for completeness
+TEST_F(LayerSnapshotTest, cleanUpUnreachableSnapshotsAfterRelZ) {
+ size_t startingNumSnapshots = mSnapshotBuilder.getSnapshots().size();
+ reparentRelativeLayer(13, 11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, {1, 11, 13, 111, 12, 121, 122, 1221, 2});
+ setZ(13, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(startingNumSnapshots, mSnapshotBuilder.getSnapshots().size());
+}
+
+TEST_F(LayerSnapshotTest, cleanUpUnreachableSnapshotsAfterLayerDestruction) {
+ size_t startingNumSnapshots = mSnapshotBuilder.getSnapshots().size();
+ destroyLayerHandle(2);
+ destroyLayerHandle(122);
+
+ std::vector<uint32_t> expected = {1, 11, 111, 12, 121, 122, 1221, 13};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+
+ EXPECT_LE(startingNumSnapshots - 2, mSnapshotBuilder.getSnapshots().size());
+}
+
} // namespace android::surfaceflinger::frontend