Android启动优化
一. 核心优化思路
开机过程主要分为以下几个阶段,优化也围绕这些阶段展开:
- Bootloader:初始化硬件,加载内核。通常由芯片厂商定制,优化空间有限
- Kernel:初始化驱动、子系统。优化重点在于减少初始化时间和裁剪不必要的驱动
- Init 进程:解析
init.rc
脚本,启动核心系统服务(如 servicemanager, surfaceflinger) - Zygote 进程:Android 运行时和系统服务的孵化器。预加载类和资源,其启动速度直接影响后续应用启动
- SystemServer:Android 框架的核心,启动所有系统服务(如 AMS, PMS, WMS 等)。这是优化潜力最大、最复杂的阶段
- Launcher:系统启动完成的标志,启动主屏幕应用
核心思想:并行化、延迟加载、缓存、裁剪
二. 具体优化方法
阶段 一:内核与 Init 阶段优化
- 内核配置优化:
○ 裁剪内核:移除设备不需要的驱动、文件系统、网络协议、调试功能等。使用make menuconfig
进行精细配置
○ 优化内核启动参数:调整控制台输出、内存管理等参数
○ 初始化调用优化:将非关键的驱动初始化(module_init
)标记为延迟初始化(late_initcall
),使其在系统启动后再初始化 - Init 阶段优化:
○ 并行执行任务:修改init.rc
文件,利用class_start
将不相互依赖的服务标记为同一个 class,让 init 进程并行启动它们
○ 减少 Shell 命令:避免在init.rc
中执行耗时的 Shell 命令(如chmod
,chown
等),这些操作应在编译时由fs_config
完成
○ 使用 Treble 和 A/B 分区:Treble 架构将系统和供应商解耦,简化了更新流程。A/B(无缝更新)分区可以让系统在后台更新,下次启动直接切换到新系统,减少感知到的启动时间
阶段 二:Zygote 优化
- 预加载优化:
○ 分析预加载类:使用工具分析 Zygote 预加载的类和资源。移除系统级应用不再使用的类,减少预加载列表(如preloaded-classes
)
○ 优化预加载逻辑:避免在预加载阶段执行复杂的逻辑或 I/O 操作 - Zygote 本身优化:
○ 关注 AOSP 上游的改进。例如,Android 10 引入了 App Zygote 和 USAP(未知应用预孵化池),进一步优化了应用启动,但其本身的初始化也需要优化
阶段 三:SystemServer 优化 - 重中之重
这是最复杂也是收益最高的部分
- 服务启动分析:
○ 使用dumpsys package startup-info
或直接查看SystemServer
的日志,了解各个服务的启动耗时
○ 重点关注SystemServer
主线程的init
和start
阶段 - 并行化启动服务:
○ 主线程优化:将不依赖其他服务的系统服务(如TelephonyRegistry
)的启动,从SystemServer
的主线程移动到单独的线程中,使用SystemServiceManager.startBootPhase()
来协调启动顺序
○ 使用 ConcurrentyFramework
:在SystemServer
中利用ExecutorService
创建线程池,并发启动多个服务 - 延迟启动与非关键服务:
○ 识别关键路径:明确启动 Launcher 所必须的系统服务(如ActivityManagerService
,PackageManagerService
)。其他服务(如BluetoothService
,WiFiService
)可以延迟加载
○ 使用StartControllers
和BackgroundLaunch
:将非关键服务标记为可以在后台启动,或者等到第一次被绑定时才初始化 - 缓存与预加载:
○ PackageManager 优化:PackageManagerService
的扫描和解析是耗时大户
◎ 使用编译时信息:启用dex2oat
的 speed 模式,在系统编译时对系统应用进行预优化
◎ 优化扫描路径:确保只扫描必要的目录(/system
,/vendor
,/product
),避免扫描data
分区
◎ 使用apex
和module
:新的模块化分发方式可以减少 PMS 的扫描负担
阶段 四:应用与 Launcher 优化
- Launcher 自身优化:
○ 将 Launcher 视为一个普通应用,应用所有应用启动优化手段
○ 避免冷启动:确保 Launcher 进程在开机前已被 Zygote 预加载 - 系统应用预加载:
○ 使用cmd package compile -m speed -f <package-name>
命令在首次启动后或工厂烧录时,预编译关键系统应用为最优的机器码
三. 分析与测量工具
没有测量就无法优化。以下是关键工具:
bootchart
:
○ 功能:生成整个启动过程的 CPU、I/O、进程树的时间线图。是启动优化的首选宏观分析工具
○ 使用:在 AOSP 源码中启用ENABLE_BOOTCHART=true
,编译后刷机。开机后会在/data/bootchart
生成日志,用pybootchart.py
解析生成图表systrace
/perfetto
:
○ 功能:提供更细粒度的性能分析,可以跟踪系统调用、CPU 调度、锁竞争等。Perfetto 是 Systrace 的升级版
○ 使用:在代码中插入Trace.beginSection("MyService.init")
和Trace.endSection()
来标记关键代码块。然后使用python systrace.py
或 Perfetto UI 抓取 trace 文件进行分析- 内核日志:
○ 功能:通过dmesg
查看内核启动日志,里面包含了每个驱动初始化的精确时间戳(通过printk
输出)
○ 使用:adb shell dmesg > dmesg.log
,然后分析时间戳间隔较大的部分 - Logcat:
○ 功能:查看系统服务的启动日志。SystemServer
会打印类似StartService ...
和Service ... started
的日志
○ 使用:adb logcat -b all -v time -d > logcat.txt
,然后搜索SystemServer
和ActivityManager
的相关日志 - 自定义打点:
○ 在SystemServer.java
等关键位置添加logcat
或Slog.i
输出时间戳,可以非常精确地测量特定服务的启动耗时
四. 实战流程建议
- 建立基线:使用
bootchart
和systrace
抓取一次未优化的启动过程,确定总启动时间和各阶段耗时 - 定位瓶颈:分析图表,找到耗时最长的阶段(是 Kernel?PMS?还是某个系统服务?)
- 制定策略:
○ 如果是 I/O 密集型(如 PMS 扫描),考虑缓存、预加载、并行扫描
○ 如果是 CPU 密集型(如服务初始化逻辑),考虑延迟加载、异步初始化、算法优化
○ 如果是等待依赖,考虑调整启动顺序或并行化 - 实施修改:修改 AOSP 代码(如
SystemServer.java
,init.rc
),每次只做一个修改 - 验证效果:重新编译刷机,再次测量,对比优化前后的数据
- 迭代:重复步骤 2-5,直到达到目标
总结
层面 | 关键优化手段 |
---|---|
内核/Init | 驱动裁剪与延迟初始化,init.rc 任务并行化 |
Zygote | 精简预加载类和资源 |
SystemServer | 服务启动并行化,非关键服务延迟加载,PMS 扫描优化 |
应用/Launcher | 预编译,应用启动优化 |
工具 | bootchart(宏观),systrace/perfetto(微观),logcat/dmesg(日志) |