Skip to content

Commit 9cfc94c

Browse files
Sungtak LeeCherrypicker Worker
authored andcommitted
Add IProducerListener::onBufferAttached
Add a new callback to IProducerListener for buffer being attached to the consumer. BYPASS_IGBP_IGBC_API_REASON=approved new code in libgui Bug: 353202582 Flag: com.android.graphics.libgui.flags.bq_consumer_attach_callback (cherry picked from https://android-review.googlesource.com/q/commit:6d223cbd07f0582ac99e4b607f6983284638aa0b) Merged-In: I21f9d4925ab6c8985ab349514bc0198e61d1de23 Change-Id: I21f9d4925ab6c8985ab349514bc0198e61d1de23
1 parent 488cfac commit 9cfc94c

7 files changed

Lines changed: 243 additions & 65 deletions

File tree

libs/gui/BufferQueueConsumer.cpp

Lines changed: 82 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242

4343
#include <system/window.h>
4444

45+
#include <com_android_graphics_libgui_flags.h>
46+
4547
namespace android {
4648

4749
// Macros for include BufferQueueCore information in log messages
@@ -370,79 +372,94 @@ status_t BufferQueueConsumer::attachBuffer(int* outSlot,
370372
return BAD_VALUE;
371373
}
372374

373-
std::lock_guard<std::mutex> lock(mCore->mMutex);
375+
sp<IProducerListener> listener;
376+
{
377+
std::lock_guard<std::mutex> lock(mCore->mMutex);
374378

375-
if (mCore->mSharedBufferMode) {
376-
BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
377-
return BAD_VALUE;
378-
}
379+
if (mCore->mSharedBufferMode) {
380+
BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
381+
return BAD_VALUE;
382+
}
379383

380-
// Make sure we don't have too many acquired buffers
381-
int numAcquiredBuffers = 0;
382-
for (int s : mCore->mActiveBuffers) {
383-
if (mSlots[s].mBufferState.isAcquired()) {
384-
++numAcquiredBuffers;
384+
// Make sure we don't have too many acquired buffers
385+
int numAcquiredBuffers = 0;
386+
for (int s : mCore->mActiveBuffers) {
387+
if (mSlots[s].mBufferState.isAcquired()) {
388+
++numAcquiredBuffers;
389+
}
385390
}
386-
}
387391

388-
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
389-
BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
390-
"(max %d)", numAcquiredBuffers,
391-
mCore->mMaxAcquiredBufferCount);
392-
return INVALID_OPERATION;
393-
}
392+
if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
393+
BQ_LOGE("attachBuffer: max acquired buffer count reached: %d "
394+
"(max %d)", numAcquiredBuffers,
395+
mCore->mMaxAcquiredBufferCount);
396+
return INVALID_OPERATION;
397+
}
394398

395-
if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
396-
BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
397-
"[queue %u]", buffer->getGenerationNumber(),
398-
mCore->mGenerationNumber);
399-
return BAD_VALUE;
400-
}
399+
if (buffer->getGenerationNumber() != mCore->mGenerationNumber) {
400+
BQ_LOGE("attachBuffer: generation number mismatch [buffer %u] "
401+
"[queue %u]", buffer->getGenerationNumber(),
402+
mCore->mGenerationNumber);
403+
return BAD_VALUE;
404+
}
401405

