Руководство по разработке модулей 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 с включенным «автономным режимом».