blast: send back previous release fences

When sending a transaction callback, send a previous release fence
instead of a boolean.

Test: Transaction_test
Bug: 80477568, 120930690

Change-Id: I608fecc3cd31fd92fcfc2abb5fc084c529ee7806
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 1be55e6..ce88d7b 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -39,7 +39,16 @@
     if (err != NO_ERROR) {
         return err;
     }
-    return output->writeBool(releasePreviousBuffer);
+    if (previousReleaseFence) {
+        err = output->writeBool(true);
+        if (err != NO_ERROR) {
+            return err;
+        }
+        err = output->write(*previousReleaseFence);
+    } else {
+        err = output->writeBool(false);
+    }
+    return err;
 }
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
@@ -51,7 +60,19 @@
     if (err != NO_ERROR) {
         return err;
     }
-    return input->readBool(&releasePreviousBuffer);
+    bool hasFence = false;
+    err = input->readBool(&hasFence);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    if (hasFence) {
+        previousReleaseFence = new Fence();
+        err = input->read(*previousReleaseFence);
+        if (err != NO_ERROR) {
+            return err;
+        }
+    }
+    return NO_ERROR;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 8acfa7a..29ab026 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -52,12 +52,12 @@
     status_t readFromParcel(const Parcel* input) override;
 
     SurfaceStats() = default;
-    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, bool releasePrevBuffer)
-          : surfaceControl(sc), acquireTime(time), releasePreviousBuffer(releasePrevBuffer) {}
+    SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence)
+          : surfaceControl(sc), acquireTime(time), previousReleaseFence(prevReleaseFence) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
-    bool releasePreviousBuffer = false;
+    sp<Fence> previousReleaseFence;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e0d9d23..2132f59 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,10 +48,28 @@
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    // The transaction completed callback can only be sent if the release fence from the PREVIOUS
-    // frame has fired. In practice, we should never actually wait on the previous release fence
-    // but we should store it just in case.
-    mPreviousReleaseFence = releaseFence;
+    // The previous release fence notifies the client that SurfaceFlinger is done with the previous
+    // buffer that was presented on this layer. The first transaction that came in this frame that
+    // replaced the previous buffer on this layer needs this release fence, because the fence will
+    // let the client know when that previous buffer is removed from the screen.
+    //
+    // Every other transaction on this layer does not need a release fence because no other
+    // Transactions that were set on this layer this frame are going to have their preceeding buffer
+    // removed from the display this frame.
+    //
+    // For example, if we have 3 transactions this frame. The first transaction doesn't contain a
+    // buffer so it doesn't need a previous release fence because the layer still needs the previous
+    // buffer. The second transaction contains a buffer so it needs a previous release fence because
+    // the previous buffer will be released this frame. The third transaction also contains a
+    // buffer. It replaces the buffer in the second transaction. The buffer in the second
+    // transaction will now no longer be presented so it is released immediately and the third
+    // transaction doesn't need a previous release fence.
+    for (auto& handle : mDrawingState.callbackHandles) {
+        if (handle->releasePreviousBuffer) {
+            handle->previousReleaseFence = releaseFence;
+            break;
+        }
+    }
 }
 
 void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -60,7 +78,10 @@
 }
 
 void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
-    return;
+    mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+            mDrawingState.callbackHandles);
+
+    mDrawingState.callbackHandles = {};
 }
 
 bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -257,14 +278,14 @@
 
             // Notify the transaction completed thread that there is a pending latched callback
             // handle
-            mFlinger->getTransactionCompletedThread().registerPendingLatchedCallbackHandle(handle);
+            mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
 
             // Store so latched time and release fence can be set
             mCurrentState.callbackHandles.push_back(handle);
 
         } else { // If this layer will NOT need to be relatched and presented this frame
             // Notify the transaction completed thread this handle is done
-            mFlinger->getTransactionCompletedThread().addUnlatchedCallbackHandle(handle);
+            mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
         }
     }
 
@@ -504,9 +525,9 @@
         return BAD_VALUE;
     }
 
-    mFlinger->getTransactionCompletedThread()
-            .addLatchedCallbackHandles(getDrawingState().callbackHandles, latchTime,
-                                       mPreviousReleaseFence);
+    for (auto& handle : mDrawingState.callbackHandles) {
+        handle->latchTime = latchTime;
+    }
 
     // Handle sync fences
     if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index a1a8692..d2b7fe0 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -62,8 +62,7 @@
     mThread = std::thread(&TransactionCompletedThread::threadMain, this);
 }
 
-void TransactionCompletedThread::registerPendingLatchedCallbackHandle(
-        const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
     std::lock_guard lock(mMutex);
 
     sp<IBinder> listener = IInterface::asBinder(handle->listener);
@@ -72,19 +71,10 @@
     mPendingTransactions[listener][callbackIds]++;
 }
 
