Vous pouvez utiliser le format de fichier APEX pour empaqueter et installer des modules d'OS Android de niveau inférieur. Il permet de créer et d'installer indépendamment des composants tels que des services et des bibliothèques natives, des implémentations HAL, des micrologiciels, des fichiers de configuration, etc.
Les APEX du fournisseur sont installés automatiquement par le système de compilation dans la partition /vendor
et activés au moment de l'exécution par apexd
, tout comme les APEX dans d'autres partitions.
Cas d'utilisation
Modularisation des images des fournisseurs
Les APEX facilitent le regroupement et la modularisation naturels des implémentations de fonctionnalités sur les images du fournisseur.
Lorsque les images du fournisseur sont créées en tant que combinaison d'APEX de fournisseurs créés indépendamment, les fabricants d'appareils peuvent facilement choisir les implémentations de fournisseurs spécifiques souhaitées sur leur appareil. Les fabricants peuvent même créer un nouvel APEX de fournisseur si aucun des APEX fournis ne répond à leurs besoins ou s'ils disposent d'un tout nouveau matériel personnalisé.
Par exemple, un OEM peut choisir de composer son appareil avec l'implémentation APEX du Wi-Fi AOSP, l'implémentation APEX du Bluetooth du SoC et une implémentation APEX de téléphonie OEM personnalisée.
Sans APEX du fournisseur, une implémentation avec autant de dépendances entre les composants du fournisseur nécessite une coordination et un suivi minutieux. En encapsulant tous les composants (y compris les fichiers de configuration et les bibliothèques supplémentaires) dans des APEX avec des interfaces clairement définies à tout moment de la communication entre les fonctionnalités, les différents composants deviennent interchangeables.
Itération du développeur
Les APEX du fournisseur aident les développeurs à itérer plus rapidement lors du développement de modules de fournisseurs en regroupant l'ensemble de l'implémentation d'une fonctionnalité, comme le HAL Wi-Fi, dans un APEX du fournisseur. Les développeurs peuvent ensuite créer et transférer individuellement l'APEX du fournisseur pour tester les modifications, au lieu de recréer l'image complète du fournisseur.
Cela simplifie et accélère le cycle d'itération des développeurs qui travaillent principalement dans un seul domaine de fonctionnalités et ne souhaitent itérer que sur ce domaine.
Le regroupement naturel d'une zone d'éléments géographiques dans un APEX simplifie également le processus de compilation, de transfert et de test des modifications pour cette zone d'éléments géographiques. Par exemple, la réinstallation d'un APEX met automatiquement à jour toute bibliothèque groupée ou tout fichier de configuration inclus dans l'APEX.
Le regroupement d'une zone de fonctionnalité dans un APEX simplifie également le débogage ou le rétablissement lorsqu'un mauvais comportement de l'appareil est observé. Par exemple, si la téléphonie fonctionne mal dans une nouvelle version, les développeurs peuvent essayer d'installer une ancienne implémentation APEX de téléphonie sur un appareil (sans avoir à flasher une version complète) et vérifier si le bon comportement est rétabli.
Exemple de workflow:
# 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 ...
Exemples
Principes de base
Consultez la page principale sur le format de fichier APEX pour obtenir des informations génériques sur APEX, y compris les exigences concernant les appareils, les détails sur le format de fichier et les étapes d'installation.
Dans Android.bp
, définir la propriété vendor: true
fait d'un module APEX un APEX du fournisseur.
apex {
..
vendor: true,
..
}
Binaires et bibliothèques partagées
Un APEX inclut des dépendances transitives dans la charge utile APEX, sauf s'il dispose d'interfaces stables.
Les interfaces natives stables pour les dépendances APEX du fournisseur incluent cc_library
avec les bibliothèques stubs
et LLNDK. Ces dépendances sont exclues du packaging et sont enregistrées dans le fichier manifeste APEX. Le fichier manifeste est traité par linkerconfig
afin que les dépendances natives externes soient disponibles au moment de l'exécution.
Dans l'extrait de code suivant, l'APEX contient à la fois le binaire (my_service
) et ses dépendances non stables (fichiers *.so
).
apex {
..
vendor: true,
binaries: ["my_service"],
..
}
Dans l'extrait de code suivant, l'APEX contient la bibliothèque partagée my_standalone_lib
et toutes ses dépendances non stables (comme décrit ci-dessus).
apex {
..
vendor: true,
native_shared_libs: ["my_standalone_lib"],
..
}
Réduire APEX
APEX peut devenir plus volumineux, car il regroupe des dépendances non stables. Nous vous recommandons d'utiliser l'association statique. Les bibliothèques courantes telles que libc++.so
et libbase.so
peuvent être liées de manière statique aux binaires HAL. Vous pouvez également créer une dépendance pour fournir une interface stable. La dépendance ne sera pas groupée dans l'APEX.
Implémentations HAL
Pour définir une implémentation HAL, fournissez les binaires et les bibliothèques correspondants dans un APEX du fournisseur semblable aux exemples suivants:
Pour encapsuler complètement l'implémentation du HAL, l'APEX doit également spécifier tous les fragments VINTF et scripts d'initialisation pertinents.
Fragments VINTF
Les fragments VINTF peuvent être diffusés à partir d'un APEX du fournisseur lorsque les fragments se trouvent dans etc/vintf
de l'APEX.
Utilisez la propriété prebuilts
pour intégrer les fragments VINTF dans l'APEX.
apex {
..
vendor: true,
prebuilts: ["fragment.xml"],
..
}
prebuilt_etc {
name: "fragment.xml",
src: "fragment.xml",
sub_dir: "vintf",
}
API de requête
Lorsque des fragments VINTF sont ajoutés à APEX, utilisez les API libbinder_ndk
pour obtenir les mappages des interfaces HAL et des noms APEX.
AServiceManager_isUpdatableViaApex("com.android.foo.IFoo/default")
:true
si l'instance HAL est définie dans APEX.AServiceManager_getUpdatableApexName("com.android.foo.IFoo/default", ...)
: obtient le nom APEX qui définit l'instance HAL.AServiceManager_openDeclaredPassthroughHal("mapper", "instance", ...)
: utilisez-le pour ouvrir un HAL de passthrough.
Scripts d'initialisation
Les APEX peuvent inclure des scripts d'initialisation de deux manières: (A) un fichier texte prédéfini dans la charge utile APEX ou (B) un script d'initialisation standard dans /vendor/etc
. Vous pouvez définir les deux pour le même APEX.
Script d'initialisation dans APEX:
prebuilt_etc {
name: "myinit.rc",
src: "myinit.rc"
}
apex {
..
vendor: true,
prebuilts: ["myinit.rc"],
..
}
Les scripts d'initialisation dans les APEX de fournisseurs peuvent comporter des définitions service
et des directives on <property or event>
.
Assurez-vous qu'une définition service
pointe vers un binaire dans le même APEX.
Par exemple, l'APEX com.android.foo
peut définir un service nommé foo-service
.
on foo-service /apex/com.android.foo/bin/foo
...
Soyez prudent lorsque vous utilisez des directives on
. Étant donné que les scripts d'initialisation dans les APEX sont analysés et exécutés après l'activation des APEX, certains événements ou propriétés ne peuvent pas être utilisés. Utilisez apex.all.ready=true
pour déclencher des actions dès que possible.
Les APEX d'amorçage peuvent utiliser on init
, mais pas on early-init
.
Micrologiciel
Exemple :
Intégrez le micrologiciel dans un APEX du fournisseur avec le type de module prebuilt_firmware
, comme suit.
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
..
}
Les modules prebuilt_firmware
sont installés dans le répertoire <apex name>/etc/firmware
de l'APEX. ueventd
analyse les répertoires /apex/*/etc/firmware
pour trouver les modules de micrologiciels.
Le file_contexts
de l'APEX doit étiqueter correctement toutes les entrées de la charge utile du micrologiciel pour s'assurer que ces fichiers sont accessibles par ueventd
au moment de l'exécution. En règle générale, l'étiquette vendor_file
est suffisante. Exemple :
(/.*)? u:object_r:vendor_file:s0
Modules du noyau
Intégrez des modules de noyau dans un APEX de fournisseur en tant que modules prédéfinis, comme suit :
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
..
}
Le file_contexts
de l'APEX doit étiqueter correctement toutes les entrées de charge utile du kernel module. Exemple :
/etc/modules(/.*)? u:object_r:vendor_kernel_modules:s0
Les modules du noyau doivent être installés explicitement. L'exemple de script d'initialisation suivant dans la partition du fournisseur montre l'installation via insmod
:
my_init.rc
:
on early-boot
insmod /apex/myapex/etc/modules/my.ko
..
Superpositions de ressources d'exécution
Exemple :
Intégrez des superpositions de ressources d'exécution dans un APEX de fournisseur à l'aide de la propriété rros
.
runtime_resource_overlay {
name: "my_rro",
soc_specific: true,
}
apex {
..
vendor: true,
rros: ["my_rro"], // installed inside APEX as /overlay/my_rro.apk
..
}
Autres fichiers de configuration
Les APEX du fournisseur prennent en charge divers autres fichiers de configuration généralement trouvés sur la partition du fournisseur en tant que précompilés dans les APEX du fournisseur. D'autres sont en cours d'ajout.
Exemples :
- Fichiers XML de déclaration de fonctionnalités
- Les capteurs comportent des fichiers XML prédéfinis dans un APEX de fournisseur de HAL de capteur.
- Fichiers de configuration d'entrée
- Configurations d'écran tactile en tant que composants prédéfinis dans un APEX de fournisseur de configuration uniquement
APEX de fournisseurs d'amorçage
Certains services HAL tels que keymint
doivent être disponibles avant l'activation des APEX. Ces HAL définissent généralement early_hal
dans leur définition de service dans le script d'initialisation. Un autre exemple est la classe animation
, qui est généralement démarrée avant l'événement post-fs-data
. Lorsqu'un tel service HAL précoce est empaqueté dans l'APEX du fournisseur, définissez l'apex sur "vendorBootstrap": true
dans son fichier manifeste APEX afin qu'il puisse être activé plus tôt. Notez que les APEX de démarrage ne peuvent être activés qu'à partir de l'emplacement prédéfini, comme /vendor/apex
, et non à partir de /data/apex
.
Propriétés système
Voici les propriétés système que le framework lit pour prendre en charge les APEX du fournisseur:
input_device.config_file.apex=<apex name>
: lorsque ce paramètre est défini, les fichiers de configuration d'entrée (*.idc
,*.kl
et*.kcm
) sont recherchés à partir du répertoire/etc/usr
de l'APEX.ro.vulkan.apex=<apex name>
: lorsque cette valeur est définie, le pilote Vulkan est chargé à partir de l'APEX. Étant donné que le pilote Vulkan est utilisé par les premiers HAL, définissez l'APEX sur APEX de démarrage et configurez ce nom d'espace de nommage du linker comme visible.
Définissez les propriétés système dans les scripts d'initialisation à l'aide de la commande setprop
.
Fonctionnalités de développement supplémentaires
Sélection d'APEX au démarrage
Exemple :
Les développeurs peuvent également installer plusieurs versions d'APEX du fournisseur qui partagent le même nom et la même clé APEX, puis choisir la version activée à chaque démarrage à l'aide de sysprops persistants. Pour certains cas d'utilisation des développeurs, cela peut être plus simple que d'installer une nouvelle copie de l'APEX à l'aide de adb install
.
Exemples de cas d'utilisation:
- Installez trois versions de l'APEX du fournisseur HAL Wi-Fi:les équipes de contrôle qualité peuvent exécuter des tests manuels ou automatisés à l'aide d'une version, puis redémarrer dans une autre version et réexécuter les tests, puis comparer les résultats finaux.
- Installez deux versions de l'APEX du fournisseur HAL de l'appareil photo, la version actuelle et la version expérimentale:les dogfooders peuvent utiliser la version expérimentale sans télécharger et installer un fichier supplémentaire, ce qui leur permet de revenir facilement à la version précédente.
Au démarrage, apexd
recherche des sysprops suivant un format spécifique pour activer la bonne version d'APEX.
Les formats attendus pour la clé de propriété sont les suivants:
- Bootconfig
- Permet de définir la valeur par défaut, dans
BoardConfig.mk
. androidboot.vendor.apex.<apex name>
- Permet de définir la valeur par défaut, dans
- Propriété système persistante
- Permet de modifier la valeur par défaut définie sur un appareil déjà démarré.
- Remplace la valeur de bootconfig, le cas échéant.
persist.vendor.apex.<apex name>
La valeur de la propriété doit être le nom de fichier de l'APEX à activer.
// 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 version par défaut doit également être configurée à l'aide de bootconfig dans 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
Une fois l'appareil démarré, modifiez la version activée en définissant la propriété système persistante:
$ adb root;
$ adb shell setprop \
persist.vendor.apex.com.oem.camera.hal \
com.oem.camera.hal.my_apex_experimental;
$ adb reboot;
Si l'appareil prend en charge la mise à jour de bootconfig après le flashage (par exemple, via des commandes fastboot
oem
), la modification de la propriété bootconfig pour l'APEX multi-installé modifie également la version activée au démarrage.
Pour les appareils de référence virtuels basés sur Cuttlefish, vous pouvez utiliser la commande --extra_bootconfig_args
pour définir directement la propriété bootconfig lors du lancement. Exemple :
launch_cvd --noresume \
--extra_bootconfig_args "androidboot.vendor.apex.com.oem.camera.hal:=com.oem.camera.hal.my_apex_experimental";