Android 12(S) 圖形顯示系統 - BufferQueue的工作流程(十一)

二的次方發表於2022-03-23

題外話

我竟然已經寫了這個系列的十一篇文章了,雖然內容很淺顯,雖然內容很枯燥,雖然內容也許沒營養,但我為自己的堅持點贊!

必讀:Android 12(S) 圖形顯示系統 - 開篇

Android 12(S) 圖形顯示系統 - BufferQueue的工作流程(十一)


 

一、前言


前面的兩篇文章,分別講解了Producer的處理邏輯和queue buffer後通過FrameAvailableListener通知到Consumer的基本過程。

流程已經走到了BufferQueueConsumer::acquireBuffer中,所以這篇文章聚焦Consumer的一些處理邏輯。

還是把流程圖貼上來

從流程圖中看,這篇文章就是講解右半部分的內容。

 

二、消費者-Consumer的相關邏輯


瞭解了 BufferQueueCore 和 BufferQueueProducer,接著看 BufferQueue 的最後一個元素:BufferQueueConsumer。

BufferQueueConsumer作為消費者的一個代表元素通過 acquireBuffer 來獲取影像緩衝區,通過 releaseBuffer 來釋放該緩衝區。

下面就分別看看 BufferQueueConsumer 中 acquireBuffer 和 releaseBuffer 兩個操作的具體流程。

2.1 程式碼位置

/frameworks/native/libs/gui/BufferQueueConsumer.cpp

 

2.2 acquireBuffer的邏輯

先看 acquireBuffer 的過程,上原始碼

