Dans Android 8.1 et versions ultérieures, le système de compilation est compatible avec le VNDK. Lorsque la prise en charge du VNDK est activée, le système de compilation vérifie les dépendances entre les modules, crée une variante spécifique au fournisseur pour les modules du fournisseur et installe automatiquement ces modules dans les répertoires désignés.
Exemple de prise en charge de la compilation VNDK
Dans cet exemple, la définition du module Android.bp
définit une bibliothèque nommée libexample
. La propriété vendor_available
indique que les modules de framework et les modules de fournisseur peuvent dépendre de libexample
:
Figure 1 : Compatibilité activée.
L'exécutable du framework /system/bin/foo
et l'exécutable du fournisseur /vendor/bin/bar
dépendent de libexample
et ont libexample
dans leurs propriétés shared_libs
.
Si libexample
est utilisé à la fois par les modules de framework et les modules du fournisseur, deux variantes de libexample
sont créées. La variante principale (nommée d'après libexample
) est utilisée par les modules du framework, et la variante du fournisseur (nommée d'après libexample.vendor
) est utilisée par les modules du fournisseur. Les deux variantes sont installées dans des répertoires différents :
- La variante principale est installée dans
/system/lib[64]/libexample.so
. - La variante du fournisseur est installée dans VNDK APEX, car
vndk.enabled
esttrue
.
Pour en savoir plus, consultez Définition du module.
Configurer la compatibilité avec les builds
Pour activer la prise en charge complète du système de compilation pour un appareil produit, ajoutez BOARD_VNDK_VERSION
à BoardConfig.mk
:
BOARD_VNDK_VERSION := current
Ce paramètre a un effet global : lorsqu'il est défini dans BoardConfig.mk
, tous les modules sont vérifiés. Comme il n'existe aucun mécanisme permettant d'ajouter un module incriminé à une liste noire ou blanche, vous devez supprimer toutes les dépendances inutiles avant d'ajouter BOARD_VNDK_VERSION
. Vous pouvez tester et compiler un module en définissant BOARD_VNDK_VERSION
dans vos variables d'environnement :
$ BOARD_VNDK_VERSION=current m module_name.vendor
Lorsque BOARD_VNDK_VERSION
est activé, plusieurs chemins de recherche d'en-tête globaux par défaut sont supprimés. En voici quelques exemples :
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 module dépend des en-têtes de ces répertoires, vous devez spécifier (de manière explicite) les dépendances avec header_libs
, static_libs
et/ou shared_libs
.
VNDK APEX
Dans Android 10 et versions antérieures, les modules avec vndk.enabled
étaient installés dans /system/lib[64]/vndk[-sp]-${VER}
. Dans Android 11 et versions ultérieures, les bibliothèques VNDK sont empaquetées au format APEX et le nom de VNDK APEX est com.android.vndk.v${VER}
. Selon la configuration de l'appareil, VNDK APEX est aplatie ou non aplatie et est disponible à partir du chemin canonique /apex/com.android.vndk.v${VER}
.
Figure 2. VNDK APEX.
Définition du module
Pour compiler Android avec BOARD_VNDK_VERSION
, vous devez modifier la définition du module dans Android.mk
ou Android.bp
. Cette section décrit différents types de définitions de modules, plusieurs propriétés de modules liées au VNDK et les vérifications de dépendances implémentées dans le système de compilation.
Modules du fournisseur
Les modules du fournisseur sont des exécutables ou des bibliothèques partagées spécifiques au fournisseur qui doivent être installés dans une partition du fournisseur. Dans les fichiers Android.bp
, les modules du fournisseur doivent définir la propriété du fournisseur ou propriétaire sur true
.
Dans les fichiers Android.mk
, les modules du fournisseur doivent définir LOCAL_VENDOR_MODULE
ou LOCAL_PROPRIETARY_MODULE
sur true
.
Si BOARD_VNDK_VERSION
est défini, le système de compilation interdit les dépendances entre les modules du fournisseur et les modules du framework, et génère des erreurs si :
- un module sans
vendor:true
dépend d'un module avecvendor:true
; - un module avec
vendor:true
dépend d'un module non-llndk_library
qui ne comporte nivendor:true
nivendor_available:true
.
La vérification des dépendances s'applique à header_libs
, static_libs
et shared_libs
dans Android.bp
, ainsi qu'à LOCAL_HEADER_LIBRARIES
, LOCAL_STATIC_LIBRARIES
et LOCAL_SHARED_LIBRARIES
dans Android.mk
.
LL-NDK
Les bibliothèques partagées LL-NDK sont des bibliothèques partagées avec des ABI stables. Les modules du framework et du fournisseur partagent la même implémentation, qui est la plus récente. Pour chaque bibliothèque partagée LL-NDK, le fichier cc_library
contient une propriété llndk
avec un fichier de symboles :
cc_library { name: "libvndksupport", llndk: { symbol_file: "libvndksupport.map.txt", }, }
Le fichier de symboles décrit les symboles visibles par les modules du fournisseur. Exemple :
LIBVNDKSUPPORT { global: android_load_sphal_library; # llndk android_unload_sphal_library; # llndk local: *; };
En fonction du fichier de symboles, le système de compilation génère une bibliothèque partagée de stub pour les modules du fournisseur, qui sont associés à ces bibliothèques lorsque BOARD_VNDK_VERSION
est activé. Un symbole n'est inclus dans la bibliothèque partagée du stub que s'il :
- n'est pas défini dans la section se terminant par
_PRIVATE
ou_PLATFORM
. - Aucune balise
#platform-only
n'est configurée. - Aucune balise
#introduce*
n'est présente ou la balise correspond à la cible.
VNDK
Dans les fichiers Android.bp
, les définitions de module cc_library
, cc_library_static
, cc_library_shared
et cc_library_headers
sont compatibles avec trois propriétés liées au VNDK : vendor_available
, vndk.enabled
et vndk.support_system_process
.
Si vendor_available
ou vndk.enabled
est défini sur true
, deux variantes (core et vendor) peuvent être créées. La variante principale doit être traitée comme un module de framework, et la variante du fournisseur doit être traitée comme un module de fournisseur. Si certains modules de framework dépendent de ce module, la variante principale est créée. Si certains modules de fournisseur dépendent de ce module, la variante du fournisseur est créée. Le système de compilation applique les vérifications de dépendances suivantes :
- La variante principale est toujours réservée au framework et inaccessible aux modules du fournisseur.
- La variante du fournisseur est toujours inaccessible aux modules du framework.
- Toutes les dépendances de la variante du fournisseur, spécifiées dans
header_libs
,static_libs
et/oushared_libs
, doivent être unllndk_library
ou un module avecvendor_available
ouvndk.enabled
. - Si la valeur de
vendor_available
esttrue
, la variante du fournisseur est accessible à tous les modules du fournisseur. - Si
vendor_available
est défini surfalse
, la variante du fournisseur n'est accessible qu'aux autres modules VNDK ou VNDK-SP (c'est-à-dire que les modules avecvendor:true
ne peuvent pas associer les modulesvendor_available:false
).
Le chemin d'installation par défaut de cc_library
ou cc_library_shared
est déterminé par les règles suivantes :
- La variante principale est installée dans
/system/lib[64]
. - Le chemin d'installation de la variante du fournisseur peut varier :
- Si
vndk.enabled
estfalse
, la variante du fournisseur est installée dans/vendor/lib[64]
. - Si
vndk.enabled
est défini surtrue
, la variante du fournisseur est installée dans VNDK APEX(com.android.vndk.v${VER}
).
- Si
Le tableau ci-dessous récapitule la façon dont le système de compilation gère les variantes du fournisseur :
vendor_available | vndk enabled |
vndk support_system_process |
Descriptions des variantes du fournisseur |
---|---|---|---|
true |
false |
false |
Les variantes du fournisseur sont VND-ONLY. Les bibliothèques partagées sont installées dans /vendor/lib[64] . |
true |
Non valide (erreur de compilation) | ||
true |
false |
Les variantes du fournisseur sont VNDK. Les bibliothèques partagées sont installées dans VNDK APEX. | |
true |
Les variantes du fournisseur sont VNDK-SP. Les bibliothèques partagées sont installées dans VNDK APEX. | ||
|
|
|
Aucune variante de fournisseur. Ce module est FWK-ONLY. |
true |
Non valide (erreur de compilation) | ||
true |
false |
Les variantes du fournisseur sont VNDK-Private. Les bibliothèques partagées sont installées dans VNDK APEX. Ils ne doivent pas être utilisés directement par les modules du fournisseur. | |
true |
Les variantes du fournisseur sont VNDK-SP-Private. Les bibliothèques partagées sont installées dans VNDK APEX. Ils ne doivent pas être utilisés directement par les modules du fournisseur. |
Extensions VNDK
Les extensions VNDK sont des bibliothèques partagées VNDK avec des API supplémentaires. Les extensions sont installées dans /vendor/lib[64]/vndk[-sp]
(sans suffixe de version) et remplacent les bibliothèques partagées VNDK d'origine au moment de l'exécution.
Définir les extensions VNDK
Dans Android 9 et versions ultérieures, Android.bp
est compatible en mode natif avec les extensions VNDK. Pour créer une extension VNDK, définissez un autre module avec une propriété vendor:true
et une propriété extends
:
cc_library { name: "libvndk", vendor_available: true, vndk: { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, }
Un module avec les propriétés vendor:true
, vndk.enabled:true
et extends
définit l'extension VNDK :
- La propriété
extends
doit spécifier un nom de bibliothèque partagée VNDK de base (ou un nom de bibliothèque partagée VNDK-SP). - Les extensions VNDK (ou VNDK-SP) sont nommées d'après les noms des modules de base à partir desquels elles s'étendent. Par exemple, le fichier binaire de sortie de
libvndk_ext
estlibvndk.so
au lieu delibvndk_ext.so
. - Les extensions VNDK sont installées dans
/vendor/lib[64]/vndk
. - Les extensions VNDK-SP sont installées dans
/vendor/lib[64]/vndk-sp
. - Les bibliothèques partagées de base doivent comporter à la fois
vndk.enabled:true
etvendor_available:true
.
Une extension VNDK-SP doit étendre une bibliothèque partagée VNDK-SP (vndk.support_system_process
doit être égal) :
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, }, }
Les extensions VNDK (ou VNDK-SP) peuvent dépendre d'autres bibliothèques partagées du fournisseur :
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, }
Utiliser les extensions VNDK
Si un module fournisseur dépend d'API supplémentaires définies par les extensions VNDK, le module doit spécifier le nom de l'extension VNDK dans sa propriété 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 module fournisseur dépend des extensions VNDK, ces extensions sont installées automatiquement dans /vendor/lib[64]/vndk[-sp]
. Si un module ne dépend plus d'une extension VNDK, ajoutez une étape de nettoyage à CleanSpec.mk
pour supprimer la bibliothèque partagée. Exemple :
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
Compilation conditionnelle
Cette section explique comment gérer les différences subtiles (par exemple, l'ajout ou la suppression d'une fonctionnalité dans l'une des variantes) entre les trois bibliothèques partagées VNDK suivantes :
- Variante principale (par exemple,
/system/lib[64]/libexample.so
) - Variante du fournisseur (par exemple,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) - Extension VNDK (par exemple,
/vendor/lib[64]/vndk[-sp]/libexample.so
)
Options de compilation conditionnelles
Le système de compilation Android définit __ANDROID_VNDK__
pour les variantes du fournisseur et les extensions VNDK par défaut. Vous pouvez protéger le code avec les protections du préprocesseur C :
void all() { } #if !defined(__ANDROID_VNDK__) void framework_only() { } #endif #if defined(__ANDROID_VNDK__) void vndk_only() { } #endif
En plus de __ANDROID_VNDK__
, vous pouvez spécifier différents cflags
ou cppflags
dans Android.bp
. Le cflags
ou le cppflags
spécifié dans target.vendor
est propre à la variante du fournisseur.
Par exemple, le Android.bp
suivant définit libexample
et 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", ], }
Voici la liste de code 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
Selon ces deux fichiers, le système de compilation génère des bibliothèques partagées avec les symboles exportés suivants :
Chemin d'installation | Symboles exportés |
---|---|
/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 , vndk_ext |
Exigences concernant les symboles exportés
Le vérificateur d'ABI VNDK compare l'ABI des variantes fournisseur VNDK et des extensions VNDK aux dumps d'ABI de référence sous prebuilts/abi-dumps/vndk
.
- Les symboles exportés par les variantes fournisseur VNDK (par exemple,
/apex/com.android.vndk.v${VER}/lib[64]/libexample.so
) doivent être identiques (et non des sur-ensembles) aux symboles définis dans les dumps ABI. - Les symboles exportés par les extensions VNDK (par exemple,
/vendor/lib[64]/vndk/libexample.so
) doivent être des sur-ensembles des symboles définis dans les dumps ABI.
Si les variantes fournisseur VNDK ou les extensions VNDK ne respectent pas les exigences ci-dessus, le vérificateur VNDK ABI émet des erreurs de compilation et arrête la compilation.
Exclure des fichiers sources ou des bibliothèques partagées des variantes du fournisseur
Pour exclure des fichiers sources de la variante du fournisseur, ajoutez-les à la propriété exclude_srcs
. De même, pour vous assurer que les bibliothèques partagées ne sont pas associées à la variante du fournisseur, ajoutez-les à la propriété exclude_shared_libs
. Exemple :
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"], }, }, }
Dans cet exemple, la variante principale de libexample_cond_exclude
inclut le code de fwk.c
et both.c
, et dépend des bibliothèques partagées libfwk_only
et libboth
. La variante fournisseur de libexample_cond_exclude
n'inclut que le code de both.c
, car fwk.c
est exclu par la propriété exclude_srcs
. De même, il ne dépend que de la bibliothèque partagée libboth
, car libfwk_only
est exclu par la propriété exclude_shared_libs
.
Exporter les en-têtes à partir des extensions VNDK
Une extension VNDK peut ajouter de nouvelles classes ou de nouvelles fonctions à une bibliothèque partagée VNDK. Il est suggéré de conserver ces déclarations dans des en-têtes indépendants et d'éviter de modifier les en-têtes existants.
Par exemple, un nouveau fichier d'en-tête include-ext/example/ext/feature_name.h
est créé pour l'extension VNDK libexample_ext
:
- Android.bp
- include-ext/example/ext/feature_name.h
- include/example/example.h
- src/example.c
- src/ext/feature_name.c
Dans l'exemple Android.bp
suivant, libexample
n'exporte que include
, tandis que libexample_ext
exporte include
et include-ext
. Cela permet de s'assurer que feature_name.h
ne sera pas inclus de manière incorrecte par les utilisateurs de 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", }, }
Si la séparation des extensions dans des fichiers d'en-tête indépendants n'est pas possible, une autre solution consiste à ajouter des gardes #ifdef
. Toutefois, assurez-vous que tous les utilisateurs de l'extension VNDK ajoutent les indicateurs de définition. Vous pouvez définir cc_defaults
pour ajouter des indicateurs de définition à cflags
et associer des bibliothèques partagées à shared_libs
.
Par exemple, pour ajouter une fonction membre Example2::get_b()
à l'extension VNDK libexample2_ext
, vous devez modifier le fichier d'en-tête existant et ajouter une protection #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_
Un cc_defaults
nommé libexample2_ext_defaults
est défini pour les utilisateurs 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", ], }
Les utilisateurs de libexample2_ext
peuvent simplement inclure libexample2_ext_defaults
dans leur propriété defaults
:
cc_binary { name: "example2_user_executable", defaults: ["libexample2_ext_defaults"], vendor: true, }
Packages de produits
Dans le système de compilation Android, la variable PRODUCT_PACKAGES
spécifie les exécutables, les bibliothèques partagées ou les packages qui doivent être installés sur l'appareil. Les dépendances transitives des modules spécifiés sont également installées de manière implicite sur l'appareil.
Si BOARD_VNDK_VERSION
est activé, les modules avec vendor_available
ou vndk.enabled
bénéficient d'un traitement spécial. Si un module de framework dépend d'un module avec vendor_available
ou vndk.enabled
, la variante principale est incluse dans l'ensemble d'installation transitive. Si un module fournisseur dépend d'un module avec vendor_available
, la variante fournisseur est incluse dans l'ensemble d'installation transitive. Toutefois, les variantes de modules du fournisseur avec vndk.enabled
sont installées, qu'elles soient utilisées ou non par les modules du fournisseur.
Lorsque les dépendances sont invisibles pour le système de compilation (par exemple, les bibliothèques partagées qui peuvent être ouvertes avec dlopen()
lors de l'exécution), vous devez spécifier les noms de module dans PRODUCT_PACKAGES
pour installer ces modules de manière explicite.
Si un module comporte vendor_available
ou vndk.enabled
, le nom du module correspond à sa variante principale. Pour spécifier explicitement la variante du fournisseur dans PRODUCT_PACKAGES
, ajoutez un suffixe .vendor
au nom du module. Exemple :
cc_library { name: "libexample", srcs: ["example.c"], vendor_available: true, }
Dans cet exemple, libexample
correspond à /system/lib[64]/libexample.so
et libexample.vendor
à /vendor/lib[64]/libexample.so
. Pour installer /vendor/lib[64]/libexample.so
, ajoutez libexample.vendor
à PRODUCT_PACKAGES
:
PRODUCT_PACKAGES += libexample.vendor