Skip to content

Руководство по разработке модулей 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, и большая часть ее содержания совпадает. Основные моменты, на которые следует обратить внимание, следующие:

  1. Расположение файлов
  2. Переменные окружения
  3. Поддержка 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, есть два способа включить ее:

  1. Установите переменной окружения ASH_STANDALONE значение 1.
    Пример: ASH_STANDALONE=1 /data/adb/ap/bin/busybox sh <script>.
  2. Переключитесь с помощью параметров командной строки:/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 со следующей структурой:

txt
/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 - это конфигурационный файл модуля. Если модуль не содержит этого файла, он не будет распознан как модуль. Формат этого файла следующий:

txt
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. Это означает, что:

  1. Файлы с таким же именем в соответствующем каталоге в системе перезаписываются файлами в этом каталоге.
  2. Папки с таким же именем в соответствующем каталоге в системе объединяются с папками в этом каталоге.

Если вы хотите удалить файл или папку в исходном каталоге системы, необходимо создать файл с тем же именем, что и файл/папка, в каталоге модуля с помощью команды mknod filename c 0 0. Таким образом, система OverlayFS автоматически "забелит" этот файл, как если бы он был удален (раздел /system при этом фактически не изменится).

Вы также можете выполнить операцию удаления, объявив переменную REMOVE в customize.sh со списком директорий, и APatch автоматически выполнит за вас 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, содержащую список заменяемых каталогов, и APatch автоматически выполнит соответствующие операции в каталоге вашего модуля. Например:

sh
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-файла следующий:

txt
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.

Функции

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».
    для всех файлов в <каталоге>, он вызовет:
       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 с включенным «автономным режимом».