文档概述
说明:
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 的配置和执行模型。

第五篇不再往下拆单模块,而是把前面几条链收回来,回答一个更接近系统视角的问题:

标准系统从内核切到用户态以后,initueventdappspawnsamgrsafwk 和具体 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 步:

  1. 内核把控制权交给 PID 1 init
  2. init first-stage 建立最小文件系统和设备环境
  3. first-stage 等待关键块设备,挂载必要分区
  4. init 切入 second-stage
  5. second-stage 初始化参数服务、group、SELinux 和控制面
  6. init 解析 .cfg,装配 job / service / import
  7. init 触发 pre-init -> init -> post-init 以及文件系统阶段
  8. ueventd 进入工作态,补齐设备节点和权限
  9. init 拉起 samgr
  10. samgr 建立全局 SA 目录并写 bootevent.samgr.ready
  11. init 根据配置拉起一批 sa_main + profile 进程
  12. safwk 在各自进程内装载 SA so,并通过 Publish() 报到 samgr
  13. init 拉起 appspawn
  14. 应用框架或系统服务通过 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. 总时序图

把核心链路压成一张文字版时序,可以写成下面这样。

  1. kernel` -> `init(first-stage)
  2. ````init(first-stage) -> 挂载关键分区 -> 触发早期 uevent
  3. ````init(first-stage) -> exec second-stage init
  4. init(second-stage)` -> `SystemInit
  5. init(second-stage)` -> `SystemConfig
  6. init -> 解析 init.cfg / import / jobs / services
  7. init -> trigger pre-init
  8. init -> start ueventd
  9. ueventd -> 处理 kernel uevent -> 创建设备节点 -> 修正权限
  10. init -> trigger init / post-init / fs / late-fs / boot
  11. init -> start samgr
  12. samgr -> SetContextObject -> AddSamgrToAbilityMap
  13. samgr -> SetParameter(bootevent.samgr.ready=true)
  14. init -> start foundation / 其他 sa_main 进程
  15. safwk -> 解析 profile / trust profile
  16. safwk -> 等待 samgr proxy ready
  17. safwk -> AddSystemProcess
  18. safwk -> dlopen SA so -> Start()
  19. SA -> Publish()
  20. samgr -> AddSystemAbility
  21. init -> start appspawn
  22. appspawn -> STAGE_SERVER_PRELOAD -> 预加载 sandbox
  23. framework/service -> connect appspawn socket
  24. appspawn -> 解码请求 -> parent pre-fork
  25. appspawn child -> child execute -> sandbox mount/unshare
  26. appspawn child -> pipe 回执
  27. 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)、系统能力链(initsamgrsafwk → SA)和应用进程链(initappspawn)。每条链有独立的核心目标与典型故障症状,理解其并行性与依赖关系是排查复杂启动问题的关键。

本章摘要:上图将总启动主线拆解为三条并行推进且相互依赖的子链:基础环境链(init + ueventd)、系统能力链(initsamgrsafwk → SA)和应用进程链(initappspawn)。图中不仅展示了每条链的内部流程,还通过虚线标明了链间的依赖关系(如系统能力链依赖基础环境链的设备就绪),并给出了每条链的典型故障症状——这为第14章的排查流程图提供了理论依据。

图表解读与导航:上图将总启动主线拆解为三条并行推进且相互依赖的子链:基础环境链(init + ueventd)、系统能力链(initsamgrsafwk → SA)和应用进程链(initappspawn)。图中不仅展示了每条链的内部流程,还通过虚线标明了链间的依赖关系,并给出了每条链的典型故障症状。关于链间更详细的依赖关系分析,请见第 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

  1. 调用方请求某个 SA
  2. samgr 查全局目录
  3. 已注册则直接返回
  4. 未注册且支持按需时,状态机触发进程拉起
  5. init 启动目标 safwk 进程
  6. safwk 装载 SA 并 Publish()
  7. samgr 回调加载完成

这条链体现的是系统能力世界的闭环。

10.2 启动一个应用进程

  1. 框架侧准备启动请求
  2. 连接 appspawn socket
  3. 发送消息、权限信息和必要 fd
  4. appspawn 做安全检查和消息解码
  5. parent pre-fork 阶段准备 sandbox 与 GID
  6. child execute 阶段执行 mount/unshare/pivot_root
  7. 子进程回执父进程
  8. appspawn 回包
  9. 应用进程开始执行后续入口

这条链体现的是应用进程世界的闭环。

这两条闭环在稳定系统里会反复发生,但它们共享同一套底层前提:

  • 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["✅ 系统运行正常"]

流程图使用说明

  1. 从起点开始:根据你遇到的症状(系统启动卡住、SA 获取不到、应用启动失败等)进入流程图。
  2. 按模块排查
    • 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 预加载以及子进程执行环境。
  3. 依赖关系:注意模块间的依赖(如 appspawn 依赖 initsafwk 依赖 samgr),下层问题可能由上层未就绪引起。
  4. 结合日志:流程图中的每个检查点都应结合系统日志(如 hilogdmesg、各模块的日志文件)进行验证。

此流程图将前文所述的各层职责、就绪信号和依赖关系整合为一张可操作的排查指南,帮助读者在复杂链路中快速定位问题环节。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