2. 显示系统基础
在 Android 多显示器集成工程中,几乎所有“画面为什么没有出现在外接屏”“为什么外接屏掉帧”“为什么 HWC 没有接管合成”这类问题,最终都会回到四个核心组件:SurfaceFlinger、HWC、Gralloc 与 DRM/KMS。它们分别位于应用图形栈、系统合成层、图形内存层与内核显示驱动层,彼此通过 Buffer、Layer、Display 与原子提交等机制协作。理解它们的分工与数据流,是后续多屏异显、主副屏合成策略、带宽评估与排障的基础。
一、四个组件的基本定位
SurfaceFlinger 是 Android 的系统合成服务,负责接收来自应用、系统 UI、视频播放器等生产者的图形缓冲区,并按照 Z 序、可见区域、变换矩阵与显示设备配置,决定哪些 Layer 交给 HWC 硬件合成,哪些回退到 GPU 合成。它并不直接操作显示控制器,而是通过 HWC 抽象层提交合成计划。
HWC(Hardware Composer)是显示硬件的抽象接口,通常由厂商以 HAL 形式实现。它向上接收 SurfaceFlinger 的 Layer 列表与显示配置,向下决定使用 Overlay、Plane、混合器或 GPU 完成最终扫描输出。HWC 的核心价值在于:尽可能让显示控制器直接读取图形缓冲区并叠加输出,从而降低 GPU 负载与功耗。
Gralloc 是图形内存分配器,负责按用途分配带格式、宽高、步长、使用标志的图形缓冲区,并保证 CPU、GPU、显示控制器与相机等不同硬件可以安全访问同一块内存。它通常由 Gralloc HAL 与内核 DMA-BUF/ION 等机制配合完成。
DRM/KMS 是 Linux 内核的显示子系统。DRM 提供显示设备、CRTC、Encoder、Connector、Plane 与 Framebuffer 等对象模型,KMS 负责模式设置与原子提交。Android 的 HWC 实现最终往往通过 DRM/KMS 把选定的图层与显示模式提交给显示控制器。
二、协作关系与数据流
从应用绘制到屏幕点亮,典型路径如下:应用通过 BufferQueue 向 SurfaceFlinger 提交 Buffer;SurfaceFlinger 汇总各 Layer 后调用 HWC 的 validate 与 present;HWC 根据硬件能力决定合成方式;若使用硬件 Overlay,则显示控制器通过 DRM/KMS 直接扫描 Gralloc 分配的 Buffer;若无法硬件合成,则 SurfaceFlinger 使用 GPU 将多个 Layer 合成到一个 Buffer,再交给 HWC 显示。
图中可以看到两条关键路径:一条是“应用 → SurfaceFlinger → HWC → DRM/KMS → 屏幕”的合成与显示路径;另一条是“Gralloc 分配 Buffer → 被 Layer 引用 → 被 HWC/DRM 扫描”的内存路径。多显示器场景下,SurfaceFlinger 会为每个 Display 维护独立的 Layer 栈与合成策略,HWC 则需要为每个 Connector 配置 Plane 与 CRTC。
三、多显示器场景下的关键参数与行为
当系统接入第二块屏幕时,SurfaceFlinger 会收到 DisplayDevice 变化,并重新计算每个显示设备的可见 Layer。HWC 在 validate 阶段会检查每个 Layer 的格式、缩放、旋转、混合模式是否满足硬件 Plane 能力。若外接屏分辨率、刷新率或色深超出 Overlay 能力,就会触发 GPU 合成回退,表现为功耗上升、帧率下降或延迟增加。
| 组件 | 核心职责 | 多屏关键点 | 常见排障入口 |
|---|---|---|---|
| SurfaceFlinger | Layer 合成决策与提交 | 每 Display 独立 Layer 栈 | dumpsys SurfaceFlinger |
| HWC | 硬件合成与显示抽象 | Plane 数量与 Overlay 能力 | dumpsys SurfaceFlinger --hwc |
| Gralloc | 图形 Buffer 分配与共享 | 跨设备格式与使用标志 | dumpsys SurfaceFlinger --gralloc |
| DRM/KMS | 内核显示模式设置与提交 | CRTC/Connector 绑定关系 | modetest、dmesg、sysfs |
四、案例:外接屏无画面时的排查顺序
假设一台 Android 设备通过 HDMI 接入外接屏,但外接屏始终黑屏。建议按以下顺序排查:
- 确认 DRM/KMS 是否识别到 Connector:查看
/sys/class/drm下是否有card0-HDMI-A-1且状态为 connected。 - 确认 HWC 是否上报了该 Display:执行
dumpsys SurfaceFlinger,检查 Display 列表中是否出现外接屏及其分辨率。 - 确认 SurfaceFlinger 是否为该 Display 创建了 Layer 栈:若没有 Layer,说明应用或系统 UI 未向该 Display 投递内容。
- 确认 Gralloc 是否成功分配了匹配格式的 Buffer:若格式不支持,HWC 会回退 GPU 合成,严重时直接黑屏。
- 确认 HWC 是否成功 present:查看 HWC 日志中 validate 与 present 的返回状态,以及 DRM atomic commit 是否报错。
# 查看 DRM Connector 状态
cat /sys/class/drm/card0-HDMI-A-1/status
# 期望输出:connected
# 查看 SurfaceFlinger Display 与 Layer 信息
dumpsys SurfaceFlinger --display-id
dumpsys SurfaceFlinger --list
# 查看 HWC 合成决策
dumpsys SurfaceFlinger | grep -A 20 "Hardware Composer"
五、常见误区与复盘
误区一:认为 SurfaceFlinger 直接操作屏幕。实际上 SurfaceFlinger 只负责合成决策与提交,真正点亮屏幕的是 HWC 与 DRM/KMS。把黑屏问题全部归因于 SurfaceFlinger,容易忽略 Connector 状态与 Plane 能力。
误区二:认为 Gralloc 只是“分配内存”。Gralloc 还决定了 Buffer 的格式、步长、使用标志与共享方式。多屏场景下,若外接屏需要 10bit 色深或特定 YUV 格式,而 Gralloc 未分配对应格式,HWC 就无法硬件合成。
误区三:忽略 HWC 的 Plane 数量限制。每块显示控制器支持的 Plane 数量有限。当 Layer 数量超过可用 Plane 时,SurfaceFlinger 必须把多个 Layer 预合成到一个 Buffer,再交给 HWC。这会增加 GPU 负载,也是多屏掉帧的常见原因。
总结来说,SurfaceFlinger 是“合成决策者”,HWC 是“硬件合成执行者”,Gralloc 是“图形内存供给者”,DRM/KMS 是“内核显示提交者”。四者形成一条从应用到像素的完整链路。多显示器集成工程的核心,就是让这条链路在多个 Display 上同时稳定、高效地运行。