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;
 }