图像显示框架十三——BufferQueue的工作流程(基于Android 15源码分析)

一.前言

书接上回,我们说到了通过acquireNextBufferLocked获取可用的缓冲区, 这里我们继续从这BLASTBufferQueue中的onFrameAvailable函数调用到acquireNextBufferLocked说起,这里我们在继续贴一下生产者消费者模型的简略流程图

源码位置:

framework/native/libs/gui/BLASTBufferQueue.cpp

framework/native/include/gui/BufferItemConsumer.h

framework/native/libs/gui/BufferItemConsumer.cpp

framework/native/libs/gui/ConsumerBase.cpp

framework/native/libs/gui/BufferQueueConsumer.cpp

二.消费者获取缓冲区

BLASTBufferQueue::acquireNextBufferLocked

继续接上面的acquireNextBufferLocked函数,在前面的文章我们基本了解了BufferQueueProducer与BufferQueueCore,这里我们来看另一个重要的角色:BufferQueueConsumer,如下是之前的acquireNextBufferLocked函数,我们贴一下,继续进行分析

复制代码
// 获取下一个可用缓冲区的核心函数
// 参数 transaction: 可选的外部事务对象。如果提供,则使用外部事务;否则创建本地事务并立即应用
status_t BLASTBufferQueue::acquireNextBufferLocked(
        const std::optional<SurfaceComposerClient::Transaction*> transaction) {
    // 1. 检查是否满足获取条件:有可用帧且未超过最大获取数量限制
    if (mNumFrameAvailable == 0) {
        BQA_LOGV("Can't acquire next buffer. No available frames");
        return BufferQueue::NO_BUFFER_AVAILABLE;
    }

    // 额外检查:防止获取过多缓冲区(最大获取数+2作为安全边界)
    if (mNumAcquired >= (mMaxAcquiredBuffers + 2)) {
        BQA_LOGV("Can't acquire next buffer. Already acquired max frames %d max:%d + 2",
                 mNumAcquired, mMaxAcquiredBuffers);
        return BufferQueue::NO_BUFFER_AVAILABLE;
    }

    // 2. 验证SurfaceControl是否存在
    if (mSurfaceControl == nullptr) {
        BQA_LOGE("ERROR : surface control is null");
        return NAME_NOT_FOUND;
    }

    // 3. 事务处理准备:决定使用外部事务还是创建本地事务
    SurfaceComposerClient::Transaction localTransaction;
    bool applyTransaction = true;  // 默认需要立即应用事务
    SurfaceComposerClient::Transaction* t = &localTransaction;
    
    if (transaction) {
        t = *transaction;          // 使用外部提供的事务
        applyTransaction = false;   // 外部事务由调用者负责应用
    }

    BufferItem bufferItem;

    // 4. 从BufferQueueConsumer中获取缓冲区
    status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
    if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
        BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
        return status;
    } else if (status != OK) {
        BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
        return status;
    }

    // 5. 获取图形缓冲区引用并更新计数器
    auto buffer = bufferItem.mGraphicBuffer;
    mNumFrameAvailable--;  // 可用帧数减1
    BBQ_TRACE("frame=%" PRIu64, bufferItem.mFrameNumber);

    // 6. 缓冲区有效性检查
    if (buffer == nullptr) {
        mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
        BQA_LOGE("Buffer was empty");
        return BAD_VALUE;
    }

    // 7. 缓冲区拒绝检查:如果缓冲区尺寸不匹配当前需求则拒绝
    if (rejectBuffer(bufferItem)) {
        BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d "
                 "buffer{size=%dx%d transform=%d}",
                 mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
                 buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
        mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
        // 递归尝试获取下一个缓冲区
        return acquireNextBufferLocked(transaction);
    }

    // 8. 更新获取状态和记录信息
    mNumAcquired++;  // 已获取缓冲区计数加1
    mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
    ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
    mSubmitted[releaseCallbackId] = bufferItem;  // 记录已提交的缓冲区

    // 9. 检查生产者连接状态
    bool needsDisconnect = false;
    mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
    if (needsDisconnect) {
        t->notifyProducerDisconnect(mSurfaceControl);  // 通知SurfaceFlinger生产者已断开
    }

    // 10. 增加引用计数,确保在事务完成回调前BLASTBufferQueue不被销毁
    incStrong((void*)transactionCallbackThunk);

    // 11. 更新尺寸信息:只有当缓冲区尺寸匹配请求尺寸或非冻结缩放模式时才更新
    if (mRequestedSize == getBufferSize(bufferItem) ||
        bufferItem.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
        mSize = mRequestedSize;
    }
    
    // 12. 计算裁剪区域并更新最后缓冲区信息
    Rect crop = computeCrop(bufferItem);
    mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
                           bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                           bufferItem.mScalingMode, crop);

    // 13. 准备缓冲区释放回调函数
    auto releaseBufferCallback =
            std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
                      std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
    
    // 14. 复制栅栏对象(用于同步)
    sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;

    // 15. 查找出队时间戳(用于性能监控)
    nsecs_t dequeueTime = -1;
    {
        std::lock_guard _lock{mTimestampMutex};
        auto dequeueTimeIt = mDequeueTimestamps.find(buffer->getId());
        if (dequeueTimeIt != mDequeueTimestamps.end()) {
            dequeueTime = dequeueTimeIt->second;
            mDequeueTimestamps.erase(dequeueTimeIt);
        }
    }

    // 16. 配置事务的各项参数
    t->setBuffer(mSurfaceControl, buffer, fence, bufferItem.mFrameNumber, mProducerId,
                 releaseBufferCallback, dequeueTime);
    t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
    t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
    t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
    t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));

    mSurfaceControlsWithPendingCallback.push(mSurfaceControl);

    // 17. 设置目标帧和标志
    if (mUpdateDestinationFrame) {
        t->setDestinationFrame(mSurfaceControl, Rect(mSize));
    } else {
        const bool ignoreDestinationFrame =
                bufferItem.mScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE;
        t->setFlags(mSurfaceControl,
                    ignoreDestinationFrame ? layer_state_t::eIgnoreDestinationFrame : 0,
                    layer_state_t::eIgnoreDestinationFrame);
    }

    // 18. 设置其他显示属性
    t->setBufferCrop(mSurfaceControl, crop);
    t->setTransform(mSurfaceControl, bufferItem.mTransform);
    t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
    t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
    if (!bufferItem.mIsAutoTimestamp) {
        t->setDesiredPresentTime(bufferItem.mTimestamp);  // 设置期望显示时间
    }

    // 19. 处理帧时间线信息:清理过时的,设置匹配的
    while (!mPendingFrameTimelines.empty() &&
           mPendingFrameTimelines.front().first < bufferItem.mFrameNumber) {
        ATRACE_FORMAT_INSTANT("dropping stale frameNumber: %" PRIu64 " vsyncId: %" PRId64,
                              mPendingFrameTimelines.front().first,
                              mPendingFrameTimelines.front().second.vsyncId);
        mPendingFrameTimelines.pop();
    }

    if (!mPendingFrameTimelines.empty() &&
        mPendingFrameTimelines.front().first == bufferItem.mFrameNumber) {
        ATRACE_FORMAT_INSTANT("Transaction::setFrameTimelineInfo frameNumber: %" PRIu64
                              " vsyncId: %" PRId64,
                              bufferItem.mFrameNumber,
                              mPendingFrameTimelines.front().second.vsyncId);
        t->setFrameTimelineInfo(mPendingFrameTimelines.front().second);
        mPendingFrameTimelines.pop();
    }

    // 20. 合并挂起的事务
    mergePendingTransactions(t, bufferItem.mFrameNumber);
    
    // 21. 应用事务或设置屏障
    if (applyTransaction) {
        // 使用应用令牌应用事务(单向操作)
        t->setApplyToken(mApplyToken).apply(false, true);
        mAppliedLastTransaction = true;
        mLastAppliedFrameNumber = bufferItem.mFrameNumber;
    } else {
        // 设置缓冲区屏障,确保事务顺序
        t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber);
        mAppliedLastTransaction = false;
    }

    // 22. 记录详细日志
    BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
             " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
             " graphicBufferId=%" PRIu64 "%s transform=%d",
             mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
             bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
             static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
             bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
    
    return OK;
}

