blast: drop buffer from SF's cache when destroyed

When an app drops its reference to an AHardwareBuffer, the buffer
should be removed from the client and SurfaceFlinger caches.

Ideally, both caches would have wp to the buffer and the buffer
would automatically be removed from the cache.

Unfortunately, GraphicBuffers are refcounted per process. If SurfaceFlinger
just has a wp to the GraphicBuffer, the buffer's destructor will
be called and SurfaceFlinger will lose access to the buffer.
SurfaceFlinger can't just hold onto a sp to the buffer because
then the buffer wouldn't be destoryed when the app drops its reference.

Instead, when the app process drops its last strong reference,
GraphicBuffer will send a callback to the client side cache.
The cache will send a Transaction to SurfaceFlinger to drop its sp
to the buffer.

Bug: 127689853
Test: SurfaceFlinger_test

Change-Id: I2182578ed33d7c731945cb88cd1decb2892266b0
diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp
index cb02d16..51ca45c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.cpp
+++ b/services/surfaceflinger/BufferStateLayerCache.cpp
@@ -23,21 +23,14 @@
 
 #include "BufferStateLayerCache.h"
 
-#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE))
-
 namespace android {
 
 ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache);
 
 BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {}
 
-void BufferStateLayerCache::add(sp<IBinder> processToken, int32_t id,
+void BufferStateLayerCache::add(const sp<IBinder>& processToken, uint64_t id,
                                 const sp<GraphicBuffer>& buffer) {
-    if (!VALID_CACHE_ID(id)) {
-        ALOGE("failed to cache buffer: invalid buffer id");
-        return;
-    }
-
     if (!processToken) {
         ALOGE("failed to cache buffer: invalid process token");
         return;
@@ -61,15 +54,33 @@
     }
 
     auto& processBuffers = mBuffers[processToken];
+
+    if (processBuffers.size() > BUFFER_CACHE_MAX_SIZE) {
+        ALOGE("failed to cache buffer: cache is full");
+        return;
+    }
+
     processBuffers[id] = buffer;
 }
 
-sp<GraphicBuffer> BufferStateLayerCache::get(sp<IBinder> processToken, int32_t id) {
-    if (!VALID_CACHE_ID(id)) {
-        ALOGE("failed to get buffer: invalid buffer id");
-        return nullptr;
+void BufferStateLayerCache::erase(const sp<IBinder>& processToken, uint64_t id) {
+    if (!processToken) {
+        ALOGE("failed to uncache buffer: invalid process token");
+        return;
     }
 
+    std::lock_guard lock(mMutex);
+
+    if (mBuffers.find(processToken) == mBuffers.end()) {
+        ALOGE("failed to uncache buffer: process token not found");
+        return;
+    }
+
+    auto& processBuffers = mBuffers[processToken];
+    processBuffers.erase(id);
+}
+
+sp<GraphicBuffer> BufferStateLayerCache::get(const sp<IBinder>& processToken, uint64_t id) {
     if (!processToken) {
         ALOGE("failed to cache buffer: invalid process token");
         return nullptr;
@@ -82,8 +93,8 @@
         return nullptr;
     }
 
-    if (id >= itr->second.size()) {
-        ALOGE("failed to get buffer: id outside the bounds of the cache");
+    if (itr->second.find(id) == itr->second.end()) {
+        ALOGE("failed to get buffer: buffer not found");
         return nullptr;
     }
 
diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h
index ede3feb..415c09c 100644
--- a/services/surfaceflinger/BufferStateLayerCache.h
+++ b/services/surfaceflinger/BufferStateLayerCache.h
@@ -34,14 +34,16 @@
 public:
     BufferStateLayerCache();
 
-    void add(sp<IBinder> processToken, int32_t id, const sp<GraphicBuffer>& buffer);
-    sp<GraphicBuffer> get(sp<IBinder> processToken, int32_t id);
+    void add(const sp<IBinder>& processToken, uint64_t id, const sp<GraphicBuffer>& buffer);
+    void erase(const sp<IBinder>& processToken, uint64_t id);
+
+    sp<GraphicBuffer> get(const sp<IBinder>& processToken, uint64_t id);
 
     void removeProcess(const wp<IBinder>& processToken);
 
 private:
     std::mutex mMutex;
-    std::map<wp<IBinder> /*caching process*/, std::array<sp<GraphicBuffer>, BUFFER_CACHE_MAX_SIZE>>
+    std::map<wp<IBinder> /*caching process*/, std::map<uint64_t /*Cache id*/, sp<GraphicBuffer>>>
             mBuffers GUARDED_BY(mMutex);
 
     class CacheDeathRecipient : public IBinder::DeathRecipient {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 55fcb01..547f30f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3508,13 +3508,15 @@
         auto& [applyToken, transactionQueue] = *it;
 
         while (!transactionQueue.empty()) {
-            const auto& [states, displays, flags, desiredPresentTime, postTime, privileged] =
-                    transactionQueue.front();
+            const auto&
+                    [states, displays, flags, desiredPresentTime, uncacheBuffer, postTime,
+                     privileged] = transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
             applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
-                                  desiredPresentTime, postTime, privileged, /*isMainThread*/ true);
+                                  desiredPresentTime, uncacheBuffer, postTime, privileged,
+                                  /*isMainThread*/ true);
             transactionQueue.pop();
         }
 
@@ -3571,7 +3573,8 @@
                                          const Vector<DisplayState>& displays, uint32_t flags,
                                          const sp<IBinder>& applyToken,
                                          const InputWindowCommands& inputWindowCommands,
-                                         int64_t desiredPresentTime) {
+                                         int64_t desiredPresentTime,
+                                         const cached_buffer_t& uncacheBuffer) {
     ATRACE_CALL();
 
     const int64_t postTime = systemTime();
@@ -3588,20 +3591,22 @@
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
         mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
-                                               postTime, privileged);
+                                               uncacheBuffer, postTime, privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
     applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
-                          postTime, privileged);
+                          uncacheBuffer, postTime, privileged);
 }
 
 void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
                                            const InputWindowCommands& inputWindowCommands,
