Android init启动过程

Android 开机第一道门槛:从内核到 init 进程,你的系统服务是怎么拉起来的?(附实战配置)

目录

  • [一、init 是什么](#一、init 是什么)
  • [二、init 的启动流程](#二、init 的启动流程)
  • [三、init.rc 语法详解](#三、init.rc 语法详解)
  • [四、init 的启动阶段](#四、init 的启动阶段)
  • [五、实战:添加自定义 Native 服务](#五、实战:添加自定义 Native 服务)
  • 六、实战:开机自启脚本
  • [七、ueventd 与设备节点](#七、ueventd 与设备节点)
  • [八、init 与 SELinux](#八、init 与 SELinux)
  • 九、常见踩坑记录
  • 十、调试技巧与总结

一、init 是什么

Android 开机:BootLoader → Linux Kernel → init → 其他所有进程。

init 是内核启动后运行的第一个用户态进程,PID 永远是 1。它是 Android 系统的大管家------负责解析 init.rc 文件,按配置把系统的各种服务和守护进程拉起来。

bash 复制代码
# 在手机上确认 init 是 PID 1
adb shell ps -A | grep " init$"
# 输出: root  1  0  0  0  init

init 干了哪些事:
#mermaid-svg-Zm5z6bnuc654JrNa{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Zm5z6bnuc654JrNa .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Zm5z6bnuc654JrNa .error-icon{fill:#552222;}#mermaid-svg-Zm5z6bnuc654JrNa .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Zm5z6bnuc654JrNa .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Zm5z6bnuc654JrNa .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Zm5z6bnuc654JrNa .marker.cross{stroke:#333333;}#mermaid-svg-Zm5z6bnuc654JrNa svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Zm5z6bnuc654JrNa p{margin:0;}#mermaid-svg-Zm5z6bnuc654JrNa .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Zm5z6bnuc654JrNa .cluster-label text{fill:#333;}#mermaid-svg-Zm5z6bnuc654JrNa .cluster-label span{color:#333;}#mermaid-svg-Zm5z6bnuc654JrNa .cluster-label span p{background-color:transparent;}#mermaid-svg-Zm5z6bnuc654JrNa .label text,#mermaid-svg-Zm5z6bnuc654JrNa span{fill:#333;color:#333;}#mermaid-svg-Zm5z6bnuc654JrNa .node rect,#mermaid-svg-Zm5z6bnuc654JrNa .node circle,#mermaid-svg-Zm5z6bnuc654JrNa .node ellipse,#mermaid-svg-Zm5z6bnuc654JrNa .node polygon,#mermaid-svg-Zm5z6bnuc654JrNa .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Zm5z6bnuc654JrNa .rough-node .label text,#mermaid-svg-Zm5z6bnuc654JrNa .node .label text,#mermaid-svg-Zm5z6bnuc654JrNa .image-shape .label,#mermaid-svg-Zm5z6bnuc654JrNa .icon-shape .label{text-anchor:middle;}#mermaid-svg-Zm5z6bnuc654JrNa .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Zm5z6bnuc654JrNa .rough-node .label,#mermaid-svg-Zm5z6bnuc654JrNa .node .label,#mermaid-svg-Zm5z6bnuc654JrNa .image-shape .label,#mermaid-svg-Zm5z6bnuc654JrNa .icon-shape .label{text-align:center;}#mermaid-svg-Zm5z6bnuc654JrNa .node.clickable{cursor:pointer;}#mermaid-svg-Zm5z6bnuc654JrNa .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Zm5z6bnuc654JrNa .arrowheadPath{fill:#333333;}#mermaid-svg-Zm5z6bnuc654JrNa .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Zm5z6bnuc654JrNa .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Zm5z6bnuc654JrNa .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zm5z6bnuc654JrNa .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Zm5z6bnuc654JrNa .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zm5z6bnuc654JrNa .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Zm5z6bnuc654JrNa .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Zm5z6bnuc654JrNa .cluster text{fill:#333;}#mermaid-svg-Zm5z6bnuc654JrNa .cluster span{color:#333;}#mermaid-svg-Zm5z6bnuc654JrNa div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Zm5z6bnuc654JrNa .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Zm5z6bnuc654JrNa rect.text{fill:none;stroke-width:0;}#mermaid-svg-Zm5z6bnuc654JrNa .icon-shape,#mermaid-svg-Zm5z6bnuc654JrNa .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Zm5z6bnuc654JrNa .icon-shape p,#mermaid-svg-Zm5z6bnuc654JrNa .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Zm5z6bnuc654JrNa .icon-shape .label rect,#mermaid-svg-Zm5z6bnuc654JrNa .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Zm5z6bnuc654JrNa .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Zm5z6bnuc654JrNa .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Zm5z6bnuc654JrNa :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} init 启动
挂载文件系统

tmpfs / devpts / proc / sysfs
解析所有 .rc 文件
按阶段触发

early-init → init → late-init
启动属性服务

property_service
拉起 zygote / servicemanager

surfaceflinger 等核心服务
进入主循环

监控子进程 / 处理属性变更

init 的源码在 AOSP 的 system/core/init/ 目录下,入口是 init.cppmain() 函数。


二、init 的启动流程

init 分两个阶段启动------第一阶段挂载基础文件系统,第二阶段加载 rc 并进入主循环。

整个流程:
#mermaid-svg-MgKApwOikixDXAyk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MgKApwOikixDXAyk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MgKApwOikixDXAyk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MgKApwOikixDXAyk .error-icon{fill:#552222;}#mermaid-svg-MgKApwOikixDXAyk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MgKApwOikixDXAyk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MgKApwOikixDXAyk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MgKApwOikixDXAyk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MgKApwOikixDXAyk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MgKApwOikixDXAyk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MgKApwOikixDXAyk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MgKApwOikixDXAyk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MgKApwOikixDXAyk .marker.cross{stroke:#333333;}#mermaid-svg-MgKApwOikixDXAyk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MgKApwOikixDXAyk p{margin:0;}#mermaid-svg-MgKApwOikixDXAyk .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MgKApwOikixDXAyk .cluster-label text{fill:#333;}#mermaid-svg-MgKApwOikixDXAyk .cluster-label span{color:#333;}#mermaid-svg-MgKApwOikixDXAyk .cluster-label span p{background-color:transparent;}#mermaid-svg-MgKApwOikixDXAyk .label text,#mermaid-svg-MgKApwOikixDXAyk span{fill:#333;color:#333;}#mermaid-svg-MgKApwOikixDXAyk .node rect,#mermaid-svg-MgKApwOikixDXAyk .node circle,#mermaid-svg-MgKApwOikixDXAyk .node ellipse,#mermaid-svg-MgKApwOikixDXAyk .node polygon,#mermaid-svg-MgKApwOikixDXAyk .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MgKApwOikixDXAyk .rough-node .label text,#mermaid-svg-MgKApwOikixDXAyk .node .label text,#mermaid-svg-MgKApwOikixDXAyk .image-shape .label,#mermaid-svg-MgKApwOikixDXAyk .icon-shape .label{text-anchor:middle;}#mermaid-svg-MgKApwOikixDXAyk .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MgKApwOikixDXAyk .rough-node .label,#mermaid-svg-MgKApwOikixDXAyk .node .label,#mermaid-svg-MgKApwOikixDXAyk .image-shape .label,#mermaid-svg-MgKApwOikixDXAyk .icon-shape .label{text-align:center;}#mermaid-svg-MgKApwOikixDXAyk .node.clickable{cursor:pointer;}#mermaid-svg-MgKApwOikixDXAyk .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MgKApwOikixDXAyk .arrowheadPath{fill:#333333;}#mermaid-svg-MgKApwOikixDXAyk .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MgKApwOikixDXAyk .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MgKApwOikixDXAyk .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MgKApwOikixDXAyk .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MgKApwOikixDXAyk .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MgKApwOikixDXAyk .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MgKApwOikixDXAyk .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MgKApwOikixDXAyk .cluster text{fill:#333;}#mermaid-svg-MgKApwOikixDXAyk .cluster span{color:#333;}#mermaid-svg-MgKApwOikixDXAyk div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MgKApwOikixDXAyk .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MgKApwOikixDXAyk rect.text{fill:none;stroke-width:0;}#mermaid-svg-MgKApwOikixDXAyk .icon-shape,#mermaid-svg-MgKApwOikixDXAyk .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MgKApwOikixDXAyk .icon-shape p,#mermaid-svg-MgKApwOikixDXAyk .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MgKApwOikixDXAyk .icon-shape .label rect,#mermaid-svg-MgKApwOikixDXAyk .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MgKApwOikixDXAyk .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MgKApwOikixDXAyk .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MgKApwOikixDXAyk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Kernel 启动

执行 /system/bin/init
FirstStageMain()

挂载 /dev /proc /sys
execv 进入

SecondStageMain()
property_init()

初始化属性系统
SelinuxInitialize()

加载 SELinux 策略
LoadBootScripts()

解析所有 .rc 文件
按阶段触发

early-init → init → late-init
while(true) 主循环

epoll 监听事件

执行 Action

重启崩溃的服务

主循环干了什么:

  • 处理子进程退出:服务挂了,按 rc 配置决定要不要自动重启
  • 执行到期的 Action:属性变化触发的命令
  • 处理控制消息ctl.start / ctl.stop 来启停服务
  • 处理关机重启 :收到 sys.powerctl 属性执行对应操作

三、init.rc 语法详解

init.rc 用 Android Init Language 写,三种核心元素:

元素 关键字 作用
Action on 条件触发时执行命令
Service service 定义守护进程
Import import 引入另一个 .rc 文件

Action 语法:

bash 复制代码
on <trigger>        # 当 trigger 触发时
    <command>       # 执行命令
    <command>

Service 语法:

bash 复制代码
service <name> <path> [ <argument> ]*
    <option>        # 各类选项
    <option>

常用 Service 选项:

选项 含义
class <name> 分组,可批量启停(class_start core)
user / group 以哪个用户/组运行
oneshot 一次性执行,挂了不重启
disabled 默认不启动,需手动 start
critical 关键服务------挂了多次进 recovery
onrestart 该服务重启时执行的命令
socket 创建 Unix Domain Socket
seclabel SELinux 上下文

实战示例:

bash 复制代码
# Action 示例
on early-init
    mount tmpfs tmpfs /mnt mode=0755
    mkdir /mnt/vendor 0755 root root

on late-init
    trigger zygote-start       # 最后拉起 zygote

# Service 示例------zygote 是最重要的服务
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media

四、init 的启动阶段

#mermaid-svg-PAx1ITYD3hfV7x3R{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PAx1ITYD3hfV7x3R .error-icon{fill:#552222;}#mermaid-svg-PAx1ITYD3hfV7x3R .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PAx1ITYD3hfV7x3R .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PAx1ITYD3hfV7x3R .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PAx1ITYD3hfV7x3R .marker.cross{stroke:#333333;}#mermaid-svg-PAx1ITYD3hfV7x3R svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PAx1ITYD3hfV7x3R p{margin:0;}#mermaid-svg-PAx1ITYD3hfV7x3R .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster-label text{fill:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster-label span{color:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster-label span p{background-color:transparent;}#mermaid-svg-PAx1ITYD3hfV7x3R .label text,#mermaid-svg-PAx1ITYD3hfV7x3R span{fill:#333;color:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R .node rect,#mermaid-svg-PAx1ITYD3hfV7x3R .node circle,#mermaid-svg-PAx1ITYD3hfV7x3R .node ellipse,#mermaid-svg-PAx1ITYD3hfV7x3R .node polygon,#mermaid-svg-PAx1ITYD3hfV7x3R .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PAx1ITYD3hfV7x3R .rough-node .label text,#mermaid-svg-PAx1ITYD3hfV7x3R .node .label text,#mermaid-svg-PAx1ITYD3hfV7x3R .image-shape .label,#mermaid-svg-PAx1ITYD3hfV7x3R .icon-shape .label{text-anchor:middle;}#mermaid-svg-PAx1ITYD3hfV7x3R .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PAx1ITYD3hfV7x3R .rough-node .label,#mermaid-svg-PAx1ITYD3hfV7x3R .node .label,#mermaid-svg-PAx1ITYD3hfV7x3R .image-shape .label,#mermaid-svg-PAx1ITYD3hfV7x3R .icon-shape .label{text-align:center;}#mermaid-svg-PAx1ITYD3hfV7x3R .node.clickable{cursor:pointer;}#mermaid-svg-PAx1ITYD3hfV7x3R .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PAx1ITYD3hfV7x3R .arrowheadPath{fill:#333333;}#mermaid-svg-PAx1ITYD3hfV7x3R .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PAx1ITYD3hfV7x3R .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PAx1ITYD3hfV7x3R .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PAx1ITYD3hfV7x3R .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PAx1ITYD3hfV7x3R .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PAx1ITYD3hfV7x3R .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster text{fill:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R .cluster span{color:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PAx1ITYD3hfV7x3R .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PAx1ITYD3hfV7x3R rect.text{fill:none;stroke-width:0;}#mermaid-svg-PAx1ITYD3hfV7x3R .icon-shape,#mermaid-svg-PAx1ITYD3hfV7x3R .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PAx1ITYD3hfV7x3R .icon-shape p,#mermaid-svg-PAx1ITYD3hfV7x3R .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PAx1ITYD3hfV7x3R .icon-shape .label rect,#mermaid-svg-PAx1ITYD3hfV7x3R .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PAx1ITYD3hfV7x3R .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PAx1ITYD3hfV7x3R .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PAx1ITYD3hfV7x3R :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} early-init
init

启动 core class 服务
early-fs → fs → post-fs
late-fs → post-fs-data

/data 分区就绪
zygote-start

★ 拉起 Zygote
early-boot → boot

启动 main class 服务
开机完成

sys.boot_completed=1

阶段 主要做什么
early-init 创建基础目录
init 启动 ueventd、logd 等服务
fs mount_all 挂载分区
post-fs-data /data 分区就绪,创建目录结构
zygote-start 拉起 Zygote → SystemServer → 所有系统服务
boot 启动 main class 的服务,发开机广播

你的 Service 如果不加 disabled,class 对上了就会在对应阶段自动启动。


五、实战:添加自定义 Native 服务

写一个 C++ 程序,让它开机自启且挂了自动重启。

第 1 步:写程序

cpp 复制代码
// my_daemon.cpp
#include <unistd.h>
#include <android/log.h>

#define LOG_TAG "MyDaemon"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

int main() {
    LOGI("MyDaemon started, PID=%d", getpid());
    while (true) {
        LOGI("MyDaemon is running...");
        sleep(10);
    }
    return 0;
}

第 2 步:Android.bp 编译

json 复制代码
cc_binary {
    name: "my_daemon",
    srcs: ["my_daemon.cpp"],
    shared_libs: ["liblog"],
    init_rc: ["my_daemon.rc"],
}

init_rc 属性会自动把你的 .rc 安装到 /system/etc/init/

第 3 步:写 my_daemon.rc

bash 复制代码
service my_daemon /system/bin/my_daemon
    class main              # 随 main class 启动
    user system
    group system
    seclabel u:r:my_daemon:s0

不加 oneshot 不加 disabled = 开机自启 + 挂了自动重启。

第 4 步:编译测试

bash 复制代码
source build/envsetup.sh
lunch <你的产品>
mmm path/to/module
make -j16

# 验证
adb shell ps -A | grep my_daemon
adb shell start my_daemon   # 手动启动
adb shell stop my_daemon    # 手动停止
adb logcat -b all | grep MyDaemon

六、实战:开机自启脚本

不需要 C++ 程序,只想开机执行几条命令。

脚本:

bash 复制代码
# /system/bin/init_custom.sh
#!/system/bin/sh
setprop vendor.my.feature.enabled 1
mkdir -p /data/my_app/config
chmod 755 /data/my_app/config

rc 配置------开机完成后执行:

bash 复制代码
# my_custom.rc
on property:sys.boot_completed=1
    exec - system system -- /system/bin/sh /system/bin/init_custom.sh

想更早执行就把 sys.boot_completed=1 换成 post-fs-data

编译配置(device.mk):

makefile 复制代码
PRODUCT_COPY_FILES += \
    $(LOCAL_PATH)/my_custom.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/my_custom.rc \
    $(LOCAL_PATH)/init_custom.sh:$(TARGET_COPY_OUT_VENDOR)/bin/init_custom.sh

七、ueventd 与设备节点

ueventd 是 init 的子进程,接管内核 uevent(设备热插拔),创建设备节点并设权限。
#mermaid-svg-BgOAJaFMZnF2Ri1X{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-BgOAJaFMZnF2Ri1X .error-icon{fill:#552222;}#mermaid-svg-BgOAJaFMZnF2Ri1X .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-BgOAJaFMZnF2Ri1X .marker{fill:#333333;stroke:#333333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .marker.cross{stroke:#333333;}#mermaid-svg-BgOAJaFMZnF2Ri1X svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-BgOAJaFMZnF2Ri1X p{margin:0;}#mermaid-svg-BgOAJaFMZnF2Ri1X .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster-label text{fill:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster-label span{color:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster-label span p{background-color:transparent;}#mermaid-svg-BgOAJaFMZnF2Ri1X .label text,#mermaid-svg-BgOAJaFMZnF2Ri1X span{fill:#333;color:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .node rect,#mermaid-svg-BgOAJaFMZnF2Ri1X .node circle,#mermaid-svg-BgOAJaFMZnF2Ri1X .node ellipse,#mermaid-svg-BgOAJaFMZnF2Ri1X .node polygon,#mermaid-svg-BgOAJaFMZnF2Ri1X .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .rough-node .label text,#mermaid-svg-BgOAJaFMZnF2Ri1X .node .label text,#mermaid-svg-BgOAJaFMZnF2Ri1X .image-shape .label,#mermaid-svg-BgOAJaFMZnF2Ri1X .icon-shape .label{text-anchor:middle;}#mermaid-svg-BgOAJaFMZnF2Ri1X .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .rough-node .label,#mermaid-svg-BgOAJaFMZnF2Ri1X .node .label,#mermaid-svg-BgOAJaFMZnF2Ri1X .image-shape .label,#mermaid-svg-BgOAJaFMZnF2Ri1X .icon-shape .label{text-align:center;}#mermaid-svg-BgOAJaFMZnF2Ri1X .node.clickable{cursor:pointer;}#mermaid-svg-BgOAJaFMZnF2Ri1X .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .arrowheadPath{fill:#333333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BgOAJaFMZnF2Ri1X .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-BgOAJaFMZnF2Ri1X .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BgOAJaFMZnF2Ri1X .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster text{fill:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X .cluster span{color:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-BgOAJaFMZnF2Ri1X .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-BgOAJaFMZnF2Ri1X rect.text{fill:none;stroke-width:0;}#mermaid-svg-BgOAJaFMZnF2Ri1X .icon-shape,#mermaid-svg-BgOAJaFMZnF2Ri1X .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-BgOAJaFMZnF2Ri1X .icon-shape p,#mermaid-svg-BgOAJaFMZnF2Ri1X .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-BgOAJaFMZnF2Ri1X .icon-shape .label rect,#mermaid-svg-BgOAJaFMZnF2Ri1X .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-BgOAJaFMZnF2Ri1X .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-BgOAJaFMZnF2Ri1X .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-BgOAJaFMZnF2Ri1X :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 内核 uevent

设备插入/拔出
ueventd
解析 ueventd.rc
创建设备节点并设权限
/dev/video0

owner=root group=camera

perm=0660

ueventd.rc 示例:

bash 复制代码
/dev/i2c-*       0660   root       system
/dev/tty*        0666   root       root
/dev/camera      0660   system     camera
/dev/video*      0660   system     camera

新加的硬件驱动,对应的设备节点权限写在这里,不然上层 App 没权限访问。


八、init 与 SELinux

Android 强制开启 SELinux,init 启动的每个 Service 都要有对应策略,不然启动直接被 kill。

调试:

bash 复制代码
adb shell getenforce           # 查看状态
adb shell setenforce 0         # 临时关掉调试
adb logcat -b all | grep avc   # 看拒绝日志

策略文件示例(my_daemon.te):

bash 复制代码
type my_daemon, domain;
type my_daemon_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(my_daemon)

allow my_daemon system_file:file { open read };
allow my_daemon property_socket:sock_file write;

调试流程:setenforce 0 → 看程序能不能跑 → 能跑就是 SELinux 问题 → 抓 avc 日志 → 补权限 → setenforce 1 验证。


九、常见踩坑记录

坑 1:改了 rc 没重新编译刷机 ------ rc 文件打包在系统镜像里,光改不编不刷等于没改。

坑 2:路径写错 ------ init 找不到可执行文件,先 adb shell ls -la /system/bin/xxx 确认。

坑 3:SELinux 权限没给够 ------ 日志里搜 avc: denied

坑 4:oneshot 和 disabled 搞混 ------ oneshot 只跑一次不重启;disabled 默认不启动;都不加才自启+自动重启。

坑 5:class 没写 ------ 没 class 就不会被 class_start 自动拉起。

坑 6:exec 脚本不指定 shell ------ 明确用 exec - system system -- /system/bin/sh /path/to/script.sh


十、调试技巧与总结

常用命令:

bash 复制代码
adb shell dumpsys | grep -A 5 "Service "     # 查看所有 Service 状态
adb shell start/stop servicename              # 启停
adb logcat -b all | grep "init: "             # init 日志
adb shell dmesg | tail -50                    # 内核日志
adb shell getprop init.svc.servicename        # 服务状态
adb shell setprop ctl.start servicename       # 等同于 start

rc 文件位置:

分区 路径 谁放的
system /system/etc/init/hw/init.rc AOSP 根 rc
system /system/etc/init/*.rc AOSP 模块
vendor /vendor/etc/init/*.rc 芯片/硬件厂商
odm /odm/etc/init/*.rc ODM 定制

小结: init 机制不复杂------开机读 rc → 触发 Action → 启动 Service → 主循环当管家。你加的任何系统服务,本质就是写个 rc 让 init 管起来。记住三句话:rc 定义 Service → class 决定何时启 → SELinux 给权限才能跑。

相关推荐
张小潇12 小时前
AOSP15 WMS/AMS系统开发 - Activity 生命周期源码详细分析
android
风别鹤12 小时前
windows android studio 工程gradlew.bat不是64位程序
android·ide·windows·android studio
韩曙亮12 小时前
【错误记录】Flutter 编译 Android APK 文件安装包报错 ( 国内镜像源设置 )
android·flutter
问心无愧051313 小时前
ctf show web入门260
android·前端·笔记
何乐乐13 小时前
【Taro 5.0 技术与实践】 - 高性能 iOS 渲染层与 TaroUI 跨端框架介绍
android·前端·ios
木子予彤13 小时前
SmartRefreshLayout 时间逆流缺陷分析
android
问心无愧051313 小时前
ctf show web入门259
android·前端·笔记
_李小白14 小时前
【android opencv学习笔记】Day 25: GrabCut 前景提取
android·opencv·学习
Kapaseker14 小时前
Kotlin 的扩展没有你看上去的那么简单
android·kotlin