函数的核心作用总结:

这个函数是消费端处理缓冲区的关键环节,主要完成以下任务:

**1.条件检查:**验证是否有可用缓冲区且未超过限制

2.缓冲区获取:从BufferQueueConsumer中实际获取一个BufferItem

**3.缓冲区验证:**检查缓冲区有效性,拒绝不符合条件的缓冲区

**4.事务配置:**将缓冲区及其属性(尺寸、裁剪、变化、HDR元数据等)设置到事务中

**5.同步处理:**处理珊栏同步和时间戳

**6.事务提交:**根据情况立即应用事务或准备外部事务

**7.状态跟踪:**维护缓冲区获取状态和回调信息

上述我们重点如何从BufferQueueConsumer中获取到一个BufferItem的,上述的mBufferItemConsumer->acquireBuffer是调用到BufferItemConsumer的acquireBuffer函数,如下

BufferItemConsumer::acquireBuffer

源代码如下:

复制代码
// 从BufferQueue中获取一个已填充数据的缓冲区
// 参数:
//   item - 输出参数,用于返回获取到的缓冲区信息
//   presentWhen - 期望的显示时间(用于缓冲区调度决策)
//   waitForFence - 是否等待栅栏信号(确保缓冲区数据就绪)
status_t BufferItemConsumer::acquireBuffer(BufferItem *item,
        nsecs_t presentWhen, bool waitForFence) {
    status_t err;

    // 1. 参数有效性检查
    if (!item) return BAD_VALUE;

    // 2. 加锁保护共享资源(线程安全)
    Mutex::Autolock _l(mMutex);

    // 3. 调用核心的获取缓冲区方法(加锁版本)
    err = acquireBufferLocked(item, presentWhen);
    if (err != OK) {
        if (err != NO_BUFFER_AVAILABLE) {
            // 记录非"无缓冲区可用"的错误
            BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
        }
        return err;
    }

    // 4. 栅栏同步处理(可选)
    if (waitForFence) {
        // 等待栅栏信号,确保生产者已完成数据写入
        err = item->mFence->waitForever("BufferItemConsumer::acquireBuffer");
        if (err != OK) {
            BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
                    strerror(-err), err);
            return err;
        }
    }

    // 5. 设置图形缓冲区引用
    item->mGraphicBuffer = mSlots[item->mSlot].mGraphicBuffer;

    return OK;
}