-                                           const int64_t desiredPresentTime, const int64_t postTime,
-                                           bool privileged, bool isMainThread) {
+                                           const int64_t desiredPresentTime,
+                                           const cached_buffer_t& uncacheBuffer,
+                                           const int64_t postTime, bool privileged,
+                                           bool isMainThread) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3636,6 +3641,10 @@
 
     transactionFlags |= addInputWindowCommands(inputWindowCommands);
 
+    if (uncacheBuffer.token) {
+        BufferStateLayerCache::getInstance().erase(uncacheBuffer.token, uncacheBuffer.cacheId);
+    }
+
     // If a synchronous transaction is explicitly requested without any changes, force a transaction
     // anyway. This can be used as a flush mechanism for previous async transactions.
     // Empty animation transaction can be used to simulate back-pressure, so also force a
@@ -3977,16 +3986,20 @@
             callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
         }
     }
-
-    if (what & layer_state_t::eBufferChanged) {
-        // Add the new buffer to the cache. This should always come before eCachedBufferChanged.
-        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId,
+    bool bufferChanged = what & layer_state_t::eBufferChanged;
+    bool cacheIdChanged = what & layer_state_t::eCachedBufferChanged;
+    sp<GraphicBuffer> buffer;
+    if (bufferChanged && cacheIdChanged) {
+        BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.cacheId,
                                                  s.buffer);
+        buffer = s.buffer;
+    } else if (cacheIdChanged) {
+        buffer = BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
+                                                          s.cachedBuffer.cacheId);
+    } else if (bufferChanged) {
+        buffer = s.buffer;
     }
-    if (what & layer_state_t::eCachedBufferChanged) {
-        sp<GraphicBuffer> buffer =
-                BufferStateLayerCache::getInstance().get(s.cachedBuffer.token,
-                                                         s.cachedBuffer.bufferId);
+    if (buffer) {
         if (layer->setBuffer(buffer)) {
             flags |= eTraversalNeeded;
             layer->setPostTime(postTime);
@@ -4230,7 +4243,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
+    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {});
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0776a1e..03146d6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -431,7 +431,8 @@
                              const Vector<DisplayState>& displays, uint32_t flags,
                              const sp<IBinder>& applyToken,
                              const InputWindowCommands& inputWindowCommands,
-                             int64_t desiredPresentTime) override;
+                             int64_t desiredPresentTime,
+                             const cached_buffer_t& uncacheBuffer) override;
     void bootFinished() override;
     bool authenticateSurfaceTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) const override;
@@ -577,7 +578,8 @@
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
-                               const int64_t desiredPresentTime, const int64_t postTime,
+                               const int64_t desiredPresentTime,
+                               const cached_buffer_t& uncacheBuffer, const int64_t postTime,
                                bool privileged, bool isMainThread = false) REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
@@ -1058,11 +1060,13 @@
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime, int64_t postTime, bool privileged)
+                         int64_t desiredPresentTime, const cached_buffer_t& uncacheBuffer,
+                         int64_t postTime, bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
                 desiredPresentTime(desiredPresentTime),
+                buffer(uncacheBuffer),
                 postTime(postTime),
                 privileged(privileged) {}
 
@@ -1070,6 +1074,7 @@
         Vector<DisplayState> displays;
         uint32_t flags;
         const int64_t desiredPresentTime;
+        cached_buffer_t buffer;
         const int64_t postTime;
         bool privileged;
     };