En Android 8.1 y versiones posteriores, el sistema de compilación tiene compatibilidad integrada con el VNDK. Cuando se habilita la compatibilidad con VNDK, el sistema de compilación verifica las dependencias entre los módulos, compila una variante específica del proveedor para los módulos del proveedor y, luego, instala automáticamente esos módulos en directorios designados.
Ejemplo de compatibilidad con la compilación de VNDK
En este ejemplo, la definición del módulo Android.bp
define una biblioteca llamada libexample
. La propiedad vendor_available
indica que los módulos del framework y los módulos del proveedor pueden depender de libexample
:
Figura 1: Compatibilidad habilitada.
Tanto el ejecutable del framework /system/bin/foo
como el ejecutable del proveedor /vendor/bin/bar
dependen de libexample
y tienen libexample
en sus propiedades shared_libs
.
Si los módulos del framework y los módulos del proveedor usan libexample
, se compilan dos variantes de libexample
. Los módulos del framework usan la variante principal (con el nombre libexample
) y los módulos del proveedor usan la variante del proveedor (con el nombre libexample.vendor
). Las dos variantes se instalan en directorios diferentes:
- La variante principal se instala en
/system/lib[64]/libexample.so
. - La variante del proveedor se instala en VNDK APEX porque
vndk.enabled
estrue
.
Para obtener más detalles, consulta Definición del módulo.
Cómo configurar la compatibilidad con compilaciones
Para habilitar la compatibilidad total del sistema de compilación para un dispositivo de producto, agrega BOARD_VNDK_VERSION
a BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Este parámetro de configuración tiene un efecto global: cuando se define en BoardConfig.mk
, se verifican todos los módulos. Como no hay un mecanismo para incluir en la lista de entidades permitidas o de entidades bloqueadas un módulo infractor, debes limpiar todas las dependencias innecesarias antes de agregar BOARD_VNDK_VERSION
. Puedes
probar y compilar un módulo si configuras BOARD_VNDK_VERSION
en
tus variables de entorno:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Cuando se habilita BOARD_VNDK_VERSION
, se quitan varias rutas de búsqueda de encabezados globales predeterminadas. Por ejemplo:
frameworks/av/include
frameworks/native/include
frameworks/native/opengl/include
hardware/libhardware/include
hardware/libhardware_legacy/include
hardware/ril/include
libnativehelper/include
libnativehelper/include_deprecated
system/core/include
system/media/audio/include
Si un módulo depende de los encabezados de estos directorios, debes especificar (de forma explícita) las dependencias con header_libs
, static_libs
o shared_libs
.
APEX de VNDK
En Android 10 y versiones anteriores, los módulos con vndk.enabled
se instalaron en /system/lib[64]/vndk[-sp]-${VER}
. En Android 11 y versiones posteriores, las bibliotecas de VNDK se empaquetan en formato APEX y el nombre de este último es com.android.vndk.v${VER}
. Según la configuración del dispositivo,
VNDK APEX está aplanado o no aplanado y está disponible desde la ruta de acceso canónica
/apex/com.android.vndk.v${VER}
.
Figura 2: APEX de VNDK
Definición del módulo
Para compilar Android con BOARD_VNDK_VERSION
, debes revisar la definición del módulo en Android.mk
o Android.bp
. En esta sección, se describen diferentes tipos de definiciones de módulos, varias propiedades de módulos relacionadas con VNDK y verificaciones de dependencias implementadas en el sistema de compilación.
Módulos de proveedores
Los módulos de proveedores son ejecutables o bibliotecas compartidas específicos del proveedor que se deben instalar en una partición del proveedor. En los archivos Android.bp
, los módulos de proveedores deben establecer la propiedad del proveedor o de propiedad en true
.
En los archivos Android.mk
, los módulos de proveedores deben configurar LOCAL_VENDOR_MODULE
o LOCAL_PROPRIETARY_MODULE
como true
.
Si se define BOARD_VNDK_VERSION
, el sistema de compilación no permite dependencias entre los módulos del proveedor y los módulos del framework, y emite errores en los siguientes casos:
- un módulo sin
vendor:true
depende de un módulo convendor:true
- Un módulo con
vendor:true
depende de un módulo que no esllndk_library
que no tienevendor:true
nivendor_available:true
.
La verificación de dependencias se aplica a header_libs
, static_libs
y shared_libs
en Android.bp
, y a LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
y LOCAL_SHARED_LIBRARIES
en Android.mk
.
LL-NDK
Las bibliotecas compartidas de LL-NDK son bibliotecas compartidas con ABI estables. Tanto el framework como los módulos del proveedor comparten la misma implementación y la más reciente. Para cada biblioteca compartida de LL-NDK, cc_library
contiene una propiedad llndk
con un archivo de símbolos:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
El archivo de símbolos describe los símbolos visibles para los módulos del proveedor. Por ejemplo:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
En función del archivo de símbolos, el sistema de compilación genera una biblioteca compartida de stub para los módulos de proveedores, que se vinculan con estas bibliotecas cuando se habilita BOARD_VNDK_VERSION
. Se incluye un símbolo en la biblioteca compartida del stub solo si cumple con las siguientes condiciones:
- No se define en la sección que termina con
_PRIVATE
o_PLATFORM
. - No tiene la etiqueta
#platform-only
. - No tiene etiquetas
#introduce*
o la etiqueta coincide con el objetivo.
VNDK
En los archivos Android.bp
, las definiciones de módulos de cc_library
, cc_library_static
, cc_library_shared
y cc_library_headers
admiten tres propiedades relacionadas con VNDK: vendor_available
, vndk.enabled
y vndk.support_system_process
.
Si vendor_available
o vndk.enabled
es true
, se pueden compilar dos variantes (core y vendor). La variante principal debe tratarse como un módulo de framework y la variante del proveedor debe tratarse como un módulo de proveedor. Si algunos módulos del framework dependen de este módulo, se compila la variante principal. Si algunos módulos de proveedores dependen de este módulo, se compila la variante del proveedor. El sistema de compilación aplica las siguientes verificaciones de dependencias:
- La variante principal siempre es solo para el framework y no es accesible para los módulos del proveedor.
- Los módulos del framework siempre pueden acceder a la variante del proveedor.
- Todas las dependencias de la variante del proveedor, que se especifican en
header_libs
,static_libs
oshared_libs
, deben serllndk_library
o un módulo convendor_available
ovndk.enabled
. - Si
vendor_available
estrue
, todos los módulos del proveedor pueden acceder a la variante del proveedor. - Si
vendor_available
esfalse
, solo se podrá acceder a la variante del proveedor a otros módulos del VNDK o VNDK-SP (es decir, los módulos convendor:true
no pueden vincular módulosvendor_available:false
).
La ruta de instalación predeterminada para cc_library
o
cc_library_shared
se determina según las siguientes reglas:
- La variante principal se instala en
/system/lib[64]
. - La ruta de instalación de la variante del proveedor puede variar:
- Si
vndk.enabled
esfalse
, la variante del proveedor se instala en/vendor/lib[64]
. - Si
vndk.enabled
estrue
, la variante del proveedor se instala en VNDK APEX(com.android.vndk.v${VER}
).
- Si
En la siguiente tabla, se resume la manera en que el sistema de compilación maneja las variantes de los proveedores:
vendor_available | vndk enabled |
vndk support_same_process |
Descripciones de las variantes del proveedor |
---|---|---|---|
true |
false |
false |
Las variantes del proveedor son VND-ONLY. Las bibliotecas compartidas se instalan en /vendor/lib[64] . |
true |
No válido (error de compilación) | ||
true |
false |
Las variantes del proveedor son VNDK. Las bibliotecas compartidas se instalan en VNDK APEX. | |
true |
Las variantes del proveedor son VNDK-SP. Las bibliotecas compartidas se instalan en VNDK APEX. | ||
|
|
|
No hay variantes de proveedores. Este módulo es SOLO PARA FWK. |
true |
No válido (error de compilación) | ||
true |
false |
Las variantes del proveedor son VNDK-Private. Las bibliotecas compartidas se instalan en VNDK APEX. Los módulos de proveedores no deben usarlos directamente. | |
true |
Las variantes del proveedor son VNDK-SP-Private. Las bibliotecas compartidas se instalan en VNDK APEX. Los módulos de proveedores no deben usarlos directamente. |
Extensiones del VNDK
Las extensiones de VNDK son bibliotecas compartidas de VNDK con APIs adicionales. Las extensiones se instalan en /vendor/lib[64]/vndk[-sp]
(sin sufijo de versión) y anula las bibliotecas compartidas del VNDK original en el tiempo de ejecución.
Define las extensiones del VNDK
En Android 9 y versiones posteriores, Android.bp
admite de forma nativa las extensiones de VNDK. Para compilar una extensión de VNDK, define otro módulo con una vendor:true
y una propiedad extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Un módulo con propiedades vendor:true
, vndk.enabled:true
y extends
define la extensión de VNDK:
- La propiedad
extends
debe especificar un nombre de biblioteca compartida de VNDK base (o un nombre de biblioteca compartida de VNDK-SP). - Las extensiones del VNDK (o extensiones del VNDK-SP) se nombran según los nombres de los módulos base desde los que se extienden. Por ejemplo, el binario de salida de
libvndk_ext
eslibvndk.so
en lugar delibvndk_ext.so
. - Las extensiones de VNDK se instalan en
/vendor/lib[64]/vndk
. - Las extensiones de VNDK-SP se instalan en
/vendor/lib[64]/vndk-sp
. - Las bibliotecas compartidas básicas deben tener
vndk.enabled:true
yvendor_available:true
.
Una extensión de VNDK-SP debe extenderse desde una biblioteca compartida de VNDK-SP (vndk.support_system_process
debe ser igual):
cc_library { name: "libvndk_sp", vendor_available: true, vndk: { enabled: true, support_system_process: true, }, } cc_library { name: "libvndk_sp_ext", vendor: true, vndk: { enabled: true, extends: "libvndk_sp", support_system_process: true, }, }
Las extensiones del VNDK (o extensiones del VNDK-SP) pueden depender de bibliotecas compartidas de otros proveedores:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, shared_libs: [ "libvendor", ], } cc_library { name: "libvendor", vendor: true, }
Cómo usar extensiones del VNDK
Si un módulo de proveedor depende de APIs adicionales definidas por extensiones de VNDK, el módulo debe especificar el nombre de la extensión de VNDK en su propiedad shared_libs
:
// A vendor shared library example cc_library { name: "libvendor", vendor: true, shared_libs: [ "libvndk_ext", ], } // A vendor executable example cc_binary { name: "vendor-example", vendor: true, shared_libs: [ "libvndk_ext", ], }
Si un módulo de proveedor depende de extensiones de VNDK, esas extensiones de VNDK se instalan en /vendor/lib[64]/vndk[-sp]
automáticamente. Si un módulo ya no depende de una extensión de VNDK, agrega un paso de limpieza a CleanSpec.mk
para quitar la biblioteca compartida. Por ejemplo:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Compilación condicional
En esta sección, se describe cómo abordar las diferencias sutiles (p.ej., agregar o quitar una función de una de las variantes) entre las siguientes tres bibliotecas compartidas de VNDK:
- Variante principal (p.ej.,
/system/lib[64]/libexample.so
) - Variante del proveedor (p.ej.,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Extensión del VNDK (p.ej.,
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Marcas de compilador condicionales
El sistema de compilación de Android define __ANDROID_VNDK__
para las variantes del proveedor y las extensiones de VNDK de forma predeterminada. Puedes proteger el código con los protectores del preprocesador C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Además de __ANDROID_VNDK__
, se pueden especificar diferentes cflags
o cppflags
en Android.bp
. El cflags
o cppflags
que se especifica en target.vendor
es específico de la variante del proveedor.
Por ejemplo, el siguiente Android.bp
define libexample
y libexample_ext
:
cc_library { name: "libexample", srcs: ["src/example.c"], vendor_available: true, vndk: { enabled: true, }, target: { vendor: { cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"], }, }, } cc_library { name: "libexample_ext", srcs: ["src/example.c"], vendor: true, vndk: { enabled: true, extends: "libexample", }, cflags: [ "-DLIBEXAMPLE_ENABLE_VNDK=1", "-DLIBEXAMPLE_ENABLE_VNDK_EXT=1", ], }
Esta es la lista de código de src/example.c
:
void all() { } #if !defined(LIBEXAMPLE_ENABLE_VNDK) void framework_only() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK) void vndk() { } #endif #if defined(LIBEXAMPLE_ENABLE_VNDK_EXT) void vndk_ext() { } #endif
Según estos dos archivos, el sistema de compilación genera bibliotecas compartidas con los siguientes símbolos exportados:
Ruta de instalación | Símbolos exportados |
---|---|
/system/lib[64]/libexample.so |
all , framework_only |
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so |
all , vndk |
/vendor/lib[64]/vndk/libexample.so |
all , vndk y vndk_ext |
Requisitos para los símbolos exportados
El verificador de ABI de VNDK compara la ABI de las variantes de proveedores de VNDK y las extensiones de VNDK con los volcados de ABI de referencia en prebuilts/abi-dumps/vndk
.
- Los símbolos exportados por variantes de proveedores del VNDK (p.ej.,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) deben ser idénticos a los símbolos definidos en los volcados de ABI (no los superconjuntos de estos). - Los símbolos exportados por las extensiones de VNDK (p.ej.,
/vendor/lib[64]/vndk/libexample.so
) deben ser superconjuntos de los símbolos definidos en los volcados de ABI.
Si las variantes de proveedores de VNDK o las extensiones de VNDK no cumplen con los requisitos anteriores, el verificador de ABI de VNDK emite errores de compilación y detiene la compilación.
Excluye archivos fuente o bibliotecas compartidas de las variantes de proveedores
Para excluir los archivos de origen de la variante del proveedor, agrégalos a la propiedad exclude_srcs
. Del mismo modo, para garantizar que las bibliotecas compartidas no estén vinculadas con la variante del proveedor, agrega esas bibliotecas a la propiedad exclude_shared_libs
. Por ejemplo:
cc_library { name: "libexample_cond_exclude", srcs: ["fwk.c", "both.c"], shared_libs: ["libfwk_only", "libboth"], vendor_available: true, target: { vendor: { exclude_srcs: ["fwk.c"], exclude_shared_libs: ["libfwk_only"], }, }, }
En este ejemplo, la variante principal de libexample_cond_exclude
incluye el código de fwk.c
y both.c
, y depende de las bibliotecas compartidas libfwk_only
y libboth
. La variante del proveedor de libexample_cond_exclude
solo incluye el código de both.c
porque la propiedad exclude_srcs
excluye fwk.c
. Del mismo modo, solo depende de la biblioteca compartida libboth
porque la propiedad exclude_shared_libs
excluye libfwk_only
.
Exporta encabezados de extensiones del VNDK
Una extensión de VNDK puede agregar clases o funciones nuevas a una biblioteca compartida de VNDK. Se recomienda mantener esas declaraciones en encabezados independientes y evitar cambiar los encabezados existentes.
Por ejemplo, se crea un nuevo archivo de encabezado include-ext/example/ext/feature_name.h
para la extensión libexample_ext
de VNDK:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
En el siguiente Android.bp
, libexample
solo exporta include
, mientras que libexample_ext
exporta include
y include-ext
. Esto garantiza que los usuarios de libexample
no incluyan incorrectamente feature_name.h
:
cc_library { name: "libexample", srcs: ["src/example.c"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample_ext", srcs: [ "src/example.c", "src/ext/feature_name.c", ], export_include_dirs: [ "include", "include-ext", ], vendor: true, vndk: { enabled: true, extends: "libexample", }, }
Si no es posible separar las extensiones en archivos de encabezado independientes, una alternativa es agregar protecciones #ifdef
. Sin embargo, asegúrate de que todos los usuarios de la extensión de VNDK agreguen las marcas de definición. Puedes definir cc_defaults
para agregar marcas de definición a cflags
y vincular bibliotecas compartidas con shared_libs
.
Por ejemplo, para agregar una nueva función de miembro Example2::get_b()
a la extensión libexample2_ext
del VNDK, debes modificar el archivo de encabezado existente y agregar una protección #ifdef
:
#ifndef LIBEXAMPLE2_EXAMPLE_H_ #define LIBEXAMPLE2_EXAMPLE_H_ class Example2 { public: Example2(); void get_a(); #ifdef LIBEXAMPLE2_ENABLE_VNDK_EXT void get_b(); #endif private: void *impl_; }; #endif // LIBEXAMPLE2_EXAMPLE_H_
Se define un cc_defaults
llamado libexample2_ext_defaults
para los usuarios de libexample2_ext
:
cc_library { name: "libexample2", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libexample2_ext", srcs: ["src/example2.cpp"], export_include_dirs: ["include"], vendor: true, vndk: { enabled: true, extends: "libexample2", }, cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], } cc_defaults { name: "libexample2_ext_defaults", shared_libs: [ "libexample2_ext", ], cflags: [ "-DLIBEXAMPLE2_ENABLE_VNDK_EXT=1", ], }
Los usuarios de libexample2_ext
pueden simplemente incluir
libexample2_ext_defaults
en su propiedad defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Paquetes de productos
En el sistema de compilación de Android, la variable PRODUCT_PACKAGES
especifica los ejecutables, las bibliotecas compartidas o los paquetes que se deben instalar en el dispositivo. Las dependencias transitivas de los módulos especificados también se instalan de forma implícita en el dispositivo.
Si BOARD_VNDK_VERSION
está habilitado, los módulos con vendor_available
o vndk.enabled
reciben un tratamiento especial. Si un módulo de framework depende de un módulo con vendor_available
o vndk.enabled
, la variante principal se incluye en el conjunto de instalación transitiva. Si un módulo del proveedor depende de un módulo con vendor_available
, la variante del proveedor se incluye en el conjunto de instalación transitivo. Sin embargo, las variantes de proveedores de módulos con vndk.enabled
se instalan, independientemente de si los módulos de proveedores las usan o no.
Cuando las dependencias son invisibles para el sistema de compilación (p.ej., bibliotecas compartidas que se pueden abrir con dlopen()
en el entorno de ejecución), debes especificar los nombres de los módulos en PRODUCT_PACKAGES
para instalarlos de forma explícita.
Si un módulo tiene vendor_available
o vndk.enabled
, el nombre del módulo representa su variante principal. Para especificar de forma explícita la variante del proveedor en PRODUCT_PACKAGES
, agrega un sufijo .vendor
al nombre del módulo. Por ejemplo:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
En este ejemplo, libexample
representa /system/lib[64]/libexample.so
y libexample.vendor
representa /vendor/lib[64]/libexample.so
. Para instalar /vendor/lib[64]/libexample.so
, agrega libexample.vendor
a PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor