АПЕКС поставщика

Формат файлов APEX можно использовать для упаковки и установки низкоуровневых модулей ОС Android. Он позволяет независимо собирать и устанавливать компоненты, такие как собственные службы и библиотеки, реализации HAL, прошивки, файлы конфигурации и т. д.

APEX-ы поставщиков автоматически устанавливаются системой сборки в раздел /vendor и активируются во время выполнения apexd , как и APEX-ы в других разделах.

Варианты использования

Модуляризация изображений поставщиков

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

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

Например, производитель оригинального оборудования может выбрать для своего устройства реализацию Wi-Fi AOSP APEX, реализацию Bluetooth SoC APEX и пользовательскую реализацию телефонии OEM APEX.

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

Итерация разработчика

APEX-файлы вендора помогают разработчикам быстрее итерировать процесс разработки модулей вендора, объединяя полную реализацию функций, например, HAL Wi-Fi, в APEX-файл вендора. Разработчики могут затем собрать и индивидуально загрузить APEX-файл вендора для тестирования изменений, вместо того чтобы пересобирать весь образ вендора.

Это упрощает и ускоряет итерационный цикл разработчика для тех, кто в основном работает в одной функциональной области и хочет работать только над ней.

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

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

Пример рабочего процесса:

# Build the entire device and flash. OR, obtain an already-flashed device.
source build/envsetup.sh && lunch oem_device-userdebug
m
fastboot flashall -w

# Test the device.
... testing ...

# Check previous behavior using a vendor APEX from one week ago, downloaded from
# your continuous integration build.
... download command ...
adb install <path to downloaded APEX>
adb reboot
... testing ...

# Edit and rebuild just the APEX to change and test behavior.
... edit APEX source contents ...
m <apex module name>
adb install out/<path to built APEX>
adb reboot
... testing ...

Примеры

Основы

Общие сведения об APEX, включая требования к устройствам, сведения о формате файла и этапы установки, см. на главной странице формата файла APEX.

В Android.bp установка свойства vendor: true делает модуль APEX поставщиком APEX.

apex {
  ..
  vendor: true,
  ..
}

Бинарные файлы и общие библиотеки

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

Стабильные нативные интерфейсы для зависимостей APEX от поставщика включают cc_library с stubs и библиотеки LLNDK. Эти зависимости исключены из упаковки и записаны в манифест APEX. Манифест обрабатывается linkerconfig , чтобы внешние нативные зависимости были доступны во время выполнения.

В следующем фрагменте APEX содержит как двоичный файл ( my_service ), так и его нестабильные зависимости (файлы *.so ).

apex {
  ..
  vendor: true,
  binaries: ["my_service"],
  ..
}

В следующем фрагменте APEX содержит общую библиотеку my_standalone_lib и все ее нестабильные зависимости (как описано выше).

apex {
  ..
  vendor: true,
  native_shared_libs: ["my_standalone_lib"],
  ..
}

Сделать APEX меньше

APEX может разрастись, поскольку он включает в себя нестабильные зависимости. Мы рекомендуем использовать статическую линковку. Распространённые библиотеки, такие как libc++.so и libbase.so , можно статически линковать с исполняемыми файлами HAL. Другой вариант — создать зависимость для обеспечения стабильного интерфейса. Эта зависимость не будет включена в APEX.

Реализации HAL

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

Чтобы полностью инкапсулировать реализацию HAL, APEX также должен указать все соответствующие фрагменты VINTF и сценарии инициализации.

Фрагменты ВИНТФ

Фрагменты VINTF могут обслуживаться поставщиком APEX, если фрагменты расположены в etc/vintf APEX.

Используйте свойство prebuilts для встраивания фрагментов VINTF в APEX.

apex {
  ..
  vendor: true,
  prebuilts: ["fragment.xml"],
  ..
}

prebuilt_etc {
  name: "fragment.xml",
  src: "fragment.xml",
  sub_dir: "vintf",
}

API запросов

При добавлении фрагментов VINTF в APEX используйте API libbinder_ndk для получения сопоставлений интерфейсов HAL и имен APEX.

  • AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default") : true , если экземпляр HAL определен в APEX.
  • AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...) : получает имя APEX, которое определяет экземпляр HAL.
  • AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...) : используйте это для открытия сквозного HAL.

Скрипты инициализации

APEX могут включать сценарии инициализации двумя способами: (A) готовый текстовый файл в составе полезной нагрузки APEX или (B) обычный сценарий инициализации в /vendor/etc . Вы можете настроить оба варианта для одного и того же APEX.

Скрипт инициализации в APEX:

prebuilt_etc {
  name: "myinit.rc",
  src: "myinit.rc"
}

apex {
  ..
  vendor: true,
  prebuilts: ["myinit.rc"],
  ..
}

Скрипты инициализации в APEX-ах поставщиков могут иметь определения service и директивы on <property or event> .

Убедитесь, что определение service указывает на исполняемый файл в том же APEX. Например, com.android.foo APEX может определять службу с именем foo-service .

on foo-service /apex/com.android.foo/bin/foo
  ...

Будьте осторожны при использовании директив on . Поскольку скрипты init в APEX анализируются и выполняются после активации APEX, некоторые события или свойства использовать невозможно. Используйте apex.all.ready=true для максимально раннего запуска действий. В APEX Bootstrap можно использовать on init , но не on early-init .

Прошивка

Пример:

Встроить прошивку в APEX поставщика с типом модуля prebuilt_firmware можно следующим образом.