上述代码的核心作用是缓冲区获取

BufferQueue的队列中取出一个生产者已经写入数据的缓冲区,然后我们继续看下acquireBufferLocked函数怎么获取的,这个函数其实在BufferItemConsumer的父类ConsumerBase中实现的

ConsumerBase::acquireBufferLocked

代码如下:

复制代码
// ConsumerBase的加锁版本缓冲区获取方法
// 这是消费者实际从BufferQueue获取缓冲区的核心实现
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
        nsecs_t presentWhen, uint64_t maxFrameNumber) {
    
    // 1. 检查消费者是否已被废弃(abandoned)
    if (mAbandoned) {
        CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
        return NO_INIT;  // 返回未初始化错误
    }

    // 2. 调用底层Consumer对象(实际是BufferQueueConsumer)的acquireBuffer方法
    status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
    if (err != NO_ERROR) {
        return err;  // 如果获取失败,直接返回错误
    }

    // 3. 缓冲区槽位管理:如果获取到新的GraphicBuffer
    if (item->mGraphicBuffer != nullptr) {
        // 如果该槽位已经有缓冲区,先释放旧的
        if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
            freeBufferLocked(item->mSlot);
        }
        // 将新缓冲区存储到对应的槽位中
        mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
    }

    // 4. 更新槽位的元数据信息
    mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;  // 帧号
    mSlots[item->mSlot].mFence = item->mFence;             // 同步栅栏

    // 5. 记录调试日志
    CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
            item->mSlot, item->mFrameNumber);

    return OK;  // 成功返回
}

上述的代码引出了我们的主角:BufferQueueConsumer ,其实真正的缓冲区获取操作是在上述的mConsumer->acquireBuffer函数,我们继续看BufferQueueConsumer::acquireBuffer函数

BufferQueueConsumer::acquireBuffer

根据之前的文章分析:

https://blog.csdn.net/gongjdde/article/details/157393485?spm=1001.2014.3001.5501

