Android 图形系统:图形总览 + SurfaceFlinger 与 WindowManager
内容整理自 AOSP 官方文档:
第一部分:Android 图形系统总览
Android 框架提供了各种用于 2D 和 3D 图形渲染的 API,可与制造商的图形驱动程序实现代码交互。这类驱动程序构建于图形硬件抽象层(HAL) 之上。应用开发者可通过三种方式将图像绘制到屏幕上:画布(Canvas)、OpenGL ES 或 Vulkan。
1.1 基本术语
| 术语 | 说明 |
|---|---|
画布 / Canvas |
一种绘图 Surface,用于对照位图或 Surface 对象处理实际的位合成。包含位图、线条、圆形、矩形、文字等标准绘制方法,是屏幕上绘制 2D 对象最简便的方式,基类为 Canvas。 |
| 可绘制对象(Drawable) | 经过编译的视觉资源,可用作背景、标题或界面其他部分。不能接收事件,但可指定状态、调度等属性以支持动画等子类。资源会被编译成 android.graphics.drawable 的子类。 |
| 布局资源 | 描述 Activity 界面布局的 XML 文件。 |
| 九宫格(NinePatch) | 可调整大小的位图资源,可用作背景或其他图片。 |
| OpenGL ES | 渲染 2D/3D 图形的跨平台 API,可实现硬件加速的 3D 渲染;2D 渲染用 Canvas 更简单。NDK、android.opengl 和 javax.microedition.khronos.opengles 包均提供支持。 |
| Surface | 表示要合成到界面的内存块。Surface 包含用于绘图的 Canvas,并提供绘制图层、调整大小的辅助方法。应使用 SurfaceView 类,而非直接使用 Surface。 |
| SurfaceView | 封装 Surface 的 View 对象,可动态指定大小和格式。为游戏、相机预览等资源密集型操作提供独立于界面线程的绘制方式(代价是占用额外内存),同时支持 Canvas 和 OpenGL ES。 |
| 主题(Theme) | 一组捆绑的默认显示属性(文字大小、背景颜色等),标准主题列于 R.style 中,以 Theme_ 开头。 |
| View | 在屏幕上绘制为矩形区域,处理点击、按键等互动事件,是大多数界面组件的基类。View 接收父对象调用以绘制自身,并向父对象报告首选大小和位置(父对象不一定遵循)。 |
| ViewGroup | 对子视图分组,负责确定子视图的位置和大小,并在适当时调用其绘制自身。有的不可见仅用于布局,有的具有固有界面(如滚动列表框)。 |
| 视图层次结构 | View 与 ViewGroup 的排列方式,定义应用界面。可通过 SDK 的 Hierarchy Viewer 可视化。 |
| Vulkan | 适用于高性能 3D 图形的低开销、跨平台 API。 |
| 微件(Widget) | 完全实现的 View 子类,渲染表单元素等界面组件(文本框、弹出式菜单),自行处理测量和绘制并响应屏幕事件,位于 android.widget 包。 |
| Window | 派生自 Window 抽象类的对象,指定常规窗口的元素(外观风格、标题栏文字、菜单位置内容等)。对话框和 Activity 使用其实现来渲染,应用无需自行实现。 |
1.2 Android 图形组件
无论开发者使用什么渲染 API,一切内容都会渲染到 Surface 上。 Surface 表示缓冲区队列中的生产方 ,而缓冲区队列通常会被 SurfaceFlinger 消耗。Android 平台上创建的每个窗口都由 Surface 提供支持,所有被渲染的可见 Surface 都被 SurfaceFlinger 合成到屏幕。

