Puedes usar el formato de archivo APEX para empaquetar y instalar módulos de SO Android de nivel inferior. Permite la compilación y la instalación independientes de componentes, como servicios y bibliotecas nativos, implementaciones de HAL, firmware, archivos de configuración, etcétera.
El sistema de compilación instala automáticamente los APEX del proveedor en la partición /vendor
y apexd
los activa en el tiempo de ejecución, al igual que los APEX en otras particiones.
Casos de uso
Modularización de imágenes de proveedores
Los APEX facilitan la agrupación y modularización naturales de las implementaciones de funciones en las imágenes del proveedor.
Cuando las imágenes de un proveedor se crean como una combinación de imágenes de proveedores creadas de forma independiente APEX, los fabricantes de dispositivos pueden elegir fácilmente el software de las implementaciones de proveedores que quisieran en su dispositivo. Los fabricantes incluso pueden crear nuevo APEX del proveedor si ninguno de los APEX proporcionados satisface sus necesidades o si tiene hardware personalizado nuevo.
Por ejemplo, un OEM puede elegir componer su dispositivo con el APEX de implementación de Wi-Fi de AOSP, el APEX de implementación de Bluetooth del SoC y un APEX de implementación de telefonía OEM personalizado.
Sin APEX del proveedor, una implementación con tantas dependencias entre los componentes del proveedor requiere una coordinación y un seguimiento cuidadosos. Uniendo todo (archivos de configuración y bibliotecas adicionales) en APEX con interfaces definidas con claridad en cualquier punto de comunicación los diferentes componentes se vuelven intercambiables.
Iteración del desarrollador
Los APEX de proveedores ayudan a los desarrolladores a iterar más rápido mientras desarrollan módulos de proveedores Cómo agrupar una implementación de función completa, como la HAL de Wi-Fi, dentro de un proveedor APEX Luego, los desarrolladores pueden compilar y enviar individualmente el APEX del proveedor para que lo pruebe. en lugar de reconstruir toda la imagen del proveedor.
Esto simplifica y acelera el ciclo de iteración de los desarrolladores que trabajan principalmente en un área de funciones y quieren iterar solo en esa función en una sola área de almacenamiento en etapa intermedia.
El empaquetado natural de un área de componentes en un APEX también simplifica el proceso de compilación, envío y prueba de cambios para esa área de componentes. Por ejemplo: La reinstalación de APEX actualiza automáticamente las bibliotecas o los archivos de configuración agrupados. que incluye APEX.
Combinar un área de componentes en un APEX también simplifica la depuración o la reversión cuando se observa un comportamiento incorrecto del dispositivo. Por ejemplo, si la telefonía funciona mal en una compilación nueva, los desarrolladores podrían intentar instalar un sistema de implementación de APEX en un dispositivo (sin necesidad de escribir una compilación completa en la memoria flash) y ver si se restablece el buen comportamiento.
Ejemplo de flujo de trabajo:
# 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 ...
Ejemplos
Conceptos básicos
Consulta la página principal Formato de archivo APEX para obtener información genérica sobre APEX, incluidos los requisitos del dispositivo, los detalles del formato de archivo y los pasos de instalación.
En Android.bp
, configurar la propiedad vendor: true
hace que un módulo APEX sea un APEX del proveedor.
apex {
..
vendor: true,
..
}
Objetos binarios y bibliotecas compartidas
Un APEX incluye dependencias transitivas dentro de la carga útil de APEX, a menos que tienen interfaces estables.
Las interfaces nativas estables para dependencias de APEX del proveedor incluyen cc_library
con
stubs
y LLNDK. Estas dependencias se excluyen de
paquetes y dependencias se registran en el manifiesto de APEX. El manifiesto es
procesados por linkerconfig
para que las dependencias nativas externas se
disponibles en el tiempo de ejecución.
En el siguiente fragmento, APEX contiene el objeto binario (my_service
) y sus dependencias no estables (archivos *.so
).
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
En el siguiente fragmento, el APEX contiene la biblioteca compartida my_standalone_lib
y cualquiera de sus dependencias no estables (como se describió anteriormente).
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Cómo reducir el tamaño de APEX
Es posible que APEX crezca porque agrupa dependencias no estables. Recomendaciones
con la vinculación estática. Puedes usar las bibliotecas comunes, como libc++.so
y libbase.so
,
vinculados estáticamente a objetos binarios de HAL. Crear una dependencia para proporcionar una interfaz estable puede ser otra opción. La dependencia no se agrupará en APEX.
Implementaciones de HAL
Para definir una implementación de HAL, proporciona los objetos binarios y las bibliotecas correspondientes dentro de un APEX de proveedor similar a los siguientes ejemplos:
Para encapsular por completo la implementación de HAL, APEX también debe especificar cualquier fragmento y secuencia de comandos de init de VINTF relevante.
Fragmentos de VINTF
Los fragmentos de VINTF se pueden entregar desde un APEX de un proveedor cuando se ubican los fragmentos en
etc/vintf
de APEX.
Usa la propiedad prebuilts
para incorporar los fragmentos de VINTF en el APEX.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
APIs de consulta
Cuando se agreguen fragmentos de VINTF a APEX, usa las APIs de libbinder_ndk
para obtener la
asignaciones de interfaces de HAL y nombres de APEX.
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
si la instancia de HAL se define en APEX.AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: Obtiene el nombre de APEX que define la instancia de HAL.AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: Úsalo para abrir un HAL de transferencia.
Secuencias de comandos Init
Los APEX pueden incluir secuencias de comandos de inicio de dos maneras: (A) con un archivo de texto precompilado dentro del
Carga útil de APEX o (B) una secuencia de comandos init normal en /vendor/etc
Puedes configurar ambos para el mismo APEX.
Secuencia de comandos Init en APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Las secuencias de comandos Init en los APEX de proveedores pueden tener definiciones de service
y
directivas on <property or event>
.
Asegúrate de que una definición service
apunte a un objeto binario en el mismo APEX.
Por ejemplo, com.android.foo
APEX puede definir un servicio llamado foo-service
.
on foo-service /apex/com.android.foo/bin/foo
...
Ten cuidado cuando uses directivas on
. Dado que las secuencias de comandos init en APEX son
analizarse y ejecutarse después de que se activen los APEX, algunos eventos o propiedades
no se pueden usar. Usa apex.all.ready=true
para activar acciones lo antes posible.
Los APEX de arranque pueden usar on init
, pero no
on early-init
Firmware
Ejemplo:
Incorpora el firmware en un APEX del proveedor con el tipo de módulo prebuilt_firmware
, como se muestra a continuación.
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
..
}
Los módulos prebuilt_firmware
se instalan en <apex name>/etc/firmware
de APEX. ueventd
analiza /apex/*/etc/firmware
directorios para
buscar módulos de firmware.
El file_contexts
de APEX debe etiquetar todas las entradas de carga útil del firmware.
de forma correcta para garantizar que ueventd
pueda acceder a estos archivos en el tiempo de ejecución.
por lo general, la etiqueta vendor_file
es suficiente. Por ejemplo:
(/.*)? u:object_r:vendor_file:s0
Módulos de kernel
Incorpora módulos de kernel en un APEX del proveedor como módulos precompilados, de la siguiente manera.
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
..
}
El file_contexts
de APEX debe etiquetar cualquier entrada de carga útil del módulo kernel
correctamente. Por ejemplo:
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Los módulos de kernel deben instalarse de forma explícita. El siguiente ejemplo de secuencia de comandos init
En la partición de proveedor, se muestra la instalación a través de insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Superposiciones de recursos en tiempo de ejecución
Ejemplo:
Incorporar superposiciones de recursos de tiempo de ejecución en el APEX de un proveedor
con la propiedad rros
.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Otros archivos de configuración
Los APEX de proveedores admiten varios otros archivos de configuración que suelen encontrarse en la partición del proveedor como precompilados dentro de los APEX de proveedores, y se agregarán más.
Ejemplos:
- Archivos XML de la declaración de funciones
- Los sensores incluyen archivos XML como compilaciones previas en un APEX de proveedor de HAL de sensores.
- Archivos de configuración de entrada
- Parámetros de configuración de la pantalla táctil como compilaciones previas en un APEX de proveedor solo de configuración
APEX del proveedor de arranque
Algunos servicios de HAL, como keymint
, deberían estar disponibles antes de que se activen los APEX. Por lo general, esos HAL establecen early_hal
en su definición de servicio en la secuencia de comandos de init. Otro ejemplo es la clase animation
, que generalmente se inicia antes que el evento post-fs-data
. Cuando un servicio HAL tan temprano se
empaquetado en el proveedor APEX, haz que el dominio raíz "vendorBootstrap": true
en su APEX
Manifiesto para que se pueda activar antes. Ten en cuenta que los APEX de arranque solo se pueden activar desde la ubicación precompilada, como /vendor/apex
, no desde /data/apex
.
Propiedades del sistema
Estas son las propiedades del sistema que el framework lee para admitir APEX del proveedor:
input_device.config_file.apex=<apex name>
: Cuando se establece, los archivos de configuración de entrada (*.idc
,*.kl
y*.kcm
) se buscan en el directorio/etc/usr
de APEX.ro.vulkan.apex=<apex name>
: Cuando se establece, el controlador de Vulkan se carga desde APEX. Como las primeras HAL usan el controlador de Vulkan, haz que el archivo APEX Inicia APEX y configura ese espacio de nombres del vinculador. sean visibles.
Configura las propiedades del sistema en las secuencias de comandos de init con el comando setprop
.
Funciones de desarrollo adicionales
Selección de APEX durante el inicio
Ejemplo:
Los desarrolladores también pueden instalar varias versiones de APEX del proveedor que comparten el mismo nombre y clave de APEX y, luego, elegir qué versión se activa durante cada inicio con sysprops persistentes. Para ciertos casos de uso de desarrolladores, esto podría ser
es más simple que instalar una copia nueva de APEX con adb install
.
Casos de uso de ejemplo:
- Instala 3 versiones del APEX del proveedor de HAL de Wi-Fi: Los equipos de QA pueden ejecutar pruebas manuales o automatizadas con una versión, reiniciar en otra versión y volver a ejecutar las pruebas, y luego comparar los resultados finales.
- Instala 2 versiones actuales y APEX del proveedor de la HAL de la cámara experimental: Los participantes de la prueba interna pueden usar la versión experimental sin descargar e instalar un archivo adicional, de modo que se puedan revertir fácilmente.
Durante el inicio, apexd
busca sysprops siguiendo un formato específico para lo siguiente:
activar la versión de APEX correcta.
Los formatos esperados para la clave de propiedad son los siguientes:
- Configuración de inicio
- Se usa para establecer el valor predeterminado en
BoardConfig.mk
. androidboot.vendor.apex.<apex name>
- Se usa para establecer el valor predeterminado en
- sysprop persistente
- Se usa para cambiar el valor predeterminado establecido en un dispositivo que ya se inició.
- Anula el valor de bootconfig si está presente.
persist.vendor.apex.<apex name>
El valor de la propiedad debe ser el nombre de archivo de APEX, activado.
// 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,
..
}
La versión predeterminada también debe configurarse con bootconfig en
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
Después de que se inicie el dispositivo, cambia la versión activada configurando la sysprop persistente:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Si el dispositivo admite la actualización de bootconfig después de la actualización de firmware (como a través de los comandos fastboot
oem
), cambiar la propiedad bootconfig para el APEX instalado varias veces también cambia la versión activada durante el inicio.
Para dispositivos de referencia virtuales basados en Cuttlefish,
puedes usar el comando --extra_bootconfig_args
para establecer la propiedad bootconfig
directamente durante el inicio. Por ejemplo:
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";