4. 显示启动关键阶段

Android 从按下电源键到用户看到可交互桌面,显示链路会经历多个“画面所有权”的交接点。真正让用户感知为“黑屏”的,往往不是屏幕没亮,而是某个阶段没有及时把有效帧送显,或者两个阶段之间出现了无内容输出的窗口期。理解开机 Logo、BootAnimation、动画退出与 Launcher 首帧这四个阶段的衔接关系,是定位启动黑屏的核心。

显示启动的本质是一条“帧生产者不断切换”的流水线:Bootloader 输出 Logo,Kernel 接管并显示 Logo,init 启动 SurfaceFlinger 后由 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 提交第一帧。首帧时间直接决定用户感知的“开机完成”时刻。

显示启动四阶段与黑屏窗口期 时间 ① 开机 Logo Bootloader / Kernel 直接扫描帧缓冲 ② BootAnimation SurfaceFlinger + bootanim Surface 合成送显 ③ 动画退出 停止信号 / 淡出 Launcher 启动中 ④ Launcher 首帧 冷启动 + 首帧提交 进入可交互桌面 W1 Logo→动画 W2 动画→桌面 黑屏窗口期判定要点 W1:Logo 已消失但 BootAnimation 首帧未出,常见于 SurfaceFlinger 启动慢、bootanim 资源缺失。 W2:动画已退出但 Launcher 首帧未提交,常见于 Launcher 冷启动慢、首帧绘制阻塞、进程被延迟调度。 排查时以 logcat 中 BootAnimation 退出时间与 Launcher 首帧时间为锚点,计算窗口期长度。

二、黑屏窗口期的判定方法

定位黑屏窗口期,关键是找到每个阶段的“开始时间”和“结束时间”。常用锚点包括: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

四、误区与复盘

常见误区一:把“黑屏”一律归因于显示驱动。实际上 W2 窗口期多由 Launcher 冷启动或系统调度引起,与显示驱动无关。误区二:只看 BootAnimation 是否播放,忽略动画退出与首帧之间的空档。误区三:用开机总时长代替分阶段耗时,导致无法定位具体窗口期。

复盘时应建立分阶段时间基线:记录每个版本的 Logo 结束、动画首帧、动画退出、Launcher 首帧四个时间点,形成趋势对比。一旦某个阶段耗时突增,就能快速锁定是图形栈、动画资源还是 Launcher 侧的问题。对于 W1,重点优化 SurfaceFlinger 启动与 bootanim 资源加载;对于 W2,重点优化 Launcher 冷启动路径与首帧绘制,必要时让动画退出与桌面首帧重叠,用“淡出+淡入”掩盖空档。

实用技巧:在 userdebug 版本上打开 adb shell setprop debug.sf.showupdates 1 可观察 SurfaceFlinger 合成情况;用 systrace 抓取 bootanim 与 Launcher 的绘制线程,能直观看到窗口期内是否有帧提交。