Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e7c09b6 authored by Sungtak Lee's avatar Sungtak Lee
Browse files

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
parent dc0f937d
Loading
Loading
Loading
Loading
+33 −24
Original line number Diff line number Diff line
@@ -318,6 +318,8 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);
    BQ_LOGV("detachBuffer: slot %d", slot);
    sp<IProducerListener> listener;
    {
        std::lock_guard<std::mutex> lock(mCore->mMutex);

        if (mCore->mIsAbandoned) {
@@ -339,6 +341,9 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
                    "(state = %s)", slot, mSlots[slot].mBufferState.string());
            return BAD_VALUE;
        }
        if (mCore->mBufferReleasedCbEnabled) {
            listener = mCore->mConnectedProducerListener;
        }

        mSlots[slot].mBufferState.detachConsumer();
        mCore->mActiveBuffers.erase(slot);
@@ -346,7 +351,11 @@ status_t BufferQueueConsumer::detachBuffer(int slot) {
        mCore->clearBufferSlotLocked(slot);
        mCore->mDequeueCondition.notify_all();
        VALIDATE_CONSISTENCY();
    }

    if (listener) {
        listener->onBufferDetached(slot);
    }
    return NO_ERROR;
}

+6 −0
Original line number Diff line number Diff line
@@ -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
+70 −0
Original line number Diff line number Diff line
@@ -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);