上述的mConsumer其实就是BufferQueueConsumer类型,所有我们就会走到BufferQueueConsumer的acquireBuffer函数,如下:

复制代码
// BufferQueueConsumer获取缓冲区的核心实现
// 这是消费者实际从BufferQueue队列中取出缓冲区的最终步骤
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
    ATRACE_CALL();  // 开始性能追踪

    int numDroppedBuffers = 0;  // 记录丢弃的缓冲区数量
    sp<IProducerListener> listener;  // 用于缓冲区释放回调的监听器
    
    {
        // 1. 加锁保护BufferQueue核心状态
        std::unique_lock<std::mutex> lock(mCore->mMutex);

        // 2. 检查消费者当前已获取的缓冲区数量是否超过限制
        int numAcquiredBuffers = 0;
        for (int s : mCore->mActiveBuffers) {
            if (mSlots[s].mBufferState.isAcquired()) {
                ++numAcquiredBuffers;  // 统计当前已获取的缓冲区数量
            }
        }
        
        // 允许临时超过最大获取数量1个(用于缓冲区切换时的平滑过渡)
        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;
        }

        // 3. 检查共享缓冲区模式是否可用
        bool sharedBufferAvailable = mCore->mSharedBufferMode &&
                mCore->mAutoRefresh && mCore->mSharedBufferSlot !=
                BufferQueueCore::INVALID_BUFFER_SLOT;

        // 4. 检查队列是否为空(共享缓冲区模式特殊处理)
        if (mCore->mQueue.empty() && !sharedBufferAvailable) {
            return NO_BUFFER_AVAILABLE;  // 没有可用缓冲区
        }

        // 5. 获取队列首部缓冲区(FIFO原则)
        BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());

        // 6. 时间戳相关的缓冲区调度逻辑
        // 如果指定了expectedPresent时间,进行智能缓冲区选择
        if (expectedPresent != 0 && !mCore->mQueue.empty()) {
            
            // 7. 缓冲区丢弃策略:丢弃过时的缓冲区
            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
                const BufferItem& bufferItem(mCore->mQueue[1]);  // 查看下一个缓冲区

                // 检查下一个缓冲区是否已准备好(帧号限制)
                if (maxFrameNumber && bufferItem.mFrameNumber > maxFrameNumber) {
                    break;  // 消费者还没准备好接收这个缓冲区
                }

                // 8. 时间戳检查:判断是否应该丢弃当前缓冲区
                nsecs_t desiredPresent = bufferItem.mTimestamp;
                // 检查时间戳是否合理(在期望时间的合理范围内)
                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                        desiredPresent > expectedPresent) {
                    // 时间戳不合理或缓冲区显示时间太晚,不丢弃
                    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());

                // 9. 实际丢弃缓冲区
                if (!front->mIsStale) {
                    // 释放被丢弃缓冲区的状态
                    mSlots[front->mSlot].mBufferState.freeQueued();

                    // 共享缓冲区模式特殊处理
                    if (!mCore->mSharedBufferMode &&
                            mSlots[front->mSlot].mBufferState.isFree()) {
                        mSlots[front->mSlot].mBufferState.mShared = false;
                    }

                    // 非共享缓冲区添加到空闲列表
                    if (!mSlots[front->mSlot].mBufferState.isShared()) {
                        mCore->mActiveBuffers.erase(front->mSlot);
                        mCore->mFreeBuffers.push_back(front->mSlot);
                    }

                    // 准备缓冲区释放回调
                    if (mCore->mBufferReleasedCbEnabled) {
                        listener = mCore->mConnectedProducerListener;
                    }
                    ++numDroppedBuffers;  // 增加丢弃计数
                }

                // 从队列中移除丢弃的缓冲区
                mCore->mQueue.erase(front);
                front = mCore->mQueue.begin();  // 更新front指向新的队首
            }

            // 10. 检查当前队首缓冲区是否可获取
            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;

        // 11. 共享缓冲区模式处理
        if (sharedBufferAvailable && mCore->mQueue.empty()) {
            // 等待缓冲区分配完成
            mCore->waitWhileAllocatingLocked(lock);

            slot = mCore->mSharedBufferSlot;

            // 从缓存数据重新创建BufferItem(共享缓冲区特殊处理)
            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;
        } 
        // 12. 检查是否可以获取非可丢弃缓冲区
        else if (acquireNonDroppableBuffer && front->mIsDroppable) {
            BQ_LOGV("acquireBuffer: front buffer is not droppable");
            return NO_BUFFER_AVAILABLE;
        } 
        // 13. 正常缓冲区获取
        else {
            slot = front->mSlot;
            *outBuffer = *front;  // 复制缓冲区数据
        }

        ATRACE_BUFFER_INDEX(slot);  // 追踪特定缓冲区的操作

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

        // 14. 更新缓冲区状态为"已获取"
        if (!outBuffer->mIsStale) {
            mSlots[slot].mAcquireCalled = true;
            // 根据是否在队列中调用不同的状态转换
            if (mCore->mQueue.empty()) {
                mSlots[slot].mBufferState.acquireNotInQueue();  // 共享缓冲区模式
            } else {
                mSlots[slot].mBufferState.acquire();  // 正常模式
            }
            mSlots[slot].mFence = Fence::NO_FENCE;  // 重置栅栏
        }

        // 15. 优化:如果缓冲区之前已被获取过,不返回GraphicBuffer引用
        // 避免在消费者端不必要的重新映射
        if (outBuffer->mAcquireCalled) {
            outBuffer->mGraphicBuffer = nullptr;
        }

        // 16. 从队列中移除已获取的缓冲区
        mCore->mQueue.erase(front);

        // 17. 唤醒可能等待的生产者(因为队列有空间了)
        mCore->mDequeueCondition.notify_all();

        // 18. 更新性能追踪和统计信息
        ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
        mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
        VALIDATE_CONSISTENCY();  // 验证内部状态一致性
    }  // 自动释放锁

    // 19. 在锁外执行缓冲区释放回调(避免死锁)
    if (listener != nullptr) {
        for (int i = 0; i < numDroppedBuffers; ++i) {
            listener->onBufferReleased();  // 通知生产者缓冲区被释放
        }
    }

    return NO_ERROR;  // 成功获取缓冲区
}