prebuilt_firmware {
  name: "my.bin",
  src: "path_to_prebuilt_firmware",
  vendor: true,
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.bin"],  // installed inside APEX as /etc/firmware/my.bin
  ..
}

Модули prebuilt_firmware устанавливаются в каталоге <apex name>/etc/firmware сервера APEX. ueventd сканирует каталоги /apex/*/etc/firmware для поиска модулей прошивки.

Файл file_contexts APEX должен правильно помечать все записи полезной нагрузки прошивки, чтобы гарантировать доступ к этим файлам для ueventd во время выполнения; обычно метки vendor_file достаточно. Например:

(/.*)? u:object_r:vendor_file:s0

Модули ядра

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

prebuilt_etc {
  name: "my.ko",
  src: "my.ko",
  vendor: true,
  sub_dir: "modules"
}

apex {
  ..
  vendor: true,
  prebuilts: ["my.ko"],  // installed inside APEX as /etc/modules/my.ko
  ..
}

Файл file_contexts APEX должен правильно маркировать все записи полезной нагрузки модуля ядра. Например:

/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0

Модули ядра необходимо устанавливать явно. Следующий пример скрипта инициализации в разделе поставщика демонстрирует установку через insmod :

my_init.rc :

on early-boot
  insmod /apex/myapex/etc/modules/my.ko
  ..

Наложения ресурсов времени выполнения

Пример:

Встраивайте наложения ресурсов времени выполнения в APEX поставщика, используя свойство rros .

runtime_resource_overlay {
    name: "my_rro",
    soc_specific: true,
}


apex {
  ..
  vendor: true,
  rros: ["my_rro"],  // installed inside APEX as /overlay/my_rro.apk
  ..
}

Другие файлы конфигурации

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

Примеры:

Bootstrap Vendor APEXes

Некоторые службы HAL, такие как keymint должны быть доступны до активации APEX. Эти службы HAL обычно устанавливают early_hal в определении службы в скрипте инициализации. Другой пример — класс animation , который обычно запускается раньше события post-fs-data . Если такая ранняя служба HAL упакована в APEX поставщика, добавьте в манифест APEX параметр "vendorBootstrap": true , чтобы её можно было активировать раньше. Обратите внимание, что APEX-ы начальной загрузки можно активировать только из предустановленного расположения, например, /vendor/apex , а не из /data/apex .

Свойства системы

Это системные свойства, которые считывает фреймворк для поддержки APEX-ов поставщиков:

  • input_device.config_file.apex=<apex name> — если установлено, файлы конфигурации ввода ( *.idc , *.kl и *.kcm ) ищутся в каталоге /etc/usr APEX.
  • ro.vulkan.apex=<apex name> — если установлено, драйвер Vulkan загружается из APEX. Поскольку драйвер Vulkan используется ранними HAL, сделайте APEX Bootstrap APEX видимым и настройте это пространство имён компоновщика.

Установите свойства системы в скриптах инициализации с помощью команды setprop .

Дополнительные функции

Выбор APEX при загрузке

Пример:

APEX-серверы вендоров можно опционально активировать во время загрузки. Если указать имя файла с помощью системного свойства ro.vendor.apex.<apex name> , для указанного <apex name> будет активирован только APEX, соответствующий этому имени. APEX с <apex name> игнорируется (не активируется), если этому системному свойству присвоено значение none . Эту функцию можно использовать для установки нескольких копий APEX с одинаковым именем. Если существует несколько версий одного и того же APEX, они должны использовать один и тот же ключ.

Примеры использования:

  • Установите 3 версии поставщика Wi-Fi HAL APEX: команды по контролю качества могут запустить ручное или автоматизированное тестирование с использованием одной версии, затем перезагрузить систему в другую версию и повторно запустить тесты, а затем сравнить окончательные результаты.
  • Установите 2 версии поставщика HAL камеры APEX, текущую и экспериментальную : участники тестирования могут использовать экспериментальную версию без загрузки и установки дополнительного файла, поэтому они могут легко переключиться обратно.

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

Ожидаемые форматы ключа свойства:

  • Bootconfig
    • Используется для установки значения по умолчанию в BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Постоянное системное свойство
    • Используется для изменения значения по умолчанию, установленного на уже загруженном устройстве.
    • Переопределяет значение bootconfig, если оно присутствует.
    • persist.vendor.apex.<apex name>

Значением свойства должно быть имя файла APEX, который необходимо активировать, или none для отключения APEX.

// Default version.
apex {
  name: "com.oem.camera.hal.my_apex_default",
  vendor: true,
  ..
}

// Non-default version.
apex {
  name: "com.oem.camera.hal.my_apex_experimental",
  vendor: true,
  ..
}

Версию по умолчанию также следует настроить с помощью bootconfig в BoardConfig.mk :

# Example for APEX "com.oem.camera.hal" with the default above:
BOARD_BOOTCONFIG += \
    androidboot.vendor.apex.com.oem.camera.hal=com.oem.camera.hal.my_apex_default

После загрузки устройства измените активированную версию, установив постоянный sysprop:

$ adb root;
$ adb shell setprop \
    persist.vendor.apex.com.oem.camera.hal \
    com.oem.camera.hal.my_apex_experimental;
$ adb reboot;

Если устройство поддерживает обновление bootconfig после перепрошивки (например, с помощью команд fastboot oem ), то изменение свойства bootconfig для многоустановленного APEX также изменяет версию, активируемую при загрузке.

Для виртуальных эталонных устройств на основе Cuttlefish можно использовать команду --extra_bootconfig_args , чтобы задать свойство bootconfig непосредственно при запуске. Например:

launch_cvd --noresume \
  --extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";