第3章 SurfaceFlinger源码结构:核心文件介绍
好,咱们今天来聊聊SurfaceFlinger的源码结构。说实话,我刚接触这部分代码时,也被庞大的代码量吓到了。但别慌,核心文件其实就那么几个。我带你捋一遍,你就明白了。
3.1 SurfaceFlinger.cpp —— 绝对的核心
这个文件,说白了就是SurfaceFlinger的大脑。所有关键逻辑都在这里。我个人习惯把它叫做「大管家」—— 它负责调度、合成、显示,几乎啥都管。
来看看它里面几个关键方法:
// SurfaceFlinger.cpp 核心方法一览
void SurfaceFlinger::init() {
// 初始化硬件 composer
// 创建 DispSync 线程
// 启动事件处理循环
}
void SurfaceFlinger::onMessageReceived(int32_t what) {
// 处理各种消息,比如 vsync、hotplug
}
void SurfaceFlinger::doComposition() {
// 执行图层合成
// 调用 HWComposer 进行硬件合成
}
void SurfaceFlinger::handleTransaction() {
// 处理应用提交的 transaction
// 更新图层状态
}
我在项目中遇到过一个问题:某个设备上滑动列表总是掉帧。查了两天,最后发现是 handleTransaction 里有个死循环。嗯,从那以后我每次改这块代码都格外小心。
核心要点:SurfaceFlinger.cpp 是整个系统的调度中心。它通过消息驱动的方式工作,每个 vsync 信号都会触发一次完整的合成流程。
3.2 DisplayDevice.cpp —— 显示设备的抽象
这个文件负责管理物理显示设备。比如你的手机屏幕、外接显示器,每个都对应一个 DisplayDevice 对象。
它主要干三件事:
- 管理显示参数:分辨率、刷新率、旋转角度等
- 维护图层列表:当前显示设备上所有可见图层
- 与 HWC 交互:把合成结果提交给硬件
你想想看,如果 DisplayDevice 出了问题,最常见的现象就是屏幕闪烁或者显示不全。我记得有一次调试双屏异显,就是这里的一个参数没配对,折腾了我一整天。
3.3 其他关键文件一览
| 文件名 | 职责 | 我踩过的坑 |
|---|---|---|
| Layer.cpp | 管理单个图层,包括缓冲区、透明度、裁剪区域 | 图层裁剪边界没处理好,导致 UI 被切掉一块 |
| BufferQueue.cpp | 生产者-消费者模型,管理图形缓冲区 | 缓冲区分配策略不对,导致应用 ANR |
| HWComposer.cpp | 封装硬件合成器 HAL 接口 | HWC 版本兼容性问题,老设备上直接黑屏 |
| DispSync.cpp | 模拟 vsync 信号,控制合成节奏 | vsync 偏移量算错了,画面一直抖动 |
调试小技巧:如果你遇到显示异常,先看 dumpsys SurfaceFlinger 的输出。它能告诉你每个图层的状态、缓冲区数量、合成方式。我几乎每次调试都先用这招。
3.4 关键类图
光说文件不够直观,咱们来看看类之间的关系。我画了个简化的类图:
SurfaceFlinger
├── DisplayDevice (多个)
│ ├── Layer (多个)
│ │ └── BufferQueue
│ └── HWComposer
├── DispSync
└── MessageQueue
这个结构其实很清晰:SurfaceFlinger 持有多个 DisplayDevice,每个 DisplayDevice 管理自己的 Layer 列表。每个 Layer 通过 BufferQueue 从应用获取数据。最后通过 HWComposer 把结果送到屏幕。
注意:千万别以为类图就这么简单。实际代码里还有 Client、SurfaceFlingerConsumer、RenderEngine 等一堆辅助类。但核心骨架就是上面这个,先把主干搞明白,枝叶慢慢加。
3.5 我的学习建议
说了这么多,最后给你点实际建议:
- 先从 SurfaceFlinger.cpp 入手,把
onMessageReceived和doComposition看懂,基本就掌握了 60% - 遇到问题多打 log,我习惯在关键路径上加
ALOGD,比看代码快多了 - 别怕改代码,SurfaceFlinger 虽然是系统服务,但编译起来其实不慢。我经常改一行就编译测试
嗯,今天就先聊到这儿。下一章咱们深入看看 doComposition 的具体实现,那可是 SurfaceFlinger 最精彩的部分。