256 lines
23 KiB
Markdown
256 lines
23 KiB
Markdown
# Руководство по разработке модулей {#introduction}
|
||
|
||
KernelSU предоставляет механизм модулей, позволяющий добиться эффекта модификации системного каталога при сохранении целостности системного раздела. Этот механизм принято называть "бессистемным".
|
||
|
||
Модульный механизм KernelSU практически аналогичен механизму Magisk. Если вы знакомы с разработкой модулей Magisk, то разработка модулей KernelSU очень похожа. Представление модулей ниже можно пропустить, достаточно прочитать [различия-с-magisk] (difference-with-magisk.md).
|
||
|
||
## Busybox
|
||
|
||
В комплект поставки KernelSU входит полнофункциональный бинарный файл BusyBox (включая полную поддержку SELinux). Исполняемый файл находится по адресу `/data/adb/ksu/bin/busybox`. BusyBox от KernelSU поддерживает переключаемый во время работы "ASH Standalone Shell Mode". Этот автономный режим означает, что при запуске в оболочке `ash` BusyBox каждая команда будет напрямую использовать апплет внутри BusyBox, независимо от того, что задано в качестве `PATH`. Например, такие команды, как `ls`, `rm`, `chmod` будут **НЕ** использовать то, что находится в `PATH` (в случае Android по умолчанию это будут `/system/bin/ls`, `/system/bin/rm` и `/system/bin/chmod` соответственно), а вместо этого будут напрямую вызывать внутренние апплеты BusyBox. Это гарантирует, что скрипты всегда будут выполняться в предсказуемом окружении и всегда будут иметь полный набор команд, независимо от того, на какой версии Android они выполняются. Чтобы заставить команду _не_ использовать BusyBox, необходимо вызвать исполняемый файл с полными путями.
|
||
|
||
Каждый сценарий оболочки, запущенный в контексте KernelSU, будет выполняться в оболочке BusyBox `ash` с включенным автономным режимом. Для сторонних разработчиков это касается всех загрузочных скриптов и скриптов установки модулей.
|
||
|
||
Для тех, кто хочет использовать эту возможность "Автономного режима" вне KernelSU, есть два способа включить ее:
|
||
|
||
1. Установите переменной окружения `ASH_STANDALONE` значение `1`<br>Пример: `ASH_STANDALONE=1 /data/adb/ksu/bin/busybox sh <script>`
|
||
2. Переключитесь с помощью параметров командной строки:<br>`/data/adb/ksu/bin/busybox sh -o standalone <script>`
|
||
|
||
Чтобы убедиться, что все последующие запуски оболочки `sh` также выполняются в автономном режиме, предпочтительным методом является вариант 1 (и это то, что KernelSU и менеджер KernelSU используют внутри), поскольку переменные окружения наследуются вплоть до дочерних процессов.
|
||
|
||
::: tip отличие от Magisk
|
||
|
||
BusyBox в KernelSU теперь использует бинарный файл, скомпилированный непосредственно из проекта Magisk. **Поэтому вам не нужно беспокоиться о проблемах совместимости между скриптами BusyBox в Magisk и KernelSU, поскольку они абсолютно одинаковы!
|
||
:::
|
||
|
||
## Модули KernelSU {#kernelsu-modules}
|
||
|
||
Модуль KernelSU - это папка, размещенная в каталоге `/data/adb/modules` и имеющая следующую структуру:
|
||
|
||
```txt
|
||
/data/adb/modules
|
||
├── .
|
||
├── .
|
||
|
|
||
├── $MODID <--- Папка имеет имя с идентификатором модуля
|
||
│ │
|
||
│ │ *** Идентификация модуля ***
|
||
│ │
|
||
│ ├── module.prop <--- В этом файле хранятся метаданные модуля
|
||
│ │
|
||
│ │ *** Основное содержимое ***
|
||
│ │
|
||
│ ├── system <--- Эта папка будет смонтирована, если skip_mount не существует
|
||
│ │ ├── ...
|
||
│ │ ├── ...
|
||
│ │ └── ...
|
||
│ │
|
||
│ │ *** Флаги состояния ***
|
||
│ │
|
||
│ ├── skip_mount <--- Если он существует, то KernelSU НЕ будет монтировать вашу системную папку
|
||
│ ├── disable <--- Если модуль существует, то он будет отключен
|
||
│ ├── remove <--- Если модуль существует, то при следующей перезагрузке он будет удален
|
||
│ │
|
||
│ │ *** Необязательные файлы ***
|
||
│ │
|
||
│ ├── post-fs-data.sh <--- Этот скрипт будет выполняться в post-fs-data
|
||
│ ├── service.sh <--- Этот скрипт будет выполняться в сервисе late_start
|
||
| ├── uninstall.sh <--- Этот скрипт будет выполнен, когда KernelSU удалит ваш модуль
|
||
│ ├── system.prop <--- Свойства из этого файла будут загружены в качестве системных свойств программой resetprop
|
||
│ ├── sepolicy.rule <--- Дополнительные пользовательские правила sepolicy
|
||
│ │
|
||
│ │ *** Автоматически генерируется, НЕЛЬЗЯ создавать или изменять вручную ***
|
||
│ │
|
||
│ ├── vendor <--- Символьная ссылка на $MODID/system/vendor
|
||
│ ├── product <--- Символьная ссылка на $MODID/system/product
|
||
│ ├── system_ext <--- Симлинк на $MODID/system/system_ext
|
||
│ │
|
||
│ │ *** Допускается использование любых дополнительных файлов/папок ***
|
||
│ │
|
||
│ ├── ...
|
||
│ └── ...
|
||
|
|
||
├── another_module
|
||
│ ├── .
|
||
│ └── .
|
||
├── .
|
||
├── .
|
||
```
|
||
|
||
::: tip различия с Magisk
|
||
KernelSU не имеет встроенной поддержки Zygisk, поэтому в модуле нет содержимого, связанного с Zygisk. Однако для поддержки модулей Zygisk можно использовать [ZygiskNext](https://github.com/Dr-TSNG/ZygiskNext). В этом случае содержимое модуля Zygisk идентично содержимому, поддерживаемому Magisk.
|
||
:::
|
||
|
||
### 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._-]+$`<br>
|
||
экс: ✓ `a_module`, ✓ `a.module`, ✓ `module-101`, ✗ `a module`, ✗ `1_module`, ✗ `-a-module`<br>
|
||
Это **уникальный идентификатор** вашего модуля. Не следует изменять его после публикации.
|
||
- `versionCode` должен быть **целым**. Это используется для сравнения версий
|
||
- Другими, не упомянутыми выше, могут быть любые **однострочные** строки.
|
||
- Обязательно используйте тип перевода строки `UNIX (LF)`, а не `Windows (CR+LF)` или `Macintosh (CR)`.
|
||
|
||
### Сценарии командной оболочки {#shell-scripts}
|
||
|
||
Чтобы понять разницу между `post-fs-data.sh` и `Service.sh`, прочитайте раздел [Boot Scripts](#boot-scripts). Для большинства разработчиков модулей `service.sh` должно быть достаточно, если вам нужно просто запустить загрузочный скрипт.
|
||
|
||
Во всех скриптах вашего модуля используйте `MODDIR=${0%/*}` для получения пути к базовому каталогу вашего модуля; **НЕ** кодируйте жестко путь к вашему модулю в скриптах.
|
||
|
||
::: tip различия с Magisk
|
||
С помощью переменной окружения KSU можно определить, выполняется ли сценарий в KernelSU или в Magisk. Если скрипт выполняется в KernelSU, то это значение будет равно true.
|
||
:::
|
||
|
||
### каталог `system` {#system-directories}
|
||
|
||
После загрузки системы содержимое этого каталога будет наложено поверх раздела /system с помощью overlayfs. Это означает, что:
|
||
|
||
1. Файлы с теми же именами, что и в соответствующем каталоге в системе, будут перезаписаны файлами в этом каталоге.
|
||
2. Папки с теми же именами, что и в соответствующем каталоге в системе, будут объединены с папками в этом каталоге.
|
||
|
||
Если вы хотите удалить файл или папку в исходном каталоге системы, необходимо создать файл с тем же именем, что и файл/папка, в каталоге модуля с помощью команды `mknod filename c 0 0`. Таким образом, система overlayfs автоматически "забелит" этот файл, как если бы он был удален (раздел /system при этом фактически не изменится).
|
||
|
||
Вы также можете объявить в `customize.sh` переменную с именем `REMOVE`, содержащую список каталогов для выполнения операций удаления, и KernelSU автоматически выполнит команду `mknod <TARGET> c 0 0` в соответствующих каталогах модуля. Например:
|
||
|
||
```sh
|
||
REMOVE="
|
||
/system/app/YouTube
|
||
/system/app/Bloatware
|
||
"
|
||
```
|
||
|
||
В приведенном выше списке будут выполнены команды `mknod $MODPATH/system/app/YouTuBe c 0 0` и `mknod $MODPATH/system/app/Bloatware c 0 0`; при этом `/system/app/YouTube` и `/system/app/Bloatware` будут удалены после вступления модуля в силу.
|
||
|
||
Если вы хотите заменить каталог в системе, то необходимо создать каталог с тем же путем в каталоге модуля, а затем установить для этого каталога атрибут `setfattr -n trusted.overlay.opaque -v y <TARGET>`. Таким образом, система overlayfs автоматически заменит соответствующий каталог в системе (без изменения раздела /system).
|
||
|
||
Вы можете объявить в файле `customize.sh` переменную с именем `REPLACE`, содержащую список заменяемых каталогов, и KernelSU автоматически выполнит соответствующие операции в каталоге вашего модуля. Например:
|
||
|
||
REPLACE="
|
||
/system/app/YouTube
|
||
/system/app/Bloatware
|
||
"
|
||
|
||
В этом списке будут автоматически созданы каталоги `$MODPATH/system/app/YouTube` и `$MODPATH/system/app/Bloatware`, а затем выполнены команды `setfattr -n trusted.overlay.opaque -v y $MODPATH/system/app/YouTube` и `setfattr -n trusted.overlay.opaque -v y $MODPATH/system/app/Bloatware`. После вступления модуля в силу каталоги `/system/app/YouTube` и `/system/app/Bloatware` будут заменены на пустые.
|
||
|
||
::: tip различия с Magisk
|
||
|
||
В KernelSU бессистемный механизм реализован через overlayfs ядра, а в Magisk в настоящее время используется магическое монтирование (bind mount). Эти два метода реализации имеют существенные различия, но конечная цель у них одна: модификация файлов /system без физического изменения раздела /system.
|
||
:::
|
||
|
||
Если вы заинтересованы в использовании overlayfs, рекомендуется прочитать [документацию по overlayfs](https://docs.kernel.org/filesystems/overlayfs.html) ядра Linux.
|
||
|
||
### system.prop
|
||
|
||
Этот файл имеет тот же формат, что и `build.prop`. Каждая строка состоит из `[key]=[value]`.
|
||
|
||
### sepolicy.rule
|
||
|
||
Если для вашего модуля требуются дополнительные патчи sepolicy, добавьте эти правила в данный файл. Каждая строка в этом файле будет рассматриваться как утверждение политики.
|
||
|
||
## Установщик модулей {#module-installer}
|
||
|
||
Инсталлятор модуля KernelSU - это модуль KernelSU, упакованный в zip-файл, который может быть прошит в APP-менеджере KernelSU. Простейший установщик модуля KernelSU - это просто модуль KernelSU, упакованный в zip-файл.
|
||
|
||
```txt
|
||
module.zip
|
||
│
|
||
├── customize.sh <--- (Необязательно, более подробно позже)
|
||
│ Этот скрипт будет использоваться в update-binary
|
||
├── ...
|
||
├── ... /* Остальные файлы модуля */
|
||
│
|
||
```
|
||
|
||
:::warning
|
||
Модуль KernelSU НЕ поддерживается для установки в пользовательское Recovery!!!
|
||
:::
|
||
|
||
### Персонализация {#customizing-installation}
|
||
|
||
Если вам необходимо настроить процесс установки модуля, то в качестве опции вы можете создать в программе установки скрипт с именем `customize.sh`. Этот скрипт будет _источником_ (не исполняться!) сценария установщика модуля после извлечения всех файлов и применения стандартных разрешений и secontext. Это очень удобно, если ваш модуль требует дополнительной настройки в зависимости от ABI устройства, или вам необходимо установить специальные разрешения/секонтекст для некоторых файлов модуля.
|
||
|
||
Если вы хотите полностью контролировать и настраивать процесс установки, объявите `SKIPUNZIP=1` в файле `customize.sh`, чтобы пропустить все шаги установки по умолчанию. При этом ваш `customize.sh` будет сам отвечать за установку.
|
||
|
||
Сценарий `customize.sh` запускается в оболочке BusyBox `ash` KernelSU с включенным "Автономным режимом". Доступны следующие переменные и функции:
|
||
|
||
#### Переменные
|
||
|
||
- `KSU` (bool): переменная, отмечающая, что скрипт выполняется в окружении KernelSU, причем значение этой переменной всегда будет true. Ее можно использовать для различения KernelSU и 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): установочный zip-архив вашего модуля
|
||
- `ARCH` (string): архитектура процессора устройства. Значение: `arm`, `arm64`, `x86` или `x64`.
|
||
- `IS64BIT` (bool): `true`, если `$ARCH` имеет значение `arm64` или `x64`.
|
||
- `API` (int): уровень API (версия Android) устройства (например, `23` для Android 6.0)
|
||
|
||
::: warning
|
||
В KernelSU MAGISK_VER_CODE всегда равен 25200, а MAGISK_VER всегда равен v25.2. Пожалуйста, не используйте эти две переменные для определения того, запущен ли он на KernelSU или нет.
|
||
:::
|
||
|
||
#### Функции {#functions}
|
||
|
||
```txt
|
||
ui_print <msg>
|
||
вывести <msg> на консоль
|
||
Избегайте использования 'echo', так как он не будет отображаться в консоли пользовательского recovery
|
||
|
||
abort <msg>
|
||
вывести сообщение об ошибке <msg> на консоль и завершить установку
|
||
Избегайте использования команды 'exit', так как в этом случае будут пропущены шаги очистки завершения установки
|
||
|
||
set_perm <target> <owner> <group> <permission> [context]
|
||
если [context] не задан, то по умолчанию используется "u:object_r:system_file:s0".
|
||
Эта функция является сокращением для следующих команд:
|
||
chown owner.group target
|
||
chmod permission target
|
||
chcon context target
|
||
|
||
set_perm_recursive <directory> <owner> <group> <dirpermission> <filepermission> [context]
|
||
если [context] не задан, то по умолчанию используется "u:object_r:system_file:s0".
|
||
для всех файлов в <directory> будет вызвана команда:
|
||
set_perm file owner group filepermission context
|
||
для всех каталогов в <directory> (включая себя самого), он вызовет:
|
||
set_perm dir owner group dirpermission context
|
||
```
|
||
|
||
## Загрузочные сценарии {#boot-scripts}
|
||
|
||
В KernelSU скрипты делятся на два типа в зависимости от режима их работы: режим post-fs-data и режим late_start service:
|
||
|
||
- режим post-fs-data
|
||
- Эта стадия является БЛОКИРУЮЩЕЙ. Процесс загрузки приостанавливается до завершения выполнения или по истечении 10 секунд.
|
||
- Сценарии запускаются до того, как будут смонтированы какие-либо модули. Это позволяет разработчику модулей динамически настраивать свои модули до того, как они будут смонтированы.
|
||
- Этот этап происходит до запуска Zygote, что практически означает, что все в Android
|
||
- **ПРЕДУПРЕЖДЕНИЕ:** использование `setprop` приведет к блокировке процесса загрузки! Вместо этого используйте `resetprop -n <prop_name> <prop_value>`.
|
||
- Запускайте скрипты в этом режиме только в случае необходимости.
|
||
- режим обслуживания late_start
|
||
- Эта стадия является НЕБЛОКИРУЮЩЕЙ. Ваш скрипт выполняется параллельно с остальным процессом загрузки.
|
||
- **Это рекомендуемый этап для запуска большинства скриптов.**
|
||
|
||
В KernelSU скрипты запуска делятся на два типа по месту их хранения: общие скрипты и скрипты модулей:
|
||
|
||
- Общие скрипты
|
||
- Размещаются в файлах `/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.
|
||
|
||
Все загрузочные скрипты будут выполняться в оболочке BusyBox `ash` от KernelSU с включенным "Автономным режимом".
|