Don't blur too many layers

An application requesting lots and lots of blurs:
a. Enables pixel stealing by measuring how long it takes to perform a
blur across windows
b. Probably isn't very valid anyways.

So, just arbitrarily pick an upper bound for blur requests that a
display is allowed to manage (10), and disable everything else.
Arbitrarily, pick the 10 "front-most" blurs to be respected.

Bug: 399120953
Flag: EXEMPT security
Test: Security PoC no longer PoCs
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:acf65e7b90c8313b3cf939d14b8299818d77cc18)
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:63bb5e1c89ff74d1eb6725029769d00706a31857)
Merged-In: Ie7195eb852b52aff2f58da8bd095d8684baceef6
Change-Id: Ie7195eb852b52aff2f58da8bd095d8684baceef6
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 191d475..4664155 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -157,6 +157,7 @@
         // only has a value if there's something needing it, like when a TrustedPresentationListener
         // is set
         std::optional<Region> aboveCoveredLayersExcludingOverlays;
+        int32_t aboveBlurRequests = 0;
     };
 
     virtual ~Output();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 9990a74..3613c04 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -168,6 +168,7 @@
 private:
     void dirtyEntireOutput();
     compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const;
+    void sanitizeOutputLayers() const;
     void finishPrepareFrame();
     ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
     compositionengine::Output::ColorProfile pickColorProfile(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 6c419da..f1ea497 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -100,6 +100,9 @@
     // order to save power.
     Region outputSpaceBlockingRegionHint;
 
+    // ignore blur requests if there's just too many on top of this layer
+    bool ignoreBlur{false};
+
     // Overrides the buffer, acquire fence, and display frame stored in LayerFECompositionState
     struct {
         std::shared_ptr<renderengine::ExternalTexture> buffer = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
index 86bcf20..e09e308 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/CachedSet.h
@@ -42,6 +42,7 @@
         const std::string& getName() const { return mState->getName(); }
         int32_t getBackgroundBlurRadius() const { return mState->getBackgroundBlurRadius(); }
         Rect getDisplayFrame() const { return mState->getDisplayFrame(); }
+        bool hasBlurBehind() const { return mState->hasBlurBehind(); }
         const Region& getVisibleRegion() const { return mState->getVisibleRegion(); }
         const sp<GraphicBuffer>& getBuffer() const {
             return mState->getOutputLayer()->getLayerFE().getCompositionState()->buffer;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 5e3e3d8..eb94242 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -75,6 +75,7 @@
     HasProtectedContent   = 1u << 19,
     CachingHint           = 1u << 20,
     DimmingEnabled        = 1u << 21,
+    BlursDisabled         = 1u << 22,
 };
 // clang-format on
 
@@ -236,7 +237,8 @@
     Rect getDisplayFrame() const { return mDisplayFrame.get(); }
     const Region& getVisibleRegion() const { return mVisibleRegion.get(); }
     bool hasBlurBehind() const {
-        return mBackgroundBlurRadius.get() > 0 || !mBlurRegions.get().empty();
+        return (mBackgroundBlurRadius.get() > 0 || !mBlurRegions.get().empty()) &&
+                !mIsBlursDisabled.get();
     }
     int32_t getBackgroundBlurRadius() const { return mBackgroundBlurRadius.get(); }
     aidl::android::hardware::graphics::composer3::Composition getCompositionType() const {
@@ -508,7 +510,10 @@
     OutputLayerState<bool, LayerStateField::DimmingEnabled> mIsDimmingEnabled{
             [](auto layer) { return layer->getLayerFE().getCompositionState()->dimmingEnabled; }};
 
-    static const constexpr size_t kNumNonUniqueFields = 20;
+    OutputLayerState<bool, LayerStateField::BlursDisabled> mIsBlursDisabled{
+            [](auto layer) { return layer->getState().ignoreBlur; }};
+
+    static const constexpr size_t kNumNonUniqueFields = 21;
 
     std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
         std::array<const StateInterface*, kNumNonUniqueFields> constFields =
@@ -522,11 +527,12 @@
     }
 
     std::array<const StateInterface*, kNumNonUniqueFields> getNonUniqueFields() const {
-        return {&mDisplayFrame, &mSourceCrop,     &mBufferTransform,      &mBlendMode,
-                &mAlpha,        &mLayerMetadata,  &mVisibleRegion,        &mOutputDataspace,
-                &mPixelFormat,  &mColorTransform, &mCompositionType,      &mSidebandStream,
-                &mBuffer,       &mSolidColor,     &mBackgroundBlurRadius, &mBlurRegions,
-                &mFrameNumber,  &mIsProtected,    &mCachingHint,          &mIsDimmingEnabled};
+        return {&mDisplayFrame,   &mSourceCrop,     &mBufferTransform,      &mBlendMode,
+                &mAlpha,          &mLayerMetadata,  &mVisibleRegion,        &mOutputDataspace,
+                &mPixelFormat,    &mColorTransform, &mCompositionType,      &mSidebandStream,
+                &mBuffer,         &mSolidColor,     &mBackgroundBlurRadius, &mBlurRegions,
+                &mFrameNumber,    &mIsProtected,    &mCachingHint,          &mIsDimmingEnabled,
+                &mIsBlursDisabled};
     }
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index b40aea4..ea6fe73 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -779,6 +779,9 @@
     // one, or create a new one if we do not.
     auto result = ensureOutputLayer(prevOutputLayerIndex, layerFE);
 
+    coverage.aboveBlurRequests += static_cast<int32_t>(layerFEState->backgroundBlurRadius > 0 ||
+                                                       !layerFEState->blurRegions.empty());
+
     // Store the layer coverage information into the layer state as some of it
     // is useful later.
     auto& outputLayerState = result->editState();
@@ -793,6 +796,11 @@
             ? outputState.transform.transform(
                       transparentRegion.intersect(outputState.layerStackSpace.getContent()))
             : Region();
+
+    // See b/399120953: blurs are so expensive that they may be susceptible to compression side
+    // channel attacks
+    static constexpr auto kMaxBlurRequests = 10;
+    outputLayerState.ignoreBlur = coverage.aboveBlurRequests > kMaxBlurRequests;
     if (CC_UNLIKELY(computeAboveCoveredExcludingOverlays)) {
         outputLayerState.coveredRegionExcludingDisplayOverlays =
                 std::move(coveredRegionExcludingDisplayOverlays);
@@ -1437,7 +1445,7 @@
     const Region viewportRegion(outputState.layerStackSpace.getContent());
     bool firstLayer = true;
 
-    bool disableBlurs = false;
+    bool disableBlursWholesale = false;
     uint64_t previousOverrideBufferId = 0;
 
     for (auto* layer : getOutputLayersOrderedByZ()) {
@@ -1454,7 +1462,8 @@
             continue;
         }
 
-        disableBlurs |= layerFEState->sidebandStream != nullptr;
+        disableBlursWholesale |= layerFEState->sidebandStream != nullptr;
+        bool disableBlurForLayer = layer->getState().ignoreBlur || disableBlursWholesale;
 
         const bool clientComposition = layer->requiresClientComposition();
 
@@ -1484,7 +1493,8 @@
                           layer->getLayerFE().getDebugName());
                 }
             } else {
-                LayerFE::ClientCompositionTargetSettings::BlurSetting blurSetting = disableBlurs
+                LayerFE::ClientCompositionTargetSettings::BlurSetting blurSetting =
+                        disableBlurForLayer
                         ? LayerFE::ClientCompositionTargetSettings::BlurSetting::Disabled
                         : (layer->getState().overrideInfo.disableBackgroundBlur
                                    ? LayerFE::ClientCompositionTargetSettings::BlurSetting::
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index ea9442d..63e01b4 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -196,9 +196,14 @@
     std::vector<renderengine::LayerSettings> layerSettings;
     renderengine::LayerSettings highlight;
     for (const auto& layer : mLayers) {
+        auto blurSettings = targetSettings;
+        if (!layer.hasBlurBehind()) {
+            blurSettings.blurSetting =
+                    LayerFE::ClientCompositionTargetSettings::BlurSetting::Disabled;
+        }
         if (auto clientCompositionSettings =
                     layer.getState()->getOutputLayer()->getLayerFE().prepareClientComposition(
-                            targetSettings)) {
+                            blurSettings)) {
             layerSettings.push_back(std::move(*clientCompositionSettings));
         }
     }
diff --git a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
index d61d7ba..5b33407 100644
--- a/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/planner/CachedSetTest.cpp
@@ -1011,12 +1011,12 @@
     EXPECT_CALL(*layerFE1,
                 prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq(
                         compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::
-                                Enabled)))
+                                Disabled)))
             .WillOnce(Return(clientComp1));
     EXPECT_CALL(*layerFE2,
                 prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq(
                         compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::
-                                Enabled)))
+                                Disabled)))
             .WillOnce(Return(clientComp2));
     EXPECT_CALL(*layerFE3,
                 prepareClientComposition(ClientCompositionTargetSettingsBlurSettingsEq(