-void TransactionCompletedThread::addLatchedCallbackHandles(
-        const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
-        const sp<Fence>& previousReleaseFence) {
+void TransactionCompletedThread::addPresentedCallbackHandles(
+        const std::deque<sp<CallbackHandle>>& handles) {
     std::lock_guard lock(mMutex);
 
-    // If the previous release fences have not signaled, something as probably gone wrong.
-    // Store the fences and check them again before sending a callback.
-    if (previousReleaseFence &&
-        previousReleaseFence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) {
-        ALOGD("release fence from the previous frame has not signaled");
-        mPreviousReleaseFences.push_back(previousReleaseFence);
-    }
-
     for (const auto& handle : handles) {
         auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
         auto& pendingCallbacks = listener->second;
@@ -101,17 +91,16 @@
             ALOGE("there are more latched callbacks than there were registered callbacks");
         }
 
-        addCallbackHandle(handle, latchTime);
+        addCallbackHandle(handle);
     }
 }
 
-void TransactionCompletedThread::addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle) {
+void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
     std::lock_guard lock(mMutex);
     addCallbackHandle(handle);
 }
 
-void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
-                                                   nsecs_t latchTime) {
+void TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
     const sp<IBinder> listener = IInterface::asBinder(handle->listener);
 
     // If we don't already have a reference to this listener, linkToDeath so we get a notification
@@ -128,9 +117,9 @@
     listenerStats.listener = handle->listener;
 
     auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
-    transactionStats.latchTime = latchTime;
+    transactionStats.latchTime = handle->latchTime;
     transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
-                                               handle->releasePreviousBuffer);
+                                               handle->previousReleaseFence);
 }
 
 void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
@@ -151,15 +140,6 @@
     while (mKeepRunning) {
         mConditionVariable.wait(mMutex);
 
-        // We should never hit this case. The release fences from the previous frame should have
-        // signaled long before the current frame is presented.
-        for (const auto& fence : mPreviousReleaseFences) {
-            status_t status = fence->wait(100);
-            if (status != NO_ERROR) {
-                ALOGE("previous release fence has not signaled, err %d", status);
-            }
-        }
-
         // For each listener
         auto it = mListenerStats.begin();
         while (it != mListenerStats.end()) {
@@ -200,7 +180,6 @@
 
         if (mPresentFence) {
             mPresentFence.clear();
-            mPreviousReleaseFences.clear();
         }
     }
 }
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 1612f69..f49306d 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -40,7 +40,9 @@
     sp<IBinder> surfaceControl;
 
     bool releasePreviousBuffer = false;
+    sp<Fence> previousReleaseFence;
     nsecs_t acquireTime = -1;
+    nsecs_t latchTime = -1;
 };
 
 class TransactionCompletedThread {
@@ -54,14 +56,13 @@
     // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
     // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
     // presented.
-    void registerPendingLatchedCallbackHandle(const sp<CallbackHandle>& handle);
-    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been latched.
-    void addLatchedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles, nsecs_t latchTime,
-                                   const sp<Fence>& previousReleaseFence);
+    void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+    void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
-    void addUnlatchedCallbackHandle(const sp<CallbackHandle>& handle);
+    void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
 
     void addPresentFence(const sp<Fence>& presentFence);
 
@@ -70,8 +71,7 @@
 private:
     void threadMain();
 
-    void addCallbackHandle(const sp<CallbackHandle>& handle, nsecs_t latchTime = -1)
-            REQUIRES(mMutex);
+    void addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
@@ -110,7 +110,6 @@
     bool mKeepRunning GUARDED_BY(mMutex) = true;
 
     sp<Fence> mPresentFence GUARDED_BY(mMutex);
-    std::vector<sp<Fence>> mPreviousReleaseFences GUARDED_BY(mMutex);
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ef6999d..9339761 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -2542,6 +2542,7 @@
     enum PreviousBuffer {
         NOT_RELEASED = 0,
         RELEASED,
+        UNKNOWN,
     };
 
     void reset() {
@@ -2596,14 +2597,19 @@
               : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
 
         void verifySurfaceStats(const SurfaceStats& surfaceStats, nsecs_t latchTime) const {
-            const auto& [surfaceControl, acquireTime, releasePreviousBuffer] = surfaceStats;
+            const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceStats;
 
             ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
                     << "bad acquire time";
             ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
-            ASSERT_EQ(releasePreviousBuffer,
-                      mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED)
-                    << "bad previous buffer released";
+
+            if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+                ASSERT_NE(previousReleaseFence, nullptr)
+                        << "failed to set release prev buffer fence";
+            } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+                ASSERT_EQ(previousReleaseFence, nullptr)
+                        << "should not have set released prev buffer fence";
+            }
         }
 
     private:
@@ -3177,13 +3183,11 @@
     Transaction transaction;
     CallbackHelper callback;
     std::vector<ExpectedResult> expectedResults(50);
-    ExpectedResult::PreviousBuffer previousBufferResult =
-            ExpectedResult::PreviousBuffer::NOT_RELEASED;
     for (auto& expected : expectedResults) {
         expected.reset();
         expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                            ExpectedResult::Buffer::ACQUIRED, previousBufferResult);
-        previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED;
+                            ExpectedResult::Buffer::ACQUIRED,
+                            ExpectedResult::PreviousBuffer::UNKNOWN);
 
         int err = fillTransaction(transaction, &callback, layer);
         if (err) {