此指南由coolapk@依然的爱翻译
翻译不易,如果这篇指南帮到了你,你可以给我捐赠(当然,不捐赠也没关系)
Magisk附带了功能完整的BusyBox二进制文件(包括对SELinux的完整支持)。执行文件位于/data/adb/magisk/busybox
。Magisk的BusyBox支持运行时可切换的“ASH Standalone Shell Mode(ASH独立Shell模式)”。这种独立模式的意思是,在ash
shell的中的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
设置为1
ASH_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-module
versionCode
必须为整数。这用于比较版本。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-binary
updater-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中,则为true
MODPATH
(path): 你的模块应该被安装到的路径TMPDIR
(path): 一个你可以临时存储文件的路径ZIPFILE
(path): 模块的安装包(zip)的路径ARCH
(string): 设备的CPU构架。值可以是arm
, arm64
, x86
, or x64
IS64BIT
(bool): 如果$ARCH
(上方的ARCH
变量)为 arm64
或x64
,则为true
API
(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.d
chmod +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