Формат файла АПЕКС

Формат контейнеров Android Pony EXpress (APEX) был представлен в Android 10 и используется в процессе установки низкоуровневых системных модулей. Этот формат упрощает обновление системных компонентов, которые не вписываются в стандартную модель приложений Android. Примерами таких компонентов являются нативные сервисы и библиотеки, уровни аппаратной абстракции ( HAL ), среда выполнения ( ART ) и библиотеки классов.

Термин "APEX" также может обозначать файл APEX.

Фон

Хотя Android поддерживает обновление модулей, соответствующих стандартной модели приложений (например, служб, действий), с помощью приложений-установщиков пакетов (таких как приложение Google Play Store), использование аналогичной модели для низкоуровневых компонентов ОС имеет следующие недостатки:

  • Модули на основе APK-файлов нельзя использовать на ранних этапах загрузки. Менеджер пакетов является центральным хранилищем информации о приложениях и может быть запущен только из менеджера действий, который становится доступным на более позднем этапе процедуры загрузки.
  • Формат APK (в частности, манифест) разработан для приложений Android, и системные модули не всегда подходят для этой цели.

Дизайн

В этом разделе описывается высокоуровневая архитектура формата файлов APEX и менеджера APEX, который представляет собой службу для управления файлами APEX.

Для получения более подробной информации о причинах выбора именно этого варианта дизайна для APEX, см. раздел «Альтернативные варианты, рассмотренные при разработке APEX» .

формат APEX

Это формат файла APEX.

формат файла APEX

Рисунок 1. Формат файла APEX.

На самом верхнем уровне файл APEX представляет собой ZIP-архив, в котором файлы хранятся в несжатом виде и расположены по границам 4 КБ.

В состав файла APEX входят четыре файла:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

Файл apex_manifest.json содержит имя и версию пакета, которые идентифицируют файл APEX. Это протокол ApexManifest в формате JSON.

Файл AndroidManifest.xml позволяет файлу APEX использовать инструменты и инфраструктуру, связанные с APK, такие как ADB, PackageManager и приложения для установки пакетов (например, Play Store). Например, файл APEX может использовать существующий инструмент, такой как aapt для анализа основных метаданных файла. Файл содержит информацию об имени и версии пакета. Эта информация, как правило, также доступна в apex_manifest.json .

Для нового кода и систем, работающих с APEX, рекомендуется использовать apex_manifest.json вместо AndroidManifest.xml . AndroidManifest.xml может содержать дополнительную информацию о таргетинге, которая может использоваться существующими инструментами публикации приложений.

apex_payload.img — это образ файловой системы ext4, поддерживаемый dm-verity. Образ монтируется во время выполнения через устройство обратной связи. В частности, хеш-дерево и блок метаданных создаются с помощью библиотеки libavb . Полезная нагрузка файловой системы не анализируется (поскольку образ должен быть монтируемым на месте). В файл apex_payload.img включены обычные файлы.

apex_pubkey — это открытый ключ, используемый для подписи образа файловой системы. Во время выполнения этот ключ гарантирует, что загруженный APEX будет подписан тем же самым объектом, который подписывает тот же APEX во встроенных разделах.

Рекомендации по именованию APEX

Чтобы предотвратить конфликты имен между новыми APEX-модулями по мере развития платформы, используйте следующие рекомендации по именованию:

  • com.android.*
    • Предназначено только для AOSP APEX. Не является уникальным для какой-либо компании или устройства.
  • com.<companyname>.*
    • Зарезервировано для компании. Потенциально может использоваться несколькими устройствами этой компании.
  • com.<companyname>.<devicename>.*
    • Зарезервировано для APEX, уникальных для конкретного устройства (или подмножества устройств).

Менеджер APEX

Менеджер APEX (или apexd ) — это автономный нативный процесс, отвечающий за проверку, установку и удаление файлов APEX. Этот процесс запускается и готов к работе на ранней стадии загрузки системы. Файлы APEX обычно предварительно установлены на устройстве в каталоге /system/apex . Менеджер APEX по умолчанию использует эти пакеты, если обновления недоступны.

Последовательность обновления APEX использует класс PackageManager и выглядит следующим образом.

  1. Файл APEX загружается через приложение для установки пакетов, ADB или другой источник.
  2. Менеджер пакетов запускает процедуру установки. После распознавания файла как APEX-файла менеджер пакетов передает управление менеджеру APEX-файлов.
  3. Менеджер APEX проверяет файл APEX.
  4. Если файл APEX проверен, внутренняя база данных менеджера APEX обновляется, чтобы отразить тот факт, что файл APEX будет активирован при следующей загрузке.
  5. После успешной проверки пакета отправитель запроса на установку получает широковещательное сообщение.
  6. Для продолжения установки необходимо перезагрузить систему.
  7. При следующей загрузке запускается менеджер APEX, считывает внутреннюю базу данных и выполняет следующие действия для каждого указанного файла APEX:

    1. Проверяет файл APEX.
    2. Создает устройство обратной связи из файла APEX.
    3. Создает блок сопоставления устройств поверх устройства обратной связи.
    4. Монтирует блочное устройство сопоставления устройств по уникальному пути (например, /apex/ name @ ver ).

Когда все файлы APEX, перечисленные во внутренней базе данных, смонтированы, менеджер APEX предоставляет службу привязки для других системных компонентов, позволяющую запрашивать информацию об установленных файлах APEX. Например, другие системные компоненты могут запросить список файлов APEX, установленных на устройстве, или запросить точный путь, по которому смонтирован конкретный файл APEX, чтобы получить к нему доступ.

Файлы APEX — это файлы APK.

Файлы APEX являются действительными APK-файлами, поскольку они представляют собой подписанные ZIP-архивы (с использованием схемы подписи APK), содержащие файл AndroidManifest.xml . Это позволяет файлам APEX использовать инфраструктуру для APK-файлов, такую ​​как приложение для установки пакетов, утилита подписи и менеджер пакетов.

Файл AndroidManifest.xml внутри APEX-файла является минимальным и содержит name пакета, versionCode , а также необязательные targetSdkVersion , minSdkVersion и maxSdkVersion для более точной настройки целевых платформ. Эта информация позволяет распространять APEX-файлы через существующие каналы, такие как приложения-установщики пакетов и ADB.

Поддерживаемые типы файлов

Формат APEX поддерживает следующие типы файлов:

  • Нативные разделяемые библиотеки
  • Исполняемые файлы нативного уровня
  • JAR-файлы
  • Файлы данных
  • Файлы конфигурации

Это не означает, что APEX может обновлять все эти типы файлов. Возможность обновления того или иного типа файла зависит от платформы и от стабильности определений интерфейсов для этих типов файлов.

Варианты подписания

Файлы APEX подписываются двумя способами. Сначала файл apex_payload.img (в частности, дескриптор vbmeta, добавляемый к apex_payload.img ) подписывается ключом. Затем весь файл APEX подписывается с использованием схемы подписи APK v3 . В этом процессе используются два разных ключа.

На стороне устройства устанавливается открытый ключ, соответствующий закрытому ключу, используемому для подписи дескриптора vbmeta. Менеджер APEX использует открытый ключ для проверки APEX-файлов, запрашиваемых для установки. Каждый APEX-файл должен быть подписан разными ключами, и это требование применяется как во время сборки, так и во время выполнения.

APEX во встроенных разделах

Файлы APEX могут располагаться во встроенных разделах, таких как /system . Этот раздел уже находится под управлением dm-verity, поэтому файлы APEX монтируются непосредственно через устройство обратной связи.

Если APEX присутствует во встроенном разделе, его можно обновить, предоставив пакет APEX с тем же именем и кодом версии, равным или превышающим указанный. Новый APEX сохраняется в /data и, подобно APK-файлам, новая установленная версия дублирует версию, уже присутствующую во встроенном разделе. Но в отличие от APK-файлов, новая установленная версия APEX активируется только после перезагрузки.

Требования ядра

