一、图形系统总览:Android图形架构演进与核心组件
大家好,我是你们的老朋友。今天咱们来聊聊Android图形系统。说实话,这个领域我研究了快十年,踩过的坑比走过的路还多。图形系统是Android最复杂、也最容易被忽视的部分——你想想看,用户每天滑动屏幕、打开应用、玩游戏,每一帧画面背后都有一整套流水线在运转。
我个人习惯把图形系统比作一个「电影制片厂」:应用负责写剧本(绘制UI),SurfaceFlinger是导演(合成画面),HWC是特效团队(硬件加速),而Choreographer就是场记(控制节奏)。今天我们就从整体架构入手,看看这些角色是怎么协作的。
1.1 从SurfaceFlinger到HWC:架构演进之路
Android图形架构不是一天建成的。早期版本(Android 4.x之前)的架构很简单:应用绘制好画面,交给SurfaceFlinger,然后SurfaceFlinger用CPU把所有图层合成,再送到显示设备。那时候屏幕分辨率低,图层少,CPU还能扛得住。
但问题很快就来了。我记得在Android 4.4时代,我参与过一个平板项目,屏幕分辨率从1280x800升级到1920x1200,结果SurfaceFlinger的CPU占用率直接翻倍,滑动卡顿得一塌糊涂。这就是纯CPU合成的瓶颈——像素越多,计算量越大,功耗也越高。
于是Google引入了HWC(Hardware Composer)。HWC说白了就是把合成工作交给GPU或显示控制器去做。CPU只负责「指挥」,不负责「干活」。这个变化有多大?我给你们看个对比:
| 特性 | 纯SurfaceFlinger合成 | 引入HWC后 |
|---|---|---|
| 合成方式 | CPU逐像素合成 | GPU/显示控制器硬件合成 |
| 功耗 | 高(CPU满载) | 低(硬件加速) |
| 图层数量限制 | 无限制(但越多越卡) | 受硬件Overlay层数限制 |
| 典型场景 | Android 4.x及之前 | Android 5.0+ |
到了Android 8.0,Google又做了个大手术——把SurfaceFlinger和HWC的交互方式从「同步」改成了「异步」。以前SurfaceFlinger要等HWC处理完才能干下一件事,现在可以提前准备下一帧的数据。这个改动让帧率稳定性提升了不少。
核心演进脉络:
- Android 1.0-4.4:CPU合成时代,SurfaceFlinger独揽大权
- Android 5.0-7.1:引入HWC,硬件加速合成
- Android 8.0+:异步合成模型,提升帧率稳定性
- Android 10+:HWC 2.0,支持更多合成策略
1.2 核心组件:三个关键角色
好,现在我们来认识一下图形系统的三个核心组件。它们各司其职,缺一不可。
SurfaceFlinger:画面合成的总导演
SurfaceFlinger是Android图形系统的核心服务,运行在system_server进程中。它的工作很简单——把所有应用的画面「叠」在一起,然后输出到显示设备。但简单不代表容易。
我遇到过最头疼的问题是什么?是SurfaceFlinger的VSYNC同步。有一次线上反馈说某款手机在打开相机时屏幕会闪一下,查了两天才发现是SurfaceFlinger在处理相机预览图层时,VSYNC信号被某个第三方服务阻塞了。嗯,这里要注意:SurfaceFlinger对VSYNC的依赖非常强,任何阻塞都会导致掉帧。
SurfaceFlinger的核心职责:
- 管理所有应用的Surface(图层)
- 决定图层的合成顺序(Z-order)
- 调用HWC进行硬件合成(或自己用GPU合成)
- 处理VSYNC信号,控制帧率
WindowManager:窗口布局的指挥官
WindowManager(WMS)负责管理所有窗口的位置、大小、层级。你可能觉得它和图形没关系——错了。WMS决定了每个应用窗口在屏幕上的「地盘」,而SurfaceFlinger根据这个「地盘」来合成画面。
举个例子:你打开分屏模式,左边是微信,右边是浏览器。WMS会告诉SurfaceFlinger:「微信的Surface在屏幕左半部分,浏览器的Surface在右半部分」。SurfaceFlinger拿到这个信息后,才知道怎么裁剪和合成。
我曾经在调试一个多窗口拖拽卡顿的问题时发现,WMS在窗口位置变化时,会频繁触发Surface的重新创建。每次重新创建Surface,SurfaceFlinger就要重新配置HWC的Overlay层,这个过程如果超过16ms,就会掉帧。解决方案?嗯,后来我们在WMS里加了个缓存机制,避免频繁重建Surface。
Choreographer:帧率控制的节拍器
Choreographer这个名字很有意思——「编舞者」。它的作用就是控制每一帧的节奏,让应用的绘制、SurfaceFlinger的合成、显示器的刷新保持同步。
Choreographer的工作原理:
- 应用通过Choreographer注册一个「帧回调」
- Choreographer等待下一个VSYNC信号
- VSYNC到来时,Choreographer通知应用开始绘制
- 应用绘制完成后,通知SurfaceFlinger合成
说白了,Choreographer就是那个喊「一二三,开始!」的人。没有它,应用和SurfaceFlinger就会各干各的,画面撕裂、卡顿就来了。
避坑指南:我曾经在优化一个视频播放器时发现,Choreographer的回调如果执行耗时操作(比如网络请求),会直接导致下一帧延迟。记住:Choreographer回调里只做UI相关的事,别干别的。
1.3 协作流程:一帧画面的诞生
好了,三个核心组件都认识了。现在咱们看看它们是怎么配合的。我用一个典型的场景来说明:你在手机上滑动一个列表。
整个流程大概是这样:
- VSYNC触发:显示器以60Hz(或120Hz)的频率发出VSYNC信号。Choreographer收到信号后,开始新一帧的工作。
- 应用绘制:Choreographer通知应用开始绘制。应用在CPU上执行onDraw(),生成一帧画面数据,写入到自己的Surface(BufferQueue中的一个Buffer)。
- 提交Surface:应用绘制完成后,通过BufferQueue把Surface提交给SurfaceFlinger。
- SurfaceFlinger合成:SurfaceFlinger收到所有应用的Surface后,决定合成策略。如果图层少且硬件支持,就交给HWC做硬件合成;否则自己用GPU合成。
- HWC处理:HWC把多个Overlay层合成到显示缓冲区,或者SurfaceFlinger用GPU合成到Framebuffer。
- 显示输出:合成后的画面通过显示控制器输出到屏幕。
整个过程必须在16.6ms内完成(60Hz下),否则就会掉帧。你想想看,从应用绘制到最终显示,中间要经过这么多步骤,任何一个环节出问题,用户都能感觉到卡顿。
注意:这里有个常见的误解——很多人以为「掉帧」是应用绘制太慢。其实很多时候是SurfaceFlinger合成太慢,或者HWC配置太慢。我曾经遇到过一个案例,应用绘制只用了5ms,但SurfaceFlinger合成用了15ms,结果还是掉帧。所以优化时要全面排查,别只盯着应用层。
1.4 整体架构图
下面这张图是我自己画的,把整个图形系统的核心流程和组件关系展示出来了。建议你保存下来,后面每个章节都会用到。
这张图里,我特意把VSYNC信号画成了虚线。为什么?因为VSYNC是整个系统的「心跳」,它贯穿了所有组件。没有VSYNC,Choreographer不知道什么时候该通知应用绘制,SurfaceFlinger不知道什么时候该合成,HWC不知道什么时候该输出。说白了,VSYNC就是那个让所有人步调一致的节拍器。
1.5 小结
好了,第一章的内容就到这里。我们梳理了Android图形架构从CPU合成到HWC硬件加速的演进过程,认识了SurfaceFlinger、WindowManager、Choreographer这三个核心组件,也看了一帧画面从应用到显示的完整流程。
我个人觉得,理解这个整体架构是后面所有优化的基础。你想想看,如果你连画面是怎么从应用走到屏幕的都不知道,那遇到卡顿问题就只能瞎猜。后面我们会深入到每个组件的内部,看看它们到底是怎么工作的,以及怎么优化。
记住一句话:图形优化不是玄学,是科学。每一帧的延迟都有迹可循。
公众号:蓝海资料掘金营,微信deep3321