一、系统启动日志分析——从按下电源键开始
做Android系统开发这些年,我有个习惯:每次拿到一台新设备,第一件事就是抓一份完整的启动日志。为什么?因为启动过程就像系统的“出生证明”,里面藏着太多信息了。
说白了,系统启动就是一场接力赛。从Bootloader到Kernel,从init进程到Zygote,再到System Server,最后到Launcher。每个环节都有特定的日志输出。今天我就带你走一遍这个流程。
1.1 启动流程概览
先看一张图,把整个启动链路串起来。我画这张图的时候,特意把关键日志输出点标了出来。
1.2 各阶段日志特征
每个阶段的日志都有独特的“味道”。我整理了一个表格,方便你对照着看。
| 启动阶段 | 日志缓冲区 | 关键Tag | 典型日志内容 |
|---|---|---|---|
| Bootloader | 无(串口) | - | 串口输出,logcat不可见 |
| Kernel | kernel / main | kernel, init | init: init first stage started! |
| init | main | init, ueventd | init: starting service 'zygote' |
| Zygote | main, system | Zygote, dalvikvm | Zygote: Preloading classes... |
| System Server | system, events | SystemServer, ActivityManager | SystemServer: Entered the Android system server! |
| Launcher | events, main | Launcher, WindowManager | ActivityManager: Start proc Launcher |
1.3 实战抓取启动日志
嗯,这里要注意一个细节:抓启动日志不能用普通的 adb logcat,因为那只能抓到当前时刻之后的日志。要抓完整的启动过程,得用 -b all -d 参数。
我个人习惯用这条命令:
# 抓取所有缓冲区的历史日志
adb logcat -b all -d > boot_log.txt
# 如果想实时看启动过程,先清空缓冲区再重启
adb logcat -c
adb reboot
adb logcat -b all > boot_log.txt
adb logcat -G 16M 把缓冲区扩大到16MB。默认只有256KB,启动日志很容易被冲掉。这个坑我踩过好几次。
1.4 关键日志解读
拿到日志后,怎么快速定位关键节点?我总结了几个“灯塔”日志,看到它们就知道启动到哪一步了。
1.4.1 Kernel 启动完成
// 搜索 "init first stage" 或 "Freeing unused kernel memory"
[ 5.123456] init: init first stage started!
[ 5.234567] Freeing unused kernel memory: 1024K
看到这条日志,说明Kernel已经完成初始化,init进程开始运行了。我记得有一次设备卡在这里,查了半天发现是Kernel的initramfs损坏了。
1.4.2 Zygote 启动
// 搜索 "starting service 'zygote'"
01-01 00:00:12.345 123 123 I init : starting service 'zygote'
01-01 00:00:12.456 456 456 I Zygote : Preloading classes...
01-01 00:00:15.678 456 456 I Zygote : ...preloaded 5234 classes in 3.2s
Zygote启动时有个关键动作:预加载类。预加载的类数量和时间,直接反映了系统性能。如果预加载时间超过5秒,那启动速度肯定有问题。
1.4.3 System Server 就绪
// 搜索 "Entered the Android system server"
01-01 00:00:16.789 789 789 I SystemServer: Entered the Android system server!
01-01 00:00:16.790 789 789 I SystemServer: Starting services...
01-01 00:00:20.123 789 789 I SystemServer: Services started in 3.3s
1.4.4 Launcher 启动
// 搜索 "Start proc" 和 "Launcher"
01-01 00:00:21.456 789 789 I ActivityManager: Start proc 1234:com.android.launcher3/u0a1 for activity
01-01 00:00:22.789 1234 1234 I Launcher: Launcher started. Time to first frame: 1.2s
看到Launcher的进程启动日志,说明系统已经基本就绪了。从按下电源键到Launcher显示,这个总时间就是“开机时间”。
1.5 常见问题排查
实战中,启动问题是最让人头疼的。我整理了几个高频问题,你可以直接对照着查。
- 卡在Bootloader:日志里没有任何输出。检查电源、硬件连接,或者刷boot.img。
- Kernel panic:dmesg里有
Kernel panic - not syncing。通常是驱动问题。 - init 进程崩溃:日志停在
init first stage之后。检查init.rc语法。 - Zygote 预加载超时:预加载类时间超过10秒。检查是否有自定义的preload-classes。
- System Server 启动慢:某个服务初始化卡住。用
logcat -b system | grep "ServiceManager"定位。 - Launcher 黑屏:Launcher进程启动但没显示。检查SurfaceFlinger和WindowManager日志。
1.6 实战演练:分析一次完整的启动日志
来,我们动手做一次完整的分析。假设你拿到了下面这段日志(我简化了时间戳):
// 阶段1: Kernel 启动
[ 0.000] Booting Linux on physical CPU 0
[ 3.456] init: init first stage started!
[ 4.567] Freeing unused kernel memory: 1024K
// 阶段2: init 启动服务
01-01 00:00:05.678 I init : starting service 'zygote'
01-01 00:00:05.679 I init : starting service 'servicemanager'
// 阶段3: Zygote 预加载
01-01 00:00:06.890 I Zygote : Preloading classes...
01-01 00:00:10.234 I Zygote : ...preloaded 5234 classes in 3.3s
// 阶段4: System Server
01-01 00:00:11.345 I SystemServer: Entered the Android system server!
01-01 00:00:11.346 I SystemServer: Starting services...
01-01 00:00:15.678 I SystemServer: Services started in 4.3s
// 阶段5: Launcher
01-01 00:00:16.789 I ActivityManager: Start proc 1234:com.android.launcher3
01-01 00:00:18.012 I Launcher: Launcher started. Time to first frame: 1.2s
分析一下:
- Kernel启动耗时:3.456秒(正常)
- Zygote预加载耗时:3.3秒(正常范围)
- System Server启动耗时:4.3秒(正常)
- 总开机时间:约18秒(从Kernel开始算)
这个启动速度属于中等水平。如果总时间超过30秒,就需要优化了。
好了,这一章的内容就到这里。启动日志分析是个熟能生巧的活,多抓几次、多分析几次,你就能一眼看出问题在哪。下一章我们会深入分析应用启动过程中的日志,到时候再聊。
公众号:蓝海资料掘金营,微信deep3321