Для поддержки основных модулей APEX на устройстве Android необходимы следующие компоненты ядра Linux: драйвер loopback и dm-verity. Драйвер loopback монтирует образ файловой системы в модуль APEX, а dm-verity проверяет модуль APEX.

Производительность драйвера обратной связи и dm-verity важна для достижения хорошей производительности системы при использовании модулей APEX.

Поддерживаемые версии ядра

Модули основной ветки APEX поддерживаются на устройствах с ядром версии 4.4 и выше. Новые устройства, выпущенные с Android 10 или выше, должны использовать ядро ​​версии 4.9 или выше для поддержки модулей APEX.

Необходимые патчи ядра

Необходимые патчи ядра для поддержки модулей APEX включены в общее дерево исходного кода Android. Чтобы получить патчи для поддержки APEX, используйте последнюю версию общего дерева исходного кода Android.

Версия ядра 4.4

Эта версия поддерживается только для устройств, обновлённых с Android 9 до Android 10 и желающих использовать модули APEX. Для получения необходимых патчей настоятельно рекомендуется выполнить слияние изменений из ветки android-4.4 . Ниже приведён список необходимых отдельных патчей для версии ядра 4.4.

  • UPSTREAM: loop: добавить ioctl для изменения размера логического блока ( 4.4 )
  • BACKPORT: block/loop: set hw_sectors ( 4.4 )
  • UPSTREAM: loop: Добавить LOOP_SET_BLOCK_SIZE в compat ioctl ( 4.4 )
  • ANDROID: mnt: Исправлена ​​ошибка next_descendent ( 4.4 )
  • ANDROID: mnt: remount должен распространяться на подчиненных подчиненных ( 4.4 )
  • ANDROID: mnt: Правильно распространить и перемонтировать ( 4.4 )
  • Отменить "ANDROID: dm verity: add minimum prefetch size" ( 4.4 )
  • UPSTREAM: loop: drop caches if offset or block_size are changed ( 4.4 )

Версии ядра 4.9/4.14/4.19

Чтобы получить необходимые патчи для версий ядра 4.9/4.14/4.19, выполните слияние изменений из ветки android-common .

Необходимые параметры конфигурации ядра

Ниже приведен список базовых требований к конфигурации для поддержки модулей APEX, представленных в Android 10. Пункты, отмеченные звездочкой (*), соответствуют требованиям Android 9 и более ранних версий.

(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support

Требования к параметрам командной строки ядра

Для поддержки APEX убедитесь, что параметры командной строки ядра соответствуют следующим требованиям:

  • loop.max_loop НЕ должен быть установлен.
  • loop.max_part должно быть <= 8

Создайте APEX

В этом разделе описывается, как собрать APEX с помощью системы сборки Android. Ниже приведен пример файла Android.bp для APEX с именем apex.test .

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so and libcutils.so are included in the apex
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

Пример файла apex_manifest.json :

{
  "name": "com.android.example.apex",
  "version": 1
}

Пример file_contexts :

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

Типы и расположение файлов в APEX

Тип файла Расположение в APEX
Общие библиотеки /lib и /lib64 ( /lib/arm для транслированного arm в x86)
Исполняемые файлы /bin
библиотеки Java /javalib
Готовые сборки /etc

Транзитивные зависимости

Файлы APEX автоматически включают транзитивные зависимости собственных разделяемых библиотек или исполняемых файлов. Например, если libFoo зависит от libBar , то обе библиотеки будут включены, если в свойстве native_shared_libs указана только libFoo .

Обработка нескольких ABI

Установите свойство native_shared_libs для основного и дополнительного интерфейсов двоичных файлов приложений (ABI) устройства. Если APEX ориентирован на устройства с одним ABI (то есть только 32-битным или только 64-битным), устанавливаются только библиотеки с соответствующим ABI.

Установите свойство binaries только для основного ABI устройства, как описано ниже:

  • Если устройство поддерживает только 32-битную архитектуру, устанавливается только 32-битный вариант исполняемого файла.
  • Если устройство 64-битное, то устанавливается только 64-битная версия исполняемого файла.

Для более точного управления ABI собственных библиотек и бинарных файлов используйте свойства multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] .

  • first : Соответствует основному ABI устройства. Это значение по умолчанию для бинарных файлов.
  • lib32 : Соответствует 32-битному ABI устройства, если он поддерживается.
  • lib64 : Соответствует 64-битному ABI устройства, которое оно поддерживает.
  • prefer32 : Соответствует 32-битному ABI устройства, если он поддерживается. Если 32-битный ABI не поддерживается, соответствует 64-битному ABI.
  • both : Соответствует обоим ABI. Это значение по умолчанию для native_shared_libraries .

