Add docs for module

This commit is contained in:
tiann
2023-03-26 15:43:06 +08:00
parent ecd5af76ab
commit 43ca2b9831
6 changed files with 532 additions and 0 deletions

View File

@@ -50,6 +50,7 @@ function sidebarGuide() {
{ text: 'How to build?', link: '/guide/how-to-build' }, { text: 'How to build?', link: '/guide/how-to-build' },
{ text: 'Intergrate for non-GKI devices', link: '/guide/how-to-integrate-for-non-gki'}, { text: 'Intergrate for non-GKI devices', link: '/guide/how-to-integrate-for-non-gki'},
{ text: 'Unofficially supported devices', link: '/guide/unofficially-support-devices.md' }, { text: 'Unofficially supported devices', link: '/guide/unofficially-support-devices.md' },
{ text: 'Module Guide', link: '/guide/module.md' },
{ text: 'FAQ', link: '/guide/faq' }, { text: 'FAQ', link: '/guide/faq' },
] ]
} }

View File

@@ -50,6 +50,7 @@ function sidebarGuide() {
{ text: '如何构建?', link: '/zh_CN/guide/how-to-build' }, { text: '如何构建?', link: '/zh_CN/guide/how-to-build' },
{ text: '如何为非GKI设备集成 KernelSU', link: '/zh_CN/guide/how-to-integrate-for-non-gki'}, { text: '如何为非GKI设备集成 KernelSU', link: '/zh_CN/guide/how-to-integrate-for-non-gki'},
{ text: '非官方支持设备', link: '/zh_CN/guide/unofficially-support-devices.md' }, { text: '非官方支持设备', link: '/zh_CN/guide/unofficially-support-devices.md' },
{ text: '模块开发指南', link: '/zh_CN/guide/module.md' },
{ text: '常见问题', link: '/zh_CN/guide/faq' }, { text: '常见问题', link: '/zh_CN/guide/faq' },
] ]
} }

View File

