Maintain the active buffer when clearing buffer slots

When an app discards graphic buffers, for example when a MediaCodec
disconnects from a surface, those buffers will be uncached and removed
from HWC buffer slots. The active buffer, however, should still remain
active until the next buffer is queued up.

Bug: 262037933
Bug: 258196272
Test: atest OutputLayerUncacheBufferTest
Test: atest VtsHalGraphicsComposer3_TargetTest
Test: atest VtsHalGraphicsComposerV2_2TargetTest
Change-Id: I7c4eefb17e8bad694d698f9ad6d1d289f4af8d2c
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0ac2d43..766d7ea 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -610,21 +610,27 @@
     }
 }
 
-void OutputLayer::uncacheBuffers(std::vector<uint64_t> const& bufferIdsToUncache) {
+void OutputLayer::uncacheBuffers(const std::vector<uint64_t>& bufferIdsToUncache) {
     auto& state = editState();
     // Skip doing this if there is no HWC interface
     if (!state.hwc) {
         return;
     }
 
-    for (auto bufferId : bufferIdsToUncache) {
+    std::vector<uint32_t> slotsToClear;
+    for (uint64_t bufferId : bufferIdsToUncache) {
         uint32_t slot = state.hwc->hwcBufferCache.uncache(bufferId);
-        if (slot != UINT32_MAX && state.hwc->hwcLayer) {
-            hal::Error error = state.hwc->hwcLayer->clearBufferSlot(slot);
-            ALOGE("[%s] Failed to clear buffer slot %d: %s (%d)", getLayerFE().getDebugName(), slot,
-                  to_string(error).c_str(), static_cast<int32_t>(error));
+        if (slot != UINT32_MAX) {
+            slotsToClear.push_back(slot);
         }
     }
+
+    hal::Error error =
+            state.hwc->hwcLayer->setBufferSlotsToClear(slotsToClear, state.hwc->activeBufferSlot);
+    if (error != hal::Error::NONE) {
+        ALOGE("[%s] Failed to clear buffer slots: %s (%d)", getLayerFE().getDebugName(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
 }
 
 void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
@@ -641,15 +647,25 @@
 
     HwcSlotAndBuffer hwcSlotAndBuffer;
     sp<Fence> hwcFence;
-    // Override buffers use a special cache slot so that they don't evict client buffers.
-    if (getState().overrideInfo.buffer != nullptr && !skipLayer) {
-        hwcSlotAndBuffer = editState().hwc->hwcBufferCache.getHwcSlotAndBufferForOverride(
-                getState().overrideInfo.buffer->getBuffer());
-        hwcFence = getState().overrideInfo.acquireFence;
-    } else {
-        hwcSlotAndBuffer =
-                editState().hwc->hwcBufferCache.getHwcSlotAndBuffer(outputIndependentState.buffer);
-        hwcFence = outputIndependentState.acquireFence;
+    {
+        // Editing the state only because we update the HWC buffer cache and active buffer.
+        auto& state = editState();
+        // Override buffers use a special cache slot so that they don't evict client buffers.
+        if (state.overrideInfo.buffer != nullptr && !skipLayer) {
+            hwcSlotAndBuffer = state.hwc->hwcBufferCache.getOverrideHwcSlotAndBuffer(
+                    state.overrideInfo.buffer->getBuffer());
+            hwcFence = state.overrideInfo.acquireFence;
+        } else {
+            hwcSlotAndBuffer =
+                    state.hwc->hwcBufferCache.getHwcSlotAndBuffer(outputIndependentState.buffer);
+            hwcFence = outputIndependentState.acquireFence;
+        }
+
+        // Keep track of the active buffer slot, so we can restore it after clearing other buffer
+        // slots.
+        if (hwcSlotAndBuffer.buffer) {
+            state.hwc->activeBufferSlot = hwcSlotAndBuffer.slot;
+        }
     }
 
     if (auto error = hwcLayer->setBuffer(hwcSlotAndBuffer.slot, hwcSlotAndBuffer.buffer, hwcFence);