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.cpp的main()函数。
二、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 给权限才能跑。