Le format de conteneur Android Pony EXpress (APEX) a été introduit dans Android 10 et est utilisé dans le flux d'installation des modules système de niveau inférieur. Ce format facilite la mise à jour des composants système qui ne correspondent pas au modèle d'application Android standard. Parmi les exemples de composants, on trouve les services et bibliothèques natifs, les couches d'abstraction matérielle (HAL), le runtime (ART) et les bibliothèques de classes.
Le terme "APEX" peut également faire référence à un fichier APEX.
Arrière-plan
Bien qu'Android soit compatible avec les mises à jour des modules qui s'intègrent au modèle d'application standard (par exemple, les services et les activités) via les applications d'installation de packages (telles que l'application Google Play Store), l'utilisation d'un modèle similaire pour les composants d'OS de niveau inférieur présente les inconvénients suivants :
- Les modules basés sur des APK ne peuvent pas être utilisés au début de la séquence de démarrage. Le gestionnaire de packages est le dépôt central d'informations sur les applications. Il ne peut être démarré qu'à partir du gestionnaire d'activités, qui devient prêt à une étape ultérieure de la procédure de démarrage.
- Le format APK (en particulier le fichier manifeste) est conçu pour les applications Android et ne convient pas toujours aux modules système.
Conception
Cette section décrit la conception générale du format de fichier APEX et du gestionnaire APEX, qui est un service qui gère les fichiers APEX.
Pour en savoir plus sur les raisons pour lesquelles cette conception a été choisie pour APEX, consultez Alternatives envisagées lors du développement d'APEX.
Format APEX
Il s'agit du format d'un fichier APEX.
Figure 1 : Format de fichier APEX
Au niveau supérieur, un fichier APEX est un fichier ZIP dans lequel les fichiers sont stockés sans compression et situés à des limites de 4 Ko.
Un fichier APEX contient les quatre fichiers suivants :
apex_manifest.json
AndroidManifest.xml
apex_payload.img
apex_pubkey
Le fichier apex_manifest.json
contient le nom et la version du package, qui identifient un fichier APEX. Il s'agit d'un tampon de protocole ApexManifest
au format JSON.
Le fichier AndroidManifest.xml
permet au fichier APEX d'utiliser des outils et une infrastructure liés aux APK, tels qu'ADB, PackageManager et les applications d'installation de packages (comme le Play Store). Par exemple, le fichier APEX peut utiliser un outil existant tel que aapt
pour inspecter les métadonnées de base du fichier. Le fichier contient le nom et la version du package. Ces informations sont généralement également disponibles dans apex_manifest.json
.
apex_manifest.json
est recommandé plutôt que AndroidManifest.xml
pour les nouveaux codes et systèmes qui traitent d'APEX. AndroidManifest.xml
peut contenir des informations de ciblage supplémentaires qui peuvent être utilisées par les outils de publication d'applications existants.
apex_payload.img
est une image de système de fichiers ext4 soutenue par dm-verity. L'image est montée au moment de l'exécution via un périphérique de bouclage. Plus précisément, l'arbre de hachage et le bloc de métadonnées sont créés à l'aide de la bibliothèque libavb
. La charge utile du système de fichiers n'est pas analysée (car l'image doit pouvoir être montée sur place). Les fichiers standards sont inclus dans le fichier apex_payload.img
.
apex_pubkey
est la clé publique utilisée pour signer l'image du système de fichiers. Au moment de l'exécution, cette clé garantit que l'APEX téléchargé est signé avec la même entité qui signe le même APEX dans les partitions intégrées.
Consignes de dénomination APEX
Pour éviter les conflits de noms entre les nouveaux APEX à mesure que la plate-forme évolue, suivez les consignes de dénomination suivantes :
com.android.*
- Réservé aux APEX AOSP. Il n'est propre à aucune entreprise ni aucun appareil.
com.<companyname>.*
- Réservé pour une entreprise. Potentiellement utilisé par plusieurs appareils de cette entreprise.
com.<companyname>.<devicename>.*
- Réservé aux APEX propres à un appareil spécifique (ou à un sous-ensemble d'appareils).
Gestionnaire APEX
Le gestionnaire APEX (ou apexd
) est un processus natif autonome chargé de vérifier, d'installer et de désinstaller les fichiers APEX. Ce processus est lancé et prêt dès le début de la séquence de démarrage. Les fichiers APEX sont normalement préinstallés sur l'appareil sous /system/apex
. Le gestionnaire APEX utilise ces packages par défaut si aucune mise à jour n'est disponible.
La séquence de mise à jour d'un APEX utilise la classe PackageManager et se présente comme suit.
- Un fichier APEX est téléchargé via une application d'installation de packages, ADB ou une autre source.
- Le gestionnaire de paquets lance la procédure d'installation. Lorsqu'il reconnaît que le fichier est un APEX, le gestionnaire de packages transfère le contrôle au gestionnaire APEX.
- Le gestionnaire APEX vérifie le fichier APEX.
- Si le fichier APEX est validé, la base de données interne du gestionnaire APEX est mise à jour pour indiquer que le fichier APEX sera activé au prochain démarrage.
- Le demandeur de l'installation reçoit une diffusion une fois la validation du package réussie.
- Pour poursuivre l'installation, le système doit être redémarré.
Au prochain démarrage, le gestionnaire APEX démarre, lit la base de données interne et effectue les opérations suivantes pour chaque fichier APEX listé :
- Vérifie le fichier APEX.
- Crée un périphérique de bouclage à partir du fichier APEX.
- Crée un périphérique de bloc de mappeur de périphérique au-dessus du périphérique de bouclage.
- Monte le périphérique de bloc de mappeur de périphérique sur un chemin d'accès unique (par exemple,
/apex/name@ver
).
Lorsque tous les fichiers APEX listés dans la base de données interne sont montés, le gestionnaire APEX fournit un service Binder aux autres composants système pour qu'ils puissent interroger des informations sur les fichiers APEX installés. Par exemple, les autres composants du système peuvent interroger la liste des fichiers APEX installés sur l'appareil ou le chemin d'accès exact où un APEX spécifique est installé, afin que les fichiers puissent être consultés.
Les fichiers APEX sont des fichiers APK
Les fichiers APEX sont des fichiers APK valides, car il s'agit d'archives ZIP signées (à l'aide du schéma de signature APK) contenant un fichier AndroidManifest.xml
. Cela permet aux fichiers APEX d'utiliser l'infrastructure des fichiers APK, comme une application d'installation de packages, l'utilitaire de signature et le gestionnaire de packages.
Le fichier AndroidManifest.xml
à l'intérieur d'un fichier APEX est minimal. Il se compose du package name
, versionCode
et des fichiers targetSdkVersion
, minSdkVersion
et maxSdkVersion
facultatifs pour un ciblage précis. Ces informations permettent de distribuer les fichiers APEX via les canaux existants tels que les applications d'installation de packages et ADB.
Types de fichiers acceptés
Le format APEX est compatible avec les types de fichiers suivants :
- Bibliothèques partagées natives
- Exécutables natifs
- Fichiers JAR
- Fichiers de données
- Fichiers de configuration
Cela ne signifie pas qu'APEX peut mettre à jour tous ces types de fichiers. La possibilité de mettre à jour un type de fichier dépend de la plate-forme et de la stabilité des définitions des interfaces pour les types de fichiers.
Options de signature
Les fichiers APEX sont signés de deux manières. Tout d'abord, le fichier apex_payload.img
(plus précisément, le descripteur vbmeta ajouté à apex_payload.img
) est signé avec une clé.
L'ensemble de l'APEX est ensuite signé à l'aide du schéma de signature des APK v3. Deux clés différentes sont utilisées dans ce processus.
Du côté de l'appareil, une clé publique correspondant à la clé privée utilisée pour signer le descripteur vbmeta est installée. Le gestionnaire APEX utilise la clé publique pour valider les APEX dont l'installation est demandée. Chaque APEX doit être signé avec des clés différentes. Cette exigence est appliquée à la fois au moment de la compilation et de l'exécution.
APEX dans les partitions intégrées
Les fichiers APEX peuvent se trouver dans des partitions intégrées telles que /system
. La partition est déjà sur dm-verity. Les fichiers APEX sont donc montés directement sur le périphérique de bouclage.
Si un APEX est présent dans une partition intégrée, il peut être mis à jour en fournissant un package APEX avec le même nom de package et un code de version supérieur ou égal. Le nouvel APEX est stocké dans /data
et, comme pour les APK, la version nouvellement installée masque la version déjà présente dans la partition intégrée. Toutefois, contrairement aux APK, la version APEX nouvellement installée n'est activée qu'après le redémarrage.
Exigences concernant le noyau
Pour prendre en charge les modules APEX mainline sur un appareil Android, les fonctionnalités du noyau Linux suivantes sont requises : le pilote de bouclage et dm-verity. Le pilote de bouclage monte l'image du système de fichiers dans un module APEX, et dm-verity vérifie le module APEX.
Les performances du pilote de bouclage et de dm-verity sont importantes pour obtenir de bonnes performances du système lors de l'utilisation de modules APEX.
Versions du noyau compatibles
Les modules APEX principaux sont compatibles avec les appareils utilisant le noyau version 4.4 ou ultérieure. Les nouveaux appareils équipés d'Android 10 ou version ultérieure doivent utiliser la version 4.9 ou ultérieure du noyau pour prendre en charge les modules APEX.
Correctifs du noyau requis
Les correctifs du noyau requis pour la prise en charge des modules APEX sont inclus dans l'arborescence commune Android. Pour obtenir les correctifs permettant de prendre en charge APEX, utilisez la dernière version de l'arborescence commune Android.
Version 4.4 du noyau
Cette version n'est compatible qu'avec les appareils mis à niveau d'Android 9 vers Android 10 et qui souhaitent prendre en charge les modules APEX. Pour obtenir les correctifs requis, il est fortement recommandé d'effectuer une fusion descendante à partir de la branche android-4.4
. Vous trouverez ci-dessous la liste des correctifs individuels requis pour la version 4.4 du noyau.
- UPSTREAM: loop: add ioctl for changing logical block size (4.4)
- BACKPORT: block/loop: set hw_sectors (4.4)
- UPSTREAM: loop: Add LOOP_SET_BLOCK_SIZE in compat ioctl (4.4)
- ANDROID: mnt: Fix next_descendent (4.4)
- ANDROID : le remontage mnt doit se propager aux esclaves des esclaves (4.4)
- ANDROID: mnt: Propagate remount correctly (4.4)
- Revert "ANDROID: dm verity: add minimum prefetch size" (4.4)
- UPSTREAM: loop: drop caches if offset or block_size are changed (4.4)
Versions du noyau 4.9/4.14/4.19
Pour obtenir les correctifs requis pour les versions 4.9, 4.14 et 4.19 du noyau, effectuez une fusion descendante à partir de la branche android-common
.
Options de configuration du noyau requises
La liste suivante présente les exigences de configuration de base pour la prise en charge des modules APEX introduits dans Android 10. Les éléments marqués d'un astérisque (*) sont des exigences existantes d'Android 9 et des versions antérieures.
(*) CONFIG_AIO=Y # AIO support (for direct I/O on loop devices)
CONFIG_BLK_DEV_LOOP=Y # for loop device support
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # pre-create 16 loop devices
(*) CONFIG_CRYPTO_SHA1=Y # SHA1 hash for DM-verity
(*) CONFIG_CRYPTO_SHA256=Y # SHA256 hash for DM-verity
CONFIG_DM_VERITY=Y # DM-verity support
Exigences concernant les paramètres de ligne de commande du noyau
Pour prendre en charge APEX, assurez-vous que les paramètres de ligne de commande du noyau répondent aux exigences suivantes :
loop.max_loop
ne doit PAS être définiloop.max_part
doit être <= 8
Créer un APEX
Cette section explique comment créer un APEX à l'aide du système de compilation Android.
Voici un exemple de Android.bp
pour un APEX nommé apex.test
.
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
// libc.so and libcutils.so are included in the apex
native_shared_libs: ["libc", "libcutils"],
binaries: ["vold"],
java_libs: ["core-all"],
prebuilts: ["my_prebuilt"],
compile_multilib: "both",
key: "apex.test.key",
certificate: "platform",
}
Exemple apex_manifest.json
:
{
"name": "com.android.example.apex",
"version": 1
}
Exemple file_contexts
:
(/.*)? u:object_r:system_file:s0
/sub(/.*)? u:object_r:sub_file:s0
/sub/file3 u:object_r:file3_file:s0
Types et emplacements de fichiers dans APEX
Type de fichier | Emplacement dans APEX |
---|---|
Photothèques partagées | /lib et /lib64 (/lib/arm pour l'arm traduit en x86) |
Exécutables | /bin |
Bibliothèques Java | /javalib |
Préconfigurés | /etc |
Dépendances transitives
Les fichiers APEX incluent automatiquement les dépendances transitives des bibliothèques partagées ou des exécutables natifs. Par exemple, si libFoo
dépend de libBar
, les deux bibliothèques sont incluses lorsque seul libFoo
est listé dans la propriété native_shared_libs
.
Gérer plusieurs ABI
Installez la propriété native_shared_libs
pour les interfaces binaires d'application (ABI) principales et secondaires de l'appareil. Si un APEX cible des appareils avec une seule ABI (c'est-à-dire 32 bits uniquement ou 64 bits uniquement), seules les bibliothèques avec l'ABI correspondante sont installées.
Installez la propriété binaries
uniquement pour l'ABI principale de l'appareil, comme décrit ci-dessous :
- Si l'appareil est uniquement en 32 bits, seule la variante 32 bits du binaire est installée.
- Si l'appareil est uniquement 64 bits, seule la variante 64 bits du binaire est installée.
Pour contrôler précisément les ABI des bibliothèques et des binaires natifs, utilisez les propriétés multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries]
.
first
: correspond à l'ABI principale de l'appareil. Il s'agit de la valeur par défaut pour les binaires.lib32
: correspond à l'ABI 32 bits de l'appareil, si elle est prise en charge.lib64
: correspond à l'ABI 64 bits de l'appareil, si elle est prise en charge.prefer32
: correspond à l'ABI 32 bits de l'appareil, si elle est prise en charge. Si l'ABI 32 bits n'est pas prise en charge, elle correspond à l'ABI 64 bits.both
: correspond aux deux ABI. Il s'agit de la valeur par défaut pournative_shared_libraries
.
Les propriétés java
, libraries
et prebuilts
sont indépendantes de l'ABI.
Cet exemple concerne un appareil compatible avec les architectures 32 et 64 bits, mais qui ne préfère pas l'architecture 32 bits :
apex {
// other properties are omitted
native_shared_libs: ["libFoo"], // installed for 32 and 64
binaries: ["exec1"], // installed for 64, but not for 32
multilib: {
first: {
native_shared_libs: ["libBar"], // installed for 64, but not for 32
binaries: ["exec2"], // same as binaries without multilib.first
},
both: {
native_shared_libs: ["libBaz"], // same as native_shared_libs without multilib
binaries: ["exec3"], // installed for 32 and 64
},
prefer32: {
native_shared_libs: ["libX"], // installed for 32, but not for 64
},
lib64: {
native_shared_libs: ["libY"], // installed for 64, but not for 32
},
},
}
Signature vbmeta
Signez chaque APEX avec des clés différentes. Lorsqu'une nouvelle clé est requise, créez une paire de clés publique/privée et créez un module apex_key
. Utilisez la propriété key
pour signer le fichier APEX à l'aide de la clé. La clé publique est automatiquement incluse dans l'APEX sous le nom avb_pubkey
.
# create an rsa key pairopenssl genrsa -out foo.pem 4096
# extract the public key from the key pairavbtool extract_public_key --key foo.pem --output foo.avbpubkey
# in Android.bpapex_key { name: "apex.test.key", public_key: "foo.avbpubkey", private_key: "foo.pem", }
Dans l'exemple ci-dessus, le nom de la clé publique (foo
) devient l'ID de la clé. L'ID de la clé utilisée pour signer un APEX est écrit dans l'APEX. Lors de l'exécution, apexd
valide l'APEX à l'aide d'une clé publique portant le même ID sur l'appareil.
Signature APEX
Signez les APEX de la même manière que les APK. Signez les APEX deux fois : une fois pour le mini système de fichiers (fichier apex_payload.img
) et une fois pour l'ensemble du fichier.
Pour signer un APEX au niveau du fichier, définissez la propriété certificate
de l'une des trois manières suivantes :
- Non défini : si aucune valeur n'est définie, l'APEX est signé avec le certificat situé à l'adresse
PRODUCT_DEFAULT_DEV_CERTIFICATE
. Si aucun indicateur n'est défini, le chemin d'accès est défini par défaut surbuild/target/product/security/testkey
. <name>
: l'APEX est signé avec le certificat<name>
dans le même répertoire quePRODUCT_DEFAULT_DEV_CERTIFICATE
.:<name>
: l'APEX est signé avec le certificat défini par le module Soong nommé<name>
. Le module de certificat peut être défini comme suit.
android_app_certificate {
name: "my_key_name",
certificate: "dir/cert",
// this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}
Installer un APEX
Pour installer un APEX, utilisez ADB.
adb install apex_file_name
adb reboot
Si supportsRebootlessUpdate
est défini sur true
dans apex_manifest.json
et que l'APEX actuellement installé n'est pas utilisé (par exemple, si tous les services qu'il contient ont été arrêtés), un nouvel APEX peut être installé sans redémarrage avec l'indicateur --force-non-staged
.
adb install --force-non-staged apex_file_name
Utiliser un APEX
Après le redémarrage, le fichier APEX est monté dans le répertoire /apex/<apex_name>@<version>
. Plusieurs versions du même APEX peuvent être montées en même temps.
Parmi les chemins de montage, celui qui correspond à la dernière version est monté par liaison à /apex/<apex_name>
.
Les clients peuvent utiliser le chemin d'accès monté pour lire ou exécuter des fichiers à partir d'APEX.
Les APEX sont généralement utilisés comme suit :
- Un OEM ou un ODM précharge un APEX sous
/system/apex
lors de l'expédition de l'appareil. - Les fichiers de l'APEX sont accessibles via le chemin
/apex/<apex_name>/
. - Lorsqu'une version mise à jour de l'APEX est installée dans
/data/apex
, le chemin d'accès pointe vers le nouvel APEX après le redémarrage.
Mettre à jour un service avec un APEX
Pour mettre à jour un service à l'aide d'un APEX :
Marquez le service dans la partition système comme pouvant être mis à jour. Ajoutez l'option
updatable
à la définition du service./system/etc/init/myservice.rc: service myservice /system/bin/myservice class core user system ... updatable
Créez un fichier
.rc
pour le service mis à jour. Utilisez l'optionoverride
pour redéfinir le service existant./apex/my.apex/etc/init.rc: service myservice /apex/my.apex/bin/myservice class core user system ... override
Les définitions de service ne peuvent être définies que dans le fichier .rc
d'un APEX. Les déclencheurs d'action ne sont pas acceptés dans les APEX.
Si un service marqué comme pouvant être mis à jour démarre avant l'activation des APEX, le démarrage est retardé jusqu'à ce que l'activation des APEX soit terminée.
Configurer le système pour prendre en charge les mises à jour APEX
Définissez la propriété système suivante sur true
pour prendre en charge les mises à jour des fichiers APEX.
<device.mk>:
PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true
BoardConfig.mk:
TARGET_FLATTEN_APEX := false
ou simplement
<device.mk>:
$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)
APEX aplati
Pour les anciens appareils, il est parfois impossible ou irréalisable de mettre à jour l'ancien noyau pour qu'il soit entièrement compatible avec APEX. Par exemple, le noyau peut avoir été compilé sans CONFIG_BLK_DEV_LOOP=Y
, qui est essentiel pour monter l'image du système de fichiers à l'intérieur d'un APEX.
Un APEX aplati est un APEX spécialement conçu qui peut être activé sur les appareils dotés d'un ancien noyau. Les fichiers d'un APEX aplati sont directement installés dans un répertoire de la partition intégrée. Par exemple, lib/libFoo.so
dans un APEX aplati my.apex
est installé dans /system/apex/my.apex/lib/libFoo.so
.
L'activation d'un APEX aplati n'implique pas le périphérique de boucle. L'intégralité du répertoire /system/apex/my.apex
est directement montée sur /apex/name@ver
.
Il est impossible de mettre à jour les APEX aplatis en téléchargeant des versions mises à jour des APEX depuis le réseau, car les APEX téléchargés ne peuvent pas être aplatis. Les APEX aplatis ne peuvent être mis à jour que par le biais d'une OTA régulière.
La configuration par défaut est "APEX aplati". Cela signifie que tous les APEX sont aplatis par défaut, sauf si vous configurez explicitement votre appareil pour qu'il crée des APEX non aplatis afin de prendre en charge les mises à jour d'APEX (comme expliqué ci-dessus).
Il est DÉCONSEILLÉ de mélanger des APEX aplatis et non aplatis dans un appareil. Les APEX d'un appareil doivent tous être non aplatis ou tous être aplatis.
Cela est particulièrement important lorsque vous expédiez des modules APEX précompilés et pré-signés pour des projets tels que Mainline. Les APEX non pré-signés (c'est-à-dire construits à partir de la source) doivent également être non aplatis et signés avec les clés appropriées. L'appareil doit hériter de updatable_apex.mk
, comme expliqué dans Mettre à jour un service avec un APEX.
APEX compressés
Android 12 et les versions ultérieures proposent la compression APEX pour réduire l'impact du stockage des packages APEX pouvant être mis à jour. Une fois la mise à jour d'un APEX installée, même si sa version préinstallée n'est plus utilisée, elle occupe toujours la même quantité d'espace. Cet espace occupé reste indisponible.
La compression APEX minimise cet impact sur le stockage en utilisant un ensemble de fichiers APEX hautement compressés sur des partitions en lecture seule (telles que la partition /system
). Android 12 et versions ultérieures utilisent un algorithme de compression ZIP DEFLATE.
La compression n'optimise pas les éléments suivants :
Amorce les APEX qui doivent être montés très tôt dans la séquence de démarrage.
APEX non modifiables. La compression n'est utile que si une version mise à jour d'un APEX est installée sur la partition
/data
. La liste complète des APEX pouvant être mis à jour est disponible sur la page Composants du système modulaire.APEX de bibliothèques partagées dynamiques. Étant donné que
apexd
active toujours les deux versions de ces APEX (préinstallée et mise à niveau), leur compression n'apporte aucune valeur ajoutée.
Format de fichier APEX compressé
Il s'agit du format d'un fichier APEX compressé.
Figure 2. Format de fichier APEX compressé
Au premier niveau, un fichier APEX compressé est un fichier ZIP contenant le fichier APEX d'origine sous forme décompressée avec un niveau de compression de 9, et d'autres fichiers stockés sans compression.
Un fichier APEX se compose de quatre fichiers :
original_apex
: décompressé avec un niveau de compression de 9. Il s'agit du fichier APEX d'origine non compressé.apex_manifest.pb
: stocké uniquementAndroidManifest.xml
: stocké uniquementapex_pubkey
: stocké uniquement
Les fichiers apex_manifest.pb
, AndroidManifest.xml
et apex_pubkey
sont des copies de leurs fichiers correspondants dans original_apex
.
Créer un APEX compressé
Les APEX compressés peuvent être créés à l'aide de l'outil apex_compression_tool.py
situé à l'adresse system/apex/tools
.
Plusieurs paramètres liés à la compression APEX sont disponibles dans le système de compilation.
Dans Android.bp
, la compressibilité d'un fichier APEX est contrôlée par la propriété compressible
:
apex {
name: "apex.test",
manifest: "apex_manifest.json",
file_contexts: "file_contexts",
compressible: true,
}
Un indicateur de produit PRODUCT_COMPRESSED_APEX
détermine si une image système créée à partir de la source doit contenir des fichiers APEX compressés.
Pour les tests en local, vous pouvez forcer la compression des APEX en définissant OVERRIDE_PRODUCT_COMPRESSED_APEX=
sur true
.
Les fichiers APEX compressés générés par le système de compilation ont l'extension .capex
.
L'extension permet de distinguer plus facilement les versions compressées et non compressées d'un fichier APEX.
Algorithmes de compression compatibles
Android 12 n'est compatible qu'avec la compression deflate-zip.
Activer un fichier APEX compressé au démarrage
Avant qu'un APEX compressé puisse être activé, le fichier original_apex
qu'il contient est décompressé dans le répertoire /data/apex/decompressed
. Le fichier APEX décompressé obtenu est lié en dur au répertoire /data/apex/active
.
Prenons l'exemple suivant pour illustrer le processus décrit ci-dessus.
Considérez /system/apex/com.android.foo.capex
comme un APEX compressé en cours d'activation, avec le versionCode 37.
- Le fichier
original_apex
dans/system/apex/com.android.foo.capex
est décompressé dans/data/apex/decompressed/com.android.foo@37.apex
. restorecon /data/apex/decompressed/com.android.foo@37.apex
est exécuté pour vérifier qu'il possède un libellé SELinux correct.- Des vérifications sont effectuées sur
/data/apex/decompressed/com.android.foo@37.apex
pour s'assurer de sa validité :apexd
vérifie que la clé publique incluse dans/data/apex/decompressed/com.android.foo@37.apex
est identique à celle incluse dans/system/apex/com.android.foo.capex
. - Le fichier
/data/apex/decompressed/com.android.foo@37.apex
est lié en dur au répertoire/data/apex/active/com.android.foo@37.apex
. - La logique d'activation régulière des fichiers APEX non compressés est exécutée sur
/data/apex/active/com.android.foo@37.apex
.
Interaction avec l'OTA
Les fichiers APEX compressés ont des implications sur la diffusion et l'application des mises à jour OTA. Étant donné qu'une mise à jour OTA peut contenir un fichier APEX compressé avec un niveau de version supérieur à celui qui est actif sur un appareil, une certaine quantité d'espace libre doit être réservée avant le redémarrage d'un appareil pour appliquer une mise à jour OTA.
Pour prendre en charge le système OTA, apexd
expose les deux API Binder suivantes :
calculateSizeForCompressedApex
: calcule la taille requise pour décompresser les fichiers APEX dans un package OTA. Cela peut être utilisé pour vérifier qu'un appareil dispose de suffisamment d'espace avant le téléchargement d'une mise à jour OTA.reserveSpaceForCompressedApex
: réserve de l'espace sur le disque pour une utilisation ultérieure parapexd
afin de décompresser les fichiers APEX compressés dans le package OTA.
Dans le cas d'une mise à jour OTA A/B, apexd
tente la décompression en arrière-plan dans le cadre de la routine OTA post-installation. Si la décompression échoue, apexd
effectue la décompression lors du démarrage qui applique la mise à jour OTA.
Alternatives envisagées lors du développement d'APEX
Voici quelques options qu'AOSP a envisagées lors de la conception du format de fichier APEX, et les raisons pour lesquelles elles ont été incluses ou exclues.
Systèmes de gestion de packages standards
Les distributions Linux disposent de systèmes de gestion de paquets tels que dpkg
et rpm
, qui sont puissants, matures et robustes. Toutefois, ils n'ont pas été adoptés pour APEX, car ils ne peuvent pas protéger les packages après l'installation. La validation n'est effectuée que lors de l'installation des packages.
Les pirates informatiques peuvent compromettre l'intégrité des packages installés sans se faire remarquer. Il s'agit d'une régression pour Android, où tous les composants système étaient stockés dans des systèmes de fichiers en lecture seule dont l'intégrité est protégée par dm-verity pour chaque E/S. Toute tentative de falsification des composants du système doit être interdite ou détectable afin que l'appareil puisse refuser de démarrer s'il est compromis.
dm-crypt pour l'intégrité
Les fichiers d'un conteneur APEX proviennent de partitions intégrées (par exemple, la partition /system
) protégées par dm-verity, où toute modification des fichiers est interdite même après le montage des partitions. Pour offrir le même niveau de sécurité aux fichiers, tous les fichiers d'un APEX sont stockés dans une image du système de fichiers associée à un arbre de hachage et à un descripteur vbmeta. Sans dm-verity, un APEX dans la partition /data
est vulnérable aux modifications involontaires apportées après sa validation et son installation.
En fait, la partition /data
est également protégée par des couches de chiffrement telles que dm-crypt. Bien que cela offre un certain niveau de protection contre la falsification, son objectif principal est la confidentialité, et non l'intégrité. Lorsqu'un pirate informatique accède à la partition /data
, il n'y a plus aucune protection possible. Il s'agit là encore d'une régression par rapport à la situation où chaque composant du système se trouve dans la partition /system
.
L'arbre de hachage à l'intérieur d'un fichier APEX associé à dm-verity offre le même niveau de protection du contenu.
Rediriger les chemins d'accès de /system vers /apex
Les fichiers de composants système inclus dans un APEX sont accessibles via de nouveaux chemins d'accès, comme /apex/<name>/lib/libfoo.so
. Lorsque les fichiers faisaient partie de la partition /system
, ils étaient accessibles via des chemins d'accès tels que /system/lib/libfoo.so
. Un client d'un fichier APEX (autres fichiers APEX ou la plate-forme) doit utiliser les nouveaux chemins d'accès. Vous devrez peut-être mettre à jour le code existant en raison de la modification du chemin d'accès.
Bien qu'il soit possible d'éviter le changement de chemin en superposant le contenu du fichier dans un fichier APEX sur la partition /system
, l'équipe Android a décidé de ne pas superposer les fichiers sur la partition /system
, car cela pourrait avoir un impact sur les performances à mesure que le nombre de fichiers superposés (voire empilés les uns après les autres) augmente.
Une autre option consistait à détourner les fonctions d'accès aux fichiers telles que open
, stat
et readlink
, afin que les chemins commençant par /system
soient redirigés vers leurs chemins correspondants sous /apex
. L'équipe Android a écarté cette option, car il est impossible de modifier toutes les fonctions qui acceptent les chemins d'accès.
Par exemple, certaines applications associent statiquement Bionic, qui implémente les fonctions.
Dans ce cas, ces applications ne sont pas redirigées.