Add buffer release callback in NDK

Introduce a new API, ASurfaceTransaction_setBufferWithRelease, which provides C/C++ code with the ability to register a callback function that is executed when a buffer is ready to be reused. This functionality mirrors the existing Java Transaction#setBuffer API, allowing for correct buffer management if the buffer is released when its overwritten in a transaction before the transaction is applied.

Flag: EXEMPT NDK
Test: atest ASurfaceControlTest
Bug:362513091

Change-Id: I49fd8d21adb34c193144035cfa2bee5bd6143dab
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 346c87d..b20cb77 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -273,6 +273,7 @@
     ASurfaceTransaction_fromJava; # introduced=34
     ASurfaceTransaction_reparent; # introduced=29
     ASurfaceTransaction_setBuffer; # introduced=29
+    ASurfaceTransaction_setBufferWithRelease; # introduced=36
     ASurfaceTransaction_setBufferAlpha; # introduced=29
     ASurfaceTransaction_setBufferDataSpace; # introduced=29
     ASurfaceTransaction_setBufferTransparency; # introduced=29
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 6ce83cd..e46db6b 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -416,6 +416,35 @@
     transaction->setBuffer(surfaceControl, graphic_buffer, fence);
 }
 
+void ASurfaceTransaction_setBufferWithRelease(
+        ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl,
+        AHardwareBuffer* buffer, int acquire_fence_fd, void* _Null_unspecified context,
+        ASurfaceTransaction_OnBufferRelease aReleaseCallback) {
+    CHECK_NOT_NULL(aSurfaceTransaction);
+    CHECK_NOT_NULL(aSurfaceControl);
+    CHECK_NOT_NULL(aReleaseCallback);
+
+    sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
+    Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
+
+    sp<GraphicBuffer> graphic_buffer(GraphicBuffer::fromAHardwareBuffer(buffer));
+
+    std::optional<sp<Fence>> fence = std::nullopt;
+    if (acquire_fence_fd != -1) {
+        fence = new Fence(acquire_fence_fd);
+    }
+
+    ReleaseBufferCallback releaseBufferCallback =
+            [context,
+             aReleaseCallback](const ReleaseCallbackId&, const sp<Fence>& releaseFence,
+                               std::optional<uint32_t> /* currentMaxAcquiredBufferCount */) {
+                (*aReleaseCallback)(context, (releaseFence) ? releaseFence->dup() : -1);
+            };
+
+    transaction->setBuffer(surfaceControl, graphic_buffer, fence, /* frameNumber */ std::nullopt,
+                           /* producerId */ 0, releaseBufferCallback);
+}
+
 void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction,
                                      ASurfaceControl* aSurfaceControl, const ARect& source,
                                      const ARect& destination, int32_t transform) {