Proveedor APEX

Puede utilizar el formato de archivo APEX para empaquetar e instalar módulos del sistema operativo Android de nivel inferior. Permite la construcción e instalación independiente de componentes como bibliotecas y servicios nativos, implementaciones HAL, firmware, archivos de configuración, etc.

Los APEX de proveedor son instalados automáticamente por el sistema de compilación en la partición /vendor y apexd los activa en 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 una agrupación y modularización natural de implementaciones de funciones en imágenes de proveedores.

Cuando las imágenes de proveedores se crean como una combinación de APEX de proveedores creados de forma independiente, los fabricantes de dispositivos pueden elegir fácilmente las implementaciones de proveedores específicas que desean en su dispositivo. Los fabricantes pueden incluso crear un nuevo APEX de proveedor si ninguno de los APEX proporcionados se ajusta a sus necesidades o si tienen un hardware personalizado nuevo.

Por ejemplo, un OEM puede optar por componer su dispositivo con la implementación APEX de wifi AOSP, la implementación APEX de bluetooth de SoC y una implementación APEX de telefonía OEM personalizada.

Sin APEX de proveedores, una implementación con tantas dependencias entre los componentes de los proveedores requiere una cuidadosa coordinación y seguimiento. Al envolver todos los componentes (incluidos los archivos de configuración y las bibliotecas adicionales) en APEX con interfaces claramente definidas en cualquier punto de comunicación entre funciones, los diferentes componentes se vuelven intercambiables.

Iteración del desarrollador

Los APEX de proveedor ayudan a los desarrolladores a iterar más rápido mientras desarrollan módulos de proveedor al agrupar una implementación de funciones completa, como wifi HAL, dentro de un APEX de proveedor. Luego, los desarrolladores pueden crear e impulsar individualmente el APEX del proveedor para probar los cambios, en lugar de reconstruir toda la imagen del proveedor.

Esto simplifica y acelera el ciclo de iteración del desarrollador para los desarrolladores que trabajan principalmente en un área de funciones y desean iterar solo en esa área de funciones.

La agrupación natural de un área de características en un APEX también simplifica el proceso de creación, impulso y prueba de cambios para esa área de características. Por ejemplo, reinstalar un APEX actualiza automáticamente cualquier biblioteca incluida o archivos de configuración que incluya el APEX.

Agrupar un área de funciones en un APEX también simplifica la depuración o reversión cuando se observa un mal comportamiento del dispositivo. Por ejemplo, si la telefonía funciona mal en una nueva versión, entonces los desarrolladores podrían intentar instalar una implementación de telefonía anterior APEX en un dispositivo (sin necesidad de actualizar una versión completa) 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

Lo esencial

Consulte la página principal de formato de archivo APEX para obtener información genérica de APEX, incluidos los requisitos del dispositivo, detalles del formato de archivo y pasos de instalación.

En Android.bp , configurar la vendor: true convierte un módulo APEX en un APEX de proveedor.

apex {
  ..
  vendor: true,
  ..
}

Binarios y bibliotecas compartidas

Un APEX incluye dependencias transitivas dentro de la carga útil de APEX a menos que tengan interfaces estables.

Las interfaces nativas estables para las dependencias APEX del proveedor incluyen cc_library con stubs , ndk_library o llndk_library . Estas dependencias se excluyen del empaquetado y se registran en el manifiesto APEX. linkerconfig procesa el manifiesto para que las dependencias nativas externas estén disponibles en tiempo de ejecución.

A diferencia de los APEX en la partición /system , los APEX del proveedor generalmente están vinculados a una versión específica de VNDK. Las bibliotecas VNDK garantizan la estabilidad de ABI dentro de la versión, por lo que podemos tratar las bibliotecas VNDK como estables y reducir el tamaño de los APEX del proveedor excluyéndolos de los APEX mediante la propiedad use_vndk_as_stable .

En el siguiente fragmento, APEX contendrá tanto el binario ( my_service ) como sus dependencias no estables (archivos *.so ). No contendrá bibliotecas VNDK, incluso cuando my_service esté creado con bibliotecas VNDK como libbase . En cambio, en tiempo de ejecución my_service utilizará libbase de las bibliotecas VNDK proporcionadas por el sistema.

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

En el siguiente fragmento, APEX contendrá la biblioteca compartida my_standalone_lib y cualquiera de sus dependencias no estables (como se describe anteriormente).

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