Свойства java , libraries и prebuilts не зависят от ABI.

Этот пример предназначен для устройства, поддерживающего 32/64-битные системы и не отдающего предпочтение 32-битным системам:

apex {
    // other properties are omitted
    native_shared_libs: ["libFoo"], // installed for 32 and 64
    binaries: ["exec1"], // installed for 64, but not for 32
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // installed for 64, but not for 32
            binaries: ["exec2"], // same as binaries without multilib.first
        },
        both: {
            native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
            binaries: ["exec3"], // installed for 32 and 64
        },
        prefer32: {
            native_shared_libs: ["libX"], // installed for 32, but not for 64
        },
        lib64: {
            native_shared_libs: ["libY"], // installed for 64, but not for 32
        },
    },
}

Подписание vbmeta

Подписывайте каждый APEX разными ключами. Когда требуется новый ключ, создайте пару открытого и закрытого ключей и модуль apex_key . Используйте свойство key для подписи APEX с помощью этого ключа. Открытый ключ автоматически включается в APEX под именем avb_pubkey .

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

В приведенном выше примере имя открытого ключа ( foo ) становится идентификатором ключа. Идентификатор ключа, используемого для подписи APEX, записывается в APEX. Во время выполнения apexd проверяет APEX, используя открытый ключ с тем же идентификатором на устройстве.

APEX подписывает контракт

Подписывайте файлы APEX так же, как и файлы APK. Подписывайте файлы APEX дважды: один раз для мини-файловой системы (файл apex_payload.img ) и один раз для всего файла целиком.

Для подписи APEX-файла на уровне файла установите свойство certificate одним из трех способов:

  • Не задано: Если значение не задано, APEX подписывается сертификатом, расположенным по адресу PRODUCT_DEFAULT_DEV_CERTIFICATE . Если флаг не задан, путь по умолчанию равен build/target/product/security/testkey .
  • <name> : APEX подписан сертификатом <name> , расположенным в том же каталоге, что и PRODUCT_DEFAULT_DEV_CERTIFICATE .
  • :<name> : APEX подписывается сертификатом, определенным модулем Soong с именем <name> . Модуль сертификата может быть определен следующим образом.
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

Управление ключами

Тестовые ключи используются для отладочных сборок, а ключи для релизных сборок — для подписи общедоступных сборок. Как описано в разделе «Замена ключа подписи APEX» , все тестовые ключи должны быть заменены соответствующими ключами для релизных сборок перед публичным релизом. Серверы сборки OEM могут интегрировать инструмент sign_target_files_apks , который переподписывает как образ файловой системы, так и весь файл APEX для всех файлов APEX, найденных в ZIP-архиве target-files.

В целях безопасности крайне важно придерживаться следующих передовых методов управления ключами и подписания разрешений:

  • Храните ключи активации в защищенной среде, чтобы ограничить доступ к ним.

  • Список контроля доступа (ACL) должен контролировать начало операций по подписанию соглашений об освобождении от ответственности.

  • Подписывать артефакты ключом выпуска следует только после того, как они будут протестированы и сертифицированы для выпуска.

  • Инициировать подписание соглашения должен человек; не следует автоматизировать этот процесс.

  • Артефакты, подписанные ключом выпуска, должны храниться в защищенной среде.

  • Доступ к артефактам, подписанным ключом выпуска, должен быть ограничен только обоснованными деловыми причинами.

  • Сервер сборки OEM-производителя должен хранить запись каждого запроса на подписание в базе данных для подписания.