status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
    ATRACE_CALL();

    int numDroppedBuffers = 0;
    sp<IProducerListener> listener;
    {
        std::unique_lock<std::mutex> lock(mCore->mMutex);

        // Check that the consumer doesn't currently have the maximum number of
        // buffers acquired. We allow the max buffer count to be exceeded by one
        // buffer so that the consumer can successfully set up the newly acquired
        // buffer before releasing the old one.
        
        // 檢查acquire的buffer的數量是否超出了限制
        int numAcquiredBuffers = 0;
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isAcquired()) {
                ++numAcquiredBuffers;
            }
        }
        const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire &&
                numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1;
        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 &&
            !acquireNonDroppableBuffer) {
            BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                    numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
            return INVALID_OPERATION;
        }

        bool sharedBufferAvailable = mCore->mSharedBufferMode &&
                mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
                BufferQueueCore::INVALID_BUFFER_SLOT;

        // In asynchronous mode the list is guaranteed to be one buffer deep,
        // while in synchronous mode we use the oldest buffer.
        // 檢查BufferQueueCore中的mQueue佇列是否為空
        if (mCore->mQueue.empty() && !sharedBufferAvailable) {
            return NO_BUFFER_AVAILABLE;
        }
        // 獲取BufferQueueCore中的mQueue佇列的迭代器
        BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
        
        // If expectedPresent is specified, we may not want to return a buffer yet.
        // If it's specified and there's more than one buffer queued, we may want
        // to drop a buffer.
        // Skip this if we're in shared buffer mode and the queue is empty,
        // since in that case we'll just return the shared buffer.
        if (expectedPresent != 0 && !mCore->mQueue.empty()) {
            
            // expectedPresent表示期望這個buffer什麼時候顯示到螢幕上。
            // 如果buffer的期望顯示時間小於expectedPresent,我們會acquire and return這個buffer
            // 如果我們不想顯示它直到expectedPresent之後,可以返回PRESENT_LATER
            
            // The 'expectedPresent' argument indicates when the buffer is expected
            // to be presented on-screen. If the buffer's desired present time is
            // earlier (less) than expectedPresent -- meaning it will be displayed
            // on time or possibly late if we show it as soon as possible -- we
            // acquire and return it. If we don't want to display it until after the
            // expectedPresent time, we return PRESENT_LATER without acquiring it.
            //
            
            // 安全起見,如果expectedPresent超過了buffer的期望顯示時間1秒,我們會推遲acquire
            // To be safe, we don't defer acquisition if expectedPresent is more
            // than one second in the future beyond the desired present time
            // (i.e., we'd be holding the buffer for a long time).
            //
            // NOTE: Code assumes monotonic time values from the system clock
            // are positive.
            
            // 檢查是否需要丟棄一些幀,主要是判斷timestamps & expectedPresent
            // Start by checking to see if we can drop frames. We skip this check if
            // the timestamps are being auto-generated by Surface. If the app isn't
            // generating timestamps explicitly, it probably doesn't want frames to
            // be discarded based on them.
            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
                const BufferItem& bufferItem(mCore->mQueue[1]);

                // If dropping entry[0] would leave us with a buffer that the
                // consumer is not yet ready for, don't drop it.
                if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
                    break;
                }

                // If entry[1] is timely, drop entry[0] (and repeat). We apply an
                // additional criterion here: we only drop the earlier buffer if our
                // desiredPresent falls within +/- 1 second of the expected present.
                // Otherwise, bogus desiredPresent times (e.g., 0 or a small
                // relative timestamp), which normally mean "ignore the timestamp
                // and acquire immediately", would cause us to drop frames.
                //
                // We may want to add an additional criterion: don't drop the
                // earlier buffer if entry[1]'s fence hasn't signaled yet.
                nsecs_t desiredPresent = bufferItem.mTimestamp;
                
                // desiredPresent比expectedPresent小了1 second多,或desiredPresent大於expectedPresent
                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                        desiredPresent > expectedPresent) {
                    // This buffer is set to display in the near future, or
                    // desiredPresent is garbage. Either way we don't want to drop
                    // the previous buffer just to get this on the screen sooner.
                    BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
                            PRId64 " (%" PRId64 ") now=%" PRId64,
                            desiredPresent, expectedPresent,
                            desiredPresent - expectedPresent,
                            systemTime(CLOCK_MONOTONIC));
                    break;
                }

                BQ_LOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64
                        " size=%zu",
                        desiredPresent, expectedPresent, mCore->mQueue.size());
                // 處理要drop的buffer
                if (!front->mIsStale) {
                    // Front buffer is still in mSlots, so mark the slot as free 
                    // 對應的BufferSlot設定為FREE狀態
                    mSlots[front->mSlot].mBufferState.freeQueued();

                    // After leaving shared buffer mode, the shared buffer will
                    // still be around. Mark it as no longer shared if this
                    // operation causes it to be free.
                    if (!mCore->mSharedBufferMode &&
                            mSlots[front->mSlot].mBufferState.isFree()) {
                        mSlots[front->mSlot].mBufferState.mShared = false;
                    }
                    
                    // mActiveBuffers :繫結了GraphicBuffer且狀態為非FREE的BufferSlot集合;
                    // mFreeBuffers :繫結了GraphicBuffer且狀態為FREE的BufferSlot集合;
                    
                    // Don't put the shared buffer on the free list
                    if (!mSlots[front->mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(front->mSlot); // 從mActiveBuffers刪除
                        mCore->mFreeBuffers.push_back(front->mSlot);// 新增進mFreeBuffers
                    }

                    if (mCore->mBufferReleasedCbEnabled) {
                        listener = mCore->mConnectedProducerListener; // 設定生產者的監聽器
                    }
                    ++numDroppedBuffers; // 計數加1,記錄drop了幾個buffer
                }

                mCore->mQueue.erase(front);// 從mQueue中刪除
                front = mCore->mQueue.begin();// 重置front,進入下一次while迴圈
            }

            // See if the front buffer is ready to be acquired
            nsecs_t desiredPresent = front->mTimestamp;
            bool bufferIsDue = desiredPresent <= expectedPresent ||
                    desiredPresent > expectedPresent + MAX_REASONABLE_NSEC;
            bool consumerIsReady = maxFrameNumber > 0 ?
                    front->mFrameNumber <= maxFrameNumber : true;
            if (!bufferIsDue || !consumerIsReady) {
                BQ_LOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64
                        " (%" PRId64 ") now=%" PRId64 " frame=%" PRIu64
                        " consumer=%" PRIu64,
                        desiredPresent, expectedPresent,
                        desiredPresent - expectedPresent,
                        systemTime(CLOCK_MONOTONIC),
                        front->mFrameNumber, maxFrameNumber);
                ATRACE_NAME("PRESENT_LATER");
                return PRESENT_LATER;
            }

            BQ_LOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " "
                    "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent,
                    desiredPresent - expectedPresent,
                    systemTime(CLOCK_MONOTONIC));
        }
        // 走到這裡就說明:該丟棄的已經都丟棄了,餘下的就可以拿去顯示了。
        int slot = BufferQueueCore::INVALID_BUFFER_SLOT;

        if (sharedBufferAvailable && mCore->mQueue.empty()) {
            // make sure the buffer has finished allocating before acquiring it
            // 共享Buffer模式下處理
            mCore->waitWhileAllocatingLocked(lock);

            slot = mCore->mSharedBufferSlot;

            // Recreate the BufferItem for the shared buffer from the data that
            // was cached when it was last queued.
            outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer;
            outBuffer->mFence = Fence::NO_FENCE;
            outBuffer->mFenceTime = FenceTime::NO_FENCE;
            outBuffer->mCrop = mCore->mSharedBufferCache.crop;
            outBuffer->mTransform = mCore->mSharedBufferCache.transform &
                    ~static_cast<uint32_t>(
                    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
            outBuffer->mScalingMode = mCore->mSharedBufferCache.scalingMode;
            outBuffer->mDataSpace = mCore->mSharedBufferCache.dataspace;
            outBuffer->mFrameNumber = mCore->mFrameCounter;
            outBuffer->mSlot = slot;
            outBuffer->mAcquireCalled = mSlots[slot].mAcquireCalled;
            outBuffer->mTransformToDisplayInverse =
                    (mCore->mSharedBufferCache.transform &
                    NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
            outBuffer->mSurfaceDamage = Region::INVALID_REGION;
            outBuffer->mQueuedBuffer = false;
            outBuffer->mIsStale = false;
            outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
                    mCore->mAutoRefresh;
        } else if (acquireNonDroppableBuffer && front->mIsDroppable) {
            BQ_LOGV("acquireBuffer: front buffer is not droppable");
            return NO_BUFFER_AVAILABLE;
        } else {
            // 從front獲取對應的slot index
            slot = front->mSlot;
            *outBuffer = *front;
        }

        ATRACE_BUFFER_INDEX(slot);

        BQ_LOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }",
                slot, outBuffer->mFrameNumber, outBuffer->mGraphicBuffer->handle);

        if (!outBuffer->mIsStale) {
            mSlots[slot].mAcquireCalled = true;
            // Don't decrease the queue count if the BufferItem wasn't
            // previously in the queue. This happens in shared buffer mode when
            // the queue is empty and the BufferItem is created above.
            if (mCore->mQueue.empty()) {
                mSlots[slot].mBufferState.acquireNotInQueue();
            } else {
                // 將BufferState狀態改為acquire
                mSlots[slot].mBufferState.acquire();
            }
            mSlots[slot].mFence = Fence::NO_FENCE;
        }

        // If the buffer has previously been acquired by the consumer, set
        // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
        // on the consumer side
        if (outBuffer->mAcquireCalled) {
            outBuffer->mGraphicBuffer = nullptr;
        }
        //將該Buffer從mQueue中移除
        mCore->mQueue.erase(front);

        // We might have freed a slot while dropping old buffers, or the producer
        // may be blocked waiting for the number of buffers in the queue to
        // decrease.
        mCore->mDequeueCondition.notify_all();

        ATRACE_INT(mCore->mConsumerName.string(),
                static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
        VALIDATE_CONSISTENCY();
    }
    // 回撥,通知生產者
    if (listener != nullptr) {
        for (int i = 0; i < numDroppedBuffers; ++i) {
            listener->onBufferReleased();
        }
    }

    return NO_ERROR;
}

 