Implementaciones HAL

Para definir una implementación HAL, proporcione los binarios y bibliotecas correspondientes dentro de un proveedor APEX similar a los siguientes ejemplos:

Para encapsular completamente la implementación de HAL, APEX también debe especificar los fragmentos VINTF y scripts de inicio relevantes.

Fragmentos VINTF

Los fragmentos VINTF se pueden entregar desde un proveedor APEX cuando los fragmentos se encuentran en etc/vintf del APEX.

Utilice la propiedad prebuilts para incrustar los fragmentos VINTF en APEX.

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

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

Guiones de inicio

Los APEX pueden incluir scripts de inicio de dos maneras: (A) un archivo de texto prediseñado dentro de la carga útil de APEX, o (B) un script de inicio normal en /vendor/etc . Puede configurar ambos para el mismo APEX.

Guión de inicio en APEX:

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

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

Los scripts de inicio dentro de APEX solo pueden tener definiciones service . Los scripts de inicio en los proveedores APEX también pueden tener directivas on <property> .

Tenga cuidado al utilizar on . Dado que los scripts de inicio en APEX se analizan y ejecutan después de activar APEX, algunos eventos o propiedades no se pueden usar. Utilice apex.all.ready=true para activar acciones lo antes posible.

firmware

Ejemplo:

Incruste el firmware en un proveedor APEX con el tipo de módulo prebuilt_firmware , como se indica 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 el directorio <apex name>/etc/firmware de APEX. ueventd escanea los directorios /apex/*/etc/firmware para encontrar módulos de firmware.

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del firmware para garantizar que ueventd pueda acceder a estos archivos en tiempo de ejecución; normalmente, la etiqueta vendor_file es suficiente. Por ejemplo:

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

Módulos del núcleo

Incruste módulos del kernel en un proveedor APEX como módulos prediseñados, como se indica a continuación.

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
  ..
}

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del módulo del kernel. Por ejemplo:

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

Los módulos del kernel deben instalarse explícitamente. El siguiente script de inicio de ejemplo en la partición del proveedor muestra la instalación mediante insmod :

my_init.rc :

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

Superposiciones de recursos en tiempo de ejecución

Ejemplo:

Incruste superposiciones de recursos de tiempo de ejecución en un APEX de proveedor utilizando 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 normalmente se encuentran en la partición del proveedor como elementos precompilados dentro de los APEX de proveedores, y se están agregando más.

Ejemplos:

Funciones de desarrollo adicionales

Selección de APEX en el arranque

Ejemplo:

Los desarrolladores también pueden instalar varias versiones de APEX de proveedores que comparten el mismo nombre y clave de APEX, y luego elegir qué versión se activa durante cada inicio utilizando sysprops persistentes. Para ciertos casos de uso de desarrolladores, esto podría ser más sencillo que instalar una nueva copia de APEX usando adb install .

Casos de uso de ejemplo:

  • Instale 3 versiones del proveedor de wifi HAL APEX: los equipos de control de calidad pueden ejecutar pruebas manuales o automatizadas usando una versión, luego reiniciar en otra versión y volver a ejecutar las pruebas, luego comparar los resultados finales.
  • Instale 2 versiones de la cámara HAL del proveedor APEX, actual y experimental : los dogfooders pueden usar la versión experimental sin descargar e instalar un archivo adicional, por lo que pueden volver a intercambiarla fácilmente.

Durante el arranque, apexd busca sysprops que sigan un formato específico para activar la versión APEX correcta.

Los formatos esperados para la clave de propiedad son:

  • configuración de arranque
    • Se utiliza para establecer el valor predeterminado, en BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Propiedad del sistema persistente
    • Se utiliza para cambiar el valor predeterminado, configurado en un dispositivo ya iniciado.
    • Anula el valor de bootconfig si está presente.
    • persist.vendor.apex.<apex name>

El valor de la propiedad debe ser el nombre del archivo del APEX que debe activarse.

// 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 usando 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 iniciar el dispositivo, cambie la versión activada configurando el 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 flashear (como mediante comandos fastboot oem ), cambiar la propiedad bootconfig para APEX multiinstalado también cambia la versión activada en el arranque.

Para dispositivos de referencia virtuales basados ​​en Cuttlefish , puede usar el comando --extra_bootconfig_args para configurar 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";
,

Puede utilizar el formato de archivo APEX para empaquetar e instalar módulos del sistema operativo Android de nivel inferior. Permite la construcción e instalación independiente de componentes como bibliotecas y servicios nativos, implementaciones HAL, firmware, archivos de configuración, etc.

Los APEX de proveedor son instalados automáticamente por el sistema de compilación en la partición /vendor y apexd los activa en 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 una agrupación y modularización natural de implementaciones de funciones en imágenes de proveedores.

Cuando las imágenes de proveedores se crean como una combinación de APEX de proveedores creados de forma independiente, los fabricantes de dispositivos pueden elegir fácilmente las implementaciones de proveedores específicas que desean en su dispositivo. Los fabricantes pueden incluso crear un nuevo APEX de proveedor si ninguno de los APEX proporcionados se ajusta a sus necesidades o si tienen un hardware personalizado nuevo.

Por ejemplo, un OEM puede optar por componer su dispositivo con la implementación APEX de wifi AOSP, la implementación APEX de bluetooth de SoC y una implementación APEX de telefonía OEM personalizada.

Sin APEX de proveedores, una implementación con tantas dependencias entre los componentes de los proveedores requiere una cuidadosa coordinación y seguimiento. Al envolver todos los componentes (incluidos los archivos de configuración y las bibliotecas adicionales) en APEX con interfaces claramente definidas en cualquier punto de comunicación entre funciones, los diferentes componentes se vuelven intercambiables.

Iteración del desarrollador

Los APEX de proveedor ayudan a los desarrolladores a iterar más rápido mientras desarrollan módulos de proveedor al agrupar una implementación de funciones completa, como wifi HAL, dentro de un APEX de proveedor. Luego, los desarrolladores pueden crear e impulsar individualmente el APEX del proveedor para probar los cambios, en lugar de reconstruir toda la imagen del proveedor.

Esto simplifica y acelera el ciclo de iteración del desarrollador para los desarrolladores que trabajan principalmente en un área de funciones y desean iterar solo en esa área de funciones.

La agrupación natural de un área de características en un APEX también simplifica el proceso de creación, impulso y prueba de cambios para esa área de características. Por ejemplo, reinstalar un APEX actualiza automáticamente cualquier biblioteca incluida o archivos de configuración que incluya el APEX.

Agrupar un área de funciones en un APEX también simplifica la depuración o reversión cuando se observa un mal comportamiento del dispositivo. Por ejemplo, si la telefonía funciona mal en una nueva versión, entonces los desarrolladores podrían intentar instalar una implementación de telefonía anterior APEX en un dispositivo (sin necesidad de actualizar una versión completa) 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

Lo esencial

Consulte la página principal de formato de archivo APEX para obtener información genérica de APEX, incluidos los requisitos del dispositivo, detalles del formato de archivo y pasos de instalación.

En Android.bp , configurar la vendor: true convierte un módulo APEX en un APEX de proveedor.

apex {
  ..
  vendor: true,
  ..
}

Binarios y bibliotecas compartidas

Un APEX incluye dependencias transitivas dentro de la carga útil de APEX a menos que tengan interfaces estables.

Las interfaces nativas estables para las dependencias APEX del proveedor incluyen cc_library con stubs , ndk_library o llndk_library . Estas dependencias se excluyen del empaquetado y se registran en el manifiesto APEX. linkerconfig procesa el manifiesto para que las dependencias nativas externas estén disponibles en tiempo de ejecución.

A diferencia de los APEX en la partición /system , los APEX del proveedor generalmente están vinculados a una versión específica de VNDK. Las bibliotecas VNDK garantizan la estabilidad de ABI dentro de la versión, por lo que podemos tratar las bibliotecas VNDK como estables y reducir el tamaño de los APEX del proveedor excluyéndolos de los APEX mediante la propiedad use_vndk_as_stable .

En el siguiente fragmento, APEX contendrá tanto el binario ( my_service ) como sus dependencias no estables (archivos *.so ). No contendrá bibliotecas VNDK, incluso cuando my_service esté creado con bibliotecas VNDK como libbase . En cambio, en tiempo de ejecución my_service utilizará libbase de las bibliotecas VNDK proporcionadas por el sistema.

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

En el siguiente fragmento, APEX contendrá la biblioteca compartida my_standalone_lib y cualquiera de sus dependencias no estables (como se describe anteriormente).

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

Implementaciones HAL

Para definir una implementación HAL, proporcione los binarios y bibliotecas correspondientes dentro de un proveedor APEX similar a los siguientes ejemplos:

Para encapsular completamente la implementación de HAL, APEX también debe especificar los fragmentos VINTF y scripts de inicio relevantes.

Fragmentos VINTF

Los fragmentos VINTF se pueden entregar desde un proveedor APEX cuando los fragmentos se encuentran en etc/vintf del APEX.

Utilice la propiedad prebuilts para incrustar los fragmentos VINTF en APEX.

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

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

Guiones de inicio

Los APEX pueden incluir scripts de inicio de dos maneras: (A) un archivo de texto prediseñado dentro de la carga útil de APEX, o (B) un script de inicio normal en /vendor/etc . Puede configurar ambos para el mismo APEX.

Guión de inicio en APEX:

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

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

Los scripts de inicio dentro de APEX solo pueden tener definiciones service . Los scripts de inicio en los proveedores APEX también pueden tener directivas on <property> .

Tenga cuidado al utilizar on . Dado que los scripts de inicio en APEX se analizan y ejecutan después de activar APEX, algunos eventos o propiedades no se pueden usar. Utilice apex.all.ready=true para activar acciones lo antes posible.

firmware

Ejemplo:

Incruste el firmware en un proveedor APEX con el tipo de módulo prebuilt_firmware , como se indica 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 el directorio <apex name>/etc/firmware de APEX. ueventd escanea los directorios /apex/*/etc/firmware para encontrar módulos de firmware.

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del firmware para garantizar que ueventd pueda acceder a estos archivos en tiempo de ejecución; normalmente, la etiqueta vendor_file es suficiente. Por ejemplo:

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