acquireBuffer的逻辑主要就是消费者获取BufferSlot,详细流程在源码中有详细的注释:

总结主要做了如下的几件事:

1.缓冲区数量限制检查,通过numAcquiredBuffers变量进行检查,防止数量过多出现oom或者生产者与消费者数量不平衡

2.队列是否为空检查,通过mCore->mQueue.empty()进行检查,为空则不继续进行下去

3.智能缓冲区丢弃算法,通过时间戳等进行检查,将不合理的缓冲区进行丢弃

4.对显示时间进行判断,主要是基于时间戳通过一系列算法最终通过bufferIsDue和consumerIsReady变量进行的智能决策机制,防止过早显示出现画面撕裂

5.缓冲区获取,取出对应的BufferSlot

6.关键状态转换,通过mSlots[slot].mBufferState.acquire();将BufferState状态进行转换:QUEUED → ACQUIRED

7.将mGraphicBuffer 置空,防止重复映射

8.队列维护和生产者唤醒,通过mCore->mQueue.erase(front);将buffer移除队列;通过mCore->mDequeueCondition.notify_all();唤醒生产者

9.回调通知,通过listener->onBufferReleased(); 将被丢弃的buffer通知生产者缓冲区

三.消费者释放缓冲区

释放回调

消费者acquire拿到buffer后又是怎样通知release buffer呢?

这个其实就是在我们之前分析的BLASTBufferQueue::acquireNextBufferLocked函数中,我们逐步分析:

1.接前面分析的调用acquireBuffer获取一个BufferItem;

2.通过GraphicBuffer -- auto buffer = bufferItem.mGraphicBuffer;取出buffer

  1. 设置释放回调函数(步骤13),就是设置releaseBufferCallback的值,它就是释放的回调函数

4.通过t->setBuffer函数调用将buffer和释放回调函数都设置到事务中

然后releaseBufferCallbackThunk的逻辑和前面的获取缓冲区类似,如下:

>>> releaseBufferCallbackThunk >>> BLASTBufferQueue::releaseBufferCallback >>> BLASTBufferQueue::releaseBufferCallbackLocked >>> BLASTBufferQueue::releaseBuffer >>> BufferItemConsumer::releaseBuffer >>> ConsumerBase::releaseBufferLocked >>> BufferQueueConsumer::releaseBuffer

