点击上方“IT烂笔头”,选择“置顶公众号”
第一时间获取 IT 技术干货!


Android图形子系统核心机制全链路剖析
阅读文本大概需要 15 分钟。

①主要的类
DecorView、ViewRootImpl、Window、WMS、Surface、SurfaceFlinger、BufferQueue、FrameBuffer
1. DecorView
是 Android 视图系统里的关键组件,在 Activity 界面显示与布局管理方面扮演着重要角色。下面详细介绍其主要作用:
1.1 作为视图树的根节点
DecorView 是每个 Activity 视图树的顶级视图,继承自 FrameLayout。当 Activity 启动时,系统会创建一个 Window 对象(通常是 PhoneWindow),并为其关联一个 DecorView。所有添加到 Activity 中的视图,最终都会被添加到 DecorView 之下,形成一个完整的视图树。示例如下:
DecorView
├─ 状态栏区域
├─ 标题栏区域(可选)
└─ ContentParent(id 为 android.R.id.content)
└─ 用户自定义布局
├─ 子视图 1
├─ 子视图 2
└─ ...1.2 承载系统界面元素
DcorView 会包含一些系统级的界面元素,像状态栏、标题栏(在启用的情况下)。这些元素由系统统一管理,且通常位于用户自定义布局的上方。借助 DecorView,系统能够统一管理这些公共界面元素的显示与交互。
1.3 关联 Window 和视图树
DecorView是Window和视图树之间的桥梁。Window代表屏幕上的一个显示区域,而DecorView则是这个区域内视图的容器。Window的属性(如背景、透明度等)会影响DecorView的显示效果,DecorView也会将用户的交互事件传递给Window进行处理。
1.4 处理输入事件分发
DecorView是输入事件进入视图树的入口。当用户触摸屏幕、按下按键等操作发生时,系统会将事件传递给DecorView,然后由DecorView将事件分发给其下的子视图。在事件分发过程中,DecorView会根据视图的层级和位置,决定哪个子视图应该接收和处理该事件。
1.5 配合 ViewRootImpl 工作
DecorView 与 ViewRootImpl 紧密协作。ViewRootImpl 负责管理视图的测量、布局和绘制过程,而 DecorView 作为视图树的根节点,会接收 ViewRootImpl 发起的这些操作请求,并将其递归传递给子视图。例如,ViewRootImpl 调用 DecorView 的 measure 方法,DecorView 会依次调用子视图的 measure 方法,从而完成整个视图树的测量。
小结
DecorView 作为 Activity 视图树的根节点,不仅承载系统界面元素,还关联 Window 和视图树,负责输入事件分发,并且与 ViewRootImpl 配合完成视图的测量、布局和绘制工作,在 Android 界面显示和交互中起着关键作用。
2. ViewRootImpl
是 Android 视图系统里的核心类,在视图的渲染、事件处理和窗口管理等方面起着关键作用。下面详细介绍其主要作用:
2.1 连接视图树和窗口系统
ViewRootImpl 是视图树和 WindowManagerService(WMS)之间的桥梁。每个 Activity 里的视图树都有一个对应的 ViewRootImpl 实例,它负责与 WMS 进行通信,将视图的状态和请求传递给系统窗口管理服务。
2.2 视图的测量、布局和绘制
测量(Measure):ViewRootImpl 会触发视图树的测量过程,调用 View 的 measure 方法,确定每个 View 的尺寸。通过递归调用子 View 的 measure 方法,最终确定整个视图树的大小。
布局(Layout):在测量完成后,ViewRootImpl 会调用 View 的 layout 方法,为每个 View 分配在父容器中的位置。同样通过递归调用子 View 的 layout 方法,完成整个视图树的布局。
绘制(Draw):布局完成后,ViewRootImpl 会触发视图树的绘制过程,调用 View 的 draw 方法,将视图绘制到 Surface 上。
2.3 处理输入事件
ViewRootImpl 负责接收来自系统的输入事件(如触摸、按键等),并将这些事件分发给视图树中的相应 View。它会根据事件的坐标和视图的位置,确定哪个 View 应该处理该事件,然后调用相应 View 的事件处理方法。
2.4 管理视图的生命周期
ViewRootImpl 会监听窗口的状态变化,如窗口的显示、隐藏、大小改变等,并根据这些变化触发视图树的重新测量、布局和绘制。例如,当窗口大小改变时,ViewRootImpl 会重新测量和布局视图树,以适应新的窗口尺寸。
2.5 同步 UI 线程和渲染线程
ViewRootImpl 会确保 UI 线程的操作与渲染线程的同步。在 Android 中,UI 操作必须在主线程进行,而渲染操作可能在单独的线程中进行。ViewRootImpl 会协调这两个线程的操作,避免出现渲染冲突和界面闪烁的问题。
ViewRootImpl 是 Android 视图系统的核心组件,负责连接视图树和窗口系统,处理视图的测量、布局、绘制和输入事件,管理视图的生命周期,以及同步 UI 线程和渲染线程。它确保了视图能够正确显示和响应用户操作。
3. Window
指的是PhoneWindow,每一个ViewRootImpl都对应了一个Window,ViewRootImpl其实就是负责处理视图本身的一些逻辑事务(绘制,事件等管理)。而Window的作用主要是处理不同层级window之间的关系,便于WMS进行层级管理的一个抽象概念。Window主要有几大类:
- 应用窗口:Activity
- 子窗口:Dialog
- 系统窗口:状态栏/导航栏/悬浮窗/Toast
4. WMS
是SystemServer进程的一个服务,主要负责管理各层级Window的关系,以及分配Surface用于绘制画面。
5. Surface
提供画图的API以及画布进行渲染,一个Window对应一个Surface,除了SurfaceView有自己独立的Surface。根据是否开启硬件加速,调用GPU或者CPU进行渲染,将View树转换成一帧画面GraphicBuffer入到BufferQueue当中:
- 提供绘图接口
- Canvas API:通过
lockCanvas()获取Canvas对象,支持 2D 图形绘制(如线条、文字)。 - OpenGL ES:通过
EGLSurface支持 3D 渲染,适用于游戏、视频等高性能场景。
- Canvas API:通过
- 缓冲机制(双缓冲/三缓冲)
Surface内部维护多个GraphicBuffer(通常为 2-3 个),通过交替使用避免绘制过程中的画面撕裂。
- Front Buffer:当前显示在屏幕的缓冲区。
- Back Buffer:供应用绘制的缓冲区,完成后通过
unlockCanvasAndPost()提交,替换为新的 Front Buffer。
- 生产者-消费者模型
- 生产者:应用通过
Surface绘制内容(填充缓冲区)。 - 消费者:
SurfaceFlinger消费缓冲区数据,合成最终帧并送
- 生产者:应用通过
6. SurfaceFlinger
主要是当vsync-sf信号到来时,获取BufferQueue中的GraphicBuffer与各层中的画面根据z-order /大小/位置/透明度等信息进行合并操作
7. BufferQueue
用来管理Surface与SurfaceFlingger之间数据GraphicBuffer)的容器,三重缓冲说的就是BufferQueue里面有三个缓冲区对应三个缓冲的帧
8. FrameBuffer
这个是SurfaceFlinger将合成好待显示的帧缓存的地方

