云计算百科
云计算领域专业知识百科平台

图像显示框架十三——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

3. 设置释放回调函数(步骤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 状态​​,并被加入到空闲缓冲区集合中。随后通过回调通知生产者,从而完成一个“释放-申请-使用”的完整循环。
赞(0)
未经允许不得转载:网硕互联帮助中心 » 图像显示框架十三——BufferQueue的工作流程(基于Android 15源码分析)
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!