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/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f800627..637a9cf 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -133,6 +133,9 @@
     if (handle) {
         free_handle();
     }
+    for (auto& [callback, context] : mDeathCallbacks) {
+        callback(context, mId);
+    }
 }
 
 void GraphicBuffer::free_handle()
@@ -534,6 +537,10 @@
     return NO_ERROR;
 }
 
+void GraphicBuffer::addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context) {
+    mDeathCallbacks.emplace_back(deathCallback, context);
+}
+
 #ifndef LIBUI_IN_VNDK
 bool GraphicBuffer::isBufferHubBuffer() const {
     return mBufferHubBuffer != nullptr;
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 1c88777..f86ca59 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -21,6 +21,8 @@
 #include <sys/types.h>
 
 #include <string>
+#include <utility>
+#include <vector>
 
 #include <android/hardware_buffer.h>
 #include <ui/ANativeObjectBase.h>
@@ -42,6 +44,8 @@
 
 class GraphicBufferMapper;
 
+using GraphicBufferDeathCallback = std::function<void(void* /*context*/, uint64_t bufferId)>;
+
 // ===========================================================================
 // GraphicBuffer
 // ===========================================================================
@@ -219,6 +223,8 @@
         return mBufferMapper.getMapperVersion();
     }
 
+    void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context);
+
 #ifndef LIBUI_IN_VNDK
     // Returns whether this GraphicBuffer is backed by BufferHubBuffer.
     bool isBufferHubBuffer() const;
@@ -280,6 +286,20 @@
     // IGBP::setGenerationNumber), attempts to attach the buffer will fail.
     uint32_t mGenerationNumber;
 
+    // Send a callback when a GraphicBuffer dies.
+    //
+    // This is used for BufferStateLayer caching. GraphicBuffers are refcounted per process. When
+    // A GraphicBuffer doesn't have any more sp<> in a process, it is destroyed. This causes
+    // problems when trying to implicitcly cache across process boundaries. Ideally, both sides
+    // of the cache would hold onto wp<> references. When an app dropped its sp<>, the GraphicBuffer
+    // would be destroyed. Unfortunately, when SurfaceFlinger has only a wp<> reference to the
+    // GraphicBuffer, it immediately goes out of scope in the SurfaceFlinger process. SurfaceFlinger
+    // must hold onto a sp<> to the buffer. When the GraphicBuffer goes out of scope in the app's
+    // process, the client side cache will get this callback. It erases the buffer from its cache
+    // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer.
+    std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>>
+            mDeathCallbacks;
+
 #ifndef LIBUI_IN_VNDK
     // Stores a BufferHubBuffer that handles buffer signaling, identification.
     std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;