(原文图 1:Surface 如何被渲染------展示关键组件如何协同工作)
图像流生产方
可以是生成图形缓冲区以供消耗的任何东西,例如 OpenGL ES、Canvas 2D、mediaserver 视频解码器。
图像流消耗方
- 最常见的消耗方是 SurfaceFlinger :该系统服务消耗当前可见的 Surface,并使用 WindowManager 提供的信息将它们合成到屏幕。SurfaceFlinger 是唯一可以修改所显示内容的服务,它使用 OpenGL 和 Hardware Composer 来合成一组 Surface。
- 其他 OpenGL ES 应用也可以消耗图像流(如相机应用消耗相机预览图像流)。
- 非 GL 应用也可以是消耗方,例如
ImageReader类。
硬件混合渲染器(Hardware Composer, HWC)
- 显示子系统的硬件抽象实现。SurfaceFlinger 可以将某些合成工作委托给 HWC,以分担 OpenGL 和 GPU 上的工作量。
- SurfaceFlinger 本身只是充当另一个 OpenGL ES 客户端:当它把一个或两个缓冲区合成到第三个缓冲区时使用 OpenGL ES,这比完全通过 GPU 计算功耗更低。
- HWC HAL 是所有 Android 图形渲染的中心点 ,它必须支持事件,其中之一是 VSYNC(另一个是支持即插即用 HDMI 的热插拔)。
Gralloc
显存分配器,用于分配图像生产方请求的内存(详见 Gralloc HAL 文档)。
1.3 数据流

(原文图 2:流经 Android 的图形数据流------左侧是生成图形缓冲区的渲染器,如主屏幕、状态栏和系统界面;SurfaceFlinger 是合成器,HWC 是混合渲染器)
BufferQueue
BufferQueue 是 Android 图形组件之间的粘合剂 :一对队列,调解缓冲区从生产方到消耗方的固定周期。一旦生产方移交缓冲区,SurfaceFlinger 便负责将所有内容合成到显示部分。