402-
// Find a free slot to put the buffer into
403-
int found = BufferQueueCore::INVALID_BUFFER_SLOT;
404-
if (!mCore->mFreeSlots.empty()) {
405-
auto slot = mCore->mFreeSlots.begin();
406-
found = *slot;
407-
mCore->mFreeSlots.erase(slot);
408-
} else if (!mCore->mFreeBuffers.empty()) {
409-
found = mCore->mFreeBuffers.front();
410-
mCore->mFreeBuffers.remove(found);
411-
}
412-
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
413-
BQ_LOGE("attachBuffer: could not find free buffer slot");
414-
return NO_MEMORY;
406+
// Find a free slot to put the buffer into
407+
int found = BufferQueueCore::INVALID_BUFFER_SLOT;
408+
if (!mCore->mFreeSlots.empty()) {
409+
auto slot = mCore->mFreeSlots.begin();
410+
found = *slot;
411+
mCore->mFreeSlots.erase(slot);
412+
} else if (!mCore->mFreeBuffers.empty()) {
413+
found = mCore->mFreeBuffers.front();
414+
mCore->mFreeBuffers.remove(found);
415+
}
416+
if (found == BufferQueueCore::INVALID_BUFFER_SLOT) {
417+
BQ_LOGE("attachBuffer: could not find free buffer slot");
418+
return NO_MEMORY;
419+
}
420+
421+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
422+
if (mCore->mBufferAttachedCbEnabled) {
423+
listener = mCore->mConnectedProducerListener;
424+
}
425+
#endif
426+
427+
mCore->mActiveBuffers.insert(found);
428+
*outSlot = found;
429+
ATRACE_BUFFER_INDEX(*outSlot);
430+
BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
431+
432+
mSlots[*outSlot].mGraphicBuffer = buffer;
433+
mSlots[*outSlot].mBufferState.attachConsumer();
434+
mSlots[*outSlot].mNeedsReallocation = true;
435+
mSlots[*outSlot].mFence = Fence::NO_FENCE;
436+
mSlots[*outSlot].mFrameNumber = 0;
437+
438+
// mAcquireCalled tells BufferQueue that it doesn't need to send a valid
439+
// GraphicBuffer pointer on the next acquireBuffer call, which decreases
440+
// Binder traffic by not un/flattening the GraphicBuffer. However, it
441+
// requires that the consumer maintain a cached copy of the slot <--> buffer
442+
// mappings, which is why the consumer doesn't need the valid pointer on
443+
// acquire.
444+
//
445+
// The StreamSplitter is one of the primary users of the attach/detach
446+
// logic, and while it is running, all buffers it acquires are immediately
447+
// detached, and all buffers it eventually releases are ones that were
448+
// attached (as opposed to having been obtained from acquireBuffer), so it
449+
// doesn't make sense to maintain the slot/buffer mappings, which would
450+
// become invalid for every buffer during detach/attach. By setting this to
451+
// false, the valid GraphicBuffer pointer will always be sent with acquire
452+
// for attached buffers.
453+
mSlots[*outSlot].mAcquireCalled = false;
454+
455+
VALIDATE_CONSISTENCY();
415456
}
416457

417-
mCore->mActiveBuffers.insert(found);
418-
*outSlot = found;
419-
ATRACE_BUFFER_INDEX(*outSlot);
420-
BQ_LOGV("attachBuffer: returning slot %d", *outSlot);
421-
422-
mSlots[*outSlot].mGraphicBuffer = buffer;
423-
mSlots[*outSlot].mBufferState.attachConsumer();
424-
mSlots[*outSlot].mNeedsReallocation = true;
425-
mSlots[*outSlot].mFence = Fence::NO_FENCE;
426-
mSlots[*outSlot].mFrameNumber = 0;
427-
428-
// mAcquireCalled tells BufferQueue that it doesn't need to send a valid
429-
// GraphicBuffer pointer on the next acquireBuffer call, which decreases
430-
// Binder traffic by not un/flattening the GraphicBuffer. However, it
431-
// requires that the consumer maintain a cached copy of the slot <--> buffer
432-
// mappings, which is why the consumer doesn't need the valid pointer on
433-
// acquire.
434-
//
435-
// The StreamSplitter is one of the primary users of the attach/detach
436-
// logic, and while it is running, all buffers it acquires are immediately
437-
// detached, and all buffers it eventually releases are ones that were
438-
// attached (as opposed to having been obtained from acquireBuffer), so it
439-
// doesn't make sense to maintain the slot/buffer mappings, which would
440-
// become invalid for every buffer during detach/attach. By setting this to
441-
// false, the valid GraphicBuffer pointer will always be sent with acquire
442-
// for attached buffers.
443-
mSlots[*outSlot].mAcquireCalled = false;
444-
445-
VALIDATE_CONSISTENCY();
458+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
459+
if (listener != nullptr) {
460+
listener->onBufferAttached();
461+
}
462+
#endif
446463

447464
return NO_ERROR;
448465
}

libs/gui/BufferQueueCore.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ BufferQueueCore::BufferQueueCore()
9696
mLinkedToDeath(),
9797
mConnectedProducerListener(),
9898
mBufferReleasedCbEnabled(false),
99+
mBufferAttachedCbEnabled(false),
99100
mSlots(),
100101
mQueue(),
101102
mFreeSlots(),