acquireBuffer 函式中的邏輯也非常的清晰,原始碼中也做了詳細註釋。

主要就是這幾件事情:

  1. 判斷 BufferQueueCore 中的 mQueue 是否為空,mQueue 就是前面 BufferQueueProducer 呼叫 queueBuffer 函式時,將緩衝區入隊的容器;
  2. 取出對應的 BufferSlot(會有一些判斷規則,捨棄一些buffer);
  3. 將 BufferState 改為 acquire 狀態;
  4. 將該 Buffer 從 mQueue 中移除;

Android 12(S) 圖形顯示系統 - BufferQueue的工作流程(十一)


2.3 消費者acquire拿到buffer後又是怎樣通知release buffer呢?

要回答這個問題,我們需要在回到呼叫acquireBuffer的地方,即 BLASTBufferQueue::processNextBufferLocked 函式中,先看其程式碼:

void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) {
    ......
    SurfaceComposerClient::Transaction localTransaction;
    bool applyTransaction = true;
    SurfaceComposerClient::Transaction* t = &localTransaction;

    // acquireBuffer獲取要處理的buffer
    BufferItem bufferItem;
    status_t status =
            mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
    ......
    // 拿到了實際的GraphicBuffer了
    auto buffer = bufferItem.mGraphicBuffer;
    mNumFrameAvailable--;
    
    // 某些情況下,直接releaseBuffer而無需送SurfaceFlinger合成顯示

    mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
    ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
    mSubmitted[releaseCallbackId] = bufferItem;

    ....

    // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
    incStrong((void*)transactionCallbackThunk);

    // release buffer的回到函式
    auto releaseBufferCallback =
            std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
                      std::placeholders::_4);
    t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);

    ......


    if (applyTransaction) {
        t->setApplyToken(mApplyToken).apply();
    }
}

