Руководство по разработке модулей APM
APatch предоставляет модульный механизм (AndroidPatch Module) для модификации системного раздела с сохранением его целостности. Этот механизм часто называют бессистемным (systemless
).
Реализация модулей APatch скопирована и модифицирована из KernelSU.
Модифицированный код находится здесь:
KernelSU: https://github.com/tiann/KernelSU/tree/main/userspace/ksud APatch: https://github.com/bmax121/APatch/tree/main/apd
Приведенная ниже документация скопирована и изменена из документации KernelSU, и большая часть ее содержания совпадает. Основные моменты, на которые следует обратить внимание, следующие:
- Расположение файлов
- Переменные окружения
- Поддержка SELinux, APatch напрямую использует
magiskpolicy
Механизм работы модулей APatch почти такой же, как и Magisk. Если вы знакомы с разработкой модулей Magisk, то разработка модулей APatch очень похожа. Представление модулей ниже можно пропустить, достаточно прочитать в чем заключаются различия.
BusyBox
APatch предоставляет полнофункциональный бинарный файл BusyBox (включая полную поддержку SELinux). Исполняемый файл находится по адресу /data/adb/ap/bin/busybox
. BusyBox от APatch поддерживает переключаемый во время выполнения «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, вы должны вызвать исполняемый файл с полным путем.
Каждый сценарий оболочки, запущенный в контексте APatch, будет выполняться в оболочке BusyBox ash
с включенным автономным режимом. Для сторонних разработчиков это касается всех загрузочных скриптов и скриптов установки модулей.
Для тех, кто хочет использовать эту функцию «автономного режима» вне APatch, есть два способа включить ее:
- Установите переменной окружения
ASH_STANDALONE
значение1
.
Пример:ASH_STANDALONE=1 /data/adb/ap/bin/busybox sh <script>
. - Переключитесь с помощью параметров командной строки:
/data/adb/ap/bin/busybox sh -o standalone <script>
.
Чтобы гарантировать, что все последующие оболочки sh
будут выполняться в автономном режиме, первый способ является предпочтительным (это также метод, используемый APatch и менеджером APatch), поскольку переменные окружения наследуются в дочерних процессах.
Различия с KernelSU
Расположение busybox было изменено с /data/adb/ksu/bin/busybox
на /data/adb/ap/bin/busybox
.
Различия с Magisk
BusyBox от APatch теперь представляет собой бинарник, скомпилированный непосредственно с помощью проекта Magisk, спасибо Magisk! Поэтому вам не нужно беспокоиться о совместимости скриптов BusyBox со скриптами Magisk и APatch, потому что они абсолютно одинаковы!
Модули APM
Модуль APatch - это папка внутри /data/adb/modules
со следующей структурой:
/data/adb/modules
├── .
├── .
|
├── $MODID <--- Имя папки модуля совпадает с его идентификатором
│ │
│ │ *** Идентификация модуля ***
│ │
│ ├── module.prop <--- В этом файле хранятся метаданные модуля
│ │
│ │ *** Основное содержание ***
│ │
│ ├── system <--- Эта папка будет смонтирована, если skip_mount не задан
│ │ ├── ...
│ │ ├── ...
│ │ └── ...
│ │
│ │ *** Флаги состояния ***
│ │
│ ├── skip_mount <--- Если этот файл существует, то папка `/system` модуля не будет смонтирована
│ ├── disable <--- Если этот файл существует, то модуль отключен
│ ├── remove <--- Если этот файл существует, модуль будет удален при следующей перезагрузке
│ │
│ │ *** Дополнительные файлы ***
│ │
│ ├── post-fs-data.sh <--- Этот скрипт будет выполняться в режиме post-fs-data
│ ├── post-mount.sh <--- Этот скрипт будет запущен после монтирования файлов
│ ├── service.sh <--- Этот скрипт будет запущен в режиме late_start сервиса
│ ├── boot-completed.sh <--- Этот скрипт будет запущен после завершения загрузки Android
| ├── uninstall.sh <--- Этот скрипт будет запущен, когда модуль будет удален
│ ├── system.prop <--- Свойства, указанные в этом файле, будут изменены во время загрузки с помощью resetprop
│ ├── sepolicy.rule <--- Политика SELinux в этом файле будет загружаться во время загрузки
│ │
│ │ *** Автоматически генерируемые каталоги, не создавайте и не изменяйте их вручную! ***
│ │
│ ├── vendor <--- Симлинк на $MODID/system/vendor
│ ├── product <--- Симлинк на $MODID/system/product
│ ├── system_ext <--- Симлинк на $MODID/system/system_ext
│ │
│ │ *** Любые дополнительные файлы / папки разрешены ***
│ │
│ ├── ...
│ └── ...
|
├── another_module
│ ├── .
│ └── .
├── .
├── .
Различия с Magisk
APatch не имеет встроенной поддержки Zygisk, поэтому в модуле нет содержимого, связанного с Zygisk. Однако для поддержки модулей Zygisk можно использовать ZygiskNext или Zygisk_mod. В этом случае содержимое модуля Zygisk идентично содержимому, поддерживаемому Magisk.
module.prop
module.prop
- это конфигурационный файл модуля. Если модуль не содержит этого файла, он не будет распознан как модуль. Формат этого файла следующий:
id=<строка>
name=<строка>
version=<строка>
versionCode=<целое число>
author=<строка>
description=<строка>
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)
.
Сценарии командной оболочки
Различия между post-fs-data.sh
, post-mount.sh
, service.sh
и boot-completed.sh
описаны в разделе Загрузочные сценарии. Для большинства разработчиков модулей service.sh
должно быть достаточно, если вам нужно запустить только загрузочный скрипт.
Во всех скриптах для вашего модуля используйте MODDIR=${0%/*}
для получения пути к базовому каталогу вашего модуля. Не вводите путь к модулю в скриптах жестко!
Различия с Magisk, KernelSU
Вы можете определить, запущен ли скрипт в APatch, используя переменную окружения APATCH
, если он запущен в APatch, это значение будет установлено в true
.
Каталог system
После загрузки системы содержимое этого каталога будет наложено поверх раздела /system
с помощью OverlayFS. Это означает, что:
- Файлы с таким же именем в соответствующем каталоге в системе перезаписываются файлами в этом каталоге.
- Папки с таким же именем в соответствующем каталоге в системе объединяются с папками в этом каталоге.
Если вы хотите удалить файл или папку в исходном каталоге системы, необходимо создать файл с тем же именем, что и файл/папка, в каталоге модуля с помощью команды mknod filename c 0 0
. Таким образом, система OverlayFS автоматически "забелит" этот файл, как если бы он был удален (раздел /system при этом фактически не изменится).
Вы также можете выполнить операцию удаления, объявив переменную REMOVE
в customize.sh
со списком директорий, и APatch автоматически выполнит за вас mknod <TARGET> c 0 0
в соответствующей директории модуля. Например:
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
, содержащую список заменяемых каталогов, и APatch автоматически выполнит соответствующие операции в каталоге вашего модуля. Например:
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
будут заменены на пустые.
Различия с Magisk
Бессистемный механизм APatch реализован через OverlayFS ядра, в то время как Magisk в настоящее время использует магическое монтирование (bind mount). Между этими двумя реализациями существует огромная разница, но конечная цель фактически одна и та же: модифицировать файл /system
без изменения физического раздела /system
.
Если вы заинтересованы в использовании OverlayFS, рекомендуется прочитать документацию по OverlayFS ядра Linux.
system.prop
Формат этого файла точно такой же, как и у build.prop
: каждая строка имеет вид [key]=[value]
.
sepolicy.rule
Если ваш модуль требует дополнительных патчей политики SELinux, добавьте эти правила в этот файл. Каждая строка в этом файле будет считаться утверждением политики.
Установщик модулей
Пакет установки модуля APatch представляет собой zip-файл, который можно прошить через APatch Manager, и формат этого zip-файла следующий:
module.zip
│
├── customize.sh <--- (Необязательно, подробнее позже)
│ Этот скрипт будет использоваться в update-binary
├── ...
├── ... /* Остальные файлы модуля */
│
WARNING
Модуль APatch не поддерживается для установки в Recovery!
Индивидуальный процесс установки
Если вам необходимо настроить процесс установки модуля, то в качестве опции вы можете создать в программе установки скрипт с именем customize.sh
. Этот скрипт будет источником (не исполняться) сценария установщика модуля после извлечения всех файлов и применения стандартных разрешений и secontext. Это очень удобно, если ваш модуль требует дополнительной настройки в зависимости от ABI устройства, или вам необходимо установить специальные разрешения/секонтекст для некоторых файлов модуля.
Если вы хотите полностью контролировать и настраивать процесс установки, объявите SKIPUNZIP=1
в файле customize.sh
, чтобы пропустить все шаги установки по умолчанию. При этом ваш customize.sh
будет сам отвечать за установку.
Сценарий customize.sh
запускается в «автономном режиме» в оболочке BusyBox ash
от APatch. Вы можете использовать следующие переменные и функции:
Переменные
KERNELPATCH
(bool): Пометьте этот скрипт для запуска в среде APatch, и значение этой переменной всегда будетtrue
.KERNEL_VERSION
(hex): Наследуется от KernelPatch, номер версии ядра (например,50a01
означает5.10.1
).KERNELPATCH_VERSION
(hex): Наследуется от KernelPatch, номер версии KernelPatch (например,a05
означает0.10.5
).SUPERKEY
(string): Наследуется от KernelPatch, используется для вызова kpatch или supercall.APATCH
(bool): Пометьте этот скрипт для запуска в среде APatch, и значение этой переменной всегда будетtrue
.APATCH_VER_CODE
(int): Номер текущей версии APatch (например.10672
).APATCH_VER
(string): Имя текущей версии APatch (например.10672
).BOOTMODE
(bool): В APatch эта переменная всегда будет иметь значениеtrue
.MODPATH
(path): Каталог установки текущего модуля.TMPDIR
(path): Каталог, в котором могут храниться временные файлы.ZIPFILE
(path): Файл пакета установки для текущего модуля.ARCH
(string): Архитектура процессора устройства, толькоarm64
.IS64BIT
(bool): Является ли это устройство 64-битным.API
(int): Текущая версия Android API устройства (например,23
на Android 6.0).
WARNING
В APatch MAGISK_VER_CODE
имеет значение 27000
, а MAGISK_VER
- 27.0
.
Функции
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».
для всех файлов в <каталоге>, он вызовет:
set_perm file owner group filepermission context
для всех каталогов в <каталоге> (включая себя), он вызовет:
set_perm dir owner group dirpermission context
Загрузочные сценарии
В APatch существует два типа скриптов в зависимости от режима их работы: режим post-fs-data и режим late_start service.
Режим post-fs-data
- Эта фаза является блокирующей. Процесс запуска приостанавливается до завершения выполнения или через 10 секунд.
- Скрипт запускается до установки любого модуля. Это позволяет разработчикам модулей динамически адаптировать свои модули до того, как они будут смонтированы.
- Эта фаза наступает перед началом развития зиготы.
- Использование setprop может привести к зависанию во время запуска! Вместо этого используйте
resetprop -n <prop_name> <prop_value>
. - Запускайте скрипты в этом режиме только в случае необходимости.
Режим late_start сервиса
- Эта фаза является неблокирующей. Ваш скрипт будет выполняться параллельно с остальным процессом запуска.
- Большинство скриптов рекомендуется запускать в этом режиме.
В APatch есть еще два типа стартовых скриптов в зависимости от места их хранения: общие скрипты и скрипты модулей.
Общие скрипты
- Поместите его в
/data/adb/post-fs-data.d
,/data/adb/post-mount.d
,/data/adb/service.d
или/data/adb/boot-completed.d
. - Скрипты будут выполняться только в том случае, если они установлены как исполняемые (
chmod +x script.sh
). - Скрипты в
post-fs-data.d
выполняются в режиме post-fs-data, а скрипты вservice.d
- в режиме late_start сервиса. - Модули не должны добавлять общие скрипты во время установки.
- Поместите его в
Скрипты модуля
- Поместите его в собственную папку модуля.
- Выполняется только при включенном модуле.
post-fs-data.sh
запускается в режиме post-fs-data,post-mount.sh
- в режиме post-mount, аservice.sh
- в режиме late_start сервиса, аboot-completed
- в режиме сервиса после завершения загрузки Android.
Все сценарии запуска будут выполняться в оболочке BusyBox ash
от APatch с включенным «автономным режимом».