Установите APEX

Для установки APEX используйте ADB.

adb install apex_file_name
adb reboot

Если в файле apex_manifest.json supportsRebootlessUpdate установлен в true , и текущий установленный APEX не используется (например, все содержащиеся в нем службы остановлены), то новый APEX можно установить без перезагрузки с помощью флага --force-non-staged .

adb install --force-non-staged apex_file_name

Используйте APEX

После перезагрузки APEX монтируется в каталог /apex/<apex_name>@<version> . Одновременно можно монтировать несколько версий одного и того же APEX. Среди путей монтирования, путь /apex/<apex_name> будет привязан к последней версии.

Клиенты могут использовать путь, подключенный через монтирование, для чтения или выполнения файлов из APEX.

Как правило, APEX-ы используются следующим образом:

  1. OEM-производитель или ODM-партнер предварительно загружает APEX в каталог /system/apex при отгрузке устройства.
  2. Доступ к файлам в APEX осуществляется по пути /apex/<apex_name>/ .
  3. Когда обновлённая версия APEX устанавливается в /data/apex , после перезагрузки путь указывает на новую версию APEX.

Обновите сервис с помощью APEX.

Для обновления сервиса с помощью APEX:

  1. Пометьте службу в системном разделе как обновляемую. Добавьте параметр updatable в определение службы.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. Создайте новый файл .rc для обновленной службы. Используйте опцию override , чтобы переопределить существующую службу.

    /apex/my.apex/etc/init.rc:
    
    service myservice /apex/my.apex/bin/myservice
        class core
        user system
        ...
        override
    

Определения сервисов можно задать только в файле .rc объекта APEX. Триггеры действий в объектах APEX не поддерживаются.

Если служба, помеченная как обновляемая, запускается до активации APEX-модулей, запуск откладывается до завершения активации APEX-модулей.

Настройте систему для поддержки обновлений APEX.

Установите для поддержки обновления файлов APEX значение true для следующего системного свойства.

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

или просто

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

Сплющенная вершина

Для устаревших устройств обновление старого ядра для полной поддержки APEX иногда невозможно или нецелесообразно. Например, ядро ​​могло быть собрано без CONFIG_BLK_DEV_LOOP=Y , который имеет решающее значение для монтирования образа файловой системы внутри APEX.

Flattened APEX — это специально созданный APEX, который можно активировать на устройствах с устаревшим ядром. Файлы в Flattened APEX устанавливаются непосредственно в каталог внутри встроенного раздела. Например, lib/libFoo.so в Flattened APEX my.apex устанавливается в /system/apex/my.apex/lib/libFoo.so .

Активация сглаженного APEX не задействует устройство loop. Весь каталог /system/apex/my.apex напрямую монтируется в /apex/name@ver .

Обновление APEX-файлов, содержащих сглаженные конфигурации, путем загрузки обновленных версий APEX-файлов из сети невозможно, поскольку загруженные APEX-файлы не могут быть сглажены. Обновление APEX-файлов, содержащих сглаженные конфигурации, возможно только через обычное OTA-обновление.

По умолчанию используется конфигурация Flattened APEX. Это означает, что все APEX-файлы по умолчанию имеют плоскую структуру, если вы явно не настроите устройство на создание несглаженных APEX-файлов для поддержки обновлений APEX (как описано выше).

Смешивание сглаженных и несглаженных APEX-файлов в одном устройстве НЕ поддерживается. Все APEX-файлы в устройстве должны быть либо несглаженными, либо полностью сглаженными. Это особенно важно при поставке предварительно подписанных APEX-файлов, собранных для таких проектов, как Mainline. APEX-файлы, которые не подписаны (то есть, собраны из исходного кода), также должны быть несглаженными и подписаны соответствующими ключами. Устройство должно наследовать от updatable_apex.mk , как описано в разделе «Обновление сервиса с помощью APEX» .

Сжатые APEX

В Android 12 и более поздних версиях используется сжатие APEX для уменьшения объема памяти, занимаемого обновляемыми пакетами APEX. После установки обновления APEX, даже если предустановленная версия больше не используется, она все равно занимает тот же объем места. Занятое пространство остается недоступным.

Сжатие APEX минимизирует это влияние на объем памяти, используя сильно сжатый набор файлов APEX на разделах только для чтения (например, в разделе /system ). В Android 12 и более поздних версиях используется алгоритм сжатия Deflate zip.

Сжатие не обеспечивает оптимизацию для следующих случаев:

  • APEX-файлы, которые необходимо монтировать на самом раннем этапе загрузки системы.

  • APEX-файлы, которые нельзя обновлять. Сжатие полезно только в том случае, если на разделе /data установлена ​​обновленная версия APEX-файла. Полный список обновляемых APEX-файлов доступен на странице «Модульные системные компоненты» .

  • Динамически разделяемые библиотеки APEX. Поскольку apexd всегда активирует обе версии таких APEX (предустановленную и обновленную), их сжатие не приносит пользы.

Сжатый формат файла APEX

Это формат сжатого файла APEX.

Diagram shows the format of a compressed APEX file

Рисунок 2. Сжатый формат файла APEX.

На самом верхнем уровне сжатый файл APEX представляет собой ZIP-архив, содержащий исходный файл APEX в сжатом виде с уровнем сжатия 9, а также другие файлы, хранящиеся в несжатом виде.

Файл APEX состоит из четырех файлов:

  • original_apex : сжат с уровнем сжатия 9. Это исходный несжатый файл APEX .
  • apex_manifest.pb : сохранен только
  • AndroidManifest.xml : хранится только
  • apex_pubkey : хранится только

Файлы apex_manifest.pb , AndroidManifest.xml и apex_pubkey являются копиями соответствующих файлов в original_apex .

Создать сжатый APEX

Сжатый APEX можно создать с помощью инструмента apex_compression_tool.py , расположенного в system/apex/tools .

В системе сборки доступны несколько параметров, связанных со сжатием APEX.

В Android.bp возможность сжатия файла APEX контролируется свойством compressible :

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    compressible: true,
}

Флаг PRODUCT_COMPRESSED_APEX определяет, должен ли образ системы, созданный из исходного кода, содержать сжатые файлы APEX.

Для локальных экспериментов вы можете принудительно сжать APEX-файлы при сборке, установив параметр OVERRIDE_PRODUCT_COMPRESSED_APEX= в true .

Сжатые файлы APEX, созданные системой сборки, имеют расширение .capex . Это расширение упрощает различение сжатых и несжатых версий файла APEX.

Поддерживаемые алгоритмы сжатия

Android 12 поддерживает только сжатие ZIP-архивов с помощью Deflate.

Активировать сжатый файл APEX во время загрузки

Перед активацией сжатого файла APEX original_apex файл APEX, находящийся внутри него, распаковывается в каталог /data/apex/decompressed . Полученный распакованный файл APEX создаётся жёсткой ссылкой на каталог /data/apex/active .

Рассмотрим следующий пример в качестве иллюстрации описанного выше процесса.

Рассматривайте /system/apex/com.android.foo.capex как сжатый APEX, который активируется, с versionCode 37.

  1. Исходный файл original_apex , находящийся в /system/apex/com.android.foo.capex , распаковывается в /data/apex/decompressed/com.android.foo@37.apex .
  2. Для проверки корректности метки SELinux выполняется restorecon /data/apex/decompressed/com.android.foo@37.apex .
  3. Для проверки корректности данных в /data/apex/decompressed/com.android.foo@37.apex выполняются следующие действия: apexd проверяет открытый ключ, находящийся в /data/apex/decompressed/com.android.foo@37.apex , чтобы убедиться, что он совпадает с ключом, находящимся в /system/apex/com.android.foo.capex .
  4. Файл /data/apex/decompressed/com.android.foo@37.apex имеет жёсткую ссылку на каталог /data/apex/active/com.android.foo@37.apex .
  5. Стандартная логика активации для несжатых файлов APEX выполняется по адресу /data/apex/active/com.android.foo@37.apex .

Взаимодействие с OTA

