Android: 显示过程 📅 发布时间:2026/9/4 16:39:51 👁 浏览次数: 基础1.硬件基石渲染与合成分离Android图形显示依赖两大核心硬件单元GPU图形处理器负责渲染。将应用下发的绘图指令如画圆、画线转化为具体的像素数据二维数组产出单个图层。DPU显示处理器负责合成与送显。将多个渲染好的图层如状态栏、壁纸、应用界面按Z轴顺序合并计算重叠区域的最终颜色并驱动屏幕显示。HWC硬件合成器HAL层的抽象接口厂商实现DPU驱动。面试核心点HWC有图层合成数量上限超出部分会回退给GPU处理标记为CLIENT合成GPU处理不完则丢帧。2.核心数据流转GraphicBuffer与BufferQueueGraphicBuffer图形数据的载体本质是一块共享内存分配在RAM移动端无独立显存。Fence机制跨硬件同步锁。GPU/DPU/CPU访问GraphicBuffer前需检查Fence信号防止数据读写冲突如GPU还在写DPU就来读导致花屏。BufferQueue基于生产者-消费者模式。APP是生产者Surface作为图像的生产者持有BufferQueue的引用并且封装了出列和入列两个方法dequeue获取空缓冲queue提交绘满的缓冲SFSurfaceFlinger是消费者acquire取出渲染完的缓冲release释放回空闲队列。状态流转FREE → DEQUEUED → QUEUED → ACQUIRED → FREE。3.双端进程职责APP进程生产者通过ViewRootImpl持有Surface触发绘制后提交Buffer给BufferQueue。SurfaceFlinger进程消费者核心系统服务接收APP的Buffer执行图层合成最后通过DRM提交给硬件显示。4.VSync驱动机制灵魂为了画面流畅系统引入VSync垂直同步信号。为了解决“渲染合成”耗时长的问题Offset偏移量设计让APP和SF接收信号的时机错开理论上可在一个硬件周期内完成两步降低触控延迟。正常的显示流程VSync1 VSync2 VSync3 │ │ │ APP 开始绘制 │ └── queueBuffer │ SF 获取Buffer 调用hwc合成, 执行合成 │ └── 提交显示 │ Display 扫描显示ViewRootImpl.requestLayout() 的执行流程在 Activity 的 onResume 周期后会调用 WindowManager.addView() 方法 其内部 会 创建 ViewRootImpl 并且会 通过 Binder 给 WMS 添加 窗口。ViewRootImpl.requestLayout() ↓ scheduleTraversals() ↓ 1. 向 MessageQueue 插入同步消息屏障 postSyncBarrier() ↓ 2. 向 Choreographer 注册 CALLBACK_TRAVERSAL ↓ 3. Choreographer 请求/等待下一次 VSync ↓ VSync 到来 ↓ DisplayEventReceiver 收到 VSync ↓ 向主线程 MessageQueue 投递一个“异步消息” ↓ 因为队列前面有同步消息屏障 普通同步消息先被挡住 异步消息可以越过屏障 ↓ 主线程 Looper 取出这个异步消息 ↓ 执行 Choreographer.doFrame() ↓ 执行 CALLBACK_TRAVERSAL ↓ ViewRootImpl.doTraversal() ↓ 先移除同步消息屏障 removeSyncBarrier() ↓ performTraversals() ↓ measure → layout → draw (绘制三部曲)measure过程和layout过程都是发生在CPUdraw不同如果开启硬件加速那么draw的过程发生在GPU。requestLayout() 最终会调用ViewRootImpl.scheduleTraversals()首先向主线程的 MessageQueue插入一个同步消息屏障然后通过 Choreographer 注册 Traversal 回调等待 下一次 VSync 信号。当 VSync 到来后DisplayEventReceiver 接收到 VSync并通过 Choreographer 向主线程消息队列投递一个异步消息。由于同步消息屏障会阻塞普通同步消息而异步消息可以越过屏障所以这一帧的绘制任务能够被优先处理。随后主线程执行 Choreographer.doFrame()触发 Traversal 回调进入 ViewRootImpl.doTraversal()移除同步消息屏障再调用performTraversals()最终完成 View 的 measure、layout 和 draw 流程。后续 从绘制 到 屏幕 显示的过程我会把整个流程分为四个阶段生产者入队 → SF调度触发 → 合成决策与执行 → 硬件呈现。第一阶段生产者提交APP侧APP完成一帧绘制后调用Surface.queueBuffer()。此时GraphicBuffer 被放入 BufferQueue。这一步本质上是释放生产者锁让消费者SF有机会获取。第二阶段SF唤醒与VSync对齐核心调度3. BufferQueue通知SFonFrameAvailable()。4. SF调用signalLayerUpdate()→requestNextVSync()。注意SF不会立即合成而是等待下一个VSync信号。这么做是为了对齐刷新率避免在屏幕刷新中途写入数据导致撕裂。第三阶段VSync到来与消息驱动双消息机制5. VSync信号触发 DisplayEventReceiverSF开始处理。6. SF首先发INVALIDATE消息在handleMessageInvalidate()中处理事务Transaction和图层更新。这一步是为了判断是否有图层需要重绘或合成如果没有变化则跳过合成以省电。7. 若需要合成则发REFRESH消息进入真正的合成流程。这种将“检查”和“执行”分离的设计是为了高效处理高频UI变化。第四阶段合成与送显SF核心工作8. 在handleMessageRefresh()中SF执行五步标准合成流水线preComposition()最后检查是否有新Buffer防丢帧。rebuildLayerStacks()计算可见区域和脏区只合变化的部分。setUpHWComposer()决策分水岭。决定哪些层走HWC硬件合成器哪些层走GPUClient合成。原则是能走HWC就不走GPU因为HWC是硬解码专用电路功耗更低且零拷贝。doComposition()执行合成。GPU合成会渲染到FramebufferHWC合成则只是配置显示控制器的寄存器。postComposition()收尾触发BufferQueue的release回调让APP复用Buffer。最终Display Controller 显示控制器基于VSync周期扫描Framebuffer将图像发送给屏幕用户看到画面。APP 绘制完成后通过 Surface.queueBuffer() 将 GraphicBuffer 提交到 BufferQueue。BufferQueue 可以理解为 APP 和 SurfaceFlinger 之间传递图形 Buffer 的缓冲队列。SF 侧发现有新的 Buffer 可以消费后会安排下一次 VSyncVSync 到来时SF 先检查图层和事务是否发生变化如果需要合成就通过 GPU/HWC 完成多个 Layer 的合成并将最终显示内容提交给显示系统。显示控制器会按照 VSync 对应的显示时序切换到新的显示 Buffer并逐行扫描输出到屏幕最终用户看到这一帧。GraphicBuffer 这个图层某一帧的像素数据BufferQueue 这个图层的 Buffer 流转队列