图像显示框架十三——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.关键状态转换,通过mSlotsslot.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 状态​,并被加入到空闲缓冲区集合中。随后通过回调通知生产者,从而完成一个"释放-申请-使用"的完整循环。
相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui