Support toggling layer caching at runtime

The use-case for this is dynamically enabling and disabling layer
caching when a bad layer state is encountered that is difficult to
reproduce.

Bug: 187448777
Test: adb shell service call SurfaceFlinger 1040 i32 1
Test: libcompositionengine_test
Change-Id: Id441a0894ff5a4c654db9fd706ceb1c0d1c343f0
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 4976213..9fba7aa 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,6 +163,9 @@
     // Enables (or disables) composition on this output
     virtual void setCompositionEnabled(bool) = 0;
 
+    // Enables (or disables) layer caching on this output
+    virtual void setLayerCachingEnabled(bool) = 0;
+
     // Sets the projection state to use
     virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                                const Rect& orientedDisplaySpaceRect) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index eeb20fc..2893c3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -20,6 +20,7 @@
 #include <compositionengine/Output.h>
 #include <compositionengine/impl/ClientCompositionRequestCache.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/planner/Planner.h>
 #include <renderengine/DisplaySettings.h>
 #include <renderengine/LayerSettings.h>
 #include <memory>
@@ -28,21 +29,18 @@
 
 namespace android::compositionengine::impl {
 
-namespace planner {
-class Planner;
-} // namespace planner
-
 // The implementation class contains the common implementation, but does not
 // actually contain the final output state.
 class Output : public virtual compositionengine::Output {
 public:
-    Output();
+    Output() = default;
     ~Output() override;
 
     // compositionengine::Output overrides
     bool isValid() const override;
     std::optional<DisplayId> getDisplayId() const override;
     void setCompositionEnabled(bool) override;
+    void setLayerCachingEnabled(bool) override;
     void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                        const Rect& orientedDisplaySpaceRect) override;
     void setDisplaySize(const ui::Size&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 5aa53e5..749675d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -36,6 +36,7 @@
     MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
 
     MOCK_METHOD1(setCompositionEnabled, void(bool));
+    MOCK_METHOD1(setLayerCachingEnabled, void(bool));
     MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
     MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 297e687..796fe7d 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -55,18 +55,6 @@
 
 namespace impl {
 
-Output::Output() {
-    const bool enableLayerCaching = [] {
-        const bool enable =
-                android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
-        return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
-    }();
-
-    if (enableLayerCaching) {
-        mPlanner = std::make_unique<planner::Planner>();
-    }
-}
-
 namespace {
 
 template <typename T>
@@ -135,6 +123,21 @@
     dirtyEntireOutput();
 }
 
+void Output::setLayerCachingEnabled(bool enabled) {
+    if (enabled == (mPlanner != nullptr)) {
+        return;
+    }
+
+    if (enabled) {
+        mPlanner = std::make_unique<planner::Planner>();
+        if (mRenderSurface) {
+            mPlanner->setDisplaySize(mRenderSurface->getSize());
+        }
+    } else {
+        mPlanner.reset();
+    }
+}
+
 void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                            const Rect& orientedDisplaySpaceRect) {
     auto& outputState = editState();
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 27980a0..11736d1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -238,6 +238,28 @@
 }
 
 /*
+ * Output::setLayerCachingEnabled()
+ */
+
+TEST_F(OutputTest, setLayerCachingEnabled_enablesCaching) {
+    const auto kSize = ui::Size(1, 1);
+    EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+    mOutput->setLayerCachingEnabled(false);
+    mOutput->setLayerCachingEnabled(true);
+
+    EXPECT_TRUE(mOutput->plannerEnabled());
+}
+
+TEST_F(OutputTest, setLayerCachingEnabled_disablesCaching) {
+    const auto kSize = ui::Size(1, 1);
+    EXPECT_CALL(*mRenderSurface, getSize()).WillRepeatedly(ReturnRef(kSize));
+    mOutput->setLayerCachingEnabled(true);
+    mOutput->setLayerCachingEnabled(false);
+
+    EXPECT_FALSE(mOutput->plannerEnabled());
+}
+
+/*
  * Output::setProjection()
  */
 
@@ -972,9 +994,7 @@
     mOutput.editState().usesDeviceComposition = true;
 
     EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
-    if (mOutput.plannerEnabled()) {
-        EXPECT_CALL(mOutput, getOutputLayerCount()).WillOnce(Return(0u));
-    }
+    EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(0u));
     EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
 
     mOutput.prepareFrame();