libs/gui/BufferQueueProducer.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,9 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
13601360
#endif
13611361
mCore->mConnectedProducerListener = listener;
13621362
mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
1363+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
1364+
mCore->mBufferAttachedCbEnabled = listener->needsAttachNotify();
1365+
#endif
13631366
}
13641367
break;
13651368
default:

libs/gui/IProducerListener.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ enum {
2525
ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
2626
NEEDS_RELEASE_NOTIFY,
2727
ON_BUFFERS_DISCARDED,
28+
ON_BUFFER_DETACHED,
29+
ON_BUFFER_ATTACHED,
30+
NEEDS_ATTACH_NOTIFY,
2831
};
2932

3033
class BpProducerListener : public BpInterface<IProducerListener>
@@ -64,6 +67,38 @@ class BpProducerListener : public BpInterface<IProducerListener>
6467
data.writeInt32Vector(discardedSlots);
6568
remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY);
6669
}
70+
71+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
72+
virtual void onBufferDetached(int slot) {
73+
Parcel data, reply;
74+
data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
75+
data.writeInt32(slot);
76+
remote()->transact(ON_BUFFER_DETACHED, data, &reply, IBinder::FLAG_ONEWAY);
77+
}
78+
79+
virtual void onBufferAttached() {
80+
Parcel data, reply;
81+
data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
82+
remote()->transact(ON_BUFFER_ATTACHED, data, &reply, IBinder::FLAG_ONEWAY);
83+
}
84+
85+
virtual bool needsAttachNotify() {
86+
bool result;
87+
Parcel data, reply;
88+
data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
89+
status_t err = remote()->transact(NEEDS_ATTACH_NOTIFY, data, &reply);
90+
if (err != NO_ERROR) {
91+
ALOGE("IProducerListener: binder call \'needsAttachNotify\' failed");
92+
return true;
93+
}
94+
err = reply.readBool(&result);
95+
if (err != NO_ERROR) {
96+
ALOGE("IProducerListener: malformed binder reply");
97+
return true;
98+
}
99+
return result;
100+
}
101+
#endif
67102
};
68103

69104
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -115,6 +150,27 @@ status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
115150
onBuffersDiscarded(discardedSlots);
116151
return NO_ERROR;
117152
}
153+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
154+
case ON_BUFFER_DETACHED: {
155+
CHECK_INTERFACE(IProducerListener, data, reply);
156+
int slot;
157+
status_t result = data.readInt32(&slot);
158+
if (result != NO_ERROR) {
159+
ALOGE("ON_BUFFER_DETACHED failed to read slot: %d", result);
160+
return result;
161+
}
162+
onBufferDetached(slot);
163+
return NO_ERROR;
164+
}
165+
case ON_BUFFER_ATTACHED:
166+
CHECK_INTERFACE(IProducerListener, data, reply);
167+
onBufferAttached();
168+
return NO_ERROR;
169+
case NEEDS_ATTACH_NOTIFY:
170+
CHECK_INTERFACE(IProducerListener, data, reply);
171+
reply->writeBool(needsAttachNotify());
172+
return NO_ERROR;
173+
#endif
118174
}
119175
return BBinder::onTransact(code, data, reply, flags);
120176
}

