Формат файлов APEX позволяет упаковывать и устанавливать модули операционной системы Android нижнего уровня. Он обеспечивает независимую сборку и установку таких компонентов, как нативные сервисы и библиотеки, реализации HAL, микропрограммы, файлы конфигурации и т. д.
APEX-файлы от поставщика устанавливаются системой сборки автоматически в раздел /vendor и активируются во время выполнения программой apexd так же, как и APEX-файлы в других разделах.
Варианты использования
Модульная организация образов поставщиков
APEX-ы обеспечивают естественное объединение и модульную структуру реализаций функций в образах от поставщиков.
Когда образы от поставщиков создаются как комбинация независимо разработанных APEX-файлов от разных поставщиков, производители устройств могут легко выбирать конкретные реализации от поставщиков, необходимые для их устройства. Производители могут даже создать новый APEX-файл от поставщика, если ни один из предоставленных APEX-файлов не соответствует их потребностям или если у них есть совершенно новое специализированное оборудование.
Например, производитель оборудования может выбрать для своего устройства реализацию Wi-Fi на основе AOSP (APEX), реализацию Bluetooth на основе SoC (APEX) и собственную реализацию телефонии от производителя (APEX).
Без использования APEX-файлов от сторонних поставщиков реализация с таким количеством зависимостей между компонентами от разных поставщиков требует тщательной координации и отслеживания. Обернув все компоненты (включая файлы конфигурации и дополнительные библиотеки) в APEX-файлы с четко определенными интерфейсами в любой точке взаимодействия между функциями, различные компоненты становятся взаимозаменяемыми.
Итерация разработчиков
Встроенные APEX-файлы от поставщиков помогают разработчикам быстрее вносить изменения в модули от сторонних производителей, объединяя всю реализацию функций, например, HAL для Wi-Fi, в один 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 от поставщиков относятся 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-файле. Например, APEX-файл com.android.foo может определять службу с именем foo-service .
on foo-service /apex/com.android.foo/bin/foo
...
Будьте осторожны при использовании директив ` on . Поскольку скрипты инициализации в APEX-приложениях анализируются и выполняются после активации APEX-приложений, некоторые события или свойства использовать нельзя. Используйте apex.all.ready=true , чтобы запускать действия как можно раньше. 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
Модули ядра необходимо устанавливать явно. Следующий пример скрипта инициализации в разделе vendor демонстрирует установку с помощью 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/usrAPEX. -
ro.vulkan.apex=<apex name>- если установлено, драйвер Vulkan загружается из APEX. Поскольку драйвер Vulkan используется ранними HAL, сделайте APEX Bootstrap APEX видимым и настройте это пространство имен компоновщика.
Задайте параметры системы в скриптах инициализации с помощью команды setprop .
Дополнительные функции
Выбор APEX при загрузке
Пример:
APEX-файлы от поставщика могут быть активированы во время загрузки. Если вы укажете имя файла с помощью системного свойства ro.vendor.apex.<apex name> , будет активирован только тот APEX-файл, который соответствует этому имени, для конкретного <apex name> . APEX-файл с <apex name> будет проигнорирован (не активирован), если это системное свойство установлено в none . Вы можете использовать эту функцию для установки нескольких копий APEX-файла с одинаковым именем. Если существует несколько версий одного и того же APEX-файла, они должны использовать один и тот же ключ.
Примеры вариантов использования:
- Установите 3 версии APEX от поставщика WiFi HAL: команды контроля качества могут запускать ручное или автоматизированное тестирование, используя одну версию, затем перезагрузиться в другую версию и повторно запустить тесты, после чего сравнить окончательные результаты.
- Установите две версии HAL-компонента камеры APEX: текущую и экспериментальную : пользователи Dogfood могут использовать экспериментальную версию без загрузки и установки дополнительных файлов, поэтому они легко смогут вернуться к предыдущей.
Во время загрузки apexd ищет параметры sysprops в определенном формате, чтобы активировать правильную версию APEX.
Ожидаемые форматы для ключа свойства:
- Bootconfig
- Используется для установки значения по умолчанию в
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
После загрузки устройства измените активированную версию, установив параметр persistent 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";