4. 显示启动关键阶段
Android 从按下电源键到用户看到可交互桌面,显示链路会经历多个“画面所有权”的交接点。真正让用户感知为“黑屏”的,往往不是屏幕没亮,而是某个阶段没有及时把有效帧送显,或者两个阶段之间出现了无内容输出的窗口期。理解开机 Logo、BootAnimation、动画退出与 Launcher 首帧这四个阶段的衔接关系,是定位启动黑屏的核心。
一、四个显示阶段与画面所有权
开机 Logo 阶段通常由 Bootloader 与 Kernel 共同完成。Bootloader 阶段通过显示控制器直接扫描出 Logo 帧缓冲;进入 Kernel 后,如果配置了开机 Logo,会由内核的 framebuffer 或 DRM 驱动继续显示。这个阶段的特点是“绕过 Android 图形栈”,直接操作显示硬件,因此速度快、依赖少,但一旦显示时序或分辨率配置错误,就会表现为 Logo 不显示或花屏。
BootAnimation 阶段由 init 启动的 surfaceflinger 与 bootanim 服务协作完成。此时 Android 图形栈开始工作,BootAnimation 作为一个 Surface 被合成并送显。它依赖 SurfaceFlinger 正常启动、EGL 可用、动画资源可读。如果 SurfaceFlinger 启动慢或 bootanim 服务异常,就会在 Logo 消失后出现一段黑屏,直到动画出现。
开机动画退出阶段是 BootAnimation 收到停止信号后逐渐退出,Launcher 开始启动并绘制首帧。这个交接点最容易被忽视:动画退出与 Launcher 首帧之间如果没有重叠,就会出现“动画结束—桌面未出”的黑屏窗口期。
Launcher 首帧显示阶段,系统已经进入可交互状态。Launcher 进程完成冷启动、加载布局、绑定数据后,通过 SurfaceFlinger 提交第一帧。首帧时间直接决定用户感知的“开机完成”时刻。
二、黑屏窗口期的判定方法
定位黑屏窗口期,关键是找到每个阶段的“开始时间”和“结束时间”。常用锚点包括:Kernel Logo 结束时间、SurfaceFlinger 启动完成时间、BootAnimation 首帧时间、BootAnimation 退出时间、Launcher 首帧提交时间。把这些时间点按时间轴排列,两个相邻锚点之间的空档就是候选窗口期。
# 关键日志锚点示例
adb logcat -b all | grep -E "BootAnimation|SurfaceFlinger|Launcher|Displayed"
# 查看 Launcher 首帧耗时
adb logcat | grep "Displayed com.android.launcher"
# 查看 BootAnimation 退出
adb logcat | grep -i "bootanim.*exit\|BootAnimation.*stop"
其中 Displayed 日志给出的时间,是 Activity 首帧真正上屏的时间,非常适合作为 Launcher 首帧锚点。BootAnimation 的退出时间则可以从 bootanim 服务日志或 SurfaceFlinger 的 layer 变化中获取。两者相减,就是 W2 窗口期的长度。
三、典型场景与排查清单
| 现象 | 可能阶段 | 排查方向 |
|---|---|---|
| Logo 后长时间黑屏才出动画 | W1 | SurfaceFlinger 启动耗时、bootanim 资源、EGL 初始化 |
| 动画结束后黑屏数秒才进桌面 | W2 | Launcher 冷启动、首帧绘制、进程调度、系统负载 |
| 全程黑屏但系统已启动 | Logo / 显示链路 | 显示时序、分辨率、背光、framebuffer 配置 |
| 动画卡住不退出 | BootAnimation 退出 | 停止信号、动画资源循环、服务异常 |
| 桌面出现但触摸无响应 | Launcher 首帧后 | 输入子系统、窗口焦点、ANR |
四、误区与复盘
复盘时应建立分阶段时间基线:记录每个版本的 Logo 结束、动画首帧、动画退出、Launcher 首帧四个时间点,形成趋势对比。一旦某个阶段耗时突增,就能快速锁定是图形栈、动画资源还是 Launcher 侧的问题。对于 W1,重点优化 SurfaceFlinger 启动与 bootanim 资源加载;对于 W2,重点优化 Launcher 冷启动路径与首帧绘制,必要时让动画退出与桌面首帧重叠,用“淡出+淡入”掩盖空档。
adb shell setprop debug.sf.showupdates 1 可观察 SurfaceFlinger 合成情况;用 systrace 抓取 bootanim 与 Launcher 的绘制线程,能直观看到窗口期内是否有帧提交。