上述程式碼,做了比較多的簡化,只保留我認為比較重要的部分。

  1. 呼叫acquireBuffer獲取一個BufferItem;
  2. 取出GraphicBuffer -- auto buffer = bufferItem.mGraphicBuffer;
  3. 通過事務Transaction來向SurfaceFlinger提交Buffer與圖層的屬性;

t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);

對於setBuffer,就是設定傳遞給SF的buffer,並指定了一個releaseBufferCallback,暫時可以理解為SF消費完這個buffer,就會通過這個callback通知來釋放這個buffer。


本文作者@二的次方  2022-03-23 釋出於部落格園


在acquireBuffer中加入log,列印呼叫堆疊資訊,如下:

11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#00 pc 000580ff  /system/lib/libgui.so (android::BufferQueueConsumer::releaseBuffer(int, unsigned long long, android::sp<android::Fence> const&, void*, void*)+130)
11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#01 pc 00059117  /system/lib/libgui.so (android::BufferQueueConsumer::releaseBuffer(int, unsigned long long, void*, void*, android::sp<android::Fence> const&)+30)
11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#02 pc 00076d27  /system/lib/libgui.so (android::ConsumerBase::releaseBufferLocked(int, android::sp<android::GraphicBuffer>, void*, void*)+134)
11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#03 pc 0007580d  /system/lib/libgui.so (android::BufferItemConsumer::releaseBuffer(android::BufferItem const&, android::sp<android::Fence> const&)+140)
11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#04 pc 0006c467  /system/lib/libgui.so (android::BLASTBufferQueue::releaseBufferCallback(android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)+1362)
11-13 01:23:59.275  3016  3030 E BufferQueueConsumer: stackdump:#05 pc 0006d827  /system/lib/libgui.so (android::releaseBufferCallbackThunk(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)+62)
11-13 01:23:59.276  3016  3030 E BufferQueueConsumer: stackdump:#06 pc 0007039b  /system/lib/libgui.so (std::__1::__function::__func<std::__1::__bind<void (&)(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int), android::wp<android::BLASTBufferQueue>, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&, std::__1::placeholders::__ph<4> const&>, std::__1::allocator<std::__1::__bind<void (&)(android::wp<android::BLASTBufferQueue>, android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int), android::wp<android::BLASTBufferQueue>, std::__1::placeholders::__ph<1> const&, std::__1::placeholders::__ph<2> const&, std::__1::placeholders::__ph<3> const&, std::__1::placeholders::__ph<4> const&> >, void (android::ReleaseCallbackId const&, android::sp<android::Fence> const&, unsigned int, unsigned int)>::operator()(android::ReleaseCallbackId const&, android::sp<android::Fence> const&,
11-13 01:23:59.276  3016  3030 E BufferQueueConsumer: stackdump:#07 pc 000a7d47  /system/lib/libgui.so (android::TransactionCompletedListener::onTransactionCompleted(android::ListenerStats)+3382)
11-13 01:23:59.276  3016  3030 E BufferQueueConsumer: stackdump:#08 pc 000925a5  /system/lib/libgui.so (int android::SafeBnInterface<android::ITransactionCompletedListener>::callLocalAsync<void (android::ITransactionCompletedListener::*)(android::ListenerStats)>(android::Parcel const&, android::Parcel*, void (android::ITransactionCompletedListener::*)(android::ListenerStats))+204)
11-13 01:23:59.276  3016  3030 E BufferQueueConsumer: stackdump:#09 pc 00028ddb  /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+162)

 

