一.前言
上一篇中,基本说清楚了生产端的处理逻辑,这一篇,我们来梳理下消费端的逻辑
Consumer是什么时候来消费数据的?他是自己来拿的还是别人通知他的?
这篇文章就带着这些疑问来分析源码,再把概要流程图贴一下

二.监听器的回调过程解析
源码位置:
framework/native/libs/gui/BufferQueueConsumer.cpp
framework/native/libs/gui/include/gui/BufferQueueConsumer.h
framework/native/libs/gui/ConsumerBase.cpp
上一篇说到生产者将数据写完,把buffer还给buffer queue后,又是怎么来通知消费者的呢?
首先继续贴一下上一篇中最后的生产者将buffer还给BufferQueue的函数BufferQueueProducer::queueBuffer
// 生产者将已填充数据的缓冲区入队的核心函数
// 这是BufferQueueProducer中处理生产者提交已完成渲染的缓冲区的关键函数
status_t BufferQueueProducer::queueBuffer(int slot, // 缓冲区槽位索引
const QueueBufferInput &input, // 入队输入参数(包含时间戳、裁剪、变换等信息)
QueueBufferOutput *output) { // 入队输出参数(包含帧号、尺寸等信息)
ATRACE_CALL(); // 开始性能追踪
ATRACE_BUFFER_INDEX(slot); // 追踪特定缓冲区的操作
// 1. 从输入参数中解析各种信息
int64_t requestedPresentTimestamp; // 请求显示时间戳
bool isAutoTimestamp; // 是否自动生成时间戳
android_dataspace dataSpace; // 数据空间(颜色空间)
Rect crop(Rect::EMPTY_RECT); // 裁剪区域
int scalingMode; // 缩放模式
uint32_t transform; // 变换(旋转、镜像等)
uint32_t stickyTransform; // 粘性变换(持久化的变换)
sp<Fence> acquireFence; // 获取栅栏(生产者完成渲染的同步对象)
bool getFrameTimestamps = false; // 是否获取帧时间戳
// 将input中的各种参数解压到局部变量
input.deflate(&requestedPresentTimestamp, &isAutoTimestamp, &dataSpace,
&crop, &scalingMode, &transform, &acquireFence, &stickyTransform,
&getFrameTimestamps);
// 获取表面损坏区域和HDR元数据
const Region& surfaceDamage = input.getSurfaceDamage();
const HdrMetadata& hdrMetadata = input.getHdrMetadata();
// 2. 验证acquireFence是否有效(生产者必须提供有效的栅栏)
if (acquireFence == nullptr) {
BQ_LOGE("queueBuffer: fence is NULL");
return BAD_VALUE; // 返回参数错误
}
// 3. 创建FenceTime对象用于追踪栅栏时间
auto acquireFenceTime = std::make_shared<FenceTime>(acquireFence);
// 4. 验证缩放模式是否有效
switch (scalingMode) {
case NATIVE_WINDOW_SCALING_MODE_FREEZE:
case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
break; // 有效的缩放模式
default:
BQ_LOGE("queueBuffer: unknown scaling mode %d", scalingMode);
return BAD_VALUE; // 无效的缩放模式
}
// 5. 各种监听器和状态变量的声明
sp<IConsumerListener> frameAvailableListener; // 帧可用监听器
sp<IConsumerListener> frameReplacedListener; // 帧替换监听器
int callbackTicket = 0; // 回调票号(用于保证回调顺序)
uint64_t currentFrameNumber = 0; // 当前帧号
BufferItem item; // 缓冲区项(将添加到队列)
int connectedApi; // 连接的API类型
sp<Fence> lastQueuedFence; // 上一次入队的栅栏
// 6. 核心加锁范围(保护BufferQueue核心状态)
{
std::lock_guard<std::mutex> lock(mCore->mMutex);
// 6.1 检查BufferQueue是否被废弃
if (mCore->mIsAbandoned) {
BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
return NO_INIT;
}
// 6.2 检查生产者是否已连接
if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("queueBuffer: BufferQueue has no connected producer");
return NO_INIT;
}
// 6.3 验证槽位索引有效性
if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) {
BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
slot, BufferQueueDefs::NUM_BUFFER_SLOTS);
return BAD_VALUE;
}
// 6.4 验证缓冲区状态必须是DEQUEUED(否则生产者无权入队)
else if (!mSlots[slot].mBufferState.isDequeued()) {
BQ_LOGE("queueBuffer: slot %d is not owned by the producer "
"(state = %s)", slot, mSlots[slot].mBufferState.string());
return BAD_VALUE;
}
// 6.5 验证缓冲区是否已通过requestBuffer分配
else if (!mSlots[slot].mRequestBufferCalled) {
BQ_LOGE("queueBuffer: slot %d was queued without requesting "
"a buffer", slot);
return BAD_VALUE;
}
// 6.6 共享缓冲区模式特殊处理
// 如果刚启用共享缓冲区模式,标记第一个入队的缓冲区为共享缓冲区
if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
BufferQueueCore::INVALID_BUFFER_SLOT) {
mCore->mSharedBufferSlot = slot;
mSlots[slot].mBufferState.mShared = true;
}
// 6.7 记录详细的入队日志
BQ_LOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 " dataSpace=%d"
" validHdrMetadataTypes=0x%x crop=[%d,%d,%d,%d] transform=%#x scale=%s",
slot, mCore->mFrameCounter + 1, requestedPresentTimestamp, dataSpace,
hdrMetadata.validTypes, crop.left, crop.top, crop.right, crop.bottom,
transform,
BufferItem::scalingModeName(static_cast<uint32_t>(scalingMode)));
// 6.8 获取图形缓冲区并验证裁剪区域
const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
Rect croppedRect(Rect::EMPTY_RECT);
crop.intersect(bufferRect, &croppedRect);
if (croppedRect != crop) {
BQ_LOGE("queueBuffer: crop rect is not contained within the "
"buffer in slot %d", slot);
return BAD_VALUE;
}
// 6.9 如果数据空间为未知,使用消费者默认值
if (dataSpace == HAL_DATASPACE_UNKNOWN) {
dataSpace = mCore->mDefaultBufferDataSpace;
}
// 6.10 更新缓冲区状态:保存栅栏,改变状态为QUEUED
mSlots[slot].mFence = acquireFence;
mSlots[slot].mBufferState.queue(); // 状态:DEQUEUED → QUEUED
// 6.11 递增帧计数器并保存当前帧号
++mCore->mFrameCounter;
currentFrameNumber = mCore->mFrameCounter;
mSlots[slot].mFrameNumber = currentFrameNumber;
// 6.12 准备BufferItem(将添加到队列的数据结构)
item.mAcquireCalled = mSlots[slot].mAcquireCalled;
item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
item.mCrop = crop;
item.mTransform = transform &
~static_cast<uint32_t>(NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
item.mTransformToDisplayInverse =
(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) != 0;
item.mScalingMode = static_cast<uint32_t>(scalingMode);
item.mTimestamp = requestedPresentTimestamp;
item.mIsAutoTimestamp = isAutoTimestamp;
item.mDataSpace = dataSpace;
item.mHdrMetadata = hdrMetadata;
item.mFrameNumber = currentFrameNumber;
item.mSlot = slot;
item.mFence = acquireFence;
item.mFenceTime = acquireFenceTime;
// 6.13 判断缓冲区是否可丢弃(多种条件)
item.mIsDroppable = mCore->mAsyncMode || // 异步模式
(mConsumerIsSurfaceFlinger && mCore->mQueueBufferCanDrop) || // SurfaceFlinger消费者且允许丢弃
(mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) || // 传统缓冲区丢弃
(mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot); // 共享缓冲区模式
item.mSurfaceDamage = surfaceDamage;
item.mQueuedBuffer = true;
item.mAutoRefresh = mCore->mSharedBufferMode && mCore->mAutoRefresh; // 自动刷新(共享缓冲区)
item.mApi = mCore->mConnectedApi;
// 6.14 保存粘性变换
mStickyTransform = stickyTransform;
// 6.15 如果是共享缓冲区模式,缓存共享缓冲区数据以便重建BufferItem
if (mCore->mSharedBufferMode) {
mCore->mSharedBufferCache.crop = crop;
mCore->mSharedBufferCache.transform = transform;
mCore->mSharedBufferCache.scalingMode = static_cast<uint32_t>(scalingMode);
mCore->mSharedBufferCache.dataspace = dataSpace;
}
// 6.16 初始化输出参数
output->bufferReplaced = false;
// 6.17 队列处理逻辑
if (mCore->mQueue.empty()) {
// 队列为空:直接添加缓冲区项
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener; // 通知消费者有新帧可用
} else {
// 队列不为空:检查是否需要替换最后一帧
const BufferItem& last = mCore->mQueue.itemAt(mCore->mQueue.size() - 1);
if (last.mIsDroppable) {
// 最后一帧可丢弃:替换它
if (!last.mIsStale) {
// 释放被替换的缓冲区状态
mSlots[last.mSlot].mBufferState.freeQueued();
// 共享缓冲区模式特殊处理
if (!mCore->mSharedBufferMode &&
mSlots[last.mSlot].mBufferState.isFree()) {
mSlots[last.mSlot].mBufferState.mShared = false; // 不再共享
}
// 如果不是共享缓冲区,将其加入空闲缓冲区列表
if (!mSlots[last.mSlot].mBufferState.isShared()) {
mCore->mActiveBuffers.erase(last.mSlot);
mCore->mFreeBuffers.push_back(last.mSlot);
output->bufferReplaced = true; // 标记缓冲区被替换
}
}
// 合并损坏区域(将被丢弃帧的损坏区域合并到新帧)
if (last.mSurfaceDamage.bounds() == Rect::INVALID_RECT ||
item.mSurfaceDamage.bounds() == Rect::INVALID_RECT) {
item.mSurfaceDamage = Region::INVALID_REGION;
} else {
item.mSurfaceDamage |= last.mSurfaceDamage;
}
// 覆盖可丢弃的缓冲区
mCore->mQueue.editItemAt(mCore->mQueue.size() - 1) = item;
frameReplacedListener = mCore->mConsumerListener; // 通知消费者帧被替换
} else {
// 最后一帧不可丢弃:添加到队列末尾
mCore->mQueue.push_back(item);
frameAvailableListener = mCore->mConsumerListener; // 通知消费者有新帧可用
}
}
// 6.18 更新BufferQueue状态
mCore->mBufferHasBeenQueued = true; // 标记已有缓冲区入队
mCore->mDequeueCondition.notify_all(); // 唤醒等待出队的生产者
mCore->mLastQueuedSlot = slot; // 记录最后入队的槽位
// 6.19 设置输出参数
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
// 6.20 性能追踪和占用率追踪
ATRACE_INT(mCore->mConsumerName.c_str(), static_cast<int32_t>(mCore->mQueue.size()));
#ifndef NO_BINDER
mCore->mOccupancyTracker.registerOccupancyChange(mCore->mQueue.size());
#endif
// 6.21 获取回调票号(保证回调顺序)
callbackTicket = mNextCallbackTicket++;
VALIDATE_CONSISTENCY(); // 验证内部一致性
// 6.22 保存局部状态供锁外使用
connectedApi = mCore->mConnectedApi;
lastQueuedFence = std::move(mLastQueueBufferFence);
mLastQueueBufferFence = std::move(acquireFence);
mLastQueuedCrop = item.mCrop;
mLastQueuedTransform = item.mTransform;
} // 自动锁作用域结束(释放核心锁)
// 7. 如果不是SurfaceFlinger消费者,清除GraphicBuffer引用
// SurfaceFlinger在同一进程,不需要通过Binder传递,可以保留引用
if (!mConsumerIsSurfaceFlinger) {
item.mGraphicBuffer.clear();
}
// 8. 更新帧事件历史
nsecs_t postedTime = systemTime(SYSTEM_TIME_MONOTONIC);
NewFrameEventsEntry newFrameEventsEntry = {
currentFrameNumber,
postedTime,
requestedPresentTimestamp,
std::move(acquireFenceTime)
};
addAndGetFrameTimestamps(&newFrameEventsEntry,
getFrameTimestamps ? &output->frameTimestamps : nullptr);
// 9. 回调通知(持有回调锁但不持有核心锁)
{
std::unique_lock<std::mutex> lock(mCallbackMutex);
// 9.1 等待轮到自己进行回调(确保回调顺序)
while (callbackTicket != mCurrentCallbackTicket) {
mCallbackCondition.wait(lock);
}
// 9.2 执行回调
if (frameAvailableListener != nullptr) {
frameAvailableListener->onFrameAvailable(item); // 通知新帧可用
} else if (frameReplacedListener != nullptr) {
frameReplacedListener->onFrameReplaced(item); // 通知帧被替换
}
// 9.3 递增当前回调票号,唤醒等待的线程
++mCurrentCallbackTicket;
mCallbackCondition.notify_all();
}
// 10. EGL API的特殊处理:等待上一个入队的栅栏
if (connectedApi == NATIVE_WINDOW_API_EGL) {
// 这里等待允许排队两个完整的缓冲区,但不允许第三个
// 在帧时间变化的情况下,这种设计在延迟和吞吐量之间做了一个小的权衡,偏向于延迟
lastQueuedFence->waitForever("Throttling EGL Production");
}
return NO_ERROR; // 成功返回
}
1.上一篇介绍生产者写完数据调用了BufferQueueProducer::queueBuffer将buffer写入队列中
2.然后在queueBuffer的函数中的9.2步骤调用了frameAvailableListener->onFrameAvailable(item);此处就是用来进行通知消费者的回调
3.继续查看代码frameAvailableListener是mCore->mConsumerListener,也就是frameAvailableListener = mCore->mConsumerListener;
- mCore即为BufferQueueCore, BufferQueueCore中有成员 sp mConsumerListener

5.BufferQueueCore::mConsumerListener是在哪里设置的,是什么时候设置的
①.BufferQueueConsumer::connect中设置

②.在disconnect中移除

前面介绍过,BufferQueueProducer和BufferQueueConsumer是BufferQueueCore的友元类,所以可以直接访问其私有成员
6.BufferQueueConsumer::connect、disconnect是在哪里调用的?
我们来看下BufferQueueConsumer.h中的代码,直接搜索connect和disconnect

①.consumerConnect中调用了connect函数
②.consumerDisconnect中调用了disconnect函数
7.谁调用了consumerConnect?
其实在ConsumerBase类中调用的,如下

①.可以看出来在ConsumerBase的构造函数中调用了mConsumer->consumerConnect(proxy, controlledByApp);
②.这里的mConsumer是BLASTBufferQueue中创建BLASTBufferItemConsumer时一路设置下来的BufferQueueConsumer对象;
8.设置的是Listener是从哪里传递过来的?
①.继承关系图

②.BLASTBufferQueue的构造函数中:

9.所以根据上述的流程分析,BufferQueueCore::mConsumerListener设置的就是ConsumerBase的实例
10.因此,frameAvailableListener->onFrameAvailable(item)回调时,会走到ConsumerBase::onFrameAvailable中