Módulos del núcleo

Incruste módulos del kernel en un proveedor APEX como módulos prediseñados, como se indica a continuación.

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
  ..
}

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del módulo del kernel. Por ejemplo:

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

Los módulos del kernel deben instalarse explícitamente. El siguiente script de inicio de ejemplo en la partición del proveedor muestra la instalación mediante insmod :

my_init.rc :

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

Superposiciones de recursos en tiempo de ejecución

Ejemplo:

Incruste superposiciones de recursos de tiempo de ejecución en un APEX de proveedor utilizando 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 normalmente se encuentran en la partición del proveedor como elementos precompilados dentro de los APEX de proveedores, y se están agregando más.

Ejemplos:

Funciones de desarrollo adicionales

Selección de APEX en el arranque

Ejemplo:

Los desarrolladores también pueden instalar varias versiones de APEX de proveedores que comparten el mismo nombre y clave de APEX, y luego elegir qué versión se activa durante cada inicio utilizando sysprops persistentes. Para ciertos casos de uso de desarrolladores, esto podría ser más sencillo que instalar una nueva copia de APEX usando adb install .

Casos de uso de ejemplo:

  • Instale 3 versiones del proveedor de wifi HAL APEX: los equipos de control de calidad pueden ejecutar pruebas manuales o automatizadas usando una versión, luego reiniciar en otra versión y volver a ejecutar las pruebas, luego comparar los resultados finales.
  • Instale 2 versiones de la cámara HAL del proveedor APEX, actual y experimental : los dogfooders pueden usar la versión experimental sin descargar e instalar un archivo adicional, por lo que pueden volver a intercambiarla fácilmente.

Durante el arranque, apexd busca sysprops que sigan un formato específico para activar la versión APEX correcta.

Los formatos esperados para la clave de propiedad son:

  • configuración de arranque
    • Se utiliza para establecer el valor predeterminado, en BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Propiedad del sistema persistente
    • Se utiliza para cambiar el valor predeterminado, configurado en un dispositivo ya iniciado.
    • Anula el valor de bootconfig si está presente.
    • persist.vendor.apex.<apex name>

El valor de la propiedad debe ser el nombre del archivo del APEX que debe activarse.

// 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 usando 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 iniciar el dispositivo, cambie la versión activada configurando el 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 flashear (como mediante comandos fastboot oem ), cambiar la propiedad bootconfig para APEX multiinstalado también cambia la versión activada en el arranque.

Para dispositivos de referencia virtuales basados ​​en Cuttlefish , puede usar el comando --extra_bootconfig_args para configurar 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";
,