看上面的呼叫棧,是不是一目瞭然,從遙遠的Binder來的神祕資訊觸發了這一些列的事件:

>>> releaseBufferCallbackThunk

>>> BLASTBufferQueue::releaseBufferCallback

>>> BufferItemConsumer::releaseBuffer

>>> ConsumerBase::releaseBufferLocked

>>> BufferQueueConsumer::releaseBuffer

 Android 12(S) 圖形顯示系統 - BufferQueue的工作流程(十一)

2.4 releaseBuffer的邏輯

老規矩,直接看程式碼,是不是很簡單啊!

status_t BufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber,
        const sp<Fence>& releaseFence, EGLDisplay eglDisplay,
        EGLSyncKHR eglFence) {
    ATRACE_CALL();
    ATRACE_BUFFER_INDEX(slot);

    if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
            releaseFence == nullptr) {
        BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                releaseFence.get());
        return BAD_VALUE;
    }

    sp<IProducerListener> listener;
    { // Autolock scope
        std::lock_guard<std::mutex> lock(mCore->mMutex);

        // If the frame number has changed because the buffer has been reallocated,
        // we can ignore this releaseBuffer for the old buffer.
        // Ignore this for the shared buffer where the frame number can easily
        // get out of sync due to the buffer being queued and acquired at the
        // same time.
        if (frameNumber != mSlots[slot].mFrameNumber &&
                !mSlots[slot].mBufferState.isShared()) {
            return STALE_BUFFER_SLOT;
        }

        if (!mSlots[slot].mBufferState.isAcquired()) {
            BQ_LOGE("releaseBuffer: attempted to release buffer slot %d "
                    "but its state was %s", slot,
                    mSlots[slot].mBufferState.string());
            return BAD_VALUE;
        }

        mSlots[slot].mEglDisplay = eglDisplay;
        mSlots[slot].mEglFence = eglFence;
        mSlots[slot].mFence = releaseFence;
        mSlots[slot].mBufferState.release();//置為FREE狀態

        // After leaving shared buffer mode, the shared buffer will
        // still be around. Mark it as no longer shared if this
        // operation causes it to be free.
        if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
            mSlots[slot].mBufferState.mShared = false;
        }
        // Don't put the shared buffer on the free list.
        if (!mSlots[slot].mBufferState.isShared()) {
            mCore->mActiveBuffers.erase(slot);// 從mActiveBuffers中刪除
            mCore->mFreeBuffers.push_back(slot);//加入到mFreeBuffers中
        }

        if (mCore->mBufferReleasedCbEnabled) {
            listener = mCore->mConnectedProducerListener; / 設定listener
        }
        BQ_LOGV("releaseBuffer: releasing slot %d", slot);
        // 喚醒等待的執行緒
        mCore->mDequeueCondition.notify_all();
        VALIDATE_CONSISTENCY();
    } // Autolock scope

    // Call back without lock held
    if (listener != nullptr) {
        listener->onBufferReleased(); //通知producer
    }

    return NO_ERROR;
}

