OH 标准系统启动结构梳理(五):跨子系统总启动时序
文档概述
说明:
1.文章由移远通信技术股份有限公司提供
2.以下内容包含了个人理解,仅供参考,如有不合理处,请联系笔者修改
术语与缩写
本文频繁使用以下核心术语与缩写,为方便读者快速建立概念映射,按逻辑分组整理如下。
核心进程

关键概念
| 术语/缩写 | 全称/解释 | 在本文中的核心职责 | 排查提示 |
|---|---|---|---|
| SA | System Ability,系统能力。 | 系统对外提供的服务能力单元,由 safwk 承载,通过 samgr 对外暴露。 |
调用 GetSystemAbility 确认目标 SA 是否在全局目录中;检查 samgr 日志确认 AddSystemAbility 是否执行。 |
| PID 1 | 进程 ID 为 1,特指 init 进程。 |
代表用户态启动的起点和最高控制权,负责 first-stage/second-stage 切换及后续服务管理。 | 使用 ps 确认 PID 1 进程存在且状态正常;检查内核日志确认控制权已移交。 |
| first-stage/second-stage | init 进程的两个启动阶段。 |
first-stage:建立最小文件系统和设备环境,等待关键块设备,挂载必要分区。 second-stage:读参数、读 .cfg、拉服务,驱动长期运行。 |
检查 init 日志中 first-stage 到 second-stage 的切换点;确认关键分区挂载是否成功。 |
.cfg |
init 的配置文件(如 init.cfg)。 |
定义启动阶段(jobs)、服务(services)、触发条件(triggers)和导入(imports),是 init 编排行为的依据。 |
检查 .cfg 文件是否存在且格式正确;确认目标服务的 job/trigger 配置是否在正确的阶段触发。 |
Publish() |
SA 向 samgr 注册自身能力的方法。 |
标志一个 SA 从“进程内对象”变为“全局可用能力”的关键动作,是 SA ready 的真正标志。 | 在 safwk 日志中搜索 Publish 调用记录;确认 samgr 日志中对应的 AddSystemAbility 是否完成。 |
LoadSystemAbility |
客户端向 samgr 请求获取 SA 的接口。 |
触发 samgr 的状态机,可能按需拉起目标 SA 进程,并等待其 Publish() 完成。 |
检查调用方日志确认请求是否发出;查看 samgr 日志确认状态机是否正常推进,是否超时。 |
| sandbox | 沙箱,为应用进程构造的隔离运行环境。 | 由 appspawn 在 fork 后为子进程构建,包括 mount、namespace、权限控制等,确保应用在受限环境中运行。 |
检查子进程日志中 sandbox mount/unshare 是否成功;确认基础分区挂载是否已就绪。 |
| profile / trust profile | SA 的配置文件,描述 SA 的元数据、依赖和权限。 | 由 safwk 解析,决定哪些 SA 被装载、启动以及它们的信任等级。 |
检查 profile 文件路径和内容是否正确;确认 trust profile 未错误地排除目标 SA。 |
| job/service/trigger | init 配置中的核心概念。 |
job:一组按顺序执行的动作。 service:由 init 管理的常驻进程。trigger:触发 job 执行的事件或条件。 |
检查 .cfg 中目标 service 的 critical 属性和 ondemand 标志;确认 trigger 条件是否满足。 |
重要信号

1. 说明与范围
前四篇分别拆开讲了:
init两阶段启动与.cfg解析;appspawn进程孵化主链;samgr / safwk的 SA 启动接入;appspawn sandbox的配置和执行模型。
第五篇不再往下拆单模块,而是把前面几条链收回来,回答一个更接近系统视角的问题:
标准系统从内核切到用户态以后,init、ueventd、appspawn、samgr、safwk 和具体 SA,分别在什么时刻接管系统、彼此之间靠什么信号衔接、整条链最终是怎样闭合的。
如果只保留一句话,可以这样概括:
标准系统启动不是“一个主进程把所有事做完”,而是 init 先建立控制面和配置面,ueventd 补齐设备面,samgr 建立全局能力目录,safwk 把 SA 进程接入能力体系,appspawn 把应用侧启动请求转换成受控子进程,几条链最终在 init 的启动控制和 samgr 的能力注册上完成汇合。
2. 总体视图
flowchart TD
subgraph L1["第一层:启动控制面"]
A1["PID 1 init"]
A2["启动阶段推进"]
A3[".cfg 解析"]
A4["job/service/trigger 编排"]
A5["服务管理"]
A6["参数服务"]
A1 --> A2 & A3 & A4 & A5 & A6
end
subgraph L2["第二层:设备与文件系统就绪面"]
B1["ueventd"]
B2["first-stage 挂载"]
B3["关键分区挂载"]
B4["uevent 重放"]
B5["设备节点创建"]
B6["权限修正"]
B1 --> B4 & B5 & B6
B2 --> B3
end
subgraph L3["第三层:系统能力控制面"]
C1["samgr"]
C2["全局 SA 目录"]
C3["进程-SA 映射"]
C4["LoadSystemAbility 状态机"]
C5["按需拉起控制"]
C1 --> C2 & C3 & C4 & C5
end
subgraph L4["第四层:单进程 SA 承载面"]
D1["safwk"]
D2["profile/trust profile 解析"]
D3["SA so 装载"]
D4["进程内 SA 生命周期"]
D5["Publish() 注册"]
D1 --> D2 & D3 & D4 & D5
end
subgraph L5["第五层:应用进程孵化面"]
E1["appspawn"]
E2["socket 收发"]
E3["启动请求解码"]
E4["fork/clone"]
E5["sandbox 构建"]
E6["子进程回执"]
E1 --> E2 & E3 & E4 & E5 & E6
end
L1 --> L2
L2 --> L3
L3 --> L4
L4 --> L5
style L1 fill:#e1f5fe
style L2 fill:#f3e5f5
style L3 fill:#e8f5e8
style L4 fill:#fff3e0
style L5 fill:#ffebee
本章摘要:上图将标准系统启动过程抽象为五层职责模型,从 init 的启动控制面逐层向下,经 ueventd 的设备就绪面、samgr 的能力控制面、safwk 的 SA 承载面,最终到 appspawn 的应用孵化面。这张图是全文的“地图”——后续所有章节(总启动主线、关键切换点、并行主链)都是对这张图中各层之间衔接与依赖关系的展开。
图表解读与导航:这张五层职责图是全文的“架构总纲”。它回答了“标准系统启动由哪些角色负责”的问题——init 掌控启动节奏,ueventd 补齐设备环境,samgr 建立能力目录,safwk 承载 SA 注册,appspawn 孵化应用进程。关于各层之间的具体衔接时序,请见第 4 节「总启动主线」的甘特图;关于层与层之间的控制权移交细节,请见第 5 节「五个关键切换点」;关于各层如何并行推进并相互依赖,请见第 7 节「三条并行主链」。
如果把标准系统启动压成一张职责图,可以分成五层。
2.1 第一层:启动控制面
这一层由 PID 1 的 init 负责。
它掌握的是:
- 启动阶段推进;
.cfg配置解析;job / service / trigger编排;- 服务的拉起、重启和常驻管理;
- 参数服务和基础控制 socket。
它解决的是“系统什么时候做什么”。
2.2 第二层:设备与文件系统就绪面
这一层核心是 ueventd 和 first-stage 挂载逻辑。
它掌握的是:
- 关键分区挂载;
- uevent 重放;
- 设备节点创建;
- sysfs 和设备节点权限修正。
它解决的是“后续服务是否拥有正确的设备入口和基础文件系统环境”。
2.3 第三层:系统能力控制面
这一层由 samgr 负责。
它掌握的是:
- 全局 SA 目录;
- 系统进程与 SA 的映射;
LoadSystemAbility状态机;- 按需拉起、回调和超时控制。
它解决的是“系统能力以什么目录对外暴露,以及能力还没起来时谁来负责拉起它”。
2.4 第四层:单进程 SA 承载面
这一层由 safwk 负责。
它掌握的是:
- profile/trust profile 解析;
- SA so 装载;
- 进程内 SA 生命周期;
Publish()到samgr的注册动作。
它解决的是“某个 SA 进程内部怎么把一组 SA 真正变成可用对象”。
2.5 第五层:应用进程孵化面
这一层由 appspawn 负责。
它掌握的是:
- socket 收发;
- 启动请求解码;
fork/clone;sandbox构建;- 子进程回执与孵化结果回包。
它解决的是“应用框架如何把一条启动请求变成一个实际业务进程”。
3. 为什么要拆成这五层
从工程上看,这样拆不是为了概念好看,而是为了把三种完全不同的问题隔开。
第一类问题是系统控制问题:
- 谁推进启动阶段;
- 谁拉起基础服务;
- 谁管理进程常驻和重启。
这类问题收敛在 init。
第二类问题是系统能力问题:
- 某个 SA 是否已经 ready;
- 某个 SA 属于哪个进程;
- 如果没 ready,要不要拉起。
这类问题收敛在 samgr/safwk。
第三类问题是应用进程问题:
- 如何接收启动请求;
- 如何构造运行环境;
- 如何把 sandbox、权限和进程创建合并起来。
这类问题收敛在 appspawn。
如果把这些逻辑都堆在一个进程里,后续系统演进会非常痛苦。
下面是三类问题收敛关系的决策树图:
flowchart TD
Start["启动问题分类"] --> Q1{"问题类型?"}
Q1 -->|"系统控制问题"| Init["收敛到 init"]
Init --> Init1["谁推进启动阶段"]
Init --> Init2["谁拉起基础服务"]
Init --> Init3["谁管理进程常驻和重启"]
Q1 -->|"系统能力问题"| SamgrSafwk["收敛到 samgr/safwk"]
SamgrSafwk --> SS1["某个 SA 是否 ready"]
SamgrSafwk --> SS2["SA 属于哪个进程"]
SamgrSafwk --> SS3["没 ready 时是否拉起"]
Q1 -->|"应用进程问题"| Appspawn["收敛到 appspawn"]
Appspawn --> AS1["如何接收启动请求"]
Appspawn --> AS2["如何构造运行环境"]
Appspawn --> AS3["如何合并 sandbox、权限和进程创建"]
style Init fill:#e1f5fe
style SamgrSafwk fill:#e8f5e8
style Appspawn fill:#fff3e0
4. 总启动主线
gantt
title 标准系统启动主线(14个关键步骤)
dateFormat HH:mm
axisFormat %H:%M
section 内核到用户态
内核交控制权给 init :a1, 00:00, 1m
section init 两阶段
first-stage 建立环境 :a2, after a1, 2m
first-stage 挂载分区 :a3, after a2, 2m
切入 second-stage :a4, after a3, 1m
second-stage 初始化 :a5, after a4, 2m
解析 .cfg 配置 :a6, after a5, 3m
触发 pre-init/init/post-init :a7, after a6, 3m
section 设备就绪
ueventd 进入工作态 :a8, after a7, 3m
section 能力控制面建立
init 拉起 samgr :a9, after a8, 1m
samgr 建立目录并写 ready :a10, after a9, 2m
section SA 进程启动
init 拉起 sa_main 进程 :a11, after a10, 2m
safwk 装载 SA 并注册 :a12, after a11, 3m
section 应用孵化入口
init 拉起 appspawn :a13, after a12, 1m
应用请求新进程 :a14, after a13, 3m
section 关键切换点
内核 → init :milestone, m1, 00:00, 0m
first → second :milestone, m2, after a3, 0m
init → samgr :milestone, m3, after a9, 0m
init → appspawn :milestone, m4, after a13, 0m
safwk → Publish :milestone, m5, after a12, 0m
本章摘要:上方的甘特图将全文 14 个关键步骤按时间轴排列,直观展示了从内核交权到应用进程可被请求的完整主线。图中标注的五个里程碑(内核→init、first→second、init→samgr、init→appspawn、safwk→Publish)正是下一章要深入分析的五个关键切换点——它们是理解系统控制权如何逐层移交的“锚点”。
图表解读与导航:这张甘特图将全文 14 个关键步骤按时间轴排列,直观展示了从内核交权到应用进程可被请求的完整主线。图中标注的五个里程碑(内核→init、first→second、init→samgr、init→appspawn、safwk→Publish)正是第 5 节要深入分析的五个关键切换点。关于每个切换点的详细说明与状态转换,请见第 5 节;关于图中各阶段对应的并行子链,请见第 7 节「三条并行主链」;关于每个就绪信号的具体含义,请见第 9 节「四个就绪信号」。
不展开函数细节的话,标准系统主线可以先记成下面这 14 步:
- 内核把控制权交给 PID 1
init initfirst-stage 建立最小文件系统和设备环境- first-stage 等待关键块设备,挂载必要分区
init切入 second-stage- second-stage 初始化参数服务、group、SELinux 和控制面
init解析.cfg,装配 job / service / importinit触发pre-init -> init -> post-init以及文件系统阶段ueventd进入工作态,补齐设备节点和权限init拉起samgrsamgr建立全局 SA 目录并写bootevent.samgr.readyinit根据配置拉起一批sa_main + profile进程safwk在各自进程内装载 SA so,并通过Publish()报到samgrinit拉起appspawn- 应用框架或系统服务通过 socket 向
appspawn发起新进程请求,系统进入稳定运行态
这 14 步里最关键的不是每一步本身,而是几个“控制权切换点”。
5. 五个关键切换点
5.1 从内核到 init
这是整个用户态启动的起点。
切换后,系统第一次拥有:
- 可读配置;
- 可拉起服务;
- 可维持长期控制循环的用户态进程。
从这一刻开始,系统启动从“内核 bring-up”切到“用户态编排”。
5.2 从 first-stage 到 second-stage
这是 init 内部的第一次重要 handoff。
first-stage 只解决前提条件:
- 设备出现;
- 分区挂载;
- 基础节点和最小 root 环境就绪。
second-stage 才解决策略和编排:
- 读参数;
- 读
.cfg; - 拉服务;
- 驱动长期运行。
如果没有这次 handoff,PID 1 必须同时兼顾“极早期最小依赖”和“完整系统策略”,实现会非常脆弱。
5.3 从 init 到 samgr
这一步是系统从“进程启动”走向“能力注册”的分界点。
在 samgr 启动之前:
init可以拉起进程;- 但系统还没有全局 SA 目录。
在 samgr 启动之后:
- 系统能力才有统一的名字空间;
safwk和具体 SA 才有真正的注册目标;LoadSystemAbility这类按需链路才有状态机入口。
因此,samgr 是系统控制面与能力控制面的边界点。
5.4 从 init 到 appspawn
这一步是系统从“系统服务就绪”走向“应用进程可创建”的分界点。
在 appspawn 启动之前:
- 系统服务可以启动;
- SA 体系可以逐步 ready;
- 但应用侧进程孵化入口还没正式打开。
在 appspawn 启动之后:
- 本地 socket 入口建立;
- 沙箱规则已预加载;
- 应用、Web、Native 等不同模式的孵化能力进入工作状态。
因此,appspawn 是系统服务世界和应用进程世界之间的边界点。
5.5 从 SAFWK 到 samgr Publish()
这一步是“进程起来了”和“能力真的可用了”之间的分界点。
对 SA 链路来说:
- 进程存在,不代表 SA 可用;
- so 被装载,不代表 SA 可用;
Start()被调用,也不一定已经全局可见。
只有当 SA 调用 Publish(),并最终被 samgr AddSystemAbility() 登记之后,这个能力才真正进入全局目录。
这是整个 SA 启动链最容易被误判的一个点。
下面是五个关键切换点的状态转换图:
flowchart LR
subgraph 切换点序列["五个关键切换点"]
direction LR
T1["① 内核 → init"] --> T2["② first-stage → second-stage"]
T2 --> T3["③ init → samgr"]
T3 --> T4["④ init → appspawn"]
T4 --> T5["⑤ safwk → Publish()"]
end
subgraph 切换后状态["切换后系统能力"]
T1S["用户态编排开始<br>可读配置、可拉服务"]
T2S["策略与编排阶段<br>读参数、读 .cfg、拉服务"]
T3S["全局能力目录建立<br>统一名字空间"]
T4S["应用进程入口开放<br>socket 监听、sandbox 预加载"]
T5S["能力全局可见<br>AddSystemAbility 登记"]
end
T1 --> T1S
T2 --> T2S
T3 --> T3S
T4 --> T4S
T5 --> T5S
style T1 fill:#e1f5fe
style T2 fill:#f3e5f5
style T3 fill:#e8f5e8
style T4 fill:#fff3e0
style T5 fill:#ffebee
6. 总时序图
把核心链路压成一张文字版时序,可以写成下面这样。
kernel` -> `init(first-stage)- ````init(first-stage)
-> 挂载关键分区 -> 触发早期 uevent - ````init(first-stage)
-> exec second-stage init init(second-stage)` -> `SystemInitinit(second-stage)` -> `SystemConfiginit -> 解析 init.cfg / import / jobs / servicesinit -> trigger pre-initinit -> start ueventdueventd -> 处理 kernel uevent -> 创建设备节点 -> 修正权限init -> trigger init / post-init / fs / late-fs / bootinit -> start samgrsamgr -> SetContextObject -> AddSamgrToAbilityMapsamgr -> SetParameter(bootevent.samgr.ready=true)init -> start foundation / 其他 sa_main 进程safwk -> 解析 profile / trust profilesafwk -> 等待 samgr proxy readysafwk -> AddSystemProcesssafwk -> dlopen SA so -> Start()SA -> Publish()samgr -> AddSystemAbilityinit -> start appspawnappspawn -> STAGE_SERVER_PRELOAD -> 预加载 sandboxframework/service -> connect appspawn socketappspawn -> 解码请求 -> parent pre-forkappspawn child -> child execute -> sandbox mount/unshareappspawn child -> pipe 回执appspawn parent -> 回包 -> 新进程进入运行态
这张时序图要表达的不是“所有进程严格串行启动”,而是:
- 系统控制面先起来;
- 再建立能力控制面;
- 再逐步打开应用进程入口;
- 最终收敛到多个子系统并行进入稳定态。
7. 三条并行主链
flowchart TD
Start["系统启动开始"] --> Chain1["基础环境链"]
Start --> Chain2["系统能力链"]
Start --> Chain3["应用进程链"]
subgraph Chain1["基础环境链"]
direction LR
C1A["init first-stage"] --> C1B["ueventd"] --> C1C["文件系统阶段"]
C1A --> C1D["关键分区挂载"]
C1B --> C1E["设备节点创建"]
C1C --> C1F["权限修正"]
end
subgraph Chain2["系统能力链"]
direction LR
C2A["init"] --> C2B["samgr"] --> C2C["safwk"] --> C2D["SA Publish"]
C2B --> C2E["全局能力目录"]
C2C --> C2F["SA 装载"]
C2D --> C2G["能力注册"]
end
subgraph Chain3["应用进程链"]
direction LR
C3A["init"] --> C3B["appspawn"] --> C3C["sandbox"] --> C3D["child process"]
C3B --> C3E["socket 入口"]
C3C --> C3F["环境构建"]
C3D --> C3G["进程交付"]
end
Chain1 --> Dep1["提供基础环境"]
Chain2 --> Dep2["提供能力目录"]
Chain3 --> Dep3["提供进程入口"]
Dep1 -.->|依赖| Chain3
Dep2 -.->|依赖| Chain3
%% 症状说明节点(独立于主链,用虚线箭头关联)
Symptom1["⚠️ 症状说明<br>分区挂载失败<br>设备节点不存在<br>sysfs 权限错误"] -.-> Chain1
Symptom2["⚠️ 症状说明<br>GetSystemAbility 失败<br>LoadSystemAbility 超时<br>SA 进程存在但未注册"] -.-> Chain2
Symptom3["⚠️ 症状说明<br>socket 连不上<br>子进程快速退出<br>sandbox 挂载缺失"] -.-> Chain3
style Chain1 fill:#e1f5fe
style Chain2 fill:#e8f5e8
style Chain3 fill:#fff3e0
style Symptom1 fill:#ffebee,stroke:#e57373,stroke-dasharray: 5 5
style Symptom2 fill:#ffebee,stroke:#e57373,stroke-dasharray: 5 5
style Symptom3 fill:#ffebee,stroke:#e57373,stroke-dasharray: 5 5
本章摘要:本章将总启动主线拆解为三条并行推进且相互依赖的子链:基础环境链(init + ueventd)、系统能力链(init → samgr → safwk → SA)和应用进程链(init → appspawn)。每条链有独立的核心目标与典型故障症状,理解其并行性与依赖关系是排查复杂启动问题的关键。
本章摘要:上图将总启动主线拆解为三条并行推进且相互依赖的子链:基础环境链(init + ueventd)、系统能力链(init → samgr → safwk → SA)和应用进程链(init → appspawn)。图中不仅展示了每条链的内部流程,还通过虚线标明了链间的依赖关系(如系统能力链依赖基础环境链的设备就绪),并给出了每条链的典型故障症状——这为第14章的排查流程图提供了理论依据。
图表解读与导航:上图将总启动主线拆解为三条并行推进且相互依赖的子链:基础环境链(init + ueventd)、系统能力链(init → samgr → safwk → SA)和应用进程链(init → appspawn)。图中不仅展示了每条链的内部流程,还通过虚线标明了链间的依赖关系,并给出了每条链的典型故障症状。关于链间更详细的依赖关系分析,请见第 8 节「跨子系统的依赖关系」;关于每条链中各模块的就绪信号定义,请见第 9 节「四个就绪信号」;基于本图症状的排查实操,请直接跳转到第 14 节「常见问题排查流程图」。
7.1 基础环境链
这条链由 init first-stage + ueventd + 文件系统阶段 构成。
核心目标是:
- 设备节点可见;
- 关键挂载完成;
- 基础权限正确;
- 后续服务拥有最小运行环境。
如果这条链出问题,症状通常是:
- 分区挂载失败;
- 设备节点不存在;
- sysfs 权限错误;
- 后续系统服务无法打开底层设备。
7.2 系统能力链
这条链由 init -> samgr -> safwk -> SA so Publish 构成。
核心目标是:
- 全局能力目录建立;
- SA so 进程被拉起;
- SA so 对象被注册并对外可见。
如果这条链出问题,症状通常是:
GetSystemAbility拿不到对象;LoadSystemAbility一直 pending 或超时;- SA so 进程存在,但能力并未注册;
- 某些 profile 生效,但 trust profile 把 SA so 裁掉了。
7.3 应用进程链
这条链由 init -> appspawn -> sandbox -> child process 构成。
核心目标是:
- 建立统一孵化入口;
- 让启动请求可控地转换成进程;
- 保证子进程在进入业务前已有正确权限和 sandbox。
如果这条链出问题,症状通常是:
- socket 连不上;
appspawn回包超时;- 子进程 fork 成功但很快退出;
- sandbox 挂载缺失或路径展开错误。
8. 跨子系统的依赖关系
flowchart TD
%% 启动时序与依赖关系图
subgraph 启动时序["启动时序(从上到下)"]
direction TB
%% 第一列:内核与init
Kernel["内核"] --> InitFirstStage["init first-stage<br>建立最小环境"]
InitFirstStage --> InitSecondStage["init second-stage<br>解析.cfg,管理服务"]
%% 第二列:设备就绪
InitFirstStage --> Ueventd["ueventd<br>创建设备节点"]
InitFirstStage --> Mount["关键分区挂载"]
%% 第三列:能力控制
InitSecondStage --> SamgrStart["init 拉起 samgr"]
SamgrStart --> SamgrReady["samgr ready<br>设置 bootevent.samgr.ready"]
%% 第四列:SA进程
InitSecondStage --> SafwkProcess["init 拉起 SA 进程"]
SafwkProcess --> SafwkInit["safwk 初始化"]
SafwkInit --> SALoad["SA so 装载"]
SALoad --> SAPublish["SA Publish()"]
%% 第五列:应用孵化
InitSecondStage --> AppspawnStart["init 拉起 appspawn"]
AppspawnStart --> AppspawnReady["appspawn ready<br>STAGE_SERVER_PRELOAD"]
%% 第六列:应用请求
AppspawnReady --> AppRequest["应用框架请求<br>新进程"]
AppRequest --> AppspawnProcess["appspawn 处理请求"]
AppspawnProcess --> ChildProcess["子进程创建<br>sandbox 构建"]
end
%% 关键就绪信号
SamgrReady -- "bootevent.samgr.ready" --> SafwkInit
SamgrReady -- "binder 代理 ready" --> SAPublish
%% 控制流与数据流
InitSecondStage -- "服务管理" --> SamgrStart
InitSecondStage -- "服务管理" --> SafwkProcess
InitSecondStage -- "服务管理" --> AppspawnStart
SamgrReady -- "全局 SA 目录" --> SAPublish
SAPublish -- "AddSystemAbility()" --> SamgrReady
AppspawnReady -- "socket 监听" --> AppRequest
AppRequest -- "启动请求" --> AppspawnProcess
%% 依赖关系
Mount -.->|"依赖"| Ueventd
Ueventd -.->|"提供设备环境"| SafwkProcess
Ueventd -.->|"提供设备环境"| AppspawnProcess
SamgrReady -.->|"能力目录"| AppspawnProcess
SafwkProcess -.->|"SA 可用性"| AppspawnProcess
%% 样式
style Kernel fill:#f5f5f5
style InitFirstStage fill:#e1f5fe
style InitSecondStage fill:#bbdefb
style Ueventd fill:#f3e5f5
style SamgrStart fill:#e8f5e8
style SamgrReady fill:#c8e6c9
style SafwkProcess fill:#fff3e0
style SafwkInit fill:#ffe0b2
style SAPublish fill:#ffcc80
style AppspawnStart fill:#ffebee
style AppspawnReady fill:#ffcdd2
style AppRequest fill:#fce4ec
style AppspawnProcess fill:#f8bbd9
style ChildProcess fill:#f48fb1
%% 图例说明
subgraph 图例["图例说明"]
direction LR
L1["--> 启动顺序"] --> L2["- - -> 依赖关系"]
L3["==> 控制流"] --> L4["--> 数据流/就绪信号"]
end
这几条链不是平行无关的,它们之间有明确依赖。
8.1 appspawn 依赖 init
appspawn 不自己决定生命周期,它完全由 init 配置拉起、管理和重启。
所以:
appspawn没起来,先看init配置和触发阶段;- 不要一开始就只盯着
appspawn自身逻辑。
8.2 safwk 依赖 samgr
safwk 虽然可以先起来,但如果 binder 上的 samgr 代理还没 ready,它仍然不能完成正式注册。
所以:
safwk进程存在,不等于 SA 体系 ready;- 要区分“进程启动成功”和“注册成功”。
8.3 samgr 依赖 init 服务控制
按需拉起链路里,最终把某个 SA 进程真正拉起来的动作仍然回到 init 的 service control。
所以:
samgr负责状态机;init负责最终进程控制;- 二者不是替代关系,而是上下游关系。
8.4 appspawn sandbox 依赖基础环境链
sandbox 的 mount、namespace 和路径展开,隐含依赖:
- 基础分区已经挂好;
- 关键系统目录可见;
- 设备与文件系统权限已就绪。
如果基础环境链没准备好,sandbox 侧出现的错误往往只是症状,不是根因。
9. 四个就绪信号
标准系统里最重要的不是“谁先起”,而是“谁什么时候算 ready”。
9.1 init ready
对 init 来说,真正进入稳定态的标志不是 second-stage 开始,而是:
- 配置解析结束;
- 关键 boot/normal 服务已触发;
- 参数服务主循环已经进入常驻状态。
9.2 samgr ready
对 samgr 来说,SA ready 的含义是:
- context object 已经设置;
- 自身已进入 binder 工作线程;
bootevent.samgr.ready已被写出。
但从调用方角度,更可靠的 SA ready 标志仍然是:
- binder 上能拿到
samgr代理。
9.3 SA Ready
对某个 SA 来说,ready 的含义不是:
- 进程存在;
- so 已装载;
OnStart()调过。
真正的 ready 是:
Publish()成功;- samgr 已把它放进全局目录。
9.4 appspawn ready
对 appspawn 来说,ready 的含义不是进程启动完成,而是:
- Socket 入口建立;
- 事件循环在跑;
STAGE_SERVER_PRELOAD已完成;- Sandbox 和公共模块已装好。
下面是四个就绪信号的依赖与触发关系时序图:
sequenceDiagram
participant Init as init
participant Samgr as samgr
participant Safwk as safwk
participant Appspawn as appspawn
Note over Init: 配置解析结束<br>关键服务已触发
Init->>Init: init ready
Init->>Samgr: 拉起 samgr 进程
Note over Samgr: context object 设置<br>进入 binder 工作线程
Samgr->>Samgr: 设置 bootevent.samgr.ready
Samgr->>Samgr: samgr ready
Init->>Safwk: 拉起 sa_main 进程
Safwk->>Samgr: 等待 samgr 代理 ready
Samgr-->>Safwk: binder 代理就绪
Safwk->>Safwk: 装载 SA so
Safwk->>Samgr: Publish()
Samgr->>Samgr: AddSystemAbility()
Note over Safwk: SA ready
Init->>Appspawn: 拉起 appspawn 进程
Appspawn->>Appspawn: STAGE_SERVER_PRELOAD
Appspawn->>Appspawn: socket 入口建立
Appspawn->>Appspawn: appspawn ready
10. 端到端理解:从一次能力请求到一个应用进程
前面的时序更偏“系统 bring-up”,这里补一个更贴近业务视角的理解。
在标准系统稳定运行后,典型的后续动作有两条。
10.1 获取一个 SA
- 调用方请求某个 SA
samgr查全局目录- 已注册则直接返回
- 未注册且支持按需时,状态机触发进程拉起
init启动目标safwk进程safwk装载 SA 并Publish()samgr回调加载完成
这条链体现的是系统能力世界的闭环。
10.2 启动一个应用进程
- 框架侧准备启动请求
- 连接
appspawnsocket - 发送消息、权限信息和必要 fd
appspawn做安全检查和消息解码- parent pre-fork 阶段准备 sandbox 与 GID
- child execute 阶段执行 mount/unshare/pivot_root
- 子进程回执父进程
appspawn回包- 应用进程开始执行后续入口
这条链体现的是应用进程世界的闭环。
这两条闭环在稳定系统里会反复发生,但它们共享同一套底层前提:
init的控制面已经稳定;samgr的能力目录已经可用;appspawn的孵化入口已经开放;- 基础文件系统和设备环境已经准备好。
11. 常见误判点
总链路看清之后,下面这几类误判就比较容易避免。
11.1 “进程起来了,所以系统应该没问题”
这是最常见的误判。
在这套系统里:
samgr进程起来,不代表某个 SA 已 ready;safwk进程起来,不代表Publish()已完成;appspawn进程起来,不代表它已经完成 pre-load;- 子进程 fork 成功,不代表它已经可交付给上游。
所以排查时一定要看“ready 的定义”,不要只看 ps。
11.2 “能力拿不到,一定是 samgr 的问题”

