菜单

模块系统

相关源文件

Magisk 模块系统提供了一个框架,通过用户安装的模块来扩展 Magisk 的功能。本页将介绍模块在 Magisk 环境中的结构、安装、加载和执行方式。有关开发自己的模块的信息,请参阅 模块开发

模块系统概述

模块系统允许在不修改实际系统文件的情况下进行系统修改,它利用了文件系统覆盖机制。这使用户能够在保持原始系统完整性的同时,增强他们的 Android 体验。

来源: native/src/core/module.cpp283-491 scripts/util_functions.sh634-739 native/src/core/scripting.cpp78-151

模块结构

Magisk 模块以具有特定结构的 ZIP 文件形式分发

组件类型描述
module.prop文件模块的元数据,包括 ID、名称、版本、作者
customize.sh脚本可选的安装脚本,在模块安装过程中运行
system.prop文件要注入系统属性的可选属性
sepolicy.rule文件可选的自定义 SELinux 策略规则
post-fs-data.sh脚本可选脚本,在早期启动阶段执行
service.sh脚本可选脚本,在后期启动阶段执行
/system/目录要覆盖到 Android 系统上的文件
/zygisk/目录Zygisk 模块功能的可选原生库
uninstall.sh脚本卸载模块时执行的可选脚本

对于模块,特定的文件具有特殊功能

  • .replace 文件在目录中表示整个目录应被替换,而不是合并
  • disable 文件表示模块当前已被禁用
  • remove 文件标记模块将在下次启动时被移除
  • update 文件是在模块被更新时创建的

来源: scripts/util_functions.sh593-611 native/src/core/module.cpp95-122 scripts/module_installer.sh1-34

模块安装

当安装模块 ZIP 时,该过程遵循以下步骤

来源: scripts/util_functions.sh634-739 scripts/module_installer.sh1-34

安装程序支持两种安装方法

  1. 传统方法:使用 install.sh 和模板回调
  2. 现代方法:使用 customize.sh 以获得更大的灵活性

安装过程中,模块将被放置在 /data/adb/modules/ 中,每个模块都有一个以模块 ID 命名的目录。

模块加载和执行

模块在启动过程中的多个阶段进行加载

1. 模块准备

在启动时,系统首先检查模块更新并准备要加载的模块

来源: native/src/core/module.cpp361-382 native/src/core/module.cpp403-457

2. 模块脚本执行

模块脚本在启动过程的特定时间执行

脚本执行计时目的
post-fs-data.sh挂载 /data 之后早期系统修改
service.sh后期启动(服务启动)期间后期系统修改、后台服务

这些脚本以 root 权限在全局命名空间中运行,允许它们根据需要修改系统。

来源: native/src/core/scripting.cpp78-151

3. 文件系统修改

文件系统修改机制是模块系统的核心

来源: native/src/core/module.cpp18-24 native/src/core/node.hpp9-14 native/src/core/module.cpp127-186

系统使用节点树来表示文件系统结构,其中包含不同的节点类型

  • inter_node:基本目录节点
  • tmpfs_node:需要虚拟化的目录(使用 tmpfs)
  • module_node:来自模块、覆盖系统文件的文件
  • root_node:分区根目录

启动过程中,Magisk

  1. 收集所有模块文件
  2. 构建虚拟文件系统树
  3. 在必要点挂载 tmpfs
  4. 将模块文件绑定到系统文件之上

这创建了一个分层视图,模块文件看起来像是替换了系统文件,但实际上并未修改它们。

模块管理

Magisk 提供了几种管理模块的机制

启用/禁用模块

可以通过在其目录中创建 disable 文件来禁用模块。被禁用的模块仍然已安装,但在启动时不会被加载。

来源: native/src/core/module.cpp415-417

移除模块

模块可以通过两种方式移除

  1. 在模块目录中创建 remove 文件(将在下次启动时移除)
  2. 使用 Magisk 应用卸载模块

当使用 remove 文件移除模块时

  1. 系统会检查 uninstall.sh 是否存在,如果存在则执行它
  2. 模块目录将被完全删除

来源: native/src/core/module.cpp503-529 native/src/core/module.cpp406-413

更新模块

模块更新由以下方式处理

  1. 将新模块版本放置在 /data/adb/modules_update/
  2. 下次启动时,将检查更新目录
  3. 旧模块将被移除,新模块将被安装到位

来源: native/src/core/module.cpp361-385

Zygisk 模块

Zygisk 是模块系统的一个特殊扩展,它允许模块将代码注入到应用程序进程中

当模块包含 Zygisk 组件时

  1. 原生库被放置在 /zygisk/ 目录中
  2. 这些库在应用程序启动时由 Zygisk 框架加载
  3. 模块可以从应用程序进程内部修改应用程序行为

Zygisk 模块可以通过提供不同的库来支持多种架构

  • /zygisk/arm64-v8a.so 用于 64 位 ARM 设备
  • /zygisk/armeabi-v7a.so 用于 32 位 ARM 设备
  • /zygisk/x86_64.so 用于 64 位 x86 设备
  • /zygisk/x86.so 用于 32 位 x86 设备

来源: native/src/core/module.cpp214-233 native/src/core/module.cpp426-446 native/src/core/zygisk/entry.cpp1-121

与其他 Magisk 系统的交互

模块系统与多个其他 Magisk 组件进行交互

与启动过程的交互

启动过程在特定阶段触发模块加载

  • post-fs-data:挂载 /data 可用后的早期阶段
  • late_start:服务启动时的后期阶段

来源: native/src/core/daemon.rs156-166 native/src/core/daemon.rs185-218

与 SELinux 系统的交互

模块文件会打上适当的 SELinux 上下文标签

  • 系统文件: u:object_r:system_file:s0
  • 供应商文件: u:object_r:vendor_file:s0

自定义 SELinux 规则,源自模块(sepolicy.rule),用于确保模块正常运行。

来源:scripts/util_functions.sh593-608

与黑名单的交互

黑名单系统可以阻止特定应用程序检测或使用 Magisk,这会影响模块在这些应用程序中的运行方式。

来源:native/src/core/deny/utils.cpp33-440

模块开发最佳实践

有关开发 Magisk 模块的详细信息,请参阅 模块开发

模块开发者需重点考虑的事项

  • 遵循正确的模块目录结构
  • 使用 customize.sh 进行安装逻辑处理
  • 妥善利用挂载点
  • 处理多种 Android 版本和设备类型
  • 提供正确的卸载清理
  • 记录模块功能和需求