②显示系统各类协作流程
1、从启动到监听VSync信号:
ActivityThread执行performLaunchActivity()方法,然后performLaunchActivity方法里调用Activity.attach()方法,attach方法里会调用实例化PhoneWindow对象,然后performLaunchActivity方法里调用Instrumentation类的callActivityOnCreate()方法,callActivityOnCreate会调用Activity类的performCreate()方法,performCreate方法调用Activity的onCreate()方法,onCreate方法中调用setContentView()方法,setContentView方法里调用PhoneWindow的setContentView()方法,PhoneWindow的setContentVIew里面实例化DecorView,PhoneWindow在继续调用LayoutInflator.inflate方法将布局解析到Decorview的视图树中。然后AMS调用ActivityThread的handleResumeActivity()方法,这个方法里面主要做两件事,第一步调用Activity的onResume()方法,然后调用WindowManager.addView(),addView方法最后是调到WindowManagerImpl的addView()再调用到WindowManagerGlobal.addView(),这个方法里面实例化ViewRootImpl并将DecorView通过ViewRootImpl.setView()传递过来,setView方法里面调用自身的requestLayout(),然后方法里调用scheduleTraversals()去Handler里放一个同步屏障,并通过Choreographer去监听VSync信号。

1.1 创建Activity实例,初始化窗口体系
1.2 视图的创建
1.3 Activity的resume阶段
1.4 注册VSync信号
2、VSync信号驱动画面绘制
当系统发出一个VSync信号时,Choreographer的内部类FrameDisplayReceiver的onVsync收到回调,然后通过Choreographer的内部类FrameHandler切换到注册时所在的线程处理doframe(),通过注册的ViewRooImpl的内部类TraversalRunnable回调其中的run方法,再调用ViewRootImpl中的doTraversal(),再调到performTraversals(),这个方法主要第一先调用relayoutWindow()来向WMS申请Surface,然后继续执行ViewRootImpl中的performMeasure()、performLayout()、performDraw()进行绘制,最终执行View的onMessure()、onLayout()、onDraw()方法(这里就是常说的渲染阶段,如果开启硬件加速,那么渲染就会交给GPU去处理)。
3、SurfaceFlinger执行合并送显操作
这个部分主要分成两个阶段,第一个阶段当应用APP中有一帧绘制完了之后,SurfaceFlinger如何知道开始进行合成?第二个阶段是当SurfaceFlinger收到合成的指令后,如何执行合成的步骤(合成五部曲)?