releaseBuffer方法的流程相對簡單:

  • slot就是需要釋放的BufferSlot的序號;

  • Buffer的FrameNumber變了,可能Buffer已經重新分配,這個是不用管;

  • 只能釋放acquire狀態的buffer序號,釋放後是Buffer放會mFreeBuffers中;

  • releaseFence,從consumer那邊傳過來,producer可以dequeue mFreeBuffers中的buffer,但是隻有releaseFence發訊號出來後,consumer才真正用完,producer才可以寫;

  • 最後通過listener通知producer。

 

2.5 ProducerListener是怎樣工作的?

在前面的講解中,有幾處都有出現 listener->onBufferReleased() ,意思是通知producer有buffer釋放了。這個listener是在哪裡設定的?onBufferReleased又做了哪些工作呢?接下來分析

定義:/frameworks/native/libs/gui/include/gui/IProducerListener.h

首先我們看到這張類圖:

1. 在BufferQueueCore中有成員 sp<IProducerListener> mConnectedProducerListener,它就是用來處理onBufferReleased事件的;

2. mConnectedProducerListener是在哪裡被設定的呢?答案是 BufferQueueProducer::connect;

3. 根據呼叫棧來追蹤:

11-13 01:20:19.388  2955  3013 E BufferQueueProducer: stackdump:#00 pc 0005e667  /system/lib/libgui.so (android::BufferQueueProducer::connect(android::sp<android::IProducerListener> const&, int, bool, android::IGraphicBufferProducer::QueueBufferOutput*)+1018)
11-13 01:20:19.388  2955  3013 E BufferQueueProducer: stackdump:#01 pc 0006ee41  /system/lib/libgui.so (android::BBQBufferQueueProducer::connect(android::sp<android::IProducerListener> const&, int, bool, android::IGraphicBufferProducer::QueueBufferOutput*)+176)
11-13 01:20:19.388  2955  3013 E BufferQueueProducer: stackdump:#02 pc 000a268b  /system/lib/libgui.so (android::Surface::connect(int, android::sp<android::IProducerListener> const&, bool)+138)
11-13 01:20:19.388  2955  3013 E BufferQueueProducer: stackdump:#03 pc 0009dd61  /system/lib/libgui.so (android::Surface::hook_perform(ANativeWindow*, int, ...)+128)

4. 可以肯定,是執行 native_window_api_connect() 一路走下來的。沿著這條路,看看listener是哪裡產生的呢?

看起來是這個位置:

int Surface::connect(int api) {
    static sp<IProducerListener> listener = new StubProducerListener();
    return connect(api, listener);
}

5. 不過,奇怪的事情發生了,StubProducerListener看起來沒有任何操作,乖乖(這一點還是很奇怪的

6. BLASTBufferQueue中還有使用AsyncProducerListener做一層封裝,實現非同步處理;

class StubProducerListener : public BnProducerListener {
public:
    virtual ~StubProducerListener();
    virtual void onBufferReleased() {}
    virtual bool needsReleaseNotify() { return false; }
};

Android 12(S) 圖形顯示系統 - BufferQueue的工作流程(十一)

三、小結


BufferQueue的運作流程到這裡就算講完了。生產者做了什麼事情?消費者做了什麼事情?圖形快取是怎樣流轉的?狀態是怎樣變化的?在幾篇文章中基本上都有做了或簡單或詳細的介紹。通過BufferQueue的幾篇文章,幫助自己建立起基本的邏輯框架,為我們後續研究和分析問題奠定基礎。

 

相關文章