Send releaseCallbackId and releaseFence to correct listener
The scenario is the following:
1. Process1 creates a T1 with a new buffer, release callback, and
transaction callback. The release callback is stored locally in
mReleaseBufferCallbacks so it only lives in Process1.
2. Process2 creates a T2 with a transaction callback
3. When T1 and T2 are merged, the SC from T1 end up getting the
transaction callbacks from T2. SC will end up with multiple transaction
callbacks
4. In BufferStateLayer, we only added mPreviousReleaseCallbackId to one
transaction callback. There's a chance the release callback would only
end up on the transaction callback for Process2.
Process2 doesn't have the data about the callback since it was only
stored in Process1. When Process2 gets the transaction callback, it
will not handle the releaseCallbackId since it doesn't know what release
callback it represents. Process1 will get a transaction callback, but will
not contain a releaseCallbackId.
To fix, add releaseBufferEndpoint that is set when the client calls
setBuffer. This is used in SurfaceFlinger to recognize which listener
was the one that set the buffer so it can send the release information
to the correct listener.
Test: ReleaseBufferCallback_test
Bug: 193565751
Change-Id: I534fbde2a54608c2e30852e48dc0c75c86b22525
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 837e5b3..5bed69c 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -174,6 +174,7 @@
SAFE_PARCEL(output.write, destinationFrame);
SAFE_PARCEL(output.writeBool, isTrustedOverlay);
+ SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
return NO_ERROR;
}
@@ -303,6 +304,7 @@
SAFE_PARCEL(input.read, destinationFrame);
SAFE_PARCEL(input.readBool, &isTrustedOverlay);
+ SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
return NO_ERROR;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index ce9a1f7..dc71b6a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -147,8 +147,16 @@
return mCallbackIdCounter++;
}
+sp<TransactionCompletedListener> TransactionCompletedListener::sInstance = nullptr;
+
+void TransactionCompletedListener::setInstance(const sp<TransactionCompletedListener>& listener) {
+ sInstance = listener;
+}
+
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
- static sp<TransactionCompletedListener> sInstance = new TransactionCompletedListener;
+ if (sInstance == nullptr) {
+ sInstance = new TransactionCompletedListener;
+ }
return sInstance;
}
@@ -1274,6 +1282,7 @@
removeReleaseBufferCallback(s);
s->what |= layer_state_t::eBufferChanged;
s->buffer = buffer;
+ s->releaseBufferEndpoint = IInterface::asBinder(TransactionCompletedListener::getIInstance());
if (mIsAutoTimestamp) {
mDesiredPresentTime = systemTime();
}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index b27d9cf..8dc8b9a 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -242,6 +242,11 @@
// is used to remove the old callback from the client process map if it is
// overwritten by another setBuffer call.
ReleaseCallbackId releaseCallbackId;
+
+ // Stores which endpoint the release information should be sent to. We don't want to send the
+ // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
+ // was called with.
+ sp<IBinder> releaseBufferEndpoint;
};
struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8993891..1d758e0 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -655,8 +655,10 @@
};
class TransactionCompletedListener : public BnTransactionCompletedListener {
+public:
TransactionCompletedListener();
+protected:
int64_t getNextIdLocked() REQUIRES(mMutex);
std::mutex mMutex;
@@ -734,8 +736,12 @@
void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence, uint32_t transformHint,
uint32_t currentMaxAcquiredBufferCount) override;
+ // For Testing Only
+ static void setInstance(const sp<TransactionCompletedListener>&);
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
+ static sp<TransactionCompletedListener> sInstance;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 6253036..5a59b67 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -158,7 +158,8 @@
// transaction doesn't need a previous release fence.
sp<CallbackHandle> ch;
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
ch = handle;
break;
}
@@ -199,14 +200,9 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid);
}
- // If there are multiple transactions in this frame, set the previous id on the earliest
- // transacton. We don't need to pass in the released buffer id to multiple transactions.
- // The buffer id does not have to correspond to any particular transaction as long as the
- // listening end point is the same but the client expects the first transaction callback that
- // replaces the presented buffer to contain the release fence. This follows the same logic.
- // see BufferStateLayer::onLayerDisplayed.
for (auto& handle : mDrawingState.callbackHandles) {
- if (handle->releasePreviousBuffer) {
+ if (handle->releasePreviousBuffer &&
+ mDrawingState.releaseBufferEndpoint == handle->listener) {
handle->previousReleaseCallbackId = mPreviousReleaseCallbackId;
break;
}
@@ -420,7 +416,8 @@
nsecs_t desiredPresentTime, bool isAutoTimestamp,
const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
- const sp<ITransactionCompletedListener>& releaseBufferListener) {
+ const sp<ITransactionCompletedListener>& releaseBufferListener,
+ const sp<IBinder>& releaseBufferEndpoint) {
ATRACE_CALL();
if (mDrawingState.buffer) {
@@ -484,6 +481,7 @@
mDrawingState.width = mDrawingState.buffer->getBuffer()->getWidth();
mDrawingState.height = mDrawingState.buffer->getBuffer()->getHeight();
+ mDrawingState.releaseBufferEndpoint = releaseBufferEndpoint;
return true;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index e567478..dbc0b05 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -59,7 +59,8 @@
const sp<Fence>& acquireFence, nsecs_t postTime, nsecs_t desiredPresentTime,
bool isAutoTimestamp, const client_cache_t& clientCacheId, uint64_t frameNumber,
std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info,
- const sp<ITransactionCompletedListener>& transactionListener) override;
+ const sp<ITransactionCompletedListener>& transactionListener,
+ const sp<IBinder>& releaseBufferEndpoint) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d9ab0a6..a53762c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -280,6 +280,8 @@
Rect bufferCrop;
Rect destinationFrame;
+
+ sp<IBinder> releaseBufferEndpoint;
};
/*
@@ -417,7 +419,8 @@
const client_cache_t& /*clientCacheId*/, uint64_t /* frameNumber */,
std::optional<nsecs_t> /* dequeueTime */,
const FrameTimelineInfo& /*info*/,
- const sp<ITransactionCompletedListener>& /* releaseBufferListener */) {
+ const sp<ITransactionCompletedListener>& /* releaseBufferListener */,
+ const sp<IBinder>& /* releaseBufferEndpoint */) {
return false;
};
virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 8704c88..bc32a1d 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -271,7 +271,7 @@
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
@@ -285,7 +285,7 @@
mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
std::nullopt /* dequeueTime */, FrameTimelineInfo{},
- nullptr /* releaseBufferListener */);
+ nullptr /* releaseBufferListener */, nullptr /* releaseBufferEndpoint */);
mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3616240..395091b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4202,7 +4202,7 @@
if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
s.cachedBuffer, frameNumber, dequeueBufferTimestamp, frameTimelineInfo,
- s.releaseBufferListener)) {
+ s.releaseBufferListener, s.releaseBufferEndpoint)) {
flags |= eTraversalNeeded;
}
} else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
diff --git a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
index 579a26e..c4d42fa 100644
--- a/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
+++ b/services/surfaceflinger/tests/ReleaseBufferCallback_test.cpp
@@ -99,10 +99,10 @@
}
static void waitForReleaseBufferCallback(ReleaseBufferCallbackHelper& releaseCallback,
- const ReleaseCallbackId& expectedCallbackId) {
+ const ReleaseCallbackId& expectedReleaseBufferId) {
ReleaseCallbackId actualReleaseBufferId;
releaseCallback.getCallbackData(&actualReleaseBufferId);
- EXPECT_EQ(expectedCallbackId, actualReleaseBufferId);
+ EXPECT_EQ(expectedReleaseBufferId, actualReleaseBufferId);
releaseCallback.verifyNoCallbacks();
}
static ReleaseBufferCallbackHelper* getReleaseBufferCallbackHelper() {
@@ -333,4 +333,60 @@
ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
}
+TEST_F(ReleaseBufferCallbackTest, DISABLED_Merge_Different_Processes) {
+ sp<TransactionCompletedListener> firstCompletedListener = new TransactionCompletedListener();
+ sp<TransactionCompletedListener> secondCompletedListener = new TransactionCompletedListener();
+
+ CallbackHelper callback1, callback2;
+
+ TransactionCompletedListener::setInstance(firstCompletedListener);
+
+ sp<SurfaceControl> layer = createBufferStateLayer();
+ ReleaseBufferCallbackHelper* releaseCallback = getReleaseBufferCallbackHelper();
+
+ sp<GraphicBuffer> firstBuffer = getBuffer();
+ ReleaseCallbackId firstBufferCallbackId(firstBuffer->getId(), generateFrameNumber());
+
+ // Send initial buffer for the layer
+ submitBuffer(layer, firstBuffer, Fence::NO_FENCE, callback1, firstBufferCallbackId,
+ *releaseCallback);
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+
+ // Sent a second buffer to allow the first buffer to get released.
+ sp<GraphicBuffer> secondBuffer = getBuffer();
+ ReleaseCallbackId secondBufferCallbackId(secondBuffer->getId(), generateFrameNumber());
+
+ Transaction transaction1;
+ transaction1.setFrameNumber(layer, secondBufferCallbackId.framenumber);
+ transaction1.setBuffer(layer, secondBuffer, secondBufferCallbackId,
+ releaseCallback->getCallback());
+ transaction1.setAcquireFence(layer, Fence::NO_FENCE);
+ transaction1.addTransactionCompletedCallback(callback1.function, callback1.getContext());
+
+ // Set a different TransactionCompletedListener to mimic a second process
+ TransactionCompletedListener::setInstance(secondCompletedListener);
+
+ // Make sure the second "process" has a callback set up.
+ Transaction transaction2;
+ transaction2.addTransactionCompletedCallback(callback2.function, callback2.getContext());
+
+ // This merging order, merge transaction1 first then transaction2, seems to ensure the listener
+ // for transaction2 is ordered first. This makes sure the wrong process is added first to the
+ // layer's vector of listeners. With the bug, only the secondCompletedListener will get the
+ // release callback id, since it's ordered first. Then firstCompletedListener would fail to get
+ // the release callback id and not invoke the release callback.
+ Transaction().merge(std::move(transaction1)).merge(std::move(transaction2)).apply();
+
+ expected = ExpectedResult();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ ASSERT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ ASSERT_NO_FATAL_FAILURE(waitForReleaseBufferCallback(*releaseCallback, firstBufferCallbackId));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 2845d0a..a749ece 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -119,7 +119,7 @@
FrameTracer::FrameEvent::QUEUE, /*duration*/ 0));
layer->setBuffer(buffer, fence, postTime, /*desiredPresentTime*/ 30, false, mClientCache,
frameNumber, dequeueTime, FrameTimelineInfo{},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint*/);
commitTransaction(layer.get());
bool computeVisisbleRegions;
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index 7bf224d..2a7921f 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -119,7 +119,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
commitTransaction(layer.get());
@@ -147,7 +148,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -160,7 +162,8 @@
mRenderEngine, false);
nsecs_t start = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
nsecs_t end = systemTime();
acquireFence2->signalForTest(12);
@@ -200,7 +203,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence->signalForTest(12);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
@@ -228,7 +232,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -260,7 +265,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 3, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -298,7 +304,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -309,7 +316,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
acquireFence2->signalForTest(12);
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -339,7 +347,8 @@
1, 0),
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 1, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX;
@@ -353,7 +362,7 @@
auto dropStartTime1 = systemTime();
layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */, nullptr /* releaseBufferEndpoint */);
auto dropEndTime1 = systemTime();
EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size());
ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX);
@@ -367,7 +376,8 @@
mRenderEngine, false);
auto dropStartTime2 = systemTime();
layer->setBuffer(buffer3, fence3, 10, 20, false, mClientCache, 1, std::nullopt,
- {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */);
+ {/*vsyncId*/ 2, /*inputEventId*/ 0}, nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
auto dropEndTime2 = systemTime();
acquireFence3->signalForTest(12);
@@ -411,7 +421,8 @@
mRenderEngine, false);
layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
{/*vsyncId*/ 1, /*inputEventId*/ 0},
- nullptr /* releaseBufferCallback */);
+ nullptr /* releaseBufferCallback */,
+ nullptr /* releaseBufferEndpoint */);
layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2,
/*inputEventId*/ 0},
10);