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

一.前言

上一篇中,基本说清楚了生产端的处理逻辑,这一篇,我们来梳理下消费端的逻辑

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;

  1. 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中

相关推荐
_F_y2 小时前
MySQL用户管理
android·mysql·adb
TheNextByte12 小时前
如何将照片从计算机传输到Android /iPhone
android·gitee·iphone
sun0077002 小时前
Android 默认的日志记录方式
android
瓦特what?2 小时前
C++编程防坑指南(小说版)
android·c++·kotlin
独处东汉4 小时前
freertos开发空气检测仪之输入子系统按键驱动测试
android·java·数据库
m0_748229994 小时前
Laravel3.x:回顾经典框架的早期特性
android
阿俊-全栈开发4 小时前
CRMEB 单商户对接汇付支付完整实现
android
weixin_440784114 小时前
OkHttp使用指南
android·java·okhttp
Xxtaoaooo5 小时前
React Native 跨平台鸿蒙开发实战:调试与真机测试全流程
android·react native·harmonyos