diff options
author | 2023-10-26 08:44:21 +0000 | |
---|---|---|
committer | 2023-11-07 08:28:32 +0000 | |
commit | 1e7c09b67034f3ff1c263b3c0b5ff0c6d46c6e4a (patch) | |
tree | 8b54c87439f7b6f8a94c03fb78dfe10963ad9b30 | |
parent | dc0f937ddfb068670a0c8ea3d32d0d0247b641e0 (diff) |
IProducerListener: Add a listener for consumer detach
Currently consumer side detach cannot be tracked from Producer side.
Add a listener from IProducerListener for consumer side detaching.
Test: m
Bug: 254050314
Change-Id: I80f4aebe276cd8bc961f498b281e771d9b6a9789
-rw-r--r-- | libs/gui/BufferQueueConsumer.cpp | 57 | ||||
-rw-r--r-- | libs/gui/include/gui/IProducerListener.h | 6 | ||||
-rw-r--r-- | libs/gui/tests/BufferQueue_test.cpp | 70 |
3 files changed, 109 insertions, 24 deletions
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 5b34ba12c8..b6a47fb4e9 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -318,35 +318,44 @@ status_t BufferQueueConsumer::detachBuffer(int slot) { ATRACE_CALL(); ATRACE_BUFFER_INDEX(slot); BQ_LOGV("detachBuffer: slot %d", slot); - std::lock_guard<std::mutex> lock(mCore->mMutex); + sp<IProducerListener> listener; + { + std::lock_guard<std::mutex> lock(mCore->mMutex); - if (mCore->mIsAbandoned) { - BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); - return NO_INIT; - } + if (mCore->mIsAbandoned) { + BQ_LOGE("detachBuffer: BufferQueue has been abandoned"); + return NO_INIT; + } - if (mCore->mSharedBufferMode || slot == mCore->mSharedBufferSlot) { - BQ_LOGE("detachBuffer: detachBuffer not allowed in shared buffer mode"); - return BAD_VALUE; - } + if (mCore->mSharedBufferMode || slot == mCore->mSharedBufferSlot) { + BQ_LOGE("detachBuffer: detachBuffer not allowed in shared buffer mode"); + return BAD_VALUE; + } - if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { - BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", - slot, BufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (!mSlots[slot].mBufferState.isAcquired()) { - BQ_LOGE("detachBuffer: slot %d is not owned by the consumer " - "(state = %s)", slot, mSlots[slot].mBufferState.string()); - return BAD_VALUE; - } + if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { + BQ_LOGE("detachBuffer: slot index %d out of range [0, %d)", + slot, BufferQueueDefs::NUM_BUFFER_SLOTS); + return BAD_VALUE; + } else if (!mSlots[slot].mBufferState.isAcquired()) { + BQ_LOGE("detachBuffer: slot %d is not owned by the consumer " + "(state = %s)", slot, mSlots[slot].mBufferState.string()); + return BAD_VALUE; + } + if (mCore->mBufferReleasedCbEnabled) { + listener = mCore->mConnectedProducerListener; + } - mSlots[slot].mBufferState.detachConsumer(); - mCore->mActiveBuffers.erase(slot); - mCore->mFreeSlots.insert(slot); - mCore->clearBufferSlotLocked(slot); - mCore->mDequeueCondition.notify_all(); - VALIDATE_CONSISTENCY(); + mSlots[slot].mBufferState.detachConsumer(); + mCore->mActiveBuffers.erase(slot); + mCore->mFreeSlots.insert(slot); + mCore->clearBufferSlotLocked(slot); + mCore->mDequeueCondition.notify_all(); + VALIDATE_CONSISTENCY(); + } + if (listener) { + listener->onBufferDetached(slot); + } return NO_ERROR; } diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index f7ffbb99ea..b15f501518 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -49,6 +49,12 @@ public: // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers // to notify the producer that certain free buffers are discarded by the consumer. virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous + // onBufferDetached is called from IGraphicBufferConsumer::detachBuffer to + // notify the producer that a buffer slot is free and ready to be dequeued. + // + // This is called without any lock held and can be called concurrently by + // multiple threads. + virtual void onBufferDetached(int /*slot*/) {} // Asynchronous }; #ifndef NO_BINDER diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 2f1fd3e78f..185ff83a86 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -1151,6 +1151,76 @@ TEST_F(BufferQueueTest, TestBufferReplacedInQueueBuffer) { ASSERT_EQ(true, output.bufferReplaced); } +struct BufferDetachedListener : public BnProducerListener { +public: + BufferDetachedListener() = default; + virtual ~BufferDetachedListener() = default; + + virtual void onBufferReleased() {} + virtual bool needsReleaseNotify() { return true; } + virtual void onBufferDetached(int slot) { + mDetachedSlots.push_back(slot); + } + const std::vector<int>& getDetachedSlots() const { return mDetachedSlots; } +private: + std::vector<int> mDetachedSlots; +}; + +TEST_F(BufferQueueTest, TestConsumerDetachProducerListener) { + createBufferQueue(); + sp<MockConsumer> mc(new MockConsumer); + ASSERT_EQ(OK, mConsumer->consumerConnect(mc, true)); + IGraphicBufferProducer::QueueBufferOutput output; + sp<BufferDetachedListener> pl(new BufferDetachedListener); + ASSERT_EQ(OK, mProducer->connect(pl, NATIVE_WINDOW_API_CPU, true, &output)); + ASSERT_EQ(OK, mProducer->setDequeueTimeout(0)); + ASSERT_EQ(OK, mConsumer->setMaxAcquiredBufferCount(1)); + + sp<Fence> fence = Fence::NO_FENCE; + sp<GraphicBuffer> buffer = nullptr; + IGraphicBufferProducer::QueueBufferInput input(0ull, true, + HAL_DATASPACE_UNKNOWN, Rect::INVALID_RECT, + NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE); + + int slots[2] = {}; + status_t result = OK; + ASSERT_EQ(OK, mProducer->setMaxDequeuedBufferCount(2)); + + result = mProducer->dequeueBuffer(&slots[0], &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); + ASSERT_EQ(OK, mProducer->requestBuffer(slots[0], &buffer)); + + result = mProducer->dequeueBuffer(&slots[1], &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); + ASSERT_EQ(OK, mProducer->requestBuffer(slots[1], &buffer)); + + // Queue & detach one from two dequeued buffes. + ASSERT_EQ(OK, mProducer->queueBuffer(slots[1], input, &output)); + BufferItem item{}; + ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0)); + ASSERT_EQ(OK, mConsumer->detachBuffer(item.mSlot)); + + // Check whether the slot from IProducerListener is same to the detached slot. + ASSERT_EQ(pl->getDetachedSlots().size(), 1); + ASSERT_EQ(pl->getDetachedSlots()[0], slots[1]); + + // Dequeue another buffer. + int slot; + result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, result); + ASSERT_EQ(OK, mProducer->requestBuffer(slot, &buffer)); + + // Dequeue should fail here, since we dequeued 3 buffers and one buffer was + // detached from consumer(Two buffers are dequeued, and the current max + // dequeued buffer count is two). + result = mProducer->dequeueBuffer(&slot, &fence, 0, 0, 0, + GRALLOC_USAGE_SW_READ_RARELY, nullptr, nullptr); + ASSERT_TRUE(result == WOULD_BLOCK || result == TIMED_OUT || result == INVALID_OPERATION); +} + TEST_F(BufferQueueTest, TestStaleBufferHandleSentAfterDisconnect) { createBufferQueue(); sp<MockConsumer> mc(new MockConsumer); |