Add explicit clearSyncTransaction instead of passing in null
When attempting to clear the last syncNextTransaction, the code was
ambiguous and it was unclear what the expectation should be. Instead,
don't allow null when calling syncNextTransaction and don't allow the
syncTransaction to be overwritten. If the caller wants to clear the
syncTransaction before a frame has arrived, they can do so by calling
clearSyncTransaction.
Test: No warning log in sync with no buffer.
Test: BLASTBufferQueueTest
Bug: 272189296
Change-Id: I3a945f5503220225f2147b0331d1fb2f9ea8dc63
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 821dd37..aeb5406 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -800,34 +800,24 @@
mDequeueTimestamps.erase(bufferId);
};
-void BLASTBufferQueue::syncNextTransaction(
+bool BLASTBufferQueue::syncNextTransaction(
std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer) {
- std::function<void(SurfaceComposerClient::Transaction*)> prevCallback = nullptr;
- SurfaceComposerClient::Transaction* prevTransaction = nullptr;
+ LOG_ALWAYS_FATAL_IF(!callback,
+ "BLASTBufferQueue: callback passed in to syncNextTransaction must not be "
+ "NULL");
- {
- std::lock_guard _lock{mMutex};
- BBQ_TRACE();
- // We're about to overwrite the previous call so we should invoke that callback
- // immediately.
- if (mTransactionReadyCallback) {
- prevCallback = mTransactionReadyCallback;
- prevTransaction = mSyncTransaction;
- }
-
- mTransactionReadyCallback = callback;
- if (callback) {
- mSyncTransaction = new SurfaceComposerClient::Transaction();
- } else {
- mSyncTransaction = nullptr;
- }
- mAcquireSingleBuffer = mTransactionReadyCallback ? acquireSingleBuffer : true;
+ std::lock_guard _lock{mMutex};
+ BBQ_TRACE();
+ if (mTransactionReadyCallback) {
+ ALOGW("Attempting to overwrite transaction callback in syncNextTransaction");
+ return false;
}
- if (prevCallback) {
- prevCallback(prevTransaction);
- }
+ mTransactionReadyCallback = callback;
+ mSyncTransaction = new SurfaceComposerClient::Transaction();
+ mAcquireSingleBuffer = acquireSingleBuffer;
+ return true;
}
void BLASTBufferQueue::stopContinuousSyncTransaction() {
@@ -835,20 +825,35 @@
SurfaceComposerClient::Transaction* prevTransaction = nullptr;
{
std::lock_guard _lock{mMutex};
- bool invokeCallback = mTransactionReadyCallback && !mAcquireSingleBuffer;
- if (invokeCallback) {
- prevCallback = mTransactionReadyCallback;
- prevTransaction = mSyncTransaction;
+ if (mAcquireSingleBuffer || !mTransactionReadyCallback) {
+ ALOGW("Attempting to stop continuous sync when none are active");
+ return;
}
+
+ prevCallback = mTransactionReadyCallback;
+ prevTransaction = mSyncTransaction;
+
mTransactionReadyCallback = nullptr;
mSyncTransaction = nullptr;
mAcquireSingleBuffer = true;
}
+
if (prevCallback) {
prevCallback(prevTransaction);
}
}
+void BLASTBufferQueue::clearSyncTransaction() {
+ std::lock_guard _lock{mMutex};
+ if (!mAcquireSingleBuffer) {
+ ALOGW("Attempting to clear sync transaction when none are active");
+ return;
+ }
+
+ mTransactionReadyCallback = nullptr;
+ mSyncTransaction = nullptr;
+}
+
bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
// Only reject buffers if scaling mode is freeze.
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 69e9f8a..a49a859 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -97,9 +97,10 @@
void releaseBufferCallbackLocked(const ReleaseCallbackId& id, const sp<Fence>& releaseFence,
std::optional<uint32_t> currentMaxAcquiredBufferCount,
bool fakeRelease) REQUIRES(mMutex);
- void syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
+ bool syncNextTransaction(std::function<void(SurfaceComposerClient::Transaction*)> callback,
bool acquireSingleBuffer = true);
void stopContinuousSyncTransaction();
+ void clearSyncTransaction();
void mergeWithNextTransaction(SurfaceComposerClient::Transaction* t, uint64_t frameNumber);
void applyPendingTransactions(uint64_t frameNumber);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index cf2593d..fd69702 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -116,15 +116,17 @@
mBlastBufferQueueAdapter->syncNextTransaction(callback, acquireSingleBuffer);
}
- void syncNextTransaction(std::function<void(Transaction*)> callback,
+ bool syncNextTransaction(std::function<void(Transaction*)> callback,
bool acquireSingleBuffer = true) {
- mBlastBufferQueueAdapter->syncNextTransaction(callback, acquireSingleBuffer);
+ return mBlastBufferQueueAdapter->syncNextTransaction(callback, acquireSingleBuffer);
}
void stopContinuousSyncTransaction() {
mBlastBufferQueueAdapter->stopContinuousSyncTransaction();
}
+ void clearSyncTransaction() { mBlastBufferQueueAdapter->clearSyncTransaction(); }
+
int getWidth() { return mBlastBufferQueueAdapter->mSize.width; }
int getHeight() { return mBlastBufferQueueAdapter->mSize.height; }
@@ -1108,7 +1110,11 @@
ASSERT_NE(nullptr, adapter.getTransactionReadyCallback());
auto callback2 = [](Transaction*) {};
- adapter.syncNextTransaction(callback2);
+ ASSERT_FALSE(adapter.syncNextTransaction(callback2));
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
std::unique_lock<std::mutex> lock(mutex);
if (!receivedCallback) {
@@ -1120,6 +1126,37 @@
ASSERT_TRUE(receivedCallback);
}
+TEST_F(BLASTBufferQueueTest, ClearSyncTransaction) {
+ std::mutex mutex;
+ std::condition_variable callbackReceivedCv;
+ bool receivedCallback = false;
+
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ ASSERT_EQ(nullptr, adapter.getTransactionReadyCallback());
+ auto callback = [&](Transaction*) {
+ std::unique_lock<std::mutex> lock(mutex);
+ receivedCallback = true;
+ callbackReceivedCv.notify_one();
+ };
+ adapter.syncNextTransaction(callback);
+ ASSERT_NE(nullptr, adapter.getTransactionReadyCallback());
+
+ adapter.clearSyncTransaction();
+
+ sp<IGraphicBufferProducer> igbProducer;
+ setUpProducer(adapter, igbProducer);
+ queueBuffer(igbProducer, 0, 255, 0, 0);
+
+ std::unique_lock<std::mutex> lock(mutex);
+ if (!receivedCallback) {
+ ASSERT_EQ(callbackReceivedCv.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ ASSERT_FALSE(receivedCallback);
+}
+
TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) {
uint8_t r = 255;
uint8_t g = 0;