Puede utilizar el formato de archivo APEX para empaquetar e instalar módulos del sistema operativo Android de nivel inferior. Permite la construcción e instalación independiente de componentes como bibliotecas y servicios nativos, implementaciones HAL, firmware, archivos de configuración, etc.

Los APEX de proveedor son instalados automáticamente por el sistema de compilación en la partición /vendor y apexd los activa en 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 una agrupación y modularización natural de implementaciones de funciones en imágenes de proveedores.

Cuando las imágenes de proveedores se crean como una combinación de APEX de proveedores creados de forma independiente, los fabricantes de dispositivos pueden elegir fácilmente las implementaciones de proveedores específicas que desean en su dispositivo. Los fabricantes pueden incluso crear un nuevo APEX de proveedor si ninguno de los APEX proporcionados se ajusta a sus necesidades o si tienen un hardware personalizado nuevo.

Por ejemplo, un OEM puede optar por componer su dispositivo con la implementación APEX de wifi AOSP, la implementación APEX de bluetooth de SoC y una implementación APEX de telefonía OEM personalizada.

Sin APEX de proveedores, una implementación con tantas dependencias entre los componentes de los proveedores requiere una cuidadosa coordinación y seguimiento. Al envolver todos los componentes (incluidos los archivos de configuración y las bibliotecas adicionales) en APEX con interfaces claramente definidas en cualquier punto de comunicación entre funciones, los diferentes componentes se vuelven intercambiables.

Iteración del desarrollador

Los APEX de proveedor ayudan a los desarrolladores a iterar más rápido mientras desarrollan módulos de proveedor al agrupar una implementación de funciones completa, como wifi HAL, dentro de un APEX de proveedor. Luego, los desarrolladores pueden crear e impulsar individualmente el APEX del proveedor para probar los cambios, en lugar de reconstruir toda la imagen del proveedor.

Esto simplifica y acelera el ciclo de iteración del desarrollador para los desarrolladores que trabajan principalmente en un área de funciones y desean iterar solo en esa área de funciones.

La agrupación natural de un área de características en un APEX también simplifica el proceso de creación, impulso y prueba de cambios para esa área de características. Por ejemplo, reinstalar un APEX actualiza automáticamente cualquier biblioteca incluida o archivos de configuración que incluya el APEX.

Agrupar un área de funciones en un APEX también simplifica la depuración o reversión cuando se observa un mal comportamiento del dispositivo. Por ejemplo, si la telefonía funciona mal en una nueva versión, entonces los desarrolladores podrían intentar instalar una implementación de telefonía anterior APEX en un dispositivo (sin necesidad de actualizar una versión completa) 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

Lo esencial

Consulte la página principal de formato de archivo APEX para obtener información genérica de APEX, incluidos los requisitos del dispositivo, detalles del formato de archivo y pasos de instalación.

En Android.bp , configurar la vendor: true convierte un módulo APEX en un APEX de proveedor.

apex {
  ..
  vendor: true,
  ..
}

Binarios y bibliotecas compartidas

Un APEX incluye dependencias transitivas dentro de la carga útil de APEX a menos que tengan interfaces estables.

Las interfaces nativas estables para las dependencias APEX del proveedor incluyen cc_library con stubs , ndk_library o llndk_library . Estas dependencias se excluyen del empaquetado y se registran en el manifiesto APEX. linkerconfig procesa el manifiesto para que las dependencias nativas externas estén disponibles en tiempo de ejecución.

A diferencia de los APEX en la partición /system , los APEX del proveedor generalmente están vinculados a una versión específica de VNDK. Las bibliotecas VNDK garantizan la estabilidad de ABI dentro de la versión, por lo que podemos tratar las bibliotecas VNDK como estables y reducir el tamaño de los APEX del proveedor excluyéndolos de los APEX mediante la propiedad use_vndk_as_stable .

En el siguiente fragmento, APEX contendrá tanto el binario ( my_service ) como sus dependencias no estables (archivos *.so ). No contendrá bibliotecas VNDK, incluso cuando my_service esté creado con bibliotecas VNDK como libbase . En cambio, en tiempo de ejecución my_service utilizará libbase de las bibliotecas VNDK proporcionadas por el sistema.

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

En el siguiente fragmento, APEX contendrá la biblioteca compartida my_standalone_lib y cualquiera de sus dependencias no estables (como se describe anteriormente).

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

Implementaciones HAL

