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在用户空间中的调度中心地位。图中同时标出了关键日志观察点,便于后续排障时对照。

Android启动链与Init调度中心 Bootloader 加载boot.img / 校验 Kernel 驱动 / 挂载rootfs Init (PID 1) 解析rc / 属性 / SELinux 启动native服务 Zygote 预加载 / fork应用 SystemServer AMS / PMS / WMS Init 内部关键子系统 rc脚本解析 Action / Service / Trigger 属性服务 property_set / getprop SELinux 策略加载 / 上下文 服务管理 start / stop / restart 日志与事件 logcat / dmesg / events 启动阶段触发 early-init / init / boot 关键日志观察点 • dmesg | grep init • logcat -b events | grep boot • getprop | grep init • ps -A | grep zygote • ls -lZ /dev/socket

实战路线图:从观察到修改的四个台阶

本课程按“观察—理解—修改—验证”的工程闭环推进,建议你按以下路线学习,不要跳步。

  1. 观察启动日志:在设备上执行adb shell dmesg | head -100与adb logcat -b events | grep -i boot,记录从内核到Zygote的时间线。
  2. 理解rc语法:阅读/system/etc/init/hw/init.rc,找出on boot、on property:sys.boot_completed=1等关键Trigger。
  3. 修改服务配置:新增一个service mysvc /system/bin/mysvc,设置class main、user system、oneshot等属性。
  4. 验证与排障:通过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,导致服务被静默拒绝。

本章小结与学习建议