11.3 “应用启动失败,一定是 appspawn 的问题”
也不一定。
应用启动链路依赖:
init是否正确拉起appspawn- sandbox 预加载是否完成
- 基础挂载是否就绪
- 相关 SA 是否可用
如果更早的基础环境链断了,最后体现出来的也可能只是 appspawn 超时或 child 退出。
12. 建议的阅读顺序
第五篇本身不提供新实现点,重点是把前四篇串起来。
如果要沿总链下钻,建议按下面顺序看源码:

按这个顺序看,先抓住“谁掌控阶段”,再看“谁提供能力目录”,最后看“谁提供应用进程入口”,整体脑图会比较稳定。
13. 和前四篇的关系
第五篇可以当成索引页来用:
- 要看 PID 1 和
.cfg,回第一篇; - 要看
appspawn主链,回第二篇; - 要看
samgr / safwk,回第三篇; - 要看 sandbox 细节,回第四篇。
如果前四篇解决的是“局部模块怎么工作”,第五篇解决的就是“这些模块在整机启动里怎么接力”。
14. 常见问题排查流程图
flowchart TD
Start["系统启动异常 / 应用启动失败"] --> Q1{"`init` 进程是否正常?<br>(PID 1 存在且 second-stage 完成)"}
Q1 -- "否" --> A1["检查内核日志与 init 启动日志"]
A1 --> A2["确认 first-stage 挂载与设备节点"]
A2 --> A3["检查 init.cfg 配置与触发阶段"]
A3 --> A4["排查 ueventd 与文件系统阶段"]
A4 --> End1["根因:基础环境链故障<br>(init 控制面未建立)"]
Q1 -- "是" --> Q2{"`samgr` 是否 ready?<br>(检查 bootevent.samgr.ready)"}
Q2 -- "否" --> B1["检查 init 是否拉起 samgr 进程"]
B1 --> B2["查看 samgr 启动日志与 binder 状态"]
B2 --> B3["确认 SetContextObject 与 AddSamgrToAbilityMap"]
B3 --> End2["根因:系统能力链故障<br>(samgr 能力目录未建立)"]
Q2 -- "是" --> Q3{"目标 SA 是否可获取?<br>(GetSystemAbility 失败)"}
Q3 -- "否" --> C1["检查目标 SA 进程是否被 init 拉起"]
C1 --> C2["查看 safwk 日志,确认 profile 解析与 so 装载"]
C2 --> C3["确认 SA 的 Start() 与 Publish() 调用"]
C3 --> C4["检查 samgr 目录中是否有该 SA 记录"]
C4 --> End3["根因:系统能力链故障<br>(SA 进程未启动或注册失败)"]
Q3 -- "是" --> Q4{"`appspawn` 是否 ready?<br>(socket 可连接且 preload 完成)"}
Q4 -- "否" --> D1["检查 init 配置中 appspawn 服务状态"]
D1 --> D2["查看 appspawn 日志,确认 STAGE_SERVER_PRELOAD"]
D2 --> D3["确认 sandbox 规则加载与基础挂载"]
D3 --> End4["根因:应用进程链故障<br>(appspawn 启动或预加载失败)"]
Q4 -- "是" --> Q5{"应用进程启动失败?"}
Q5 -- "是" --> E1["检查 appspawn 收包与解码日志"]
E1 --> E2["确认 parent pre-fork 与 child execute 阶段"]
E2 --> E3["排查 sandbox mount/unshare/pivot_root 错误"]
E3 --> E4["检查子进程回执与权限配置"]
E4 --> End5["根因:应用进程链故障<br>(sandbox 或进程执行环境问题)"]
Q5 -- "否" --> End6["系统启动与应用启动正常"]
End1 --> Conclusion["结论:按对应链路深入排查"]
End2 --> Conclusion
End3 --> Conclusion
End4 --> Conclusion
End5 --> Conclusion
End6 --> Conclusion["✅ 系统运行正常"]
style End1 fill:#e1f5fe
style End2 fill:#e8f5e8
style End3 fill:#e8f5e8
style End4 fill:#fff3e0
style End5 fill:#fff3e0
style End6 fill:#c8e6c9
flowchart TD
Start["系统启动异常 / 应用启动失败"] --> Q1{"`init` 进程是否正常?"}
Q1 -- "否" --> A1["检查内核日志与 init 启动日志"]
A1 --> A2["确认 first-stage 挂载与设备节点"]
A2 --> A3["检查 init.cfg 配置与触发阶段"]
A3 --> A4["排查 ueventd 与文件系统阶段"]
A4 --> End1["根因:基础环境链故障"]
Q1 -- "是" --> Q2{"`samgr` 是否 ready?<br>(检查 bootevent.samgr.ready)"}
Q2 -- "否" --> B1["检查 init 是否拉起 samgr 进程"]
B1 --> B2["查看 samgr 启动日志与 binder 状态"]
B2 --> B3["确认 SetContextObject 与 AddSamgrToAbilityMap"]
B3 --> End2["根因:samgr 启动或注册失败"]
Q2 -- "是" --> Q3{"目标 SA 是否可获取?<br>(GetSystemAbility 失败)"}
Q3 -- "否" --> C1["检查目标 SA 进程是否被 init 拉起"]
C1 --> C2["查看 safwk 日志,确认 profile 解析与 so 装载"]
C2 --> C3["确认 SA 的 Start() 与 Publish() 调用"]
C3 --> C4["检查 samgr 目录中是否有该 SA 记录"]
C4 --> End3["根因:SA 进程未启动或注册失败"]
Q3 -- "是" --> Q4{"`appspawn` 是否 ready?<br>(socket 可连接且 preload 完成)"}
Q4 -- "否" --> D1["检查 init 配置中 appspawn 服务状态"]
D1 --> D2["查看 appspawn 日志,确认 STAGE_SERVER_PRELOAD"]
D2 --> D3["确认 sandbox 规则加载与基础挂载"]
D3 --> End4["根因:appspawn 启动或预加载失败"]
Q4 -- "是" --> Q5{"应用进程启动失败?"}
Q5 -- "是" --> E1["检查 appspawn 收包与解码日志"]
E1 --> E2["确认 parent pre-fork 与 child execute 阶段"]
E2 --> E3["排查 sandbox mount/unshare/pivot_root 错误"]
E3 --> E4["检查子进程回执与权限配置"]
E4 --> End5["根因:sandbox 或进程执行环境问题"]
Q5 -- "否" --> End6["系统启动与应用启动正常"]
End1 --> Conclusion["结论:按对应链路深入排查"]
End2 --> Conclusion
End3 --> Conclusion
End4 --> Conclusion
End5 --> Conclusion
End6 --> Conclusion["✅ 系统运行正常"]
流程图使用说明
- 从起点开始:根据你遇到的症状(系统启动卡住、SA 获取不到、应用启动失败等)进入流程图。
- 按模块排查:
init问题:通常表现为系统早期启动失败,服务未拉起。重点检查内核切换、first-stage/second-stage 切换、.cfg解析与阶段触发。samgr问题:表现为能力目录不可用,bootevent.samgr.ready未设置。检查init是否成功拉起samgr,以及samgr自身初始化。safwk/SA 问题:表现为特定 SA 获取失败。检查该 SA 的进程是否被init拉起,safwk是否成功解析 profile、装载 so 并调用Publish()。appspawn问题:表现为应用进程无法创建。检查appspawn服务状态、socket 连接、sandbox 预加载以及子进程执行环境。
- 依赖关系:注意模块间的依赖(如
appspawn依赖init,safwk依赖samgr),下层问题可能由上层未就绪引起。 - 结合日志:流程图中的每个检查点都应结合系统日志(如
hilog、dmesg、各模块的日志文件)进行验证。
此流程图将前文所述的各层职责、就绪信号和依赖关系整合为一张可操作的排查指南,帮助读者在复杂链路中快速定位问题环节。
更多推荐

所有评论(0)