Preserve relative z layer info when moving layers offscreen

When a layer is removed from screen, by reparenting it to null, we need to
remove its relative z info as well. Otherwise, if the layer has a visible
relative parent, it will continue to be drawn.

However, there are some scenarios where it maybe useful to preserve relative z.
When a layer is temporarily moved offscreen, and the layer has children with
relative z ordered to other children, then the client logic can be made simpler
by preserving the relative z info for all the children and only removing relative
z info if its relative parent is not on the pending removal state.

Bug: 132613412

Test: atest SurfaceFlinger_test
Test: go/wm-smoke
Change-Id: Id9e2d164673c9028fb27a38ab2b3005269ad4932
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 3ca6ef5..898f3bc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -158,18 +158,26 @@
     }
 }
 
-void Layer::onRemovedFromCurrentState() {
-    mRemovedFromCurrentState = true;
+void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
+    if (mCurrentState.zOrderRelativeOf == nullptr) {
+        return;
+    }
 
-    // the layer is removed from SF mCurrentState to mLayersPendingRemoval
-    if (mCurrentState.zOrderRelativeOf != nullptr) {
-        sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
-        if (strongRelative != nullptr) {
-            strongRelative->removeZOrderRelative(this);
-            mFlinger->setTransactionFlags(eTraversalNeeded);
-        }
+    sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
+    if (strongRelative == nullptr) {
+        setZOrderRelativeOf(nullptr);
+        return;
+    }
+
+    if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
+        strongRelative->removeZOrderRelative(this);
+        mFlinger->setTransactionFlags(eTraversalNeeded);
         setZOrderRelativeOf(nullptr);
     }
+}
+
+void Layer::removeFromCurrentState() {
+    mRemovedFromCurrentState = true;
 
     // Since we are no longer reachable from CurrentState SurfaceFlinger
     // will no longer invoke doTransaction for us, and so we will
@@ -186,13 +194,18 @@
     mLocalSyncPoints.clear();
     }
 
-    for (const auto& child : mCurrentChildren) {
-        child->onRemovedFromCurrentState();
-    }
-
     mFlinger->markLayerPendingRemovalLocked(this);
 }
 
+void Layer::onRemovedFromCurrentState() {
+    auto layersInTree = getLayersInTree(LayerVector::StateSet::Current);
+    std::sort(layersInTree.begin(), layersInTree.end());
+    for (const auto& layer : layersInTree) {
+        layer->removeFromCurrentState();
+        layer->removeRelativeZ(layersInTree);
+    }
+}
+
 void Layer::addToCurrentState() {
     mRemovedFromCurrentState = false;