Android 16 显示系统 | 从View 到屏幕系列 - 6 | 提交 GraphicBuffer 到 SurfaceFlinger

前面我们了解了 App 的绘制流程:

  1. dequeueBuffer :从 BLASTQueueBufferdequeue 一块 GraphicBuffer
  2. draw :通过 Skia/OpenGL 绘制 UI 到 GraphicBuffer
  3. queueBuffer : 把绘制完成的 GraphicBuffer 插入 BLASTBufferQueue

我们接下来继续分析,我们看 queuebuffer 之后的,消费者是如何工作的

rust 复制代码
// frameworks/native/libs/gui/BufferQueueProducer.cpp
status_t BufferQueueProducer::queueBuffer(int slot,
        const QueueBufferInput &input, QueueBufferOutput *output) {
        ...
        item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
        ...
        // mCore->mQueue 在 BLastBufferQueue 已经详细介绍过
        // 把一块 GraphicBuffer 插入了队列
        mCore->mQueue.push_back(item);
        // 拿到 mConsumerListener
        frameAvailableListener = mCore->mConsumerListener;
        ...
        // 通知消费者消费 Buffer
        frameAvailableListener->onFrameAvailable(item);
        
}

BufferQueueProducer::queueBuffer 中:

  1. GraphicBuffer 插入 BufferQueueCore 的队列中
  2. frameAvailableListener 执行 onFrameAvailable通知消费者来消费这一块 Buffer

那么这个 mCore->mConsumerListener 指的是哪个对象呢?又是什么时候赋值的呢? 其实在之前的章节已经提到了,大家不熟悉的话可以回顾 BLASTBufferQueue 那一章节:juejin.cn/post/752723... ,这里我直接说结论: mCore->mConsumerListener 就是 BLASTBufferQueue 本身

接下来继续分析 BLASTBufferQueue::onFrameAvailable

scss 复制代码
//frameworks/native/libs/gui/BLASTBufferQueue.cpp
status_t BLASTBufferQueue::acquireNextBufferLocked(
        const std::optional<SurfaceComposerClient::Transaction*> transaction) {
    // 初始化一个 Transaction
    SurfaceComposerClient::Transaction localTransaction;
    SurfaceComposerClient::Transaction* t = &localTransaction;

   
    BufferItem bufferItem;
    // 获取 Available 的 BufferItem
    status_t status =
            mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
    
    auto buffer = bufferItem.mGraphicBuffer;
    ...
    Rect crop = computeCrop(bufferItem);
    mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
                           bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
                           bufferItem.mScalingMode, crop);

    auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
    sp<Fence> fence =
            bufferItem.mFence ? sp<Fence>::make(bufferItem.mFence->dup()) : Fence::NO_FENCE;

    // 开始构建 Transaction
    // 传入 buffer 等一系列参数
    // 注意这里也传入了 releaseBufferCallback 的回调,当 SurfaceFlinger 合成完成之后,会回调这个方法
    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(makeTransactionCallbackThunk(), nullptr);

    mSurfaceControlsWithPendingCallback.push(mSurfaceControl);

    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);
    }
    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);
    }
    if (com_android_graphics_libgui_flags_apply_picture_profiles() &&
        bufferItem.mPictureProfileHandle.has_value()) {
        t->setPictureProfileHandle(mSurfaceControl, *bufferItem.mPictureProfileHandle);
        // The current picture profile must be maintained in case the BBQ gets its
        // SurfaceControl switched out.
        mPictureProfileHandle = bufferItem.mPictureProfileHandle;
        // Clear out the picture profile if the requestor has asked for it to be cleared
        if (mPictureProfileHandle == PictureProfileHandle::NONE) {
            mPictureProfileHandle = std::nullopt;
        }
    }

    // Drop stale frame timeline infos
    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();
    }
    // 把 BLATSBufferQueue 内部 pending 的事物合并到一起,确保所有的变更都能同步提交给 SurfaceFlinger
    mergePendingTransactions(t, bufferItem.mFrameNumber);
    if (applyTransaction) {
        // 通过 apply 提交到 SurfaceFlinger
        t->setApplyToken(mApplyToken).apply(false, true);
        mAppliedLastTransaction = true;
        mLastAppliedFrameNumber = bufferItem.mFrameNumber;
    } else {
        t->setBufferHasBarrier(mSurfaceControl, mLastAppliedFrameNumber);
        mAppliedLastTransaction = false;
    }
    return OK;
}

acquireNextBufferLocked 方法中:

  1. 通过 mBufferItemConsumer->acquireBuffer 获取一个 BufferItem 对象,这个 BufferItem 对象内部持有 GraphicBuffer
  2. 初始化一个 SurfaceComposerClient::Transaction 事物,这里解释一下什么是 TransactionTransaction 用于封装一组对 Surface 的状态修改,并且一次原子性地提交SurfaceFlinger 进行处理,比如设置 Buffer,设置大小,透明度等。
  3. SurfaceComposerClient::Transaction 进行一系列的设置
  4. 合并已经 pending 的 Transaction,最后通过 apply 一次性提交到 SurfaceFlinger

这里重点说一下 mBufferItemConsumer->acquireBuffer 这个方法,从 BufferQueueCoremQueue 中拿到一块 BufferItem

rust 复制代码
status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer,
        nsecs_t expectedPresent, uint64_t maxFrameNumber) {
    ATRACE_CALL();

    int numDroppedBuffers = 0;
    sp<IProducerListener> listener;
    {
        std::unique_lock<std::mutex> lock(mCore->mMutex);
        ...
        // 遍历 BufferQueueCore 的 mQueue
        BufferQueueCore::Fifo::iterator front(mCore->mQueue.begin());
        if (expectedPresent != 0 && !mCore->mQueue.empty()) {
            while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) {
                const BufferItem& bufferItem(mCore->mQueue[1]);

                // 丢弃一些过期的 buffer
                nsecs_t desiredPresent = bufferItem.mTimestamp;
                if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
                        desiredPresent > expectedPresent) {
                    // This buffer is set to display in the near future, or
                    // desiredPresent is garbage. Either way we don't want to drop
                    // the previous buffer just to get this on the screen sooner.
                    BQ_LOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%"
                            PRId64 " (%" PRId64 ") now=%" PRId64,
                            desiredPresent, expectedPresent,
                            desiredPresent - expectedPresent,
                            systemTime(CLOCK_MONOTONIC));
                    break;
                }


                if (!front->mIsStale) {
                    // Front buffer is still in mSlots, so mark the slot as free
                    mSlots[front->mSlot].mBufferState.freeQueued();

                    // After leaving shared buffer mode, the shared buffer will
                    // still be around. Mark it as no longer shared if this
                    // operation causes it to be free.
                    if (!mCore->mSharedBufferMode &&
                            mSlots[front->mSlot].mBufferState.isFree()) {
                        mSlots[front->mSlot].mBufferState.mShared = false;
                    }

                    // Don't put the shared buffer on the free list
                    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);
                // 拿到队列的头部 BufferItem
                front = mCore->mQueue.begin();
            }
        }

        // 如果是共享内存
        if (sharedBufferAvailable && mCore->mQueue.empty()) {
            // make sure the buffer has finished allocating before acquiring it
            mCore->waitWhileAllocatingLocked(lock);

            slot = mCore->mSharedBufferSlot;

            // Recreate the BufferItem for the shared buffer from the data that
            // was cached when it was last queued.
            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;
        } else if (acquireNonDroppableBuffer && front->mIsDroppable) {
            BQ_LOGV("acquireBuffer: front buffer is not droppable");
            return NO_BUFFER_AVAILABLE;
        } else {
            // 如果是非共享内存,则把 mQueue 的头部可用的 BufferItem 给 outBuffer
            slot = front->mSlot;
            *outBuffer = *front;
        }

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

        if (!outBuffer->mIsStale) {
            mSlots[slot].mAcquireCalled = true;
            // Don't decrease the queue count if the BufferItem wasn't
            // previously in the queue. This happens in shared buffer mode when
            // the queue is empty and the BufferItem is created above.
            if (mCore->mQueue.empty()) {
                mSlots[slot].mBufferState.acquireNotInQueue();
            } else {
                // 更新 BufferItem 的状态为 ACQUIRED
                mSlots[slot].mBufferState.acquire();
            }
            mSlots[slot].mFence = Fence::NO_FENCE;
        }

        // If the buffer has previously been acquired by the consumer, set
        // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
        // on the consumer side
        if (outBuffer->mAcquireCalled) {
            outBuffer->mGraphicBuffer = nullptr;
        }

        mCore->mQueue.erase(front);

        // We might have freed a slot while dropping old buffers, or the producer
        // may be blocked waiting for the number of buffers in the queue to
        // decrease.
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
        mCore->notifyBufferReleased();
#else
        mCore->mDequeueCondition.notify_all();
#endif

        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();
    }

    if (listener != nullptr) {
        for (int i = 0; i < numDroppedBuffers; ++i) {
            listener->onBufferReleased();
        }
    }

    return NO_ERROR;
}

acquireBuffer 主要就是弹出 BufferQueueCoremQueue 的头部 BufferItem,并将 这个BufferItem 写入 outBuffer

最后,我们再看一下 SurfaceComposerClient::Transactionapply 方法

scss 复制代码
status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) {
    ...
    // 拿到 SurfaceFlinger 的 Binder 句柄
    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
    // Binder Call, 跨进程调用 SurfaceFlinger 的 setTransactionState 方法
    status_t binderStatus = sf->setTransactionState(std::move(mState));
    mState.mId = generateId();

    // Clear the current states and flags
    clear();

    if (synchronous && binderStatus == OK) {
        syncCallback->wait();
    }

    if (mState.mLogCallPoints) {
        ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", getId());
    }

    mStatus = NO_ERROR;
    return binderStatus;
}

这里就是一个非常典型的 Binder Call 了,

  1. 拿到 Binder Server 的句柄,这里的 Binder Server 是 SurfaceFlinger
  2. 拿到句柄之后就可以直接调用 Binder Server 的方法 setTransactionState, 并把数据作为参数传递过去。Binder 封装了底层的 IPC 通信细节,使得调用远程(跨进程)对象的方法像调用本地(本进程)对象的方法一样。

总结一下,到这里为止,

  1. App 渲染后的 GraphicBuffer 插入 BLASTBufferQueue
  2. BLASTBufferQueue 通过 Binder IPC 把 Buffer 提交给SurfaceFlinger

下一篇了解 SurfaceFlinger 如何处理从 BLASTBufferQueue 提交过来的 Buffer。

相关推荐
zandy101140 分钟前
衡石科技HENGSHI SENSE 6.0:技术架构全面革新,开启智能分析新纪元
科技·架构
文火冰糖的硅基工坊1 小时前
[硬件电路-111]:滤波的分类:模拟滤波与数字滤波; 无源滤波与有源滤波;低通、带通、带阻、高通滤波;时域滤波与频域滤波;低价滤波与高阶滤波。
嵌入式硬件·架构·信号处理·电路·跨学科融合
AirDroid_cn1 小时前
手机防沉迷新招:安卓手机如何成为管理iPhone的遥控器?
android·ios·智能手机·iphone·ipad
DemonAvenger2 小时前
Go网络安全编程:TLS/SSL实践指南
网络协议·架构·go
来来走走2 小时前
Flutter开发 StatelessWidget与StatefulWidget基本了解
android·flutter
清霜之辰3 小时前
Android 区块链 + CleanArchitecture + MVI 架构实践
android·架构·区块链·mvi·architecture·clean
毛小茛4 小时前
认识微服务
微服务·云原生·架构
洛卡卡了5 小时前
“改个配置还要发版?”搞个配置后台不好吗
前端·后端·架构
深盾安全6 小时前
Android SO导出符号的深度解析与安全防护指南
android