流程图如下:

BufferQueueConsumer::releaseBuffer

然后我们来分析下BufferQueueConsumer::releaseBuffer函数,看下如何释放buffer的

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

    // 1. 参数有效性检查
    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;
    { 
        // 2. 加锁保护核心状态
        std::lock_guard<std::mutex> lock(mCore->mMutex);

        // 3. 帧号验证(防止释放错误的缓冲区)
        if (frameNumber != mSlots[slot].mFrameNumber &&
                !mSlots[slot].mBufferState.isShared()) {
            return STALE_BUFFER_SLOT;  // 缓冲区已被重新分配
        }

        // 4. 状态验证:必须处于ACQUIRED状态才能释放
        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;
        }

        // 5. 🔥🔥🔥 真正的缓冲区释放开始 🔥🔥🔥

        // 5.1 设置同步对象
        mSlots[slot].mEglDisplay = eglDisplay;
        mSlots[slot].mEglFence = eglFence;
        mSlots[slot].mFence = releaseFence;

        // 5.2 🔥 关键:缓冲区状态转换 - ACQUIRED → FREE
        mSlots[slot].mBufferState.release();

        // 6. 共享缓冲区模式特殊处理
        if (!mCore->mSharedBufferMode && mSlots[slot].mBufferState.isFree()) {
            mSlots[slot].mBufferState.mShared = false;  // 标记为非共享
        }

        // 7. 🔥 关键:将缓冲区槽位回收到空闲列表
        // 注意:共享缓冲区不加入空闲列表(持续重用)
        if (!mSlots[slot].mBufferState.isShared()) {
            mCore->mActiveBuffers.erase(slot);      // 从活跃列表移除
            mCore->mFreeBuffers.push_back(slot);    // 🔥 加入空闲列表
        }

        // 8. 准备生产者回调
        if (mCore->mBufferReleasedCbEnabled) {
            listener = mCore->mConnectedProducerListener;
        }
        BQ_LOGV("releaseBuffer: releasing slot %d", slot);

        // 9. 🔥 关键:唤醒等待的生产者线程
        mCore->mDequeueCondition.notify_all();
        
        VALIDATE_CONSISTENCY();  // 验证状态一致性
    }  // 自动释放锁

    // 10. 在锁外执行生产者回调(避免死锁)
    if (listener != nullptr) {
        listener->onBufferReleased();  // 通知生产者缓冲区已释放
    }

    return NO_ERROR;
}

🔥 真正释放缓冲区的核心位置

位置1:缓冲区状态转换(第5.2步)

复制代码
mSlots[slot].mBufferState.release();  // ACQUIRED → FREE

作用 :这是逻辑上的释放,将缓冲区状态从"已获取"变为"空闲",允许被重新使用。

位置2:资源回收(第7步)

复制代码
if (!mSlots[slot].mBufferState.isShared()) {
    mCore->mActiveBuffers.erase(slot);      // 从活跃列表移除
    mCore->mFreeBuffers.push_back(slot);    // 🔥 加入空闲列表 - 真正的释放!
}

作用 :这是物理上的释放,将缓冲区槽位放回空闲池,供生产者重新获取。

位置3:生产者唤醒(第9步)

复制代码
mCore->mDequeueCondition.notify_all();  // 唤醒等待的生产者

作用:通知可能被阻塞的生产者线程,现在有可用的缓冲区了。

位置4:通知生产者释放完成(第10步)

复制代码
listener->onBufferReleased();  // 通知生产者缓冲区已释放

四.ProducerListener是怎样工作的

源码位置:framework/native/include/gui/IProducerListener.h

然后我们分析这个释放过程如何通知生产者的

  1. 在BufferQueueCore中有成员 sp mConnectedProducerListener,它就是用来处理onBufferReleased事件的;

  2. mConnectedProducerListener是在哪里被设置的呢?答案是 BufferQueueProducer::connect;

3.然后是通过Surface::connect调用到BufferQueueProducer::connect的,我们看下Surface::connect的代码

复制代码
int Surface::connect(
        int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) {
    if (sListener != nullptr) {
        mListenerProxy = new ProducerListenerProxy(this, sListener);
    }
    return connect(api, mListenerProxy, reportBufferRemoval);
}