Сжатые файлы APEX имеют значение для доставки и применения OTA-обновлений. Поскольку OTA-обновление может содержать сжатый файл APEX с более высоким уровнем версии, чем активный на устройстве, перед перезагрузкой устройства для применения OTA-обновления необходимо зарезервировать определенное количество свободного места.

Для поддержки системы OTA apexd предоставляет следующие два API для связывания файлов:

  • calculateSizeForCompressedApex — вычисляет размер, необходимый для декомпрессии файлов APEX в пакете OTA. Это можно использовать для проверки наличия достаточного места на устройстве перед загрузкой OTA-обновления.
  • reserveSpaceForCompressedApex — резервирует место на диске для будущего использования apexd при распаковке сжатых файлов APEX внутри пакета OTA.

В случае A/B-обновления по воздуху (OTA) apexd пытается выполнить декомпрессию в фоновом режиме в рамках процедуры пост-установочного обновления OTA. Если декомпрессия не удается, apexd выполняет ее во время загрузки, при которой применяется обновление OTA.

Альтернативные варианты, рассмотренные при разработке APEX.

Ниже представлены некоторые варианты, которые AOSP рассматривала при разработке формата файлов APEX, а также причины их включения или исключения.

Стандартные системы управления посылками

В дистрибутивах Linux используются системы управления пакетами, такие как dpkg и rpm , которые являются мощными, зрелыми и надежными. Однако они не были приняты для APEX, поскольку не могут защитить пакеты после установки. Проверка выполняется только во время установки пакетов. Злоумышленники могут незаметно нарушить целостность установленных пакетов. Это регрессия для Android, где все системные компоненты хранились в файловых системах только для чтения, целостность которых защищалась dm-verity для каждой операции ввода-вывода. Любое вмешательство в системные компоненты должно быть либо запрещено, либо обнаруживаемо, чтобы устройство могло отказаться от загрузки в случае взлома.

dm-crypt для обеспечения целостности

Файлы в контейнере APEX находятся во встроенных разделах (например, в разделе /system ), которые защищены dm-verity, что запрещает любые изменения файлов даже после монтирования разделов. Для обеспечения того же уровня безопасности все файлы в APEX хранятся в образе файловой системы, который связан с хеш-деревом и дескриптором vbmeta. Без dm-verity контейнер APEX в разделе /data уязвим для непреднамеренных изменений, внесенных после его проверки и установки.

Фактически, раздел /data также защищен слоями шифрования, такими как dm-crypt. Хотя это обеспечивает определенный уровень защиты от несанкционированного доступа, его основная цель — конфиденциальность, а не целостность. Когда злоумышленник получает доступ к разделу /data , дальнейшая защита становится невозможной, и это снова является регрессом по сравнению с ситуацией, когда все компоненты системы находятся в разделе /system . Хэш-дерево внутри файла APEX вместе с dm-verity обеспечивает тот же уровень защиты содержимого.

Перенаправление путей из /system в /apex

Файлы системных компонентов, упакованные в APEX, теперь доступны по новым путям, например, /apex/<name>/lib/libfoo.so . Когда эти файлы находились в разделе /system , они были доступны по путям, таким как /system/lib/libfoo.so . Клиент APEX-файла (другие APEX-файлы или платформа) должен использовать новые пути. В результате изменения путей может потребоваться обновление существующего кода.

Хотя один из способов избежать изменения пути — это наложить содержимое файла APEX на раздел /system , команда разработчиков Android решила не накладывать файлы на раздел /system поскольку это могло бы повлиять на производительность по мере увеличения количества накладываемых файлов (возможно, даже расположенных один за другим).

Другой вариант заключался в том, чтобы перехватить функции доступа к файлам, такие как open , stat и readlink , так чтобы пути, начинающиеся с /system перенаправлялись на соответствующие пути в /apex . Команда Android отказалась от этого варианта, поскольку изменить все функции, принимающие пути, нецелесообразно. Например, некоторые приложения статически связывают Bionic, который реализует эти функции. В таких случаях перенаправление для этих приложений не происходит.