Формат файлов 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-файлов поставщиков, и в настоящее время добавляются новые.
Примеры:
- XML-файлы деклараций функций
- Датчики содержат XML-файлы как предварительно созданные в поставщике датчиков HAL 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/usrAPEX. -
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";