int Surface::connect(
        int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
    ATRACE_CALL();
    ALOGV("Surface::connect");
    Mutex::Autolock lock(mMutex);
    IGraphicBufferProducer::QueueBufferOutput output;
    mReportRemovedBuffers = reportBufferRemoval;

    /* QTI_BEGIN */
    if (mQtiSurfaceGPPExtn) {
        mQtiSurfaceGPPExtn->Connect(api, &mGraphicBufferProducer);
    }
    /* QTI_END */

    int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);
    if (err == NO_ERROR) {
        mDefaultWidth = output.width;
        mDefaultHeight = output.height;
        mNextFrameNumber = output.nextFrameNumber;
        mMaxBufferCount = output.maxBufferCount;

        // Ignore transform hint if sticky transform is set or transform to display inverse flag is
        // set. Transform hint should be ignored if the client is expected to always submit buffers
        // in the same orientation.
        if (mStickyTransform == 0 && !transformToDisplayInverse()) {
            mTransformHint = output.transformHint;
        }

        mConsumerRunningBehind = (output.numPendingBuffers >= 2);

        /* QTI_BEGIN */
        if (mQtiSurfaceGPPExtn) {
            mQtiSurfaceGPPExtn->StoreConnect(api, listener, reportBufferRemoval);
        }
        /* QTI_END */
    }
    if (!err && api == NATIVE_WINDOW_API_CPU) {
        mConnectedToCpu = true;
        // Clear the dirty region in case we're switching from a non-CPU API
        mDirtyRegion.clear();
    } else if (!err) {
        // Initialize the dirty region for tracking surface damage
        mDirtyRegion = Region::INVALID_REGION;
    }

    return err;
}

可以看出来是将ProducerListenerProxy设置进去的

4.看一下ProducerListenerProxy代码,可以看出来是调用了上一步设置的listener

复制代码
    class ProducerListenerProxy : public BnProducerListener {
    public:
        ProducerListenerProxy(wp<Surface> parent, sp<SurfaceListener> listener)
               : mParent(parent), mSurfaceListener(listener) {}
        virtual ~ProducerListenerProxy() {}

        virtual void onBufferReleased() {
            mSurfaceListener->onBufferReleased();
        }

        virtual bool needsReleaseNotify() {
            return mSurfaceListener->needsReleaseNotify();
        }

        virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
    private:
        wp<Surface> mParent;
        sp<SurfaceListener> mSurfaceListener;
    };

5.再继续往前推还是connect函数,如下

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

int Surface::connect(int api, const sp<IProducerListener>& listener) {
    return connect(api, listener, false);
}

可以看出来最终是将StubProducerListener对象设置进去了

6.看下StubProducerListener

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

可以看出来其实什么都没做

五.总结

  • 指出了 releaseBuffer 是一个"状态更新+条件触发"的过程,其核心是更新 BufferQueueCore 中的状态机。
  • ​真正意义上的释放​ 是指缓冲区​从 ACQUIRED 状态成功迁移到 FREE 状态​,并被加入到空闲缓冲区集合中。随后通过回调通知生产者,从而完成一个"释放-申请-使用"的完整循环。
相关推荐
消失的旧时光-19435 小时前
Android 系统层学习目录
android·学习
毕设源码-赖学姐5 小时前
【开题答辩全过程】以 基于Android的考勤管理系统为例,包含答辩的问题和答案
android
m0_748233175 小时前
PHP5.2十大经典特性回顾
android
草莓熊Lotso6 小时前
脉脉独家【AI创作者xAMA第二期】| 从拼图游戏到AI设计革命
android·开发语言·c++·人工智能·脉脉
肖。35487870946 小时前
html选择页最简模板源码,用于集合很多网页!游戏大全数字导航页面,数字选择页制作灵感,已经压缩到最小,现代,讲解。
android·java·javascript·css·html
m0_748233178 小时前
PHP7.4重磅特性全解析
android
蜗牛、Z8 小时前
Android 日常开发Adb常用命令附档
android·adb
感谢地心引力15 小时前
安卓、苹果手机无线投屏到Windows
android·windows·ios·智能手机·安卓·苹果·投屏
优雅的潮叭19 小时前
cud编程之 reduce
android·redis·缓存