此指南由coolapk@依然的爱翻译
翻译不易,如果这篇指南帮到了你,你可以给我捐赠(当然,不捐赠也没关系)
Magisk附带了功能完整的BusyBox二进制文件(包括对SELinux的完整支持)。执行文件位于/data/adb/magisk/busybox。Magisk的BusyBox支持运行时可切换的“ASH Standalone Shell Mode(ASH独立Shell模式)”。这种独立模式的意思是,在ashshell的中的BusyBox运行时,无论PATH的值为何,每个命令都将直接使用BusyBox中的应用(子命令)。例如,就像ls,rm,chmod 命令一样。它们将不在使用PATH(在Android中,默认为/system/bin/ls,/system/bin/rm,和/system/bin/chmod。),而是直接调用Magisk内部的BusyBox应用(子命令)。这样可以确保脚本始终在可预测的环境中运行,并且无论运行在哪个Android版本上,始终具有完整的命令集。要强制命令不使用BusyBox,必须使用完整路径调用可执行文件。
在启用了ash的独立模式的情况下,Magisk中运行的每个单独的shell脚本都将在内部的BusyBox的shell中执行。对于与第三方开发者而言,这包括所有引导脚本和模块安装脚本。
对于那些想在Magisk之外使用此“独立模式”功能的人,有两种启用它的方法:
ASH_STANDALONE设置为1ASH_STANDALONE=1 /data/adb/magisk/busybox sh <script>/data/adb/magisk/busybox sh -o standalone <script>为确保所有后续的sh执行的shell也都以独立模式运行,推荐使用1方案(这是Magisk和Magisk应用程序内部使用的方法),因为环境变量一直继承到子进程。
Magisk模块的文件在/data/adb/modules中具有以下结构:
/data/adb/modules
├── .
├── .
|
├── $MODID                  <--- 该文件夹以模块的ID命名
│   │
│   │      *** 模块ID ***
│   │
│   ├── module.prop         <--- 该文件存储模块的基本信息
│   │
│   │      *** 主要内容 ***
│   │
│   ├── system              <--- 如果skip_mount不存在,则将挂载此文件夹
│   │   ├── ...
│   │   ├── ...
│   │   └── ...
│   │
│   │      *** 状态标志 ***
│   │
│   ├── skip_mount          <--- 如果存在,Magisk将不会挂载你的system文件夹
│   ├── disable             <--- 如果存在,该模块将被禁用
│   ├── remove              <--- 如果存在,该模块将在下次重新启动时被删除
│   │
│   │      *** 可选文件 ***
│   │
│   ├── post-fs-data.sh     <--- 该脚本将在post-fs-data模式下执行
│   ├── service.sh          <--- 该脚本将在late_start service模式执行
|   ├── uninstall.sh        <--- 当Magisk删除您的模块时,将执行此脚本
│   ├── system.prop         <--- 该文件中的properties将通过resetprop作为系统properties加载
│   ├── sepolicy.rule       <--- 添加自定义的sepolicy规则
│   │
│   │      *** 自动生成,请勿手动创建或修改 ***
│   │
│   ├── vendor              <--- 指向$MODID/system/vendor的链接
│   ├── product             <--- 指向$MODID/system/product的链接
│   ├── system_ext          <--- 指向$MODID/system/system_ext的链接
│   │
│   │      *** 允许任何其他文件/文件夹 ***
│   │
│   ├── ...
│   └── ...
|
├── another_module
│   ├── .
│   └── .
├── .
├── .
这是标准的module.prop格式
id=<string>
name=<string>
version=<string>
versionCode=<int>
author=<string>
description=<string>
id必须匹配以下正则表达式: ^[a-zA-Z][a-zA-Z0-9._-]+$a_module, ✓ a.module, ✓ module-101, ✗ a module, ✗ 1_module, ✗ -a-moduleversionCode必须为整数。这用于比较版本。UNIX (LF)类型换行符,而不是Windows (CR+LF)或Macintosh (CR)。*.sh)请阅读启动脚本部分,了解post-fs-data.sh与service.sh之间的差异。对于大多数模块开发者,service.sh如果只需运行启动脚本那便足够了。
在所有的模块脚本中,请使用MODDIR=${0%/*}来获取模块的基本目录信息;千万不要在脚本中编码模块目录。
该文件的格式与build.prop相同。每行包含[key]=[value]。
如果您的模块需要一些其他的sepolicy补丁,请将这些规则添加到此文件中。 模块安装程序脚本和Magisk的守护进程将确保将此文件复制到magiskinit,它可以读取预初始化的位置,以确保正确插入这些规则。
该文件中的每一行都将被视为策略声明。要详细了解策略声明的格式,请查看magiskpolicy的文档
system文件夹您希望Magisk为您替换/插入的所有文件都应放在此文件夹中。请查看Magic挂载 部分,以了解Magisk如何挂载文件。
Magisk模块安装程序是打包成zip文件的Magisk模块,可以在Magisk应用程序或第三方recovery(如TWRP)中进行刷入。安装程序的文件结构与Magisk模块的文件结构相同(请查看上一部分以获取更多信息)。最简单的Magisk模块安装程序只是一个打包为zip文件的Magisk模块,此外还包含以下文件:
update-binary: 下载最新的module_installer.sh并重命名/复制为update-binaryupdater-script: 此文件应仅包含字符串#MAGISK默认情况下,update-binary将检查/设置环境,加载使用的脚本,将模块安装程序的zip解压缩到将要安装模块的位置,最后执行一些琐碎的任务和清理工作,这些工作和清理应满足大多数简单模块的需求。
module.zip
│
├── META-INF
│   └── com
│       └── google
│           └── android
│               ├── update-binary      <--- 你下载的module_installer.sh
│               └── updater-script     <--- 应该只包含字符串"#MAGISK"
│
├── customize.sh                       <--- (可选,稍后会有更多详细信息)
│                                           该脚本将通过update-binary来获取
├── ...
├── ...  /* 模块的其余文件 */
│
如果您需要自定义模块安装过程,则可以选择在安装程序中创建一个名为customize.sh的脚本。这个脚本会在所有文件以默认permissions和secontext应用后,由update-binary调用(不是执行!)。如果您的模块包含基于ABI的其他文件,或者您需要为某些文件(例如/system/bin中的文件),设置特殊的permissions/secontext,这将非常有用。
如果您需要更多的自定义,并且希望自己做所有事情请在customize.sh中标注SKIPUNZIP=1以跳过提取操作并应用默认permissions/secontext。请注意,这样做后,你的customize.sh将负责自行安装所有内容。
customize.sh的运行环境这个脚本将在启用了“独立模式”Magisk的BusyBox ash shell 中运行。为了方便起见,可以使用以下变量和shell函数:
MAGISK_VER (string): 当前安装的Magisk的版本字符串 (例如 v20.0)MAGISK_VER_CODE (int): 当前安装的Magisk的版本代码 (例如 20000)BOOTMODE (bool): 如果模块当前安装在Magisk Manager中,则为trueMODPATH (path): 你的模块应该被安装到的路径TMPDIR (path): 一个你可以临时存储文件的路径ZIPFILE (path): 模块的安装包(zip)的路径ARCH (string): 设备的CPU构架。值可以是arm, arm64, x86, or x64IS64BIT (bool): 如果$ARCH(上方的ARCH变量)为 arm64或x64,则为trueAPI (int): 设备的API级别(Android版本)(例如 21为Android 5.0)
ui_print <msg>
    打印(print)<msg>到控制台
    避免使用'echo',因为它不会显示在第三方的recovery的控制台中。
abort <msg>
    打印错误信息<msg>到控制台并终止安装
    避免使用'exit',因为它会跳过终止的清理步骤
set_perm <文件名> <所有者> <用户组> <文件权限> [上下文]
    如果 [上下文] 没有设置,则默认为"u:object_r:system_file:s0"
    该函数是以下命令的简写:
       chown 所有者.用户组 文件名
       chmod 权限 文件名
       chcon 上下文 文件名
set_perm_recursive <目录> <所有者> <用户组> <目录权限> <文件权限> [上下文]
    如果 [上下文] 没有设置,则默认为"u:object_r:system_file:s0"
    对于<目录>中的所有文件,它将调用:
       set_perm 文件 所有者 用户组 文件权限 上下文
    对于<目录>中的所有目录(包括自身),它将调用:
       set_perm 目录 所有者 用户组 目录权限 上下文
您可以在变量名中声明要直接替换的文件夹列表REPLACE。模块安装程序脚本将提取此变量并创建.replace文件进行替换。声明示例:
REPLACE="
/system/app/YouTube
/system/app/Bloatware
"
上面的列表将导致创建以下文件: $MODPATH/system/app/YouTube/.replace和$MODPATH/system/app/Bloatware/.replace
module_installer.sh强制替换update-binary,以确保所有安装程序都使用最新的脚本。不要不要试图在update-binary中添加任何自定义逻辑,因为这毫无意义。install.sh的文件。该文件以前曾被使用过,将被区别对待。customize.sh末尾使用exit。模块安装程序将会自行完成。你可以将模块提交到Magisk-Module-Repo以便用户可以直接在Magisk Manager中下载你的模块。
README.md (文件名应该完全相同) ,其中包含模块的所有信息。如果你不熟悉Markdown语法,那么Markdown备忘录将会非常方便如何自动删除文件?实际使文件删除很复杂(可能,不值得付出努力)。用空文件替换它应该已经足够了!创建一个具有相同名称的空文件,并将其放置在模块内的相同路径中,它将用空文件替换你的目标文件。
与上述相同,实际上使文件夹删除是不值得的。用一个空文件夹替换它应该已经足够了!对于模块开发人员来说,一个方便的技巧是将要删除的文件夹添加到customize.sh中的REPLACE列表中。如果您的模块没有提供相应的文件夹,它将创建一个空文件夹,并自动将.replace添加到该空文件夹中,以便虚拟文件夹可以正确替换/system中的一个文件夹。
在Magisk中,您可以以两种不同的模式运行启动脚本: post-fs-data和late_start service模式
在Magisk中,还有两种脚本: 通用脚本和模块脚本.
/data/adb/post-fs-data.d或/data/adb/service.dchmod +x script.sh)post-fs-data.d中以post-fs-data 模式运行,在service.d中以late_start service 模式运行。post-fs-data.sh在post-fs-data 模式下运行,service.sh在late_start service 模式下运行。这些脚本将在启用了“独立模式”Magisk的BusyBox ash shell中运行.
由于/在system-as-root设备上是只读的, 因此Magisk提供了一个覆盖系统,使开发人员可以替换根目录中的文件或添加新的*.rc脚本。此功能主要是为自定义内核开发人员设计的。
覆盖文件应放在boot镜像ramdisk的overlay.d文件夹中并遵循以下规则:
overlay.d中所有的*.rc将在init.rc之后读取并链接为了在自定义*.rc脚本中引用其他文件, 请在overlay.d/sbin中添加它们。上面的3条规则不适用于此特定文件夹中的所有内容,因为它们将直接复制到Magisk的内部tmpfs目录(该目录始终位于/sbin)。
由于Android 11中的更改,不再保证/sbin 文件夹的存在。这种情况下,Magisk会随机生成tmpfs文件夹。在你的*.rc脚本中所有的${MAGISKTMP}会在magiskinit注入到init.rc中时,被Magisk tmpfs文件夹替换。这也可以在Android 11之前的设备上使用,因为在这种情况下${MAGISKTMP}将简单地被替换为/sbin,因此最佳实践是在引用其他文件时,不要在*.rc脚本中编码/sbin。
这是一个如何使用自定义*.rc脚本设置overlay.d的示例:
ramdisk
│
├── overlay.d
│   ├── sbin
│   │   ├── libfoo.ko      <--- 这两个文件将被复制
│   │   └── myscript.sh    <--- 到Magisk的tmpfs目录
│   ├── custom.rc          <--- 该文件将被注入到init.rc中
│   ├── res
│   │   └── random.png     <--- 该文件将替换/res/random.png
│   └── new_file           <--- 该文件将被忽略,因为
│                               /new_file不存在
├── res
│   └── random.png         <--- 该文件将被替换为
│                               /overlay.d/res/random.png
├── ...
├── ...  /* 其余的initramfs文件 */
│
这是一个示例custom.rc:
# 使用${MAGISKTMP}引用Magisk的tmpfs目录
on early-init
    setprop sys.example.foo bar
    insmod ${MAGISKTMP}/libfoo.ko
    start myservice
service myservice ${MAGISKTMP}/myscript.sh
    oneshot