Para definir una implementación HAL, proporcione los binarios y bibliotecas correspondientes dentro de un proveedor APEX similar a los siguientes ejemplos:

Para encapsular completamente la implementación de HAL, APEX también debe especificar los fragmentos VINTF y scripts de inicio relevantes.

Fragmentos VINTF

Los fragmentos VINTF se pueden entregar desde un proveedor APEX cuando los fragmentos se encuentran en etc/vintf del APEX.

Utilice la propiedad prebuilts para incrustar los fragmentos VINTF en APEX.

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

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

Guiones de inicio

Los APEX pueden incluir scripts de inicio de dos maneras: (A) un archivo de texto prediseñado dentro de la carga útil de APEX, o (B) un script de inicio normal en /vendor/etc . Puede configurar ambos para el mismo APEX.

Guión de inicio en APEX:

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

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

Los scripts de inicio dentro de APEX solo pueden tener definiciones service . Los scripts de inicio en los proveedores APEX también pueden tener directivas on <property> .

Tenga cuidado al utilizar on . Dado que los scripts de inicio en APEX se analizan y ejecutan después de activar APEX, algunos eventos o propiedades no se pueden usar. Utilice apex.all.ready=true para activar acciones lo antes posible.

firmware

Ejemplo:

Incruste el firmware en un proveedor APEX con el tipo de módulo prebuilt_firmware , como se indica 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 el directorio <apex name>/etc/firmware de APEX. ueventd escanea los directorios /apex/*/etc/firmware para encontrar módulos de firmware.

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del firmware para garantizar que ueventd pueda acceder a estos archivos en tiempo de ejecución; normalmente, la etiqueta vendor_file es suficiente. Por ejemplo:

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

Módulos del núcleo

Incruste módulos del kernel en un proveedor APEX como módulos prediseñados, como se indica a continuación.

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
  ..
}

Los file_contexts de APEX deben etiquetar correctamente las entradas de carga útil del módulo del kernel. Por ejemplo:

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

Los módulos del kernel deben instalarse explícitamente. El siguiente script de inicio de ejemplo en la partición del proveedor muestra la instalación mediante insmod :

my_init.rc :

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

Superposiciones de recursos en tiempo de ejecución

Ejemplo:

Incruste superposiciones de recursos de tiempo de ejecución en un APEX de proveedor utilizando 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 normalmente se encuentran en la partición del proveedor como elementos precompilados dentro de los APEX de proveedores, y se están agregando más.

Ejemplos:

Funciones de desarrollo adicionales

Selección de APEX en el arranque

Ejemplo:

Los desarrolladores también pueden instalar varias versiones de APEX de proveedores que comparten el mismo nombre y clave de APEX, y luego elegir qué versión se activa durante cada inicio utilizando sysprops persistentes. Para ciertos casos de uso de desarrolladores, esto podría ser más sencillo que instalar una nueva copia de APEX usando adb install .

Casos de uso de ejemplo:

  • Instale 3 versiones del proveedor de wifi HAL APEX: los equipos de control de calidad pueden ejecutar pruebas manuales o automatizadas usando una versión, luego reiniciar en otra versión y volver a ejecutar las pruebas, luego comparar los resultados finales.
  • Instale 2 versiones de la cámara HAL del proveedor APEX, actual y experimental : los dogfooders pueden usar la versión experimental sin descargar e instalar un archivo adicional, por lo que pueden volver a intercambiarla fácilmente.

Durante el arranque, apexd busca sysprops que sigan un formato específico para activar la versión APEX correcta.

Los formatos esperados para la clave de propiedad son:

  • configuración de arranque
    • Se utiliza para establecer el valor predeterminado, en BoardConfig.mk .
    • androidboot.vendor.apex.<apex name>
  • Propiedad del sistema persistente
    • Se utiliza para cambiar el valor predeterminado, configurado en un dispositivo ya iniciado.
    • Anula el valor de bootconfig si está presente.
    • persist.vendor.apex.<apex name>

El valor de la propiedad debe ser el nombre del archivo del APEX que debe activarse.

// 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 usando 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 iniciar el dispositivo, cambie la versión activada configurando el 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 flashear (como mediante comandos fastboot oem ), cambiar la propiedad bootconfig para APEX multiinstalado también cambia la versión activada en el arranque.

Para dispositivos de referencia virtuales basados ​​en Cuttlefish , puede usar el comando --extra_bootconfig_args para configurar 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";