1. 课程导入
Android设备从按下电源键到桌面可用,并不是“Linux内核启动后直接运行App”这么简单。它是一条由硬件、引导程序、内核、用户空间初始化、系统服务与框架层共同组成的多级启动链。在这条链路中,Init进程是用户空间的第一个进程(PID 1),也是Android系统工程的“总调度台”:它负责挂载文件系统、解析启动脚本、启动核心守护进程、触发属性服务、处理SELinux上下文、按需启动服务,并最终把控制权交给Zygote与SystemServer。理解Init,等于拿到了分析Android启动问题的钥匙。
学习目标:从“看得懂日志”到“改得动启动链”
本课程的目标不是背诵启动顺序,而是建立可验证、可调试、可修改的系统工程能力。完成学习后,你应当能够:
- 描述Android启动链的完整阶段划分,并说明每个阶段的输入、输出与关键进程。
- 读懂
init.rc、init.<hardware>.rc与/etc/init/目录下的启动脚本,理解Action、Trigger、Service、Command的语义。 - 使用
adb shell getprop、dmesg、logcat -b events、ps -A等工具定位启动卡点。 - 掌握属性服务(Property Service)与SELinux在启动过程中的作用,能解释“为什么服务起不来”。
- 能够新增一个自定义native服务,并让它随系统启动、按需重启、正确设置权限与SELinux标签。
核心概念:启动链中的五个关键角色
Android启动链可以抽象为五个关键角色,它们依次接力,任何一环断裂都会导致启动失败或卡在开机动画。
| 角色 | 典型实体 | 核心职责 | 常见故障现象 |
|---|---|---|---|
| Bootloader | U-Boot、LK、ABL | 初始化DDR、加载boot.img、校验并跳转内核 | 黑屏、反复重启、fastboot模式 |
| Kernel | Linux Kernel + DTB | 驱动初始化、挂载根文件系统、启动第一个用户进程 | kernel panic、卡在logo |
| Init | /system/bin/init | 解析rc、启动服务、属性初始化、SELinux加载 | 卡在“init:”日志、服务反复重启 |
| Zygote | app_process | 预加载类与资源、fork应用进程 | 开机动画循环、无法进入桌面 |
| SystemServer | system_server | 启动AMS、PMS、WMS等系统服务 | 系统UI崩溃、服务超时 |
其中,Init是承上启下的枢纽。它既要从内核接收“启动完成”的信号,又要为上层框架准备运行环境。因此,本课程会把大量篇幅放在Init的脚本解析、服务管理、属性系统与安全机制上。
整体框架:一张图看清启动链与Init的位置
下面的SVG展示了从电源上电到系统服务就绪的主干路径,并突出Init在用户空间中的调度中心地位。图中同时标出了关键日志观察点,便于后续排障时对照。
实战路线图:从观察到修改的四个台阶
本课程按“观察—理解—修改—验证”的工程闭环推进,建议你按以下路线学习,不要跳步。
- 观察启动日志:在设备上执行
adb shell dmesg | head -100与adb logcat -b events | grep -i boot,记录从内核到Zygote的时间线。 - 理解rc语法:阅读
/system/etc/init/hw/init.rc,找出on boot、on property:sys.boot_completed=1等关键Trigger。 - 修改服务配置:新增一个
service mysvc /system/bin/mysvc,设置class main、user system、oneshot等属性。 - 验证与排障:通过
getprop init.svc.mysvc查看服务状态,结合dmesg与SELinux denial日志定位失败原因。
核心命令速查:
adb shell getprop init.svc.zygote
adb shell getprop sys.boot_completed
adb shell dmesg | grep -E "init|avc"
adb shell logcat -b events | grep boot_progress
adb shell ps -A -o PID,NAME | grep -E "init|zygote|system_server"
案例场景:一次“服务起不来”的复盘
假设你新增了一个native服务mysvc,设备启动后getprop init.svc.mysvc显示stopped,但日志里没有明显崩溃。常见原因往往不是代码问题,而是启动配置与安全策略不匹配。排查顺序建议如下:
- 检查rc中是否写了
disabled,导致服务默认不启动。 - 检查
class是否属于main或late_start,是否被对应Trigger触发。 - 检查可执行文件权限与SELinux标签:
ls -lZ /system/bin/mysvc。 - 检查
dmesg中是否有avc: denied,若有则需补充te规则或调整上下文。 - 检查依赖的socket、设备节点或属性是否已就绪,避免服务启动过早。
常见误区:很多初学者把Init当成“简单的启动脚本解释器”,忽略它同时承担属性服务、SELinux策略加载、服务生命周期管理和子进程回收等职责。实际上,Init是Android用户空间的第一个进程,它的行为直接决定系统能否进入sys.boot_completed=1状态。另一个误区是只改init.rc而不验证SELinux,导致服务被静默拒绝。