Detect and recover from relative z loops
The caller can create loops in the hierarchy by relatively
reparenting layers to each other. This can be done directly
or via a chain of layers.
The logic to detect and fix this was not being called. Fix this
by making loop detection a bit harder to ignore and part of
hierarchy builder's update call.
Test: presubmit
Bug: 316236833
Change-Id: I484f9b8e2742fef22a5d76362a715eb6850c26f6
diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
index 1e5a6fb..821ac0c 100644
--- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp
@@ -190,8 +190,12 @@
return outInvalidRelativeRoot != UNASSIGNED_LAYER_ID;
}
-LayerHierarchyBuilder::LayerHierarchyBuilder(
- const std::vector<std::unique_ptr<RequestedLayerState>>& layers) {
+void LayerHierarchyBuilder::init(const std::vector<std::unique_ptr<RequestedLayerState>>& layers) {
+ mLayerIdToHierarchy.clear();
+ mHierarchies.clear();
+ mRoot = nullptr;
+ mOffscreenRoot = nullptr;
+
mHierarchies.reserve(layers.size());
mLayerIdToHierarchy.reserve(layers.size());
for (auto& layer : layers) {
@@ -202,6 +206,7 @@
onLayerAdded(layer.get());
}
detachHierarchyFromRelativeParent(&mOffscreenRoot);
+ mInitialized = true;
}
void LayerHierarchyBuilder::attachToParent(LayerHierarchy* hierarchy) {
@@ -332,7 +337,7 @@
}
}
-void LayerHierarchyBuilder::update(
+void LayerHierarchyBuilder::doUpdate(
const std::vector<std::unique_ptr<RequestedLayerState>>& layers,
const std::vector<std::unique_ptr<RequestedLayerState>>& destroyedLayers) {
// rebuild map
@@ -381,6 +386,32 @@
attachHierarchyToRelativeParent(&mRoot);
}
+void LayerHierarchyBuilder::update(LayerLifecycleManager& layerLifecycleManager) {
+ if (!mInitialized) {
+ ATRACE_NAME("LayerHierarchyBuilder:init");
+ init(layerLifecycleManager.getLayers());
+ } else if (layerLifecycleManager.getGlobalChanges().test(
+ RequestedLayerState::Changes::Hierarchy)) {
+ ATRACE_NAME("LayerHierarchyBuilder:update");
+ doUpdate(layerLifecycleManager.getLayers(), layerLifecycleManager.getDestroyedLayers());
+ } else {
+ return; // nothing to do
+ }
+
+ uint32_t invalidRelativeRoot;
+ bool hasRelZLoop = mRoot.hasRelZLoop(invalidRelativeRoot);
+ while (hasRelZLoop) {
+ ATRACE_NAME("FixRelZLoop");
+ TransactionTraceWriter::getInstance().invoke("relz_loop_detected",
+ /*overwrite=*/false);
+ layerLifecycleManager.fixRelativeZLoop(invalidRelativeRoot);
+ // reinitialize the hierarchy with the updated layer data
+ init(layerLifecycleManager.getLayers());
+ // check if we have any remaining loops
+ hasRelZLoop = mRoot.hasRelZLoop(invalidRelativeRoot);
+ }
+}
+
const LayerHierarchy& LayerHierarchyBuilder::getHierarchy() const {
return mRoot;
}