首页
/ Magisk 启动机制全解:rootdir、SAR、2SI 与设备类型划分的源码级剖析

Magisk 启动机制全解:rootdir、SAR、2SI 与设备类型划分的源码级剖析

2026-09-03 16:05:05作者:卓艾滢Kingsley

Magisk 能否在任意设备上稳定工作,取决于对 Android 启动流程的精确理解:rootdir 从哪来、system 分区何时挂载、init 进程如何被替换。本文以 docs/boot.md 为核心骨架,完整覆盖 rootdir / SAR / 2SI 等关键术语、三种启动方法(Method A/B/C)的判定标准与历史成因,以及 Type I–IV 设备分类模型,并结合 native/src/init/init.rs 等源码展示 Magisk 在不同启动路径下的实际劫持策略,帮助你准确判断设备属于哪一类,并理解对应刷入方案的底层原理。

核心术语:先统一语言

boot.md 开篇定义了一组贯穿全文的术语,理解它们是理解一切的基础:

  • rootdir:根目录(/)。所有文件/目录/文件系统都存储或挂载在 rootdir 之下。在 Android 上,文件系统可以是 rootfs,也可以是 system 分区。
  • initramfs:Android boot 镜像中的一段内容,Linux 内核将其用作 rootfs。人们也常互换使用 ramdisk 一词。
  • recoveryboot 分区:二者其实非常相似——都是包含 ramdisk 和 Linux 内核(以及一些别的东西)的 Android boot 镜像。唯一区别在于:启动 boot 分区会进入 Android,而 recovery 是一个用于维修与升级设备的极简自包含 Linux 环境。
  • SAR(System-as-Root):即设备使用 system 分区作为 rootdir,而不是 rootfs
  • A/B、A-only:支持 A/B 无缝系统更新的设备拥有所有只读分区的双 slot,称为 A/B 设备;与之相对,非 A/B 设备称为 A-only
  • 2SI(Two Stage Init):Android 10+ 的启动方式,后文详述。

此外,文档引入了两个参数来更精确地刻画一台设备的 Android 版本:

  • LV(Launch Version):设备出厂时预装的 Android 版本。
  • RV(Running Version):设备当前正在运行的 Android 版本。

文档使用 Android API level 来表示 LV 和 RV(API level 与 Android 版本的对应关系可查 AOSP 官方的平台版本表)。举例:Pixel XL 出厂搭载 Android 7.1(LV = 25),当前运行 Android 10(RV = 29),即 (LV = 25, RV = 29)

三种启动方法:Method A、B、C

Android 的启动方式大致可归为三大类。文档给出了一张核心对照表,用“初始 rootdir / 最终 rootdir”两个维度区分:

方法 初始 rootdir 最终 rootdir
A rootfs rootfs
B system system
C rootfs system

Method A - Legacy ramdisk

这是所有 Android 设备曾经使用的启动方式(“美好旧时光”):内核使用 initramfs 作为 rootdir,然后 exec /init 完成启动。

判定标准:不属于 Method B 和 C 任何条件的设备,都落入 Method A。

Method B - Legacy SAR

该方式最早出现在 Pixel 1 上:内核直接挂载 system 分区作为 rootdir,并 exec /init 启动。

判定标准:

  • (LV = 28) 的设备;
  • Google:Pixel 1 和 2;Pixel 3 和 3a 在 (RV = 28) 时;
  • OnePlus:6 – 7;
  • 也许还有一些 (LV < 29) 的 Android Go 设备?

Method C - 2SI ramdisk SAR

该方式最早出现在 Pixel 3 的 Android 10 developer preview 上:内核使用 initramfs 作为 rootdir 并 exec rootfs 中的 /init。这个 init 负责挂载 system 分区、将其设为新的 rootdir,最终 exec /system/bin/init 完成启动。

判定标准:

  • (LV >= 29) 的设备;
  • (LV < 28, RV >= 29) 的设备,排除那些原本就使用 Method B 的;
  • Google:(RV >= 29) 的 Pixel 3 和 3a。

从源码看:Magisk 如何分流这三种路径

magiskinit 替换 /init 成为开机执行的第一进程。在 native/src/init/init.rsMagiskInit::start() 中,可以看到文档所述三种方法与源码分支的一一对应:

if !argv1.is_null() && CStr::from_ptr(argv1) == c"selinux_setup" {
    self.second_stage();                    // Method C 的第二阶段
} else if CStr::from_ptr(self.config.boot_mode.as_ptr()) == c"charger" {
    self.recovery_or_charger();              // 充电模式,直接放弃
} else if self.config.skip_initramfs {
    self.legacy_system_as_root();            // Method B:内核直接用 system 作 rootdir
} else if self.config.force_normal_boot {
    self.first_stage();                     // Method C:USES_RECOVERY_AS_BOOT 设备
} else if cstr!("/sbin/recovery").exists()
    || cstr!("/system/bin/recovery").exists() {
    self.recovery_or_charger();              // 当前实际在进 recovery,放弃注入
} else if self.check_two_stage() {
    self.first_stage();                     // Method C:2SI 设备
} else {
    self.rootfs();                          // Method A:传统 ramdisk 启动
}

这里有两个值得注意的判定细节:

  1. Method B 由内核参数标识skip_initramfs 对应启动参数 androidboot.skip_initramfs。当内核直接以 system 为 rootdir 启动时(Method B),boot ramdisk 根本没被用作根文件系统,因此 Magisk 走 legacy_system_as_root() 分支,把 Magisk 数据准备到 /data 并修补只读根。
  2. 2SI 的设备判定check_two_stage()(见 native/src/init/getinfo.rs)依次检查 /first_stage_ramdisk/second_stage_resources/system/bin/init/apex 是否存在,若都无明确标志,则解析原始 init 二进制中是否包含 selinux_setup 字符串作为兜底——这正对应文档所说 2SI 是 Android 10+(LV/RV >= 29)的标志。
  3. force_normal_bootUSES_RECOVERY_AS_BOOT:文档历史章节提到,A/B 设备的 boot ramdisk 是“混合”的,内核依据 bootloader 信息决定进 Android 还是 recovery。AOSP 为此引入 USES_RECOVERY_AS_BOOT 机制,设备启动 Android 时会设置 androidboot.force_normal_boot=1,源码中它被归入 first_stage()(2SI 处理路径)。

SAR 定义之争:Google 口径 vs Magisk 口径

从公开文档看,Google 对 SAR 的定义只考虑内核如何启动设备(即上表的 Initial rootdir),也就是说只有使用 Method B 的设备才官方被视为 SAR 设备。

但对 Magisk 而言,真正的差异在于设备完全启动后使用什么作为根(上表的 Final rootdir)。因此 在 Magisk 的关注范围内,Method B 和 C 都是 SAR 的一种形态,只是实现方式不同。boot.md 后续提到的每一处 SAR 均指 Magisk 的定义,除非特别说明。

Method C 的条件稍显复杂,通俗地说:要么你的设备足够新、出厂即为 Android 10+;要么你在原本使用 Method A 的设备上刷了 Android 10+ 的自定义 ROM:

  • 任何运行 Android 10+ 的 Method A 设备都会自动变为 Method C;
  • Method B 设备则被锁定在 Method B,唯一例外是 Pixel 3 和 3a——Google 对这两台设备做了改造以适配新方法。

SAR 是 Project Treble 的重要组成:rootdir 必须与平台(platform)绑定。这也是 Method B 和 C 都带有 (LV >= ver) 条件的原因——Google 每年强制所有 OEM 遵守更新后的要求。

历史演变:A/B 更新、Dynamic Partitions 与 2SI 的由来

理解三种方法为何存在,需要回到 Google 设计 A/B 时的历史语境:

  1. A/B 无缝系统更新登场。当 Google 发布第一代 Pixel 时,同时引入了 A/B(Seamless)系统更新。出于存储容量考虑,A/B 与 A-only 存在若干差异,最相关的一点是:recovery 分区被移除,recovery ramdisk 被合并进 boot

  2. Method B 催生了“合并”的巧思。如果采用 SAR(当时只有 Boot Method B),内核启动 Android 不需要 initramfs(因为 rootdir 在 system 里)。于是可以聪明地把 recovery ramdisk(极简 Linux 环境)塞进 boot、移除 recovery 分区,让内核根据 bootloader 提供的信息选择使用哪个 rootdir(ramdisk 或 system)。

  3. Dynamic Partitions 成为 SAR 的“坏消息”。从 Android 7.1 演进到 Android 10 期间,Google 引入了动态分区(Dynamic Partitions)。这对 SAR 是坏消息:Linux 内核无法直接理解这种新的分区格式,因而无法直接把 system 挂载为 rootdir。于是 Method C 应运而生:永远先进 initramfs,把剩余启动工作交给用户空间处理——包括决定进 Android 还是 recovery,即 AOSP 官方所说的 USES_RECOVERY_AS_BOOT

  4. 部分现代设备的例外:一些采用 A/B + 2SI 的现代设备同时带有 recovery_a / recovery_b 分区,这在 Google 标准中是官方支持的。这类设备只用 boot ramdisk 启动 Android,因为 recovery 存放在独立分区中。

汇总分类:Type I – IV 设备类型

掌握以上知识后,可以把所有 Android 设备归入以下类型。这些类型按首次出现的时间先后排序:

类型 启动方法 分区 2SI boot 中的 Ramdisk
I A A-only boot ramdisk
II B A/B 任意 recovery ramdisk
III B A-only 任意 N/A
IV C 任意 Hybrid ramdisk

各类型的定位:

  • Type I:老式 legacy ramdisk 启动;
  • Type II:传统 A/B 设备。Pixel 1 是第一款此类设备,它同时是首款 A/B 设备与首款 SAR 设备;
  • Type III:2018 年底 – 2019 年的 A-only 设备。在 Magisk 看来,这是“史上最难伺候”的设备类型
  • Type IV:所有使用 Boot Method C 的设备。A/B 型 Type IV 的 ramdisk 可依据 bootloader 信息启动进 Android 或 recovery;A-only 型 Type IV 的 ramdisk 只能启动进 Android。

Type III 的特殊处境:Magisk 只能装进 recovery

Type III 设备之所以难缠,根源在于:Magisk 始终安装在 boot 镜像的 ramdisk 中。对其他所有设备类型,因为 boot 分区自带 ramdisk,Magisk 可以直接通过 Magisk App 修补 boot 镜像,或在自定义 recovery 中刷 zip 轻松安装。但 Type III 设备只能把 Magisk 装进 recovery 分区:正常开机时 Magisk 不生效,用户必须每次重启进 recovery 才能维持 Magisk 访问。

这一约束在仓库的 docs/install.md “Magisk in Recovery” 一节有对应说明:boot 镜像没有 ramdisk 的设备,只能走 hijack recovery 路径;且每次从关机状态启动时,需依靠厂商的“进 recovery 键位组合”快速松开按键 + 长按音量上键来区分“进 Magisk 管理的 recovery”还是“进真正的原厂 recovery”。

从源码侧看,这正是 native/src/init/init.rs 中这段检查的用武之地:

} else if cstr!("/sbin/recovery").exists()
    || cstr!("/system/bin/recovery").exists() {
    // 当前 ramdisk 属于 recovery,恢复原始 init 并放弃注入
    self.recovery_or_charger();
}

magiskinit 发现自己跑在 recovery ramdisk 里(说明这次是用户主动进的 recovery,而非正常启动),就恢复原始 /init 让原厂 recovery 正常跑起来——这正是文档所述的“快速松键进 Magisk、长按音量上进原厂 recovery”双模机制的内核侧实现。

此外文档还指出:部分 Type III 设备的 bootloader 仍然接受并会将手动塞入 boot 镜像的 initramfs 传递给内核(例如某些小米手机),但很多设备不接受(例如 Samsung S10、Note 10)。这完全取决于 OEM 对 bootloader 的实现方式。

实战映射:修补 boot 镜像时的设备类型参数

理解了上述分类,再看实际的修补流程就会清晰许多。Magisk 的 boot 镜像修补脚本 scripts/boot_patch.sh 在头部注释中明确列出可用环境变量:

# The following environment variables can configure the installation:
# KEEPVERITY, KEEPFORCEENCRYPT, PATCHVBMETAFLAG, RECOVERYMODE, LEGACYSAR

其中与本文主题直接相关的有两个:

  • LEGACYSAR:对应 Method B(Legacy SAR / Type II、III 设备)的修补模式,指示修补逻辑按“内核直接以 system 为 rootdir”的场景处理 ramdisk——这解释了为何文档强调 Method B 设备“被锁定在 Method B”时,修补策略也必须与之匹配;
  • RECOVERYMODE:对应 Type III 设备“Magisk 装进 recovery 分区”的情形,即 docs/install.md 中所说的“如果你修补的是 recovery 镜像,勾选 Recovery Mode 选项”。

脚本注释还说明,boot_patch.sh 需要与同目录下的 magiskinit(替换 /init 的二进制)、magiskmagiskboot(操作 boot 镜像的工具)、init-ld(作为 /init 的 LD_PRELOAD 库)、stub.apk 等文件配套工作——这份文件清单本身就是文档所述“Magisk 始终安装在 boot 镜像 ramdisk 中”这一事实的直接落证。

2SI 劫持原理:Method C 设备的第二阶段接管

Method C 设备的两段式 init 是 Magisk 启动链中最精巧的部分。magiskinit第一阶段first_stage())中调用 native/src/init/twostage.rshijack_init_with_switch_root(),利用原始 init 的 SwitchRoot 行为完成对第二阶段 init 的劫持。源码注释完整解释了这一技巧:

  1. 两个关于 2SI 的重要假设:第二阶段 init 永远是 /system/bin/initSwitchRoot 之后 /sdcard 必然是指向 /storage/self/primary 的符号链接;
  2. SwitchRoot 会做两件事:把 / 下的所有挂载递归移动到 /system 下,再 chroot 到 /system
  3. Magisk 的 trick:在第一阶段把 magiskinit 挂载到 /sdcard,并创建 /storage/self/primary -> /system/system/bin/init 的符号链接。原始 init 执行 SwitchRoot 时,会把 /sdcard(即 magiskinit)移动到 /system/sdcard,经过符号链接链最终落到 /system/bin/init——等效于强制原始 init 把 magiskinit bind mount 到 /system/bin/init,成功劫持第二阶段。

对于某些 2SI 但不执行 switch_root 的设备(如魅族),源码会检测 /sdcard 是否已存在于 ramfs 中,若已存在则回退到 hexpatch 方案:hexpatch_init_for_second_stage()native/src/init/twostage.rs)直接在 /init 二进制内把字符串 /system/bin/init 替换为 /data/magiskinit,若 /init 不可写,则把补丁后的副本写入 /data/init 并 bind mount 覆盖。

完成劫持后,magiskinit 还会通过 native/src/init/rootdir.rsinject_magisk_rc()init.rc 追加服务定义,把 Magisk 的四个生命周期钩子挂进系统启动流:

on post-fs-data                              → magisk --post-fs-data
on property:vold.decrypt=trigger_restart_framework → magisk --service
on nonencrypted                              → magisk --service
on property:sys.boot_completed=1             → magisk --boot-complete

这与 docs/details.md “Magisk Booting Process” 一节描述的 Pre-Init / post-fs-data / late_start 三阶段流程完全吻合:Magisk 的注入时机严格贴着 Android 自身的启动里程碑。

小结

docs/boot.md 的核心脉络可以浓缩为三句话:

  1. 用 LV/RV 两个 API level 参数 + 启动方法 A/B/C 的判定条件,可以推断设备大致使用哪种启动方式;
  2. 按启动方法 × 分区形态 × 2SI 与否,设备被划分为 Type I–IV 四类,其中 Type III(A-only + Method B + 无 boot ramdisk)是唯一需要把 Magisk 装进 recovery 分区的类型;
  3. Magisk 源码在 native/src/init/init.rs 中为每条路径提供了明确的分支rootfs() 对应 Method A,legacy_system_as_root() 对应 Method B,first_stage() + 2SI 劫持(native/src/init/twostage.rs)对应 Method C,recovery 检测则服务于 Type III 的双模 recovery 机制。

掌握了这套分类法与对应的源码分支,你就能在刷入前准确判断自己的设备类型、选择正确的镜像(boot.img / init_boot.img / recovery.img)与修补参数(LEGACYSAR / RECOVERYMODE),而不是盲刷盲试。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
504
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384