In Android 8.1 e versioni successive, il sistema di compilazione ha il supporto VNDK integrato. Quando l'assistenza VNDK è attivata, il sistema di compilazione controlla le dipendenze tra i moduli, crea una variante specifica per il fornitore per i moduli del fornitore e li installa automaticamente in directory designate.
Esempio di supporto per la compilazione VNDK
In questo esempio, la definizione del modulo Android.bp
definisce una libreria denominata libexample
. La proprietà vendor_available
indica che i moduli del framework e i moduli del fornitore possono dipendere da
libexample
:
Supporto Figura 1. attivato.
Sia l'eseguibile del framework /system/bin/foo
sia l'eseguibile del fornitore /vendor/bin/bar
dipendono da libexample
e hanno libexample
nelle proprietà shared_libs
.
Se libexample
viene utilizzato sia dai moduli del framework sia dai moduli del fornitore, vengono create due varianti di libexample
. La variante di base
(nome basato su libexample
) viene utilizzata dai moduli del framework e la
variante del fornitore (nome basato su libexample.vendor
) viene utilizzata dai moduli del fornitore. Le due varianti vengono installate in directory diverse:
- La variante principale è installata in
/system/lib[64]/libexample.so
. - La variante del fornitore è installata in VNDK APEX perché
vndk.enabled
ètrue
.
Per ulteriori dettagli, consulta Definizione del modulo.
Configurare il supporto per la compilazione
Per attivare il supporto completo del sistema di compilazione per un dispositivo di prodotto, aggiungi BOARD_VNDK_VERSION
a BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Questa impostazione ha un effetto globale: se definita in
BoardConfig.mk
, vengono selezionati tutti i moduli. Poiché non esiste un meccanismo per inserire un modulo in una lista consentita o bloccata, devi eliminare tutte le dipendenze non necessarie prima di aggiungere BOARD_VNDK_VERSION
. Puoi testare e compilare un modulo impostando BOARD_VNDK_VERSION
nelle variabili di ambiente:
$ BOARD_VNDK_VERSION=current m module_name.vendor
Quando BOARD_VNDK_VERSION
è attivato, diversi percorsi di ricerca delle intestazioni globali predefinite vengono rimossi. come le seguenti.
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
Se un modulo dipende dalle intestazioni di queste directory, devi specificare (esplicitamente) le dipendenze con header_libs
, static_libs
e/o shared_libs
.
VNDK APEX
In Android 10 e versioni precedenti, i moduli con vndk.enabled
sono stati installati in
/system/lib[64]/vndk[-sp]-${VER}
. In Android 11 e versioni successive, le librerie VNDK sono pacchettizzate in formato APEX e il nome VNDK APEX è com.android.vndk.v${VER}
. A seconda della configurazione del dispositivo, VNDK APEX è appiattito o non appiattito ed è disponibile dal percorso canonico /apex/com.android.vndk.v${VER}
.
Figura 2. VNDK APEX.
Definizione del modulo
Per compilare Android con BOARD_VNDK_VERSION
, devi rivedere la definizione del modulo in Android.mk
o Android.bp
. Questa sezione descrive diversi tipi di definizioni di moduli, diverse proprietà dei moduli relative a VNDK e controlli delle dipendenze implementati nel sistema di compilazione.
Moduli del fornitore
I moduli del fornitore sono eseguibili o librerie condivise specifici del fornitore che devono essere installati in una partizione del fornitore. Nei file Android.bp
,
i moduli del fornitore devono impostare la proprietà del fornitore o proprietaria su true
.
Nei file Android.mk
, i moduli del fornitore devono impostare LOCAL_VENDOR_MODULE
o LOCAL_PROPRIETARY_MODULE
su true
.
Se è definito BOARD_VNDK_VERSION
, il sistema di compilazione non consente le dipendenze tra i moduli del fornitore e i moduli del framework ed emette errori se:
- un modulo senza
vendor:true
dipende da un modulo convendor:true
oppure - un modulo con
vendor:true
dipende da un modulo nonllndk_library
che non ha névendor:true
névendor_available:true
.
Il controllo delle dipendenze si applica a header_libs
,
static_libs
e shared_libs
in
Android.bp
e a LOCAL_HEADER_LIBRARIES
,
LOCAL_STATIC_LIBRARIES
e LOCAL_SHARED_LIBRARIES
in
Android.mk
.
LL-NDK
Le librerie condivise LL-NDK sono librerie condivise con ABI stabili. Sia i moduli del framework sia i moduli del fornitore condividono la stessa implementazione e la più recente. Per ogni
libreria condivisa LL-NDK, cc_library
contiene una
proprietà llndk
con un file di simboli:
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Il file dei simboli descrive i simboli visibili nei moduli del fornitore. Ad esempio:
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
In base al file dei simboli, il sistema di compilazione genera una libreria condivisa stub per i moduli del fornitore, che si collegano a queste librerie quando BOARD_VNDK_VERSION
è abilitato. Un simbolo viene incluso nella libreria condivisa dello stub solo se:
- Non è definito nella sezione che termina con
_PRIVATE
o_PLATFORM
, - Non ha il tag
#platform-only
e - Non ha tag
#introduce*
o il tag corrisponde al target.
VNDK
Nei file Android.bp
, le definizioni dei moduli cc_library
,
cc_library_static
, cc_library_shared
e
cc_library_headers
supportano tre proprietà relative al VNDK: vendor_available
, vndk.enabled
e
vndk.support_system_process
.
Se vendor_available
o vndk.enabled
è true
, è possibile creare due varianti (core e vendor). La variante principale deve essere trattata come un modulo del framework e la variante del fornitore deve essere trattata come un modulo del fornitore. Se alcuni moduli del framework dipendono da questo modulo, viene compilata la variante di base. Se alcuni moduli del fornitore
dipendono da questo modulo, viene creata la variante del fornitore. Il sistema di compilazione applica i seguenti controlli delle dipendenze:
- La variante di base è sempre solo per il framework e non è accessibile ai moduli del fornitore.
- La variante del fornitore è sempre inaccessibile ai moduli del framework.
- Tutte le dipendenze della variante del fornitore, specificate in
header_libs
,static_libs
e/oshared_libs
, devono essere unllndk_library
o un modulo convendor_available
ovndk.enabled
. - Se
vendor_available
ètrue
, la variante del fornitore è accessibile a tutti i moduli del fornitore. - Se
vendor_available
èfalse
, la variante del fornitore è accessibile solo ad altri moduli VNDK o VNDK-SP (ovvero i moduli convendor:true
non possono collegare i modulivendor_available:false
).
Il percorso di installazione predefinito per cc_library
o
cc_library_shared
è determinato dalle seguenti regole:
- La variante principale è installata in
/system/lib[64]
. - Il percorso di installazione della variante del fornitore può variare:
- Se
vndk.enabled
èfalse
, la variante del fornitore viene installata in/vendor/lib[64]
. - Se
vndk.enabled
ètrue
, la variante del fornitore viene installata in VNDK APEX(com.android.vndk.v${VER}
).
- Se
La tabella seguente riassume il modo in cui il sistema di compilazione gestisce le varianti del fornitore:
vendor_available | vndk enabled |
vndk support_same_process |
Descrizioni delle varianti del fornitore |
---|---|---|---|
true |
false |
false |
Le varianti del fornitore sono SOLO VND. Le librerie condivise sono installate in /vendor/lib[64] . |
true |
Non valido (errore di compilazione) | ||
true |
false |
Le varianti del fornitore sono VNDK. Le librerie condivise vengono installate in VNDK APEX. | |
true |
Le varianti del fornitore sono VNDK-SP. Le librerie condivise vengono installate in VNDK APEX. | ||
|
|
|
Nessuna variante del fornitore. Questo modulo è SOLO PER IL FRAMEWORK. |
true |
Non valido (errore di compilazione) | ||
true |
false |
Le varianti del fornitore sono VNDK-Private. Le librerie condivise vengono installate in VNDK APEX. Questi non devono essere utilizzati direttamente dai moduli del fornitore. | |
true |
Le varianti del fornitore sono VNDK-SP-Private. Le librerie condivise vengono installate in VNDK APEX. Non devono essere utilizzati direttamente dai moduli del fornitore. |
Estensioni VNDK
Le estensioni VNDK sono librerie condivise VNDK con API aggiuntive. Le estensioni vengono installate in /vendor/lib[64]/vndk[-sp]
(senza suffisso di versione) e sostituiscono le librerie condivise VNDK originali in fase di esecuzione.
Definizione delle estensioni VNDK
In Android 9 e versioni successive, Android.bp
supporta in modo nativo le estensioni VNDK. Per creare un'estensione VNDK, definisci un altro modulo con una proprietà vendor:true
e extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Un modulo con le proprietà vendor:true
, vndk.enabled:true
e extends
definisce l'estensione VNDK:
- La proprietà
extends
deve specificare un nome di libreria condivisa VNDK di base (o il nome di una libreria condivisa VNDK-SP). - Le estensioni VNDK (o estensioni VNDK-SP) prendono il nome dai nomi dei moduli di base da cui si estendono. Ad esempio, il programma binario di output di
libvndk_ext
èlibvndk.so
anzichélibvndk_ext.so
. - Le estensioni VNDK vengono installate in
/vendor/lib[64]/vndk
. - Le estensioni VNDK-SP vengono installate in
/vendor/lib[64]/vndk-sp
. - Le librerie condivise di base devono avere sia
vndk.enabled:true
chevendor_available:true
.
Un'estensione VNDK-SP deve estendersi da una libreria condivisa VNDK-SP (vndk.support_system_process
deve essere uguale a):
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, }, }
Le estensioni VNDK (o VNDK-SP) possono dipendere da altre librerie condivise del fornitore:
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, }
Utilizzare le estensioni VNDK
Se un modulo del fornitore dipende da API aggiuntive definite dalle estensioni VNDK, il modulo deve specificare il nome dell'estensione VNDK nella sua proprietà 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", ], }
Se un modulo del fornitore dipende da estensioni VNDK, queste estensioni VNDK vengono installate automaticamente in /vendor/lib[64]/vndk[-sp]
. Se un modulo non dipende più da un'estensione VNDK, aggiungi un passaggio pulito a CleanSpec.mk
per rimuovere la libreria condivisa. Ad esempio:
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Compilazione condizionale
Questa sezione descrive come gestire le piccole differenze (ad es. l'aggiunta o la rimozione di una funzionalità da una delle varianti) tra le seguenti tre librerie condivise VNDK:
- Variante principale (ad es.
/system/lib[64]/libexample.so
) - Variante del fornitore (ad es.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Estensione VNDK (ad es.
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Flag del compilatore condizionale
Per impostazione predefinita, il sistema di build di Android definisce __ANDROID_VNDK__
per le varianti del fornitore e le estensioni VNDK. Puoi proteggere il codice
con protezioni del preprocessore C:
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
Oltre a __ANDROID_VNDK__
, in Android.bp
è possibile specificare diversi cflags
o cppflags
. Il valore cflags
o cppflags
specificato in target.vendor
è specifico per la variante del fornitore.
Ad esempio, il seguente Android.bp
definisce libexample
e 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", ], }
Questa è la lista di codici di 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
In base a questi due file, il sistema di compilazione genera librerie condivise con i seguenti simboli esportati:
Percorso di installazione | Simboli esportati |
---|---|
/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 e vndk_ext |
Requisiti relativi ai simboli esportati
Lo strumento VNDK ABI checker
confronta l'ABI delle varianti del fornitore VNDK e delle estensioni VNDK con i dump ABI di riferimento in prebuilts/abi-dumps/vndk
.
- I simboli esportati dalle varianti del fornitore VNDK (ad es.
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) devono essere identici (non i soprainsiemi) ai simboli definiti nei dump delle ABI. - I simboli esportati dalle estensioni VNDK (ad es.
/vendor/lib[64]/vndk/libexample.so
) devono essere superset dei simboli definiti nei dump ABI.
Se le varianti del fornitore VNDK o le estensioni VNDK non rispettano i requisiti precedenti, lo strumento di controllo ABI VNDK emette errori di compilazione e interrompe la compilation.
Escludere i file di origine o le librerie condivise dalle varianti del fornitore
Per escludere i file di origine dalla variante del fornitore, aggiungili alla proprietà exclude_srcs
. Analogamente, per assicurarti che le librerie condivise non siano collegate alla variante del fornitore, aggiungile alla proprietà exclude_shared_libs
. Ad esempio:
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"], }, }, }
In questo esempio, la variante principale di libexample_cond_exclude
include il codice di fwk.c
e both.c
e dipende dalle librerie condivise libfwk_only
e libboth
. La
variante del fornitore di libexample_cond_exclude
include solo il codice
di both.c
perché fwk.c
è escluso dalla
proprietà exclude_srcs
. Analogamente, dipende solo dalla raccolta condivisa
libboth
perché libfwk_only
è esclusa dalla proprietà
exclude_shared_libs
.
Esportare le intestazioni dalle estensioni VNDK
Un'estensione VNDK può aggiungere nuove classi o nuove funzioni a una libreria VNDK condivisa. Ti consigliamo di mantenere queste dichiarazioni in intestazioni indipendenti ed evitare di modificare quelle esistenti.
Ad esempio, viene creato un nuovo file di intestazioneinclude-ext/example/ext/feature_name.h
per l'estensione VNDKlibexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
Nel seguente Android.bp
, libexample
esporta solo include
, mentre libexample_ext
esporta sia include
sia include-ext
. In questo modo,
feature_name.h
non verrà incluso erroneamente dagli utenti di
libexample
:
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", }, }
Se non è possibile separare le estensioni in file di intestazione indipendenti, un'alternativa è aggiungere #ifdef
guard. Tuttavia, assicurati che tutti gli utenti dell'estensione VNDK aggiungano i flag di definizione. Puoi definire
cc_defaults
per aggiungere flag di definizione a cflags
e collegare
le librerie condivise con shared_libs
.
Ad esempio, per aggiungere una nuova funzione membro Example2::get_b()
all'estensione VNDK libexample2_ext
, devi modificare il file di intestazione esistente e aggiungere un'istruzione di guardia #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_
Per gli utenti di libexample2_ext
è stato definito un cc_defaults
denominato libexample2_ext_defaults
:
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", ], }
Gli utenti di libexample2_ext
possono semplicemente includere
libexample2_ext_defaults
nella loro
proprietà defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Pacchetti di prodotti
Nel sistema di build Android, la variabile PRODUCT_PACKAGES
specifica gli eseguibili, le librerie condivise o i pacchetti che devono essere
installati nel dispositivo. Anche le dipendenze transitive dei moduli specificati vengono installate implicitamente nel dispositivo.
Se BOARD_VNDK_VERSION
è attivato, i moduli con vendor_available
o vndk.enabled
ricevono un trattamento speciale. Se un modulo del framework dipende da un modulo con vendor_available
o vndk.enabled
, la variante di base è inclusa nel set di installazione transitivo. Se un modulo del fornitore dipende da un modulo con vendor_available
, la variante del fornitore è inclusa nel set di installazione transitiva. Tuttavia, le varianti del fornitore dei moduli con vndk.enabled
vengono installate indipendentemente dal fatto che vengano utilizzate o meno dai moduli del fornitore.
Quando le dipendenze sono invisibili al sistema di compilazione (ad es. le librerie condivise che possono essere aperte con dlopen()
in fase di esecuzione), devi specificare i nomi dei moduli in PRODUCT_PACKAGES
per installarli esplicitamente.
Se un modulo ha vendor_available
o vndk.enabled
,
il nome del modulo indica la variante principale. Per specificare esplicitamente la variante del fornitore in PRODUCT_PACKAGES
, aggiungi un suffisso .vendor
al nome del modulo. Ad esempio:
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
In questo esempio, libexample
indica /system/lib[64]/libexample.so
e libexample.vendor
indica /vendor/lib[64]/libexample.so
. Per installare
/vendor/lib[64]/libexample.so
, aggiungi libexample.vendor
a PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor