当前位置: 首页 > news >正文

Android 15 View 绘制触发 BufferQueue / BLAST / SurfaceFlinger 上屏流程

本文通过AI 基于 android-15.0.0_r17 整理,并跟源码做了比对校准,请参考。

普通 View 硬件加速绘制时,Java 层不会直接 Surface.lockCanvas();而是 ViewRootImpl 触发 ThreadedRenderer,RenderThread 通过 EGL/Skia/Vulkan/OpenGL 的 ANativeWindow 路径 dequeue buffer → GPU 绘制 → queue buffer。
Android 15 应用窗口默认走 BLASTBufferQueue,Buffer 被 BBQ 在 App 进程 acquire 后封装进 SurfaceControl.Transaction,提交给 SurfaceFlinger。
SurfaceFlinger 在事务/VSync 合成阶段 latch 该 buffer 并送显。
Android 官方也明确描述 BufferQueue 的基本模型:Producer dequeueBuffer() 获取 buffer,填充后 queueBuffer(),Consumer acquireBuffer() 后使用,完成后 releaseBuffer()。
BLAST 架构下,BufferQueue 从 SurfaceFlinger 侧转移到业务进程,buffer 和图层属性通过 Transaction 一起提交给 SurfaceFlinger。 [source.and…google.cn] [juejin.cn], [jianshu.com]

1. 总体调用链

1View.invalidate()/ requestLayout()23ViewRootImpl.scheduleTraversals()45Choreographer CALLBACK_TRAVERSAL,等待下一帧 VSYNC67ViewRootImpl.doTraversal()89ViewRootImpl.performTraversals()1011performMeasure / performLayout / performDraw1213ViewRootImpl.draw()1415ThreadedRenderer.draw()1617updateRootDisplayList()// UIThread 构建 RenderNode / DisplayList1819syncAndDrawFrame()// 同步给 RenderThread2021RenderThread / HWUI / Skia2223ANativeWindow.dequeueBuffer()2425Surface::dequeueBuffer()2627BufferQueueProducer::dequeueBuffer()2829Gralloc 分配 / 复用 GraphicBuffer3031GPU 绘制到 GraphicBuffer3233eglSwapBuffers / queueBuffer3435Surface::queueBuffer()3637BufferQueueProducer::queueBuffer()3839BLASTBufferQueue::onFrameAvailable()4041BLASTBufferQueue acquire buffer4243SurfaceControl.Transaction.setBuffer()4445Transaction.apply()4647SurfaceFlinger 接收事务4849SurfaceFlinger latch buffer / compose5051HWC / Display 显示

2. View 层:invalidate / requestLayout 如何触发绘制

2.1 View.invalidate()

路径:
1 frameworks/base/core/java/android/view/View.java
关键逻辑:
1 public void invalidate() {
2 invalidate(true);
3 }
4
5 public void invalidate(boolean invalidateCache) {
6 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop,
7 invalidateCache, true);
8 }
9
10 void invalidateInternal(int l, int t, int r, int b,
11 boolean invalidateCache, boolean fullInvalidate) {
12 if (skipInvalidate()) {
13 return;
14 }
15
16 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN
17 || (fullInvalidate && isOpaque() != mLastIsOpaque)) {
18
19 if (fullInvalidate) {
20 mLastIsOpaque = isOpaque();
21 mPrivateFlags &= ~PFLAG_DRAWN;
22 }
23
24 mPrivateFlags |= PFLAG_DIRTY;
25
26 final AttachInfo ai = mAttachInfo;
27 final ViewParent p = mParent;
28
29 if (p != null && ai != null) {
30 final Rect damage = ai.mTmpInvalRect;
31 damage.set(l, t, r, b);
32 p.invalidateChild(this, damage);
33 }
34 }
35 }
这一步只是把 View 区域标记为 dirty,并向父节点传播,最终会到 ViewRootImpl.invalidateChildInParent(),再触发 traversal。ViewRootImpl 是 View 树与窗口 / Surface 系统之间的桥梁,负责 measure、layout、draw。 [juejin.cn], [jianshu.com]

2.2 View.requestLayout()

路径:
1 frameworks/base/core/java/android/view/View.java
核心含义:
1 public void requestLayout() {
2 if (mMeasureCache != null) {
3 mMeasureCache.clear();
4 }
5
6 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) {
7 ViewRootImpl viewRoot = getViewRootImpl();
8 if (viewRoot != null && viewRoot.isInLayout()) {
9 if (!viewRoot.requestLayoutDuringLayout(this)) {
10 return;
11 }
12 }
13 mAttachInfo.mViewRequestingLayout = this;
14 }
15
16 mPrivateFlags |= PFLAG_FORCE_LAYOUT;
17 mPrivateFlags |= PFLAG_INVALIDATED;
18
19 if (mParent != null && !mParent.isLayoutRequested()) {
20 mParent.requestLayout();
21 }
22
23 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) {
24 mAttachInfo.mViewRequestingLayout = null;
25 }
26 }
最终也会进入 ViewRootImpl.requestLayout()。

3. ViewRootImpl:调度下一帧 Traversal

路径:
1 frameworks/base/core/java/android/view/ViewRootImpl.java
3.1 requestLayout()
1 @Override
2 public void requestLayout() {
3 if (!mHandlingLayoutInLayoutRequest) {
4 checkThread();
5 mLayoutRequested = true;
6 scheduleTraversals();
7 }
8 }
checkThread() 用来保证只有创建 ViewRootImpl 的线程能操作该 View 树,这也是常见 “Only the original thread that created a view hierarchy can touch its views” 的来源。 [blog.csdn.net]

3.2 scheduleTraversals()

1 void scheduleTraversals() {
2 if (!mTraversalScheduled) {
3 mTraversalScheduled = true;
4
5 mTraversalBarrier =
6 mHandler.getLooper().getQueue().postSyncBarrier();
7
8 mChoreographer.postCallback(
9 Choreographer.CALLBACK_TRAVERSAL,
10 mTraversalRunnable,
11 null);
12
13 notifyRendererOfFramePending();
14 pokeDrawLockIfNeeded();
15 }
16 }
这里做了几件关键事情:
1.设置 mTraversalScheduled = true,避免重复调度。
2.往主线程 MessageQueue 插入同步屏障。
3.向 Choreographer 注册 CALLBACK_TRAVERSAL。
4.等下一次 VSYNC 到来后执行 traversal。
Choreographer 驱动 ViewRootImpl 在 VSYNC 节奏下执行 measure/layout/draw,相关机制在 Android 渲染分析资料中也有一致描述。 [blog.csdn.net], [zhuanlan.zhihu.com]

3.3 TraversalRunnable

1 final class TraversalRunnable implements Runnable {
2 @Override
3 public void run() {
4 doTraversal();
5 }
6 }

3.4 doTraversal()

1 void doTraversal() {
2 if (mTraversalScheduled) {
3 mTraversalScheduled = false;
4
5 mHandler.getLooper().getQueue()
6 .removeSyncBarrier(mTraversalBarrier);
7
8 performTraversals();
9 }
10 }

4. ViewRootImpl.performTraversals:measure / layout / draw

路径:
1 frameworks/base/core/java/android/view/ViewRootImpl.java
核心结构可以抽象为:
1 private void performTraversals() {
2 final View host = mView;
3
4 // 1. 与 WMS relayout,获得 SurfaceControl / BLAST surface
5 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
6
7 // 2. 必要时 measure
8 if (mLayoutRequested) {
9 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
10 }
11
12 // 3. 必要时 layout
13 if (didLayout) {
14 performLayout(lp, mWidth, mHeight);
15 }
16
17 // 4. draw
18 if (!cancelDraw && !newSurface) {
19 performDraw();
20 }
21 }
在 Android 15 应用窗口中,relayoutWindow() 之后会通过 getOrCreateBLASTSurface() 创建 / 更新 BLASTBufferQueue Surface,这一点在 Android 12+ BLAST 机制分析中也有对应源码路径说明。 [jianshu.com], [juejin.cn]

5. ViewRootImpl 创建 BLAST Surface

路径:
1 frameworks/base/core/java/android/view/ViewRootImpl.java
关键方法:
1 Surface getOrCreateBLASTSurface() {
2 if (!mSurfaceControl.isValid()) {
3 return null;
4 }
5
6 Surface ret = null;
7
8 if (mBlastBufferQueue == null) {
9 mBlastBufferQueue = new BLASTBufferQueue(
10 mTag,
11 mSurfaceControl,
12 mSurfaceSize.x,
13 mSurfaceSize.y,
14 mWindowAttributes.format);
15
16 ret = mBlastBufferQueue.createSurface();
17 } else {
18 mBlastBufferQueue.update(
19 mSurfaceControl,
20 mSurfaceSize.x,
21 mSurfaceSize.y,
22 mWindowAttributes.format);
23 }
24
25 return ret;
26 }
这一步的意义:
1 SurfaceControl // SurfaceFlinger 里的 Layer 句柄
2 ↓
3 BLASTBufferQueue // App 进程本地 BufferQueue
4 ↓
5 Surface // 给 HWUI / EGL / ANativeWindow 使用
BLASTBufferQueue 把 BufferQueue 放在 App 进程侧,SurfaceFlinger 不再直接作为该 BufferQueue 的 Consumer,而是接收 App 通过 Transaction 提交的 buffer。 [juejin.cn], [jianshu.com]

6. performDraw / draw:进入硬件渲染

路径:
1 frameworks/base/core/java/android/view/ViewRootImpl.java
6.1 performDraw()
1 private void performDraw() {
2 boolean canUseAsync = draw(fullRedrawNeeded);
3 }
6.2 draw()
普通 View 默认硬件加速,核心会走:
1 private boolean draw(boolean fullRedrawNeeded) {
2 Surface surface = mSurface;
3
4 if (!surface.isValid()) {
5 return false;
6 }
7
8 final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
9
10 if (renderer != null && renderer.isEnabled()) {
11 renderer.draw(mView, mAttachInfo, this);
12 } else {
13 drawSoftware(surface, mAttachInfo, xOffset, yOffset,
14 scalingRequired, dirty);
15 }
16
17 return true;
18 }
注意:
硬件加速路径:ThreadedRenderer.draw(),不会调用 Java Surface.lockCanvas()。
软件绘制路径:drawSoftware() 会调用 mSurface.lockCanvas(dirty) 和 unlockCanvasAndPost()。
软件绘制中 Surface.lockCanvas() / unlockCanvasAndPost() 的路径和 BufferQueue dequeue / queue 对应,这在 Canvas 绘制源码分析中也有相同流程描述。 [cloud.tencent.com]

7. ThreadedRenderer:UIThread 构建 DisplayList,RenderThread 真正绘制 Buffer 路径:

1 frameworks/base/core/java/android/view/ThreadedRenderer.java
关键结构:
1 void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
2 attachInfo.mIgnoreDirtyState = true;
3
4 final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
5 choreographer.mFrameInfo.markDrawStart();
6
7 updateRootDisplayList(view, callbacks);
8
9 attachInfo.mIgnoreDirtyState = false;
10
11 int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
12 }
7.1 updateRootDisplayList()
1 private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
2 updateViewTreeDisplayList(view);
3
4 if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
5 RecordingCanvas canvas = mRootNode.beginRecording(
6 mSurfaceWidth, mSurfaceHeight);
7
8 try {
9 callbacks.onPreDraw(canvas);
10
11 canvas.drawRenderNode(view.updateDisplayListIfDirty());
12
13 callbacks.onPostDraw(canvas);
14 } finally {
15 mRootNode.endRecording();
16 }
17 }
18 }
这一步发生在 UIThread:
1 View.draw()
2 ↓
3 RenderNode / DisplayList 记录绘制命令
并不直接把像素写进 buffer。

7.2 syncAndDrawFrame()
1 private int syncAndDrawFrame(FrameInfo frameInfo) {
2 return nSyncAndDrawFrame(mNativeProxy, frameInfo.frameInfo,
3 frameInfo.frameInfo.length);
4 }
JNI 后进入 native HWUI:
1 android_view_ThreadedRenderer_syncAndDrawFrame
2 ↓
3 RenderProxy::syncAndDrawFrame()
4 ↓
5 DrawFrameTask::drawFrame()
6 ↓
7 CanvasContext::draw()
8 ↓
9 SkiaOpenGLPipeline / SkiaVulkanPipeline
10 ↓
11 dequeue buffer
12 ↓
13 GPU render
14 ↓
15 queue buffer / swap buffers
ThreadedRenderer 的核心职责是:UI 线程构建 DisplayList,RenderThread 负责把 DisplayList 同步并渲染到 Surface 对应的 buffer。相关资料也指出硬件渲染分为 DisplayList 构建和 RenderThread 渲染两个阶段。 [blog.csdn.net]

8. Surface / ANativeWindow:dequeueBuffer 锁定可绘制 buffer

路径:
1 frameworks/native/libs/gui/Surface.cpp
8.1 ANativeWindow hook
1 int Surface::hook_dequeueBuffer(
2 ANativeWindow* window,
3 ANativeWindowBuffer** buffer,
4 int* fenceFd) {
5 Surface* c = getSelf(window);
6 return c->dequeueBuffer(buffer, fenceFd);
7 }
8
9 int Surface::hook_queueBuffer(
10 ANativeWindow* window,
11 ANativeWindowBuffer* buffer,
12 int fenceFd) {
13 Surface* c = getSelf(window);
14 return c->queueBuffer(buffer, fenceFd);
15 }
EGL / Vulkan / HWUI 看到的是 ANativeWindow,最终回调到 Surface::dequeueBuffer() 和 Surface::queueBuffer()。

8.2 Surface::dequeueBuffer()
核心逻辑:
1 int Surface::dequeueBuffer(
2 ANativeWindowBuffer** buffer,
3 int* fenceFd) {
4 Mutex::Autolock lock(mMutex);
5
6 int buf = -1;
7 sp fence;
8
9 status_t result = mGraphicBufferProducer->dequeueBuffer(
10 &buf,
11 &fence,
12 reqWidth,
13 reqHeight,
14 reqFormat,
15 reqUsage,
16 &mBufferAge,
17 enableFrameTimestamps ? &mFrameEventHistory : nullptr);
18
19 if (result < 0) {
20 return result;
21 }
22
23 if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION)
24 || gbuf == nullptr) {
25 result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);
26 if (result != NO_ERROR) {
27 mGraphicBufferProducer->cancelBuffer(buf, fence);
28 return result;
29 }
30 }
31
32 if (fence != nullptr && fence->isValid()) {
33 *fenceFd = fence->dup();
34 } else {
35 *fenceFd = -1;
36 }
37
38 *buffer = gbuf.get();
39 return OK;
40 }
含义:
1 Surface
2 调 IGraphicBufferProducer.dequeueBuffer()
3 ↓
4 BufferQueueProducer 找一个可用 slot
5 ↓
6 必要时分配 GraphicBuffer
7 ↓
8 返回 ANativeWindowBuffer 给 HWUI / EGL
官方 BufferQueue 文档也描述了生产方通过 dequeueBuffer() 请求可用 buffer,并指定宽高、格式和 usage。 [source.and…google.cn]

9. BufferQueueProducer:真正管理 buffer slot 状态

路径:
1 frameworks/native/libs/gui/BufferQueueProducer.cpp
9.1 dequeueBuffer()
核心结构:
1 status_t BufferQueueProducer::dequeueBuffer(
2 int* outSlot,
3 spandroid::Fence* outFence,
4 uint32_t width,
5 uint32_t height,
6 PixelFormat format,
7 uint64_t usage,
8 uint64_t* outBufferAge,
9 FrameEventHistoryDelta* outTimestamps) {
10 std::unique_lockstd::mutex lock(mCore->mMutex);
11
12 int found = BufferQueueCore::INVALID_BUFFER_SLOT;
13
14 status_t status = waitForFreeSlotThenRelock(
15 FreeSlotCaller::Dequeue,
16 &found);
17
18 if (status != NO_ERROR) {
19 return status;
20 }
21
22 *outSlot = found;
23
24 mSlots[found].mBufferState.dequeue();
25
26 if (bufferNeedsReallocation) {
27 returnFlags |= BUFFER_NEEDS_REALLOCATION;
28 }
29
30 return returnFlags;
31 }
buffer 状态变化:
1 FREE → DEQUEUED
BufferQueue 的常见状态流转是:
1 FREE → DEQUEUED → QUEUED → ACQUIRED → FREE
该状态流转与 Android BufferQueue 工作流程资料一致。 [cnblogs.com], [zhuanlan.zhihu.com]

9.2 queueBuffer()
1 status_t BufferQueueProducer::queueBuffer(
2 int slot,
3 const QueueBufferInput& input,
4 QueueBufferOutput* output) {
5 sp frameAvailableListener;
6 BufferItem item;
7
8 {
9 std::unique_lockstd::mutex lock(mCore->mMutex);
10
11 mSlots[slot].mBufferState.queue();
12
13 item.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
14 item.mFence = acquireFence;
15 item.mSlot = slot;
16 item.mFrameNumber = currentFrameNumber;
17
18 mCore->mQueue.push_back(item);
19
20 frameAvailableListener = mCore->mConsumerListener;
21 }
22
23 if (frameAvailableListener != nullptr) {
24 frameAvailableListener->onFrameAvailable(item);
25 }
26
27 return NO_ERROR;
28 }
buffer 状态变化:
1 DEQUEUED → QUEUED
这一步就是“通知 buffer 可显示”的第一阶段:Producer 已经把绘制完成的 buffer queue 进 BufferQueue,并通知 Consumer。

10. BLASTBufferQueue:App 进程本地消费 BufferQueue,并通过 Transaction 交给 SurfaceFlinger

路径:
1 frameworks/native/libs/gui/BLASTBufferQueue.cpp
10.1 构造函数
1 BLASTBufferQueue::BLASTBufferQueue(
2 const std::string& name,
3 const sp& surface,
4 int width,
5 int height,
6 int32_t format)
7 : mSurfaceControl(surface),
8 mSize(width, height),
9 mRequestedSize(mSize),
10 mFormat(format) {
11
12 createBufferQueue(&mProducer, &mConsumer);
13
14 mProducer->setDequeueTimeout(
15 std::numeric_limits<int64_t>::max());
16
17 mProducer->setMaxDequeuedBufferCount(2);
18
19 mBufferItemConsumer = new BLASTBufferItemConsumer(
20 mConsumer,
21 GraphicBuffer::USAGE_HW_COMPOSER |
22 GraphicBuffer::USAGE_HW_TEXTURE,
23 1,
24 false);
25
26 mBufferItemConsumer->setFrameAvailableListener(this);
27 mBufferItemConsumer->setBufferFreedListener(this);
28 }
这里创建:
1 BufferQueueProducer
2 BufferQueueConsumer
3 BLASTBufferItemConsumer
Android 15 的 BLASTBufferQueue 分析资料也指出其构造中会 createBufferQueue(&mProducer, &mConsumer),设置 consumer listener,并设置最大 dequeue buffer 数。 [jianshu.com], [blog.csdn.net]

10.2 创建 Surface
1 sp BLASTBufferQueue::createSurface() {
2 return new BBQSurface(mProducer, true, this);
3 }
这个 Surface 最终给 ViewRootImpl.mSurface / HWUI 使用。

10.3 onFrameAvailable()
1 void BLASTBufferQueue::onFrameAvailable(
2 const BufferItem& item) {
3 std::unique_lock lock(mMutex);
4
5 mNumFrameAvailable++;
6
7 acquireNextBufferLocked(
8 std::nullopt,
9 std::nullopt,
10 false /* dropBuffer */);
11 }
当 BufferQueueProducer::queueBuffer() 通知 frame available 后,BLASTBufferQueue 作为本地 consumer 收到回调。

10.4 acquireNextBufferLocked()
核心逻辑:
1 status_t BLASTBufferQueue::acquireNextBufferLocked(
2 const std::optionalSurfaceComposerClient::Transaction* transaction,
3 const std::optional<uint64_t> frameNumber,
4 bool dropBuffer) {
5 BufferItem bufferItem;
6
7 status_t status = mBufferItemConsumer->acquireBuffer(
8 &bufferItem,
9 0 /* presentWhen/,
10 false /
waitForFence/);
11
12 if (status != NO_ERROR) {
13 return status;
14 }
15
16 sp buffer = bufferItem.mGraphicBuffer;
17 sp fence = bufferItem.mFence;
18
19 SurfaceComposerClient::Transaction localTransaction;
20 SurfaceComposerClient::Transaction
t =
21 transaction ? *transaction : &localTransaction;
22
23 t->setBuffer(mSurfaceControl, buffer, fence);
24 t->setDataspace(mSurfaceControl, bufferItem.mDataSpace);
25 t->setCrop(mSurfaceControl, bufferItem.mCrop);
26 t->setTransform(mSurfaceControl, bufferItem.mTransform);
27
28 if (!transaction) {
29 t->apply();
30 }
31
32 return OK;
33 }
这一步非常关键:
1 BLASTBufferQueue 从本地 BufferQueue acquire buffer
2 ↓
3 把 GraphicBuffer + acquire fence 塞进 SurfaceControl.Transaction
4 ↓
5 Transaction.apply()
6 ↓
7 通过 Binder 提交给 SurfaceFlinger
所以在 Android 15 BLAST 路径下:
1 SurfaceFlinger 不直接 acquire App 窗口的 BufferQueue
2 而是接收 Transaction 里的 buffer
这一点是 Android S 以后 BLASTBufferQueue 的核心变化。 [juejin.cn], [jianshu.com]

11. SurfaceFlinger:接收事务、latch buffer、合成显示

路径主要包括:
1 frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
2 frameworks/native/services/surfaceflinger/Layer.cpp
3 frameworks/native/services/surfaceflinger/BufferStateLayer.cpp
11.1 Transaction 到 SurfaceFlinger
客户端:
1 SurfaceComposerClient::Transaction::apply()
服务端大致进入:
1 status_t SurfaceFlinger::setTransactionState(
2 const FrameTimelineInfo& frameTimelineInfo,
3 const Vector& states,
4 const Vector& displays,
5 uint32_t flags,
6 const sp& applyToken,
7 const InputWindowCommands& inputWindowCommands,
8 int64_t desiredPresentTime,
9 bool isAutoTimestamp,
10 const client_cache_t& uncacheBuffer,
11 bool hasListenerCallbacks,
12 const std::vector& listenerCallbacks,
13 uint64_t transactionId) {
14 // 解析 Transaction
15 // 放入 transaction queue
16 // 请求下一帧 commit / composite
17 }

11.2 Layer 接收 buffer 状态
BLAST 提交的 buffer 最终进入 Layer 的 buffer state,例如:
1 bool BufferStateLayer::setBuffer(
2 const sp& buffer,
3 const sp& acquireFence,
4 nsecs_t postTime,
5 nsecs_t desiredPresentTime,
6 bool isAutoTimestamp,
7 const client_cache_t& clientCacheId,
8 uint64_t frameNumber,
9 std::optional<nsecs_t> dequeueTime,
10 const FrameTimelineInfo& info) {
11 mDrawingState.buffer = buffer;
12 mDrawingState.acquireFence = acquireFence;
13 mDrawingState.frameNumber = frameNumber;
14
15 return true;
16 }
含义:
1 SurfaceFlinger 的 Layer 状态里记录:
2 - GraphicBuffer
3 - acquire fence
4 - frame number
5 - dataspace / crop / transform 等属性

11.3 latch buffer
SurfaceFlinger 在 commit / composition 阶段检查事务、处理 LayerState,并把 pending buffer 变成当前可合成 buffer。
抽象流程:
1 void SurfaceFlinger::commit() {
2 // 处理 pending transaction
3 // 更新 Layer state
4 // latch buffer
5 }
6
7 void SurfaceFlinger::composite() {
8 // 选择 GLES / HWC 合成方式
9 // 等待 acquire fence
10 // 提交给 Hardware Composer
11 // present display
12 }
最终:
1 Layer buffer
2 ↓
3 SurfaceFlinger composition
4 ↓
5 HWC validate / present
6 ↓
7 Display 显示
SurfaceFlinger 的职责是合成所有 Layer 并送显,Android 显示系统资料中对此也有一致描述。 [juejin.cn], [jishuzhan.net]

12. 软件绘制路径补充:Surface.lockCanvas()

如果关闭硬件加速,或者某些特殊路径走软件绘制,则 ViewRootImpl 会走:
1 private boolean drawSoftware(
2 Surface surface,
3 AttachInfo attachInfo,
4 int xoff,
5 int yoff,
6 boolean scalingRequired,
7 Rect dirty) {
8 final Canvas canvas;
9
10 try {
11 canvas = mSurface.lockCanvas(dirty);
12
13 canvas.setDensity(mDensity);
14
15 mView.draw(canvas);
16 } finally {
17 surface.unlockCanvasAndPost(canvas);
18 }
19
20 return true;
21 }
对应 native:
1 Surface.lockCanvas()
2 ↓
3 Surface::lock()
4 ↓
5 Surface::dequeueBuffer()
6 ↓
7 GraphicBufferMapper::lock()
8 ↓
9 CPU 绘制 Canvas
10 ↓
11 Surface.unlockCanvasAndPost()
12 ↓
13 GraphicBufferMapper::unlock()
14 ↓
15 Surface::queueBuffer()
也就是说:
路径 获取 buffer 绘制方式 提交方式
硬件加速 View RenderThread / EGL dequeueBuffer GPU / Skia eglSwapBuffers / queueBuffer
软件 View Surface.lockCanvas → dequeueBuffer CPU Canvas unlockCanvasAndPost → queueBuffer

13. 三个关键行为对应源码位置

13.1 “锁定 / 获取 buffer”
硬件路径不是 Java lockCanvas(),而是:
1 RenderThread
2 ↓
3 EGL / ANativeWindow
4 ↓
5 Surface::dequeueBuffer()
6 ↓
7 BufferQueueProducer::dequeueBuffer()
关键源码:
1 mGraphicBufferProducer->dequeueBuffer(…);
状态:
1 FREE → DEQUEUED

13.2 “绘制 buffer”
硬件路径:
1 ThreadedRenderer.updateRootDisplayList()
2 ↓
3 syncAndDrawFrame()
4 ↓
5 RenderThread
6 ↓
7 Skia / GLES / Vulkan
8 ↓
9 GPU 写入 GraphicBuffer
软件路径:
1 Surface.lockCanvas()
2 ↓
3 View.draw(canvas)
4 ↓
5 CPU 写入 GraphicBuffer

13.3 “通知 buffer 可显示”
第一阶段:
1 BufferQueueProducer::queueBuffer()
状态:
1 DEQUEUED → QUEUED
并回调:
1 frameAvailableListener->onFrameAvailable(item);
第二阶段,BLAST:
1 BLASTBufferQueue::onFrameAvailable()
2 ↓
3 BLASTBufferQueue::acquireNextBufferLocked()
4 ↓
5 Transaction.setBuffer()
6 ↓
7 Transaction.apply()
第三阶段,SurfaceFlinger:
1 SurfaceFlinger 接收 Transaction
2 ↓
3 Layer latch buffer
4 ↓
5 Composition
6 ↓
7 HWC present

14. Android 15 View 渲染流程时序图

1 App UIThread RenderThread / HWUI BufferQueue / BBQ SurfaceFlinger
2 | | | |
3 | View.invalidate() | | |
4 | requestLayout() | | |
5 | ViewRootImpl.scheduleTraversals() | | |
6 | Choreographer 等 VSYNC | | |
7 | doTraversal() | | |
8 | performTraversals() | | |
9 | performMeasure/Layout | | |
10 | performDraw() | | |
11 | ThreadedRenderer.draw() | | |
12 | updateRootDisplayList() | | |
13 | syncAndDrawFrame() ----------------> | | |
14 | | dequeueBuffer() ----------------> | BQP::dequeueBuffer() |
15 | | | FREE → DEQUEUED |
16 | | GPU render GraphicBuffer | |
17 | | queueBuffer() -------------------> | BQP::queueBuffer() |
18 | | | DEQUEUED → QUEUED |
19 | | | onFrameAvailable() |
20 | | | BBQ acquireBuffer() |
21 | | | Transaction.setBuffer() ----> |
22 | | | Transaction.apply() --------> |
23 | | | | receive transaction
24 | | | | latch buffer
25 | | | | compose
26 | | | | HWC present

15. 校验结论

我按 Android 15 的渲染架构对调用链做了交叉校验:
1.ViewRootImpl 调度链正确:requestLayout() / invalidate() 最终触发 scheduleTraversals(),通过 Choreographer 在 VSYNC 后执行 performTraversals()。 [juejin.cn], [blog.csdn.net]
2.ThreadedRenderer 分工正确:UIThread 构建 DisplayList / RenderNode,RenderThread 执行 syncAndDrawFrame() 并真实渲染 buffer。 [blog.csdn.net]
3.BufferQueue 状态流转正确:Producer dequeueBuffer(),绘制后 queueBuffer(),Consumer acquireBuffer(),使用后 releaseBuffer(),对应状态 FREE → DEQUEUED → QUEUED → ACQUIRED → FREE。 [source.and…google.cn], [cnblogs.com], [zhuanlan.zhihu.com]
4.Android 15 BLAST 路径正确:应用窗口的 BufferQueue 在 App 进程侧,BLASTBufferQueue acquire buffer 后使用 SurfaceControl.Transaction.setBuffer() 提交给 SurfaceFlinger,而不是 SurfaceFlinger 直接作为传统 BufferQueue consumer。 [juejin.cn], [jianshu.com]
5.SurfaceFlinger 职责正确:接收 Transaction,更新 Layer buffer state,在合成阶段 latch buffer,并通过 HWC / GLES 合成送显。 [juejin.cn], [jishuzhan.net]

16. 最终一句话总结

Android 15 普通 View 的一次上屏,本质是:
1 View 变化
2 → ViewRootImpl 等 VSYNC 做 traversal
3 → ThreadedRenderer 构建 DisplayList
4 → RenderThread dequeue GraphicBuffer
5 → GPU 绘制
6 → queueBuffer
7 → BLASTBufferQueue acquire buffer
8 → Transaction 携带 buffer 提交给 SurfaceFlinger
9 → SurfaceFlinger latch / compose / present
其中:
1 锁定 buffer = Surface / ANativeWindow dequeueBuffer
2 绘制 buffer = RenderThread + Skia/GPU 写入 GraphicBuffer
3 通知可显示 = queueBuffer + BLAST Transaction.apply
4 最终显示 = SurfaceFlinger latch + HWC present

-------------------------------------END LINE---------------------------------------------

http://www.jsqmd.com/news/1101308/

相关文章:

  • RIDECORE学习记录之二
  • Linux 等保三员账号 sudo 配置速查手册(精简总结版)国产银河麒麟通用
  • 元器件IC测试治具是什么?
  • 浮点运算在MCU上的坑,新手十个踩九个
  • 别再死记硬背了!用一张图+大白话彻底搞懂RocketMQ的Topic、Queue和Tag
  • JD-GUI 反编译软件
  • Dism++:Windows系统维护的完整解决方案与高效优化指南
  • Mac剪贴板只能存一条?Paste v6.5.2 帮你管理历史记录
  • 给你100万,你会做一个什么样的网站?
  • Windows风扇控制神器:FanControl中文版完全指南
  • 2026年上海新风系统品牌优选指南,清新空气从这里开始
  • 5分钟零基础入门:ServerPackCreator轻松创建Minecraft服务器包终极指南
  • 别再只会用H5跳转了!Android Scheme协议从配置到实战避坑全指南
  • VMware虚拟机跨平台迁移不求人:从Windows物理机→Mac M3芯片宿主机的完整适配路径(含UEFI固件补丁包)
  • AI视觉交互项目部署指南:从环境配置到API集成实战
  • Jmeter怎么实现接口关联
  • ChatGPT写方案全流程拆解(从Prompt工程到合规审查):央企数字化转型团队内部培训手册首次公开
  • 校园社团物资管理系统源码 Java+SpringBoot+Vue 前后分离
  • 网站关键词如何优化?
  • 如何在3分钟内实现跨平台远程桌面控制?BilldDesk开源解决方案深度解析
  • OpenMontage:全链路AI视频自动化工具,如何从脚本到视频一键生成?
  • ARM多核开发避坑指南:spinlock里用WFE还是WFI?一个真实性能调优案例
  • 计算机毕业设计之基于决策树的路面情况推测方法设计与性能分析
  • Hi3D+Codex:从图像到代码,AI驱动3D场景自动化生成实战
  • AI Agent开发实战:从零构建智能体应用的全流程指南
  • 别再死记硬背了!用这5个真实场景,彻底搞懂Cisco ASA防火墙的NAT配置
  • 小心烧板!为什么你的DC-DC电路里,一体成型电感耐压可能只有50V?
  • 5个必装的Illustrator自动化脚本:提升设计效率300%
  • 别再被APC模型绕晕了!用Stata实操带你搞定年龄、时期、队列效应分离
  • # 同一句提示词,DeepSeek和豆包谁更适合你的任务?我们做了一个「AI裁判」