website/docs/zh_CN/guide/metamodule.md
元模块是 KernelSU 的一项革新性功能,它将关键的模块系统能力从核心转移到可插拔模块中。这种架构转变在保持 KernelSU 稳定性和安全性的同时,为模块生态系统释放了更大的创新潜力。
元模块是一种特殊类型的 KernelSU 模块,为模块系统提供核心基础设施功能。与常规模块不同,元模块控制常规模块的安装和挂载方式。
元模块是一种基于插件的扩展机制,允许完全自定义 KernelSU 的模块管理基础设施。通过将挂载和安装逻辑委托给元模块,KernelSU 避免成为脆弱的检测点,同时支持多样化的实现策略。
主要特征:
传统的 Root 解决方案将挂载逻辑内置在核心中,这使得它们更容易被检测且难以演进。KernelSU 的元模块架构通过关注点分离解决了这些问题。
战略优势:
挂载灵活性:
meta-overlayfs)超越挂载:
::: warning 重要
如果没有安装元模块,依赖挂载的模块,其挂载功能将不会生效。新安装的 KernelSU 需要安装元模块(如 meta-overlayfs)才能使模块正常工作。
:::
像安装常规模块一样安装元模块:
meta-overlayfs.zip)meta-overlayfs 元模块是官方参考实现,提供传统的基于 overlayfs 的模块挂载,支持读写系统分区。
您可以在 KernelSU Manager 应用的模块页面中查看当前活动的元模块。活动的元模块将显示在模块列表中,并带有特殊标识。
::: danger 警告 卸载元模块会影响所有模块。移除后,模块将不再被挂载,直到您安装另一个元模块。 :::
卸载步骤:
卸载后,如果您需要元模块的功能,应该安装另一个元模块。
只允许一个元模块处于运行状态。如果您尝试安装第二个元模块,KernelSU 将阻止安装以避免冲突。
切换元模块的步骤:
如果您正在开发常规 KernelSU 模块,您不需要太担心元模块。只要用户安装了兼容的元模块(如 meta-overlayfs),您的模块就能正常工作。
您需要知道的:
system 目录只有在用户安装了提供挂载功能的元模块时才会被挂载::: tip 如果您熟悉 Magisk 模块开发,您的模块在安装元模块后将在 KernelSU 中以相同方式工作,因为它提供了 Magisk 兼容的挂载。 :::
创建元模块允许您自定义 KernelSU 处理模块安装、挂载和卸载的方式。
元模块通过 module.prop 中的特殊属性来识别:
id=meta-example
name=My Custom Metamodule
version=1.0
versionCode=1
author=Your Name
description=Custom module mounting implementation
metamodule=1
metamodule=1(或 metamodule=true)属性将此模块标记为元模块。没有此属性,模块将被视为常规模块。
元模块结构:
meta-example/
├── module.prop (必须包含 metamodule=1)
│
│ *** 元模块特定钩子 ***
├── metamount.sh (可选: 自定义挂载处理程序)
├── metainstall.sh (可选: 常规模块的安装钩子)
├── metauninstall.sh (可选: 常规模块的清理钩子)
│
│ *** 标准模块文件(全部可选) ***
├── customize.sh (安装自定义)
├── post-fs-data.sh (post-fs-data 阶段脚本)
├── service.sh (late_start service 脚本)
├── boot-completed.sh (启动完成脚本)
├── uninstall.sh (元模块自己的卸载脚本)
└── [任何其他文件]
除了特殊的元模块钩子外,元模块可以使用所有标准模块功能(生命周期脚本等)。
元模块可以提供最多三个特殊钩子脚本:
目的: 控制启动期间模块的挂载方式。
执行时机: 参考 执行顺序
环境变量:
MODDIR: 元模块的目录路径(例如 /data/adb/modules/meta-example)职责:
skip_mount 标志::: danger 关键要求
执行挂载操作时,必须将源/设备名称设置为 "KSU"。这将挂载标识为属于 KernelSU。
示例(正确):
mount -t overlay -o lowerdir=/lower,upperdir=/upper,workdir=/work KSU /target
对于现代挂载 API,设置源字符串:
fsconfig_set_string(fs, "source", "KSU")?;
这对于 KernelSU 正确识别和管理其挂载至关重要。 :::
示例脚本:
#!/system/bin/sh
MODDIR="${0%/*}"
# 示例: 简单的绑定挂载实现
for module in /data/adb/modules/*; do
if [ -f "$module/disable" ] || [ -f "$module/skip_mount" ]; then
continue
fi
if [ -d "$module/system" ]; then
# 使用 source=KSU 挂载(必需!)
mount -o bind,dev=KSU "$module/system" /system
fi
done
目的: 自定义常规模块的安装方式。
执行时机: 在模块安装期间,文件提取后但安装完成前。此脚本被内置安装程序source(而非执行),类似于 customize.sh 的工作方式。
环境变量和函数:
此脚本继承内置 install.sh 的所有变量和函数:
MODPATH、TMPDIR、ZIPFILE、ARCH、API、IS64BIT、KSU、KSU_VER、KSU_VER_CODE、BOOTMODE 等ui_print <msg> - 向控制台打印消息abort <msg> - 打印错误并终止安装set_perm <target> <owner> <group> <permission> [context] - 设置文件权限set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context] - 递归设置权限install_module - 调用内置模块安装过程用例:
install_module)注意: 安装元模块本身时不会调用此脚本。
目的: 卸载常规模块时清理资源。
执行时机: 在模块卸载期间,在删除模块目录之前。
环境变量:
MODULE_ID: 正在卸载的模块的 ID用例:
示例脚本:
#!/system/bin/sh
# 卸载常规模块时调用
MODULE_ID="$1"
IMG_MNT="/data/adb/metamodule/mnt"
# 从镜像中删除模块文件
if [ -d "$IMG_MNT/$MODULE_ID" ]; then
rm -rf "$IMG_MNT/$MODULE_ID"
fi
了解启动执行顺序对于元模块开发至关重要:
post-fs-data 阶段:
1. 执行通用 post-fs-data.d 脚本
2. restorecon,加载 sepolicy.rule
3. 执行元模块的 post-fs-data.sh(如果存在)
4. 执行常规模块的 post-fs-data.sh
5. 加载 system.prop
6. 执行元模块的 metamount.sh
└─> 以无系统方式挂载所有模块
7. post-mount.d 阶段运行
- 通用 post-mount.d 脚本
- 元模块的 post-mount.sh(如果存在)
- 常规模块的 post-mount.sh
service 阶段:
1. 执行通用 service.d 脚本
2. 执行元模块的 service.sh(如果存在)
3. 执行常规模块的 service.sh
boot-completed 阶段:
1. 执行通用 boot-completed.d 脚本
2. 执行元模块的 boot-completed.sh(如果存在)
3. 执行常规模块的 boot-completed.sh
要点:
metamount.sh 在所有 post-fs-data 脚本(元模块和常规模块)之后运行post-fs-data.sh、service.sh、boot-completed.sh)始终在常规模块脚本之前运行.d 目录中的通用脚本在元模块脚本之前运行post-mount 阶段在挂载完成后运行当安装元模块时,KernelSU 会创建一个符号链接:
/data/adb/metamodule -> /data/adb/modules/<metamodule_id>
这为访问活动元模块提供了稳定的路径,无论其 ID 如何。
好处:
meta-overlayfs 元模块是官方参考实现。它展示了元模块开发的最佳实践。
meta-overlayfs 使用双目录架构:
元数据目录: /data/adb/modules/
module.prop、disable、skip_mount 标记内容目录: /data/adb/metamodule/mnt/
modules.img)中以下是 meta-overlayfs 如何实现挂载处理程序:
#!/system/bin/sh
MODDIR="${0%/*}"
IMG_FILE="$MODDIR/modules.img"
MNT_DIR="$MODDIR/mnt"
# 如果尚未挂载,则挂载 ext4 镜像
if ! mountpoint -q "$MNT_DIR"; then
mkdir -p "$MNT_DIR"
mount -t ext4 -o loop,rw,noatime "$IMG_FILE" "$MNT_DIR"
fi
# 为双目录支持设置环境变量
export MODULE_METADATA_DIR="/data/adb/modules"
export MODULE_CONTENT_DIR="$MNT_DIR"
# 执行挂载二进制文件
# (实际挂载逻辑在 Rust 二进制文件中)
"$MODDIR/meta-overlayfs"
Overlayfs 挂载:
/data/adb/modules/.rw/ 支持读写层源标识:
// 来自 meta-overlayfs/src/mount.rs
fsconfig_set_string(fs, "source", "KSU")?; // 必需!
这为所有 overlay 挂载设置 dev=KSU,实现正确识别。
开发元模块时:
skip_mount 和 disableecho 或日志记录进行调试发布前:
对于用户: 仅当您想使用需要挂载的模块时。如果您只使用运行脚本而不修改系统文件的模块,则不需要元模块。
对于模块开发者: 不需要,您正常开发模块。仅当您的模块需要挂载时,用户才需要元模块。
对于高级用户: 仅当您想自定义挂载行为或创建替代挂载实现时。
不可以。一次只能安装一个元模块。这可以防止冲突并确保可预测的行为。
模块将不再被挂载。您的设备将正常启动,但模块修改将不会应用,直到您安装另一个元模块。
不是。它提供与大多数模块兼容的标准 overlayfs 挂载。如果您需要不同的行为,可以创建自己的元模块。