3.1 如何通知SurfaceFlinger有待合成的GraphicBuffer?
3.1.1 Buffer提交与通知
- queueBuffer:应用绘制完成后,通过IGraphicBufferProducer::queueBuffer将GraphicBuffer放入BufferQueue队列,状态变为QUEUED;
- onFrameAvailable:BufferQueue通过FrameAvailableListener跨进程通知SurfaceFlinger有新帧待合成(Binder调用SurfaceFlinger::onFrameAvailable)
3.1.2 合成准备
- handleMessageInvalidate:SF在消息循环中监听INVALIDATE事件,调用latchBuffers()锁定新Buffer
- acquireBuffer:从BufferQueue中获取QUEUED状态的Buffer,标记为ACQUIRED(此时应用不可修改该Buffer)
3.1.3 VSync同步与触发
- onVSyncReceived:硬件VSync信号通过DisplayEventReceiver触发,调用invalidate()插入刷新消息
- handleMessageRefresh:处理Refresh消息,启动合成管线
3.2 执行合成(5部曲)
class SurfaceFlinger {
//合成五部曲
void SurfaceFlinger::handleMessageRefresh(){
//合成之前的预处理,检查是否有新的图层变化,如果有,执行请求下一次VSync信号
preComposition();
//若Layer的位置/先后顺序/可见性发生变化,重新计算Layer的目标合成区域和先后顺序
rebuildLayerStacks();
//调用hwc的prepare方法询问每个图层是否支持硬件合成
setUpHWComposer();
//当打开开发者选项中的“显示Surface刷新”时,额外为产生变化的图层绘制闪烁动画
doDebugFlashRegions();
//如果不支持硬件合成,在该方法中会调用GPU合成,接着提交buffer
doComposition();
//调Layer的onPostComposition方法,主要用于调试,可以忽略
postComposition(refreshStartTime);
}
}3.2.1 图层预处理(preComposition)
核心任务:标记所有待合成的图层(Layer),通知各图层即将 进入合成阶段。
关键操作:
- 调用各图层的onPreCompisition()方法,更新其状态(如可见性、脏区域标记)
- 检查是否有图层内容变化
技术细节:若图层无新帧(Buffer未更新),则跳过后续合成,减少冗余计算
代码:
class SurfaceFlinger {
void SurfaceFlinger::preComposition(){
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i<count ; i++) {
//因为在调用合成之前已经计算过脏区域,如果有图层在计算以后加入了队列,那么在预处理阶段要再次请求VSync信号
if (layers[i]->onPreComposition()) {
needExtraInvalidate = true;
}
}
//存在未处理的layer,执行请求下一次VSync信号,避免这段时间内的帧数据丢掉了
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
}3.2.2 图层堆栈重建(rebuildLayerStacks)
核心任务:根据窗口层级(Z-order)和可见区域,重新计算图 层的叠加顺序与裁剪区域。
关键操作:
层级排序:按窗口管理器(WindowManager)提供的Z轴顺序排序图层
可见性计算:动态裁剪重叠区域;是被脏区域,仅更新内容变化的区域
代码:
class SurfaceFlinger {
void SurfaceFlinger::rebuildLayerStacks(){
//获取当前应用程序所有按照z-order排列的layer
const LayerVector& layers(mDrawingState.layersSortedByZ);
//遍历每一个显示屏
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
//z-order排列的layer
hw->setVisibleLayersSortedByZ(layersSortedByZ);
//显示屏大小
hw->undefinedRegion.set(bounds);
//减去不透明区域
hw->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
//累加脏区域
hw->dirtyRegion.orSelf(dirtyRegion);
}
}
}3.2.3 硬件合成器准备(setUpHWComposer)
核心任务:配置硬件合成器(HWC),决策各图层的合成策略 (硬件/GPU合成)。
关键操作:
HWComposer协商:通过HWC的Prepare方法提交所有的图层信息(格式、位置、透明度);HWC根据硬件能力(Overlay层数限制)标记可硬件合成的图层(HWC2::Composition::Device),剩余标记为GPU合成(HWC2::Composition::Client)
若硬件不支持特定格式(如DRM保护内容),强制回退到GPU合成
性能优化:优先使用HWC合成(如视频播放层),降低GPU负 载
代码:
class SurfaceFlinger {
void SurfaceFlinger::setUpHWComposer() {
//prepareFrame方法中调用了HWComposer::prepare方法
//在HWC的prepare方法中,将会确定每一个图层使用哪种合成方式
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
auto& displayDevice = mDisplays[displayId];
if (!displayDevice->isDisplayOn()) {
continue;
}
status_t result = displayDevice->prepareFrame(*mHwc);
}
}
}3.2.4 执行合成(doComposition)
核心任务:按合成策略执行实际合成操作,生成最终帧。
关键操作:
- GPU合成
通过
RenderEngine(基于OpenGL ES/Vulkan)渲染复杂图层(如旋转、缩放特效)将DPU无法合成的图层(如HWC标记为
Client的图层)合并到临时缓冲区
- HWC合成
直接传递可硬件合成的图层给HWC(避免GPU内存拷贝)
HWC调用显示处理器(DPU)执行混合计算(如Alpha混合、Overlay叠加)
- 混合输出
GPU合成的结果与HWC处理的图层最终合并为单一帧(Framebuffer)
代码:
class SurfaceFlinger {
void SurfaceFlinger::doComposition(){
//遍历所有的DisplayDevice然后调用doDisplayComposition函数
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->isDisplayOn()) {
//获得屏幕的脏区域,将脏区转换为该屏幕的座标空间
const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
//在此方法中将会调用到doComposeSurfaces()方法
//在doComposeSurfaces方法中,将会为被标记为不支持硬件合成的图层调用Layer#draw()方法使用OpenGL ES合成
doDisplayComposition(hw, dirtyRegion);
}
}
postFramebuffer();
}
}3.2.5 合成后处理(postComposition)
核心任务:提交帧到显示设备,释放资源并同步状态
关键操作:
- 帧提交:
调用
Output::present()将最终帧通过Gralloc缓冲区传递到显示控制器(Display Controller) - 缓冲区释放
- 帧提交:
通知应用层释放已使用的
GraphicBuffer(通过BufferQueue::releaseBuffer)检查缓冲区泄漏(如
dumpsys SurfaceFlinger | grep "BufferQueue")
- VSync同步:
等待下一个VSync信号提交帧,避免撕裂(Tearing)
- VSync同步:
4、小结
Android 图形子系统涉及较多细节且流程较为复杂。概括来说,其核心流程主要包含以下环节:首先通过 DecorView 创建并容纳布局内容,随后由 ViewRootImpl 统一管理 View 内的事件处理(包括触发的绘制操作)。Window 作为抽象对象,定义了不同图层间的逻辑关系。每个 Window 关联一个 Surface,该 Surface 负责实际绘制画面内容。系统通过 BufferQueue 构建了一个 GraphicBuffer 的生产者-消费者模型,连接 Surface(生产者)与 SurfaceFlinger(消费者)。SurfaceFlinger 则负责协调与管理不同图层的合成工作。最终,合成后的帧图像被输出到显示器进行呈现。

扫码关注我
一起感悟技术魅力

点分享

点收藏

点点赞

点在看
2350



被折叠的 条评论
为什么被折叠?