libs/gui/include/gui/BufferQueueCore.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ class BufferQueueCore : public virtual RefBase {
192192
// callback is registered by the listener. When set to false,
193193
// mConnectedProducerListener will not trigger onBufferReleased() callback.
194194
bool mBufferReleasedCbEnabled;
195+
// mBufferAttachedCbEnabled is used to indicate whether onBufferAttached()
196+
// callback is registered by the listener. When set to false,
197+
// mConnectedProducerListener will not trigger onBufferAttached() callback.
198+
bool mBufferAttachedCbEnabled;
195199

196200
// mSlots is an array of buffer slots that must be mirrored on the producer
197201
// side. This allows buffer ownership to be transferred between the producer

libs/gui/include/gui/IProducerListener.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <hidl/HybridInterface.h>
2626
#include <utils/RefBase.h>
2727

28+
#include <com_android_graphics_libgui_flags.h>
29+
2830
namespace android {
2931

3032
// ProducerListener is the interface through which the BufferQueue notifies the
@@ -55,6 +57,16 @@ class ProducerListener : public virtual RefBase
5557
// This is called without any lock held and can be called concurrently by
5658
// multiple threads.
5759
virtual void onBufferDetached(int /*slot*/) {} // Asynchronous
60+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
61+
// onBufferAttached is called from IGraphicBufferConsumer::attachBuffer to
62+
// notify the producer that a buffer is attached.
63+
//
64+
// This is called without any lock held and can be called concurrently by
65+
// multiple threads. This callback is enabled only when needsAttachNotify()
66+
// returns {@code true}.
67+
virtual void onBufferAttached() {} // Asynchronous
68+
virtual bool needsAttachNotify() { return false; }
69+
#endif
5870
};
5971

6072
#ifndef NO_BINDER

libs/gui/tests/BufferQueue_test.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,91 @@ TEST_F(BufferQueueTest, TestConsumerDetachProducerListener) {
12621262
ASSERT_TRUE(result == WOULD_BLOCK || result == TIMED_OUT || result == INVALID_OPERATION);
12631263
}
12641264

1265+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_CONSUMER_ATTACH_CALLBACK)
1266+
struct BufferAttachedListener : public BnProducerListener {
1267+
public:
1268+
BufferAttachedListener(bool enable) : mEnabled(enable), mAttached(0) {}
1269+
virtual ~BufferAttachedListener() = default;
1270+
1271+
virtual void onBufferReleased() {}
1272+
virtual bool needsReleaseNotify() { return true; }
1273+
virtual void onBufferAttached() {
1274+
++mAttached;
1275+
}
1276+
virtual bool needsAttachNotify() { return mEnabled; }
1277+
1278+
int getNumAttached() const { return mAttached; }
1279+
private:
1280+
const bool mEnabled;
1281+
int mAttached;
1282+
};
1283+
1284+
TEST_F(BufferQueueTest, TestConsumerAttachProducerListener) {
1285+
createBufferQueue();
1286+
sp<MockConsumer> mc1(new MockConsumer);
1287+
ASSERT_EQ(OK, mConsumer->consumerConnect(mc1, true));
1288+
IGraphicBufferProducer::QueueBufferOutput output;
1289+
// Do not enable attach callback.
1290+
sp<BufferAttachedListener> pl1(new BufferAttachedListener(false));
1291+
ASSERT_EQ(OK, mProducer->connect(pl1, NATIVE_WINDOW_API_CPU, true, &output));
1292+
ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
1293+
ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
1294+
1295+
sp<Fence> fence = Fence::NO_FENCE;
1296+
sp<GraphicBuffer> buffer = nullptr;
1297+
1298+
int slot;
1299+
status_t result = OK;
1300+
1301+
ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
1302+
1303+
result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
1304+
GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
1305+
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
1306+
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
1307+
ASSERT_EQ(OK, mProducer->detachBuffer(slot));
1308+
1309+
// Check # of attach is zero.
1310+
ASSERT_EQ(0, pl1->getNumAttached());
1311+
1312+
// Attach a buffer and check the callback was not called.
1313+
ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
1314+
ASSERT_EQ(0, pl1->getNumAttached());
1315+
1316+
mProducer = nullptr;
1317+
mConsumer = nullptr;
1318+
createBufferQueue();
1319+
1320+
sp<MockConsumer> mc2(new MockConsumer);
1321+
ASSERT_EQ(OK, mConsumer->consumerConnect(mc2, true));
1322+
// Enable attach callback.
1323+
sp<BufferAttachedListener> pl2(new BufferAttachedListener(true));
1324+
ASSERT_EQ(OK, mProducer->connect(pl2, NATIVE_WINDOW_API_CPU, true, &output));
1325+
ASSERT_EQ(OK, mProducer->setDequeueTimeout(0));
1326+
ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1));
1327+
1328+
fence = Fence::NO_FENCE;
1329+
buffer = nullptr;
1330+
1331+
result = OK;
1332+
1333+
ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(1));
1334+
1335+
result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0,
1336+
GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr);
1337+
ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result);
1338+
ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer));
1339+
ASSERT_EQ(OK, mProducer->detachBuffer(slot));
1340+
1341+
// Check # of attach is zero.
1342+
ASSERT_EQ(0, pl2->getNumAttached());
1343+
1344+
// Attach a buffer and check the callback was called.
1345+
ASSERT_EQ(OK, mConsumer->attachBuffer(&slot, buffer));
1346+
ASSERT_EQ(1, pl2->getNumAttached());
1347+
}
1348+
#endif
1349+
12651350
TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) {
12661351
createBufferQueue();
12671352
sp<MockConsumer> mc(new MockConsumer);

0 commit comments

Comments
 (0)