Формат файла APEX можно использовать для упаковки и установки низкоуровневых модулей ОС Android. Он позволяет выполнять независимую сборку и установку компонентов, таких как собственные службы и библиотеки, реализации HAL, прошивки, файлы конфигурации и т. д.
APEX-файлы поставщиков устанавливаются системой сборки автоматически в раздел /vendor
и активируются во время выполнения с помощью apexd
, как и APEX-файлы в других разделах.
Варианты использования
Модуляризация изображений поставщиков
APEX облегчают естественное объединение и модуляризацию реализаций функций в образах поставщиков.
Когда образы поставщиков создаются как комбинация независимо созданных APEX-ов поставщиков, производители устройств могут легко выбирать конкретные реализации поставщиков, которые требуются для их устройства. Производители могут даже создать новый APEX-ов поставщиков, если ни один из предоставленных APEX-ов не соответствует их потребностям или у них есть совершенно новое пользовательское оборудование.
Например, OEM-производитель может выбрать для своего устройства реализацию Wi-Fi APEX от AOSP, реализацию Bluetooth APEX от SoC и пользовательскую реализацию телефонии APEX от OEM.
Без 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
Фрагменты 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
для запуска действий как можно раньше. Bootstrap APEX может использовать 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
Модули ядра должны быть установлены явно. Следующий пример скрипта init в разделе поставщика показывает установку через 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-файлов поставщиков, и в настоящее время добавляются новые файлы.
Примеры:
- XML-файлы декларации функций
- Датчики содержат XML-файлы как предварительно созданные в датчике HAL поставщика APEX
- Входные файлы конфигурации
- Конфигурации сенсорного экрана как готовые решения в поставщике APEX, предоставляющем только конфигурации
Bootstrap Vendor APEXes
Некоторые службы HAL, такие как keymint
должны быть доступны до активации APEX. Эти HAL обычно устанавливают early_hal
в своем определении службы в скрипте инициализации. Другим примером является класс animation
, который обычно запускается раньше события post-fs-data
. Когда такая ранняя служба HAL упакована в APEX поставщика, установите apex "vendorBootstrap": true
в его манифесте APEX, чтобы ее можно было активировать раньше. Обратите внимание, что 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.
Ожидаемые форматы для ключа свойства:
- Конфигурация загрузки
- Используется для установки значения по умолчанию в
BoardConfig.mk
. -
androidboot.vendor.apex.<apex name>
- Используется для установки значения по умолчанию в
- Постоянный sysprop
- Используется для изменения значения по умолчанию, установленного на уже загруженном устройстве.
- Переопределяет значение 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";