@@ -0,0 +1,25 @@
# Difference with Magisk
Although there are many similarities between KernelSU modules and Magisk modules, there are inevitably some differences due to their completely different implementation mechanisms. If you want your module to run on both Magisk and KernelSU, you must understand these differences.
## Similarities
- Module file format: both use zip format to organize modules, and the format of modules is almost the same
- Module installation directory: both located in `/data/adb/modules`
- Systemless: both support modifying /system in a systemless way through modules
- post-fs-data.sh: the execution time and semantics are exactly the same
- service.sh: the execution time and semantics are exactly the same
- system.prop: completely the same
- sepolicy.rule: completely the same
- BusyBox: scripts are run in BusyBox with "standalone mode" enabled in both cases
## Differences
Before understanding the differences, you need to know how to differentiate whether your module is running in KernelSU or Magisk. You can use the environment variable `KSU` to differentiate it in all places where you can run module scripts (`customize.sh`, `post-fs-data.sh`, `service.sh`). In KernelSU, this environment variable will be set to `true`.
Here are some differences:
- KernelSU modules cannot be installed in Recovery mode.
- KernelSU modules do not have built-in support for Zygisk (but you can use Zygisk modules through [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU).
- The method for replacing or deleting files in KernelSU modules is completely different from Magisk. KernelSU does not support the `.replace` method. Instead, you need to create a same-named file with `mknod filename c 0 0` to delete the corresponding file.
- The directories for BusyBox are different. The built-in BusyBox in KernelSU is located in `/data/adb/ksu/bin/busybox`, while in Magisk it is in `/data/adb/magisk/busybox`. **Note that this is an internal behavior of KernelSU and may change in the future!**

View File

@@ -0,0 +1,237 @@
# Module guides
KernelSU provides a module mechanism that achieves the effect of modifying the system directory while maintaining the integrity of the system partition. This mechanism is commonly known as "systemless".
The module mechanism of KernelSU is almost the same as that of Magisk. If you are familiar with Magisk module development, developing KernelSU modules is very similar. You can skip the introduction of modules below and only need to read [difference-with-magisk](difference-with-magisk.md).
## Busybox
KernelSU ships with a feature complete BusyBox binary (including full SELinux support). The executable is located at `/data/adb/ksu/bin/busybox`. KernelSU's BusyBox supports runtime toggle-able "ASH Standalone Shell Mode". What this standalone mode means is that when running in the `ash` shell of BusyBox, every single command will directly use the applet within BusyBox, regardless of what is set as `PATH`. For example, commands like `ls`, `rm`, `chmod` will **NOT** use what is in `PATH` (in the case of Android by default it will be `/system/bin/ls`, `/system/bin/rm`, and `/system/bin/chmod` respectively), but will instead directly call internal BusyBox applets. This makes sure that scripts always run in a predictable environment and always have the full suite of commands no matter which Android version it is running on. To force a command _not_ to use BusyBox, you have to call the executable with full paths.
Every single shell script running in the context of KernelSU will be executed in BusyBox's `ash` shell with standalone mode enabled. For what is relevant to 3rd party developers, this includes all boot scripts and module installation scripts.
For those who want to use this "Standalone Mode" feature outside of KernelSU, there are 2 ways to enable it:
1. Set environment variable `ASH_STANDALONE` to `1`<br>Example: `ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh <script>`
2. Toggle with command-line options:<br>`/data/adb/ksu/bin/busybox sh -o standalone <script>`
To make sure all subsequent `sh` shell executed also runs in standalone mode, option 1 is the preferred method (and this is what KernelSU and the KernelSU manager internally use) as environment variables are inherited down to child processes.
::: tip difference with Magisk
KernelSU's BusyBox is now using the binary file compiled directly from the Magisk project. **Thanks to Magisk!** Therefore, you don't have to worry about compatibility issues between BusyBox scripts in Magisk and KernelSU because they are exactly the same!
:::
## KernelSU modules
A KernelSU module is a folder placed in `/data/adb/modules` with the structure below:
```txt
/data/adb/modules
├── .
├── .
|
├── $MODID <--- The folder is named with the ID of the module
│ │
│ │ *** Module Identity ***
│ │
│ ├── module.prop <--- This file stores the metadata of the module
│ │
│ │ *** Main Contents ***
│ │
│ ├── system <--- This folder will be mounted if skip_mount does not exist
│ │ ├── ...
│ │ ├── ...
│ │ └── ...
│ │
│ │ *** Status Flags ***
│ │
│ ├── skip_mount <--- If exists, KernelSU will NOT mount your system folder
│ ├── disable <--- If exists, the module will be disabled
│ ├── remove <--- If exists, the module will be removed next reboot
│ │
│ │ *** Optional Files ***
│ │
│ ├── post-fs-data.sh <--- This script will be executed in post-fs-data
│ ├── service.sh <--- This script will be executed in late_start service
| ├── uninstall.sh <--- This script will be executed when KernelSU removes your module
│ ├── system.prop <--- Properties in this file will be loaded as system properties by resetprop
│ ├── sepolicy.rule <--- Additional custom sepolicy rules
│ │
│ │ *** Auto Generated, DO NOT MANUALLY CREATE OR MODIFY ***
│ │
│ ├── vendor <--- A symlink to $MODID/system/vendor
│ ├── product <--- A symlink to $MODID/system/product
│ ├── system_ext <--- A symlink to $MODID/system/system_ext
│ │
│ │ *** Any additional files / folders are allowed ***
│ │
│ ├── ...
│ └── ...
|
├── another_module
│ ├── .
│ └── .
├── .
├── .
```
::: tip difference with Magisk
KernelSU does not have built-in support for Zygisk, so there is no content related to Zygisk in the module. However, you can use [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) to support Zygisk modules. In this case, the content of the Zygisk module is identical to that supported by Magisk.
:::
### module.prop
module.prop is a configuration file for a module. In KernelSU, if a module does not contain this file, it will not be recognized as a module. The format of this file is as follows:
```txt
id=<string>
name=<string>
version=<string>
versionCode=<int>
author=<string>
description=<string>
```
- `id` has to match this regular expression: `^[a-zA-Z][a-zA-Z0-9._-]+$`<br>
ex: ✓ `a_module`, ✓ `a.module`, ✓ `module-101`, ✗ `a module`, ✗ `1_module`, ✗ `-a-module`<br>
This is the **unique identifier** of your module. You should not change it once published.
- `versionCode` has to be an **integer**. This is used to compare versions
- Others that weren't mentioned above can be any **single line** string.
- Make sure to use the `UNIX (LF)` line break type and not the `Windows (CR+LF)` or `Macintosh (CR)`.
### Shell scripts
Please read the [Boot Scripts](#boot-scripts) section to understand the difference between `post-fs-data.sh` and `service.sh`. For most module developers, `service.sh` should be good enough if you just need to run a boot script.
In all scripts of your module, please use `MODDIR=${0%/*}` to get your module's base directory path; do **NOT** hardcode your module path in scripts.
::: tip difference with Magisk
You can use the environment variable KSU to determine if a script is running in KernelSU or Magisk. If running in KernelSU, this value will be set to true.
:::
### `system` directory
The contents of this directory will be overlaid on top of the system's /system partition using overlayfs after the system is booted. This means that:
1. Files with the same name as those in the corresponding directory in the system will be overwritten by the files in this directory.
2. Folders with the same name as those in the corresponding directory in the system will be merged with the folders in this directory.
If you want to delete a file or folder in the original system directory, you need to create a file with the same name as the file/folder in the module directory using `mknod filename c 0 0`. This way, the overlayfs system will automatically "whiteout" this file as if it has been deleted (the /system partition is not actually changed).
::: tip difference with Magisk
KernelSU's systemless mechanism is implemented through the kernel's overlayfs, while Magisk currently uses magic mount (bind mount). The two implementation methods have significant differences, but the ultimate goal is the same: to modify /system files without physically modifying the /system partition.
:::
If you are interested in overlayfs, it is recommended to read the Linux Kernel's [documentation on overlayfs](https://docs.kernel.org/filesystems/overlayfs.html).
### system.prop
This file follows the same format as `build.prop`. Each line comprises of `[key]=[value]`.
### sepolicy.rule
If your module requires some additional sepolicy patches, please add those rules into this file. Each line in this file will be treated as a policy statement.
## Module installer
A KernelSU module installer is a KernelSU module packaged in a zip file that can be flashed in the KernelSU manager APP. The simplest KernelSU module installer is just a KernelSU module packed as a zip file.
```txt
module.zip
├── customize.sh <--- (Optional, more details later)
│ This script will be sourced by update-binary
├── ...
├── ... /* The rest of module's files */
```
:::warning
KernelSU module is NOT supported to be installed in custom recovery!!
:::
### Customization
If you need to customize the module installation process, optionally you can create a script in the installer named `customize.sh`. This script will be _sourced_ (not executed!) by the module installer script after all files are extracted and default permissions and secontext are applied. This is very useful if your module require additional setup based on the device ABI, or you need to set special permissions/secontext for some of your module files.
If you would like to fully control and customize the installation process, declare `SKIPUNZIP=1` in `customize.sh` to skip all default installation steps. By doing so, your `customize.sh` will be responsible to install everything by itself.
The `customize.sh` script runs in KernelSU's BusyBox `ash` shell with "Standalone Mode" enabled. The following variables and functions are available:
#### Variables
- `KSU` (bool): a variable to mark that the script is running in the KernelSU environment, and the value of this variable will always be true. You can use it to distinguish between KernelSU and Magisk.
- `KSU_VER` (string): the version string of current installed KernelSU (e.g. `v0.4.0`)
- `KSU_VER_CODE` (int): the version code of current installed KernelSU in userspace (e.g. `10672`)
- `KSU_KERNEL_VER_CODE` (int): the version code of current installed KernelSU in kernel space (e.g. `10672`)
- `BOOTMODE` (bool): always be `true` in KernelSU
- `MODPATH` (path): the path where your module files should be installed
- `TMPDIR` (path): a place where you can temporarily store files
- `ZIPFILE` (path): your module's installation zip
- `ARCH` (string): the CPU architecture of the device. Value is either `arm`, `arm64`, `x86`, or `x64`
- `IS64BIT` (bool): `true` if `$ARCH` is either `arm64` or `x64`
- `API` (int): the API level (Android version) of the device (e.g. `23` for Android 6.0)
::: warning
In KernelSU, MAGISK_VER_CODE is always 25200 and MAGISK_VER is always v25.2. Please do not use these two variables to determine whether it is running on KernelSU or not.
:::
#### Functions
```txt
ui_print <msg>
print <msg> to console
Avoid using 'echo' as it will not display in custom recovery's console
abort <msg>
print error message <msg> to console and terminate the installation
Avoid using 'exit' as it will skip the termination cleanup steps
set_perm <target> <owner> <group> <permission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
this function is a shorthand for the following commands:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
for all files in <directory>, it will call:
set_perm file owner group filepermission context
for all directories in <directory> (including itself), it will call:
set_perm dir owner group dirpermission context
```
## Boot scripts
In KernelSU, scripts are divided into two types based on their running mode: post-fs-data mode and late_start service mode:
- post-fs-data mode
- This stage is BLOCKING. The boot process is paused before execution is done, or 10 seconds have passed.
- Scripts run before any modules are mounted. This allows a module developer to dynamically adjust their modules before it gets mounted.
- This stage happens before Zygote is started, which pretty much means everything in Android
- **WARNING:** using `setprop` will deadlock the boot process! Please use `resetprop -n <prop_name> <prop_value>` instead.
- **Only run scripts in this mode if necessary.**
- late_start service mode
- This stage is NON-BLOCKING. Your script runs in parallel with the rest of the booting process.
- **This is the recommended stage to run most scripts.**
In KernelSU, startup scripts are divided into two types based on their storage location: general scripts and module scripts:
- General Scripts
- Placed in `/data/adb/ksu/post-fs-data.d` or `/data/adb/ksu/service.d`
- Only executed if the script is set as executable (`chmod +x script.sh`)
- Scripts in `post-fs-data.d` runs in post-fs-data mode, and scripts in `service.d` runs in late_start service mode.
- Modules should **NOT** add general scripts during installation
- Module Scripts
- Placed in the module's own folder
- Only executed if the module is enabled
- `post-fs-data.sh` runs in post-fs-data mode, and `service.sh` runs in late_start service mode.
All boot scripts will run in KernelSU's BusyBox `ash` shell with "Standalone Mode" enabled.
::: tip difference with Magisk
KernelSU's general modules are stored in `/data/adb/ksu/post-fs-data.d` and `/data/adb/ksu/service.d`, while Magisk's general modules are stored in `/data/adb/post-fs-data.d` and `/data/adb/service.d`. Apart from this difference, they are completely identical (this may be changed to make them identical in the future). This includes the timing of the execution of post-fs-data and late_start scripts, as well as the running mode of the scripts.
:::

View File

@@ -0,0 +1,25 @@
# KernelSU 模块与 Magisk 的差异
虽然 KernelSU 模块与 Magisk 模块有很多相似之处,但由于它们的实现机制完全不同,因此不可避免地会有一些差异;如果你希望你的模块能同时在 Magisk 与 KernelSU 中运行,那么你必须了解这些差异。
## 相同之处
- 模块文件格式: 都以 zip 的方式组织模块,并且模块的格式几乎相同
- 模块安装目录: 都在 `/data/adb/modules`
- systemless: 都支持通过模块的形式以 systemless 修改 /system
- `post-fs-data.sh`: 执行时机完全一致,语义也完全一致
- `service.sh`: 执行世纪完全一致,语义也完全一致
- `system.prop`: 完全相同
- `sepolicy.rule`: 完全相同
- BusyBox脚本都在 BusyBox 中以“独立模式”运行
## 不同之处
在了解不同之处之前,你需要知道如何区分你的模块是运行在 KernelSU 还是运行在 Magisk 之中;在所有你可以运行模块脚本的地方(`customize.sh`, `post-fs-data.sh`, `service.sh`),你都可以通过环境变量`KSU` 来区分,在 KernelSU 中,这个环境变量将被设置为 `true`
以下是一些不同之处:
1. KernelSU 的模块不支持在 Recovery 中安装。
2. KernelSU 的模块没有内置的 Zygisk 支持(但你可以通过 [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 来使用 Zygisk 模块)。
3. KernelSU 模块替换或者删除文件与 Magisk 完全不同。KernelSU 不支持 `.replace` 方式,相反,你需要通过 `mknod filename c 0 0` 创建同名文件夹来删除对应文件。
4. BusyBox 的目录不同KernelSU 内置的 BusyBox 在 `/data/adb/ksu/bin/busybox` 而 Magisk 在 `/data/adb/magisk/busybox`**注意此为 KernelSU 内部行为,未来可能会更改!**

View File

@@ -0,0 +1,243 @@
# 模块开发指南
KernelSU 提供了一个模块机制,它可以在保持系统分区完整性的同时达到修改系统分区的效果;这种机制通常被称之为 systemless。
KernelSU 的模块运作机制与 Magisk 几乎是一样的,如果你熟悉 Magisk 模块的开发,那么开发 KernelSU 的模块大同小异,你可以跳过下面有关模块的介绍,只需要了解 [KernelSU 模块与 Magisk 模块的异同](difference-with-magisk.md)。
## Busybox
KernelSU 提供了一个功能完备的 BusyBox 二进制文件包括完整的SELinux支持。可执行文件位于 `/data/adb/ksu/bin/busybox`
KernelSU 的 BusyBox 支持运行时可切换的 "ASH Standalone Shell Mode"。
这种独立模式意味着在运行 BusyBox 的 ash shell 时,每个命令都会直接使用 BusyBox 中内置的应用程序,而不管 PATH 设置为什么。
例如,`ls``rm``chmod` 等命令将不会使用 PATH 中设置的命令在Android的情况下默认情况下分别为 `/system/bin/ls``/system/bin/rm``/system/bin/chmod`),而是直接调用 BusyBox 内置的应用程序。
这确保了脚本始终在可预测的环境中运行并始终具有完整的命令套件无论它运行在哪个Android版本上。
要强制一个命令不使用BusyBox你必须使用完整路径调用可执行文件。
在 KernelSU 上下文中运行的每个 shell 脚本都将在 BusyBox 的 ash shell 中以独立模式运行。对于第三方开发者相关的内容,包括所有启动脚本和模块安装脚本。
对于想要在 KernelSU 之外使用这个“独立模式”功能的用户,有两种启用方法:
1. 设置环境变量 `ASH_STANDALONE``1`。例如:`ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh <script>`
2. 使用命令行选项切换:`/data/adb/ksu/bin/busybox sh -o standalone <script>`
为了确保所有后续的 `sh` shell 都在独立模式下执行,第一种是首选方法(这也是 KernelSU 和 KernelSU 管理器内部使用的方法),因为环境变量会被继承到子进程中。
::: tip 与 Magisk 的差异
KernelSU 的 BusyBox 现在是直接使用 Magisk 项目编译的二进制文件,**感谢 Magisk**
因此,你完全不用担心 BusyBox 脚本与在 Magisk 和 KernelSU 之间的兼容问题,因为他们是完全一样的!
:::
## KernelSU 模块
KernelSU 模块就是一个放置在 `/data/adb/modules` 内且满足如下结构的文件夹:
```txt
/data/adb/modules
├── .
├── .
|
├── $MODID <--- 模块的文件夹名称与模块 ID 相同
│ │
│ │ *** 模块配置文件 ***
│ │
│ ├── module.prop <--- 此文件保存模块相关的一些配置,如模块 ID、版本等
│ │
│ │ *** 模块内容 ***
│ │
│ ├── system <--- 这个文件夹通常会被挂载到系统
│ │ ├── ...
│ │ ├── ...
│ │ └── ...
│ │
│ │ *** 标记文件 ***
│ │
│ ├── skip_mount <--- 如果这个文件存在,那么模块的 `/system` 将不会被挂载
│ ├── disable <--- 如果这个文件存在,那么模块会被禁用
│ ├── remove <--- 如果这个文件存在,下次重启的时候模块会被移除
│ │
│ │ *** 可选文件 ***
│ │
│ ├── post-fs-data.sh <--- 这个脚本将会在 post-fs-data 模式下运行
│ ├── service.sh <--- 这个脚本将会在 late_start 服务模式下运行
| ├── uninstall.sh <--- 这个脚本将会在模块被卸载是运行
│ ├── system.prop <--- 这个文件中指定的属性将会在系统启动时通过 resetprop 更改
│ ├── sepolicy.rule <--- 这个文件中的 SELinux 策略将会在系统启动时加载
│ │
│ │ *** 自动生成的目录,不要手动创建或者修改! ***
│ │
│ ├── vendor <--- A symlink to $MODID/system/vendor
│ ├── product <--- A symlink to $MODID/system/product
│ ├── system_ext <--- A symlink to $MODID/system/system_ext
│ │
│ │ *** Any additional files / folders are allowed ***
│ │
│ ├── ...
│ └── ...
|
├── another_module
│ ├── .
│ └── .
├── .
├── .
```
::: tip 与 Magisk 的差异
KernelSU 没有内置的针对 Zygisk 的支持,因此模块中没有 Zygisk 相关的内容,但你可以通过 [ZygiskOnKernelSU](https://github.com/Dr-TSNG/ZygiskOnKernelSU) 来支持 Zygisk 模块,此时 Zygisk 模块的内容与 Magisk 所支持的 Zygisk 是完全相同的。
:::
### module.prop
module.prop 是一个模块的配置文件,在 KernelSU 中如果模块中不包含此文件,那么它将不被认为是一个模块;此文件的格式如下:
```txt
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 必须是一个整数,用于比较版本。
- 其他未在上面提到的内容可以是任何单行字符串。
- 请确保使用 UNIXLF换行类型而不是WindowsCR + LF或 MacintoshCR
### Shell 脚本
请阅读 [启动脚本](#启动脚本) 一节,以了解 `post-fs-data.sh``service.sh` 之间的区别。对于大多数模块开发者来说,如果您只需要运行一个启动脚本,`service.sh` 应该已经足够了。
在您的模块的所有脚本中,请使用 `MODDIR=${0%/*}`来获取您的模块的基本目录路径;请勿在脚本中硬编码您的模块路径。
:::tip 与 Magisk 的差异
你可以通过环境变量 `KSU` 来判断脚本是运行在 KernelSU 还是 Magisk 中,如果运行在 KernelSU这个值会被设置为 `true`
:::
### `system` 目录
这个目录的内容会在系统启动后,以 `overlayfs` 的方式叠加在系统的 `/system` 分区之上,这意味着:
1. 系统中对应目录的同名文件会被此目录的文件覆盖。
2. 系统中对应目录的同名文件夹会与此目录的文件夹合并。
如果你想删掉系统原来目录某个文件或者文件夹,你需要在模块目录通过 `mknod filename c 0 0` 来创建一个 `filename` 的同名文件;这样 overlayfs 系统会自动 whiteout 等效删除此文件(`/system` 分区并没有被更改)。
::: tip 与 Magisk 的差异
KernelSU 的 systemless 机制是通过内核的 overlayfs 实现的,而 Magisk 当前则是通过 magic mount (bind mount),二者实现方式有着巨大的差异,但最终的目标实际上是一致的:不修改物理的 `/system` 分区但实现修改 `/system` 文件。
:::
如果你对 overlayfs 感兴趣,建议阅读 Linux Kernel 关于 [overlayfs 的文档](https://docs.kernel.org/filesystems/overlayfs.html)
### system.prop
这个文件的格式与 `build.prop` 完全相同:每一行都是 `[key]=[value]` 的形式。
### sepolicy.rule
如果您的模块需要一些额外的 SELinux 策略补丁,请将这些规则添加到此文件中。这个文件中的每一行都将被视为一个策略语句。
## 模块安装包
KernelSU 的模块安装包就是一个可以通过 KernelSU 管理器 APP 刷入的 zip 文件,此 zip 文件的格式如下:
```txt
module.zip
├── customize.sh <--- (Optional, more details later)
│ This script will be sourced by update-binary
├── ...
├── ... /* 其他模块文件 */
```
:::warning
KernelSU 模块不支持在 Recovery 中安装!!
:::
### 定制安装过程
如果你想控制模块的安装过程,可以在模块的目录下创建一个名为 `customize.sh` 的文件,这个脚本将会在模块被解压后**导入**到当前 shell 中,如果你的模块需要根据设备的 API 版本或者设备构架做一些额外的操作,那这个脚本将非常有用。
如果你想完全控制脚本的安装过程,你可以在 `customize.sh` 中声明 `SKIPUNZIP=1` 来跳过所有的默认安装步骤;此时,你需要自行处理所有安装过程(如解压模块,设置权限等)
`customize.sh` 脚本以“独立模式”运行在 KernelSU 的 BusyBox `ash` shell 中。你可以使用如下变量和函数:
#### 变量
- `KSU` (bool): 标记此脚本运行在 KernelSU 环境下,此变量的值将永远为 `true`,你可以通过它区分 Magisk。
- `KSU_VER` (string): KernelSU 当前的版本名字 (如: `v0.4.0`)
- `KSU_VER_CODE` (int): KernelSU 用户空间当前的版本号 (如. `10672`)
- `KSU_KERNEL_VER_CODE` (int): KernelSU 内核空间当前的版本号 (如. `10672`)
- `BOOTMODE` (bool): 此变量在 KernelSU 中永远为 `true`
- `MODPATH` (path): 当前模块的安装目录
- `TMPDIR` (path): 可以存放临时文件的目录
- `ZIPFILE` (path): 当前模块的安装包文件
- `ARCH` (string): 设备的 CPU 构架,有如下几种: `arm`, `arm64`, `x86`, or `x64`
- `IS64BIT` (bool): 是否是 64 位设备
- `API` (int): 当前设备的 Android API 版本 (如Android 6.0 上为 `23`)
::: warning
`MAGISK_VER_CODE` 在 KernelSU 中永远为 `25200``MAGISK_VER` 则为 `v25.2`,请不要通过这两个变量来判断是否是 KernelSU
:::
#### 函数
```txt
ui_print <msg>
print <msg> to console
Avoid using 'echo' as it will not display in custom recovery's console
abort <msg>
print error message <msg> to console and terminate the installation
Avoid using 'exit' as it will skip the termination cleanup steps
set_perm <target> <owner> <group> <permission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
this function is a shorthand for the following commands:
chown owner.group target
chmod permission target
chcon context target
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
if [context] is not set, the default is "u:object_r:system_file:s0"
for all files in <directory>, it will call:
set_perm file owner group filepermission context
for all directories in <directory> (including itself), it will call:
set_perm dir owner group dirpermission context
```
## 启动脚本
在 KernelSU 中根据脚本运行模式的不同分为两种post-fs-data 模式和 late_start 服务模式。
- post-fs-data 模式
- 这个阶段是阻塞的。在执行完成之前或者 10 秒钟之后,启动过程会暂停。
- 脚本在任何模块被挂载之前运行。这使得模块开发者可以在模块被挂载之前动态地调整它们的模块。
- 这个阶段发生在 Zygote 启动之前。
- 使用 setprop 会导致启动过程死锁!请使用 `resetprop -n <prop_name> <prop_value>` 代替。
- **只有在必要时才在此模式下运行脚本**。
- late_start 服务模式
- 这个阶段是非阻塞的。你的脚本会与其余的启动过程**并行**运行。
- **大多数脚本都建议在这种模式下运行**。
在 KernelSU 中,启动脚本根据存放位置的不同还分为两种:通用脚本和模块脚本。
- 通用脚本
- 放置在 `/data/adb/ksu/post-fs-data.d``/data/adb/ksu/service.d` 中。
- 只有在脚本被设置为可执行(`chmod +x script.sh`)时才会被执行。
-`post-fs-data.d` 中的脚本以 post-fs-data 模式运行,在 `service.d` 中的脚本以 late_start 服务模式运行。
- 模块**不应**在安装过程中添加通用脚本。
- 模块脚本
- 放置在模块自己的文件夹中。
- 只有当模块被启用时才会执行。
- `post-fs-data.sh` 以 post-fs-data 模式运行,而 `service.sh` 则以 late_start 服务模式运行。
所有启动脚本都将在 KernelSU 的 BusyBox ash shell 中运行,并启用“独立模式”。
::: tip 与 Magisk 的差异
KernelSU 的通用模块存放在 `/data/adb/ksu/post-fs-data.d``/data/adb/ksu/service.d`,而 Magisk 的通用模块存放在 `/data/adb/post-fs-data.d``/data/adb/service.d`;除此之外二者是完全一样的(后面可能会改成一样的)。包括 post-fs-data 和 late_start 脚本的运行时机,脚本的运行模式等。
:::