(原文图 3:BufferQueue 通信过程)
要点:
- BufferQueue 包含将图像流生产方与消耗方结合在一起的逻辑。
- 生产方示例:相机 HAL 生成的相机预览、OpenGL ES 游戏。
- 消耗方示例:SurfaceFlinger、显示 GL 流的另一个应用(如相机取景器)。
- BufferQueue 是将缓冲区池与队列相结合的数据结构 ,使用 Binder IPC 在进程间传递缓冲区。
- 生产方接口为
IGraphicBufferProducer(SurfaceTexture 的一部分)。BufferQueue 通常用于渲染到 Surface,并与 GL 消耗方及其他任务一起消耗内容。
BufferQueue 的三种运行模式:
| 模式 | 行为 |
|---|---|
| 类同步模式(默认) | 从生产方进入的每个缓冲区都在消耗方那退出,不舍弃任何缓冲区。若生产方速度过快,将阻塞并等待可用缓冲区。 |
| 非阻塞模式 | 不等待缓冲区,而是生成错误;也不舍弃缓冲区。有助于避免不了解图形框架复杂依赖的应用出现潜在死锁。 |
| 舍弃模式 | 配置为丢弃旧缓冲区而非报错或等待。例如对纹理视图执行 GL 渲染并尽快绘制时,必须丢弃缓冲区。 |
合成工作分两半:SurfaceFlinger 作为 OpenGL ES 客户端执行一部分(用 GLES 把缓冲区合成),HWC HAL 执行另一半,充当所有 Android 图形渲染的中心点。
第二部分:SurfaceFlinger 和 WindowManager
一句话概括职责分工:
- SurfaceFlinger:接受缓冲区,对它们进行合成,然后发送到屏幕。
- WindowManager:为 SurfaceFlinger 提供缓冲区和窗口元数据,SurfaceFlinger 使用这些信息将 Surface 合成到屏幕。
2.1 SurfaceFlinger
SurfaceFlinger 可通过两种方式接受缓冲区:
方式一:BufferQueue + SurfaceControl
- 应用进入前台时,向 WindowManager 请求缓冲区。
- WindowManager 向 SurfaceFlinger 请求层(Layer)。
- 层 = Surface(包含 BufferQueue)+ SurfaceControl(包含显示框架等层元数据) 的组合。
- SurfaceFlinger 创建层并发送至 WindowManager。
- WindowManager 将 Surface 发送给应用 ,但保留 SurfaceControl 以操控应用在屏幕上的外观。
方式二:ASurfaceControl(Android 10 新增)
ASurfaceControl 将 Surface 和 SurfaceControl 组合到一个事务包中发送至 SurfaceFlinger。它与层相关联,应用可通过 ASurfaceTransaction 更新该层,并通过回调(传递包含锁定时间、获取时间等信息的 ASurfaceTransactionStats)获取事务信息。
| 组件 | 说明 |
|---|---|
| ASurfaceControl | 封装 SurfaceControl,让应用能创建与屏幕上各层对应的 SurfaceControl。可作为 ANativeWindow 的子级或另一个 ASurfaceControl 的子级创建。 |
| ASurfaceTransaction | 包装事务,使客户端能修改层的描述性属性(如几何图形),并将更新后的缓冲区发送至 SurfaceFlinger。 |
| ASurfaceTransactionStats | 通过预先注册的回调,将已显示事务的信息(锁定时间、获取时间、上一个释放栅栏等)发送至应用。 |
缓冲区接收时机与 VSYNC
- 应用可以随时提交缓冲区 ,但 SurfaceFlinger 仅在屏幕处于两次刷新之间时唤醒 以接受缓冲区(时机因设备而异)。这样可最大限度减少内存占用,并避免刷新期间更新显示内容造成的屏幕撕裂。
- 屏幕在两次刷新之间向 SurfaceFlinger 发送 VSYNC 信号,表明此时可刷新屏幕而不会撕裂。
- SurfaceFlinger 收到 VSYNC 后:
- 遍历其层列表,查找新缓冲区;
- 若找到新缓冲区则获取 ;否则继续使用上一次获取的缓冲区(SurfaceFlinger 必须始终显示内容,因此会保留一个缓冲区);
- 某层上没有提交缓冲区时,该层会被忽略。
- 收集完可见层的所有缓冲区后,SurfaceFlinger 询问 HWC 应如何合成 :
- 若 HWC 将层合成类型标记为客户端合成,则由 SurfaceFlinger 合成这些层;
- 然后 SurfaceFlinger 将输出缓冲区传递给 HWC。
2.2 WindowManager
- WindowManager 控制 Window 对象 (容纳 View 对象的容器),Window 对象始终由 Surface 对象提供支持。
- WindowManager 监督:生命周期、输入和聚焦事件、屏幕方向、转换、动画、位置、变形、Z 轴顺序以及窗口的许多其他方面。
- WindowManager 将所有窗口元数据发送到 SurfaceFlinger,供其在屏幕上合成 Surface 时使用。
预旋转(Pre-rotation)
- 许多硬件叠加层不支持旋转 (即使支持也要耗费处理能力),解决方案是在缓冲区到达 SurfaceFlinger 之前对其进行转换。
- Android 在
ANativeWindow中支持查询提示NATIVE_WINDOW_TRANSFORM_HINT,表示最有可能由 SurfaceFlinger 应用于缓冲区的转换。GL 驱动程序可使用此提示在缓冲区到达前预转换,使其到达时已是正确方向。 - 例如,接收到"旋转 90 度"提示时,会生成一个矩阵并应用于缓冲区,防止其从页面末尾运行。进行预旋转是为了节省电量。
- 详见
system/core/include/system/window.h中定义的ANativeWindow接口。
附:整体协作关系速览
生产方(OpenGL ES / Canvas / 视频解码器 / 相机HAL)
│ 通过 BufferQueue(Binder IPC,IGraphicBufferProducer)
▼
应用渲染到 Surface ──► WindowManager(持有 SurfaceControl,
│ 管理窗口元数据:位置/Z轴/动画/旋转...)
│ 层 = Surface + SurfaceControl(或 Android 10+ 的 ASurfaceControl 事务)
▼
SurfaceFlinger(VSYNC 触发,收集可见层缓冲区)
│ 询问 HWC 合成策略;客户端合成部分用 OpenGL ES
▼
HWC(硬件混合渲染器,图形渲染中心点)──► 屏幕
▲
Gralloc(负责图形缓冲区的内存分配)