Merge "Improve Planner stability" into sc-dev
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
index 8423a12..936dba3 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/LayerState.cpp
@@ -42,7 +42,13 @@
 }
 
 Flags<LayerStateField> LayerState::update(compositionengine::OutputLayer* layer) {
-    ALOGE_IF(layer != mOutputLayer, "[%s] Expected mOutputLayer to never change", __func__);
+    ALOGE_IF(mOutputLayer != layer && layer->getLayerFE().getSequence() != mId.get(),
+             "[%s] Expected mOutputLayer ID to never change: %d, %d", __func__,
+             layer->getLayerFE().getSequence(), mId.get());
+
+    // It's possible for the OutputLayer pointer to change even when the layer is logically the
+    // same, i.e., the LayerFE is the same. An example use-case is screen rotation.
+    mOutputLayer = layer;
 
     Flags<LayerStateField> differences;
 
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
index be2510f..f077470 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Planner.cpp
@@ -113,15 +113,6 @@
         }
     }
 
-    for (LayerId removedLayer : removedLayers) {
-        if (const auto layerEntry = mPreviousLayers.find(removedLayer);
-            layerEntry != mPreviousLayers.end()) {
-            const auto& [id, state] = *layerEntry;
-            ALOGV("Removed layer %s", state.getName().c_str());
-            mPreviousLayers.erase(removedLayer);
-        }
-    }
-
     mCurrentLayers.clear();
     mCurrentLayers.reserve(currentLayerIds.size());
     std::transform(currentLayerIds.cbegin(), currentLayerIds.cend(),
@@ -135,6 +126,7 @@
     mFlattenedHash =
             mFlattener.flattenLayers(mCurrentLayers, hash, std::chrono::steady_clock::now());
     const bool layersWereFlattened = hash != mFlattenedHash;
+
     ALOGV("[%s] Initial hash %zx flattened hash %zx", __func__, hash, mFlattenedHash);
 
     if (mPredictorEnabled) {
@@ -148,6 +140,17 @@
             ALOGV("[%s] No prediction found\n", __func__);
         }
     }
+
+    // Clean up the set of previous layers now that the view of the LayerStates in the flattener are
+    // up-to-date.
+    for (LayerId removedLayer : removedLayers) {
+        if (const auto layerEntry = mPreviousLayers.find(removedLayer);
+            layerEntry != mPreviousLayers.end()) {
+            const auto& [id, state] = *layerEntry;
+            ALOGV("Removed layer %s", state.getName().c_str());
+            mPreviousLayers.erase(removedLayer);
+        }
+    }
 }
 
 void Planner::reportFinalPlan(
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
index a09ce14..9ad3ab4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/LayerStateTest.cpp
@@ -117,6 +117,22 @@
     EXPECT_EQ(&mOutputLayer, mLayerState->getOutputLayer());
 }
 
+TEST_F(LayerStateTest, updateOutputLayer) {
+    OutputLayerCompositionState outputLayerCompositionState;
+    LayerFECompositionState layerFECompositionState;
+    setupMocksForLayer(mOutputLayer, mLayerFE, outputLayerCompositionState,
+                       layerFECompositionState);
+    mLayerState = std::make_unique<LayerState>(&mOutputLayer);
+    EXPECT_EQ(&mOutputLayer, mLayerState->getOutputLayer());
+
+    mock::OutputLayer newOutputLayer;
+    mock::LayerFE newLayerFE;
+    setupMocksForLayer(newOutputLayer, newLayerFE, outputLayerCompositionState,
+                       layerFECompositionState);
+    mLayerState->update(&newOutputLayer);
+    EXPECT_EQ(&newOutputLayer, mLayerState->getOutputLayer());
+}
+
 TEST_F(LayerStateTest, getId) {
     OutputLayerCompositionState outputLayerCompositionState;
     LayerFECompositionState layerFECompositionState;