Format de fichier APEX

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 peut citer les bibliothèques et services natifs, les couches d'abstraction matérielle (HAL), les bibliothèques d'environnement d'exécution (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 prenne en charge les mises à jour des modules qui s'inscrivent dans le modèle d'application standard (par exemple, les services, les activités) via des 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 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 des informations sur les applications. Il ne peut être démarré qu'à partir du gestionnaire d'activités, qui sera prêt lors d'une étape ultérieure de la procédure de démarrage.
  • Le format de l'APK (en particulier le fichier manifeste) est conçu pour les applications Android, et les modules système ne sont pas toujours adaptés.

Conception

Cette section décrit la conception générale du format de fichier APEX et du gestionnaire d'apex, un service qui gère les fichiers APEX.

Pour en savoir plus sur la raison pour laquelle cette conception a été sélectionnée pour APEX, consultez la section Autres solutions envisagées lors du développement d'APEX.

Format APEX

Il s'agit du format d'un fichier APEX.

Format de fichier APEX

Figure 1 : Format de fichier APEX

De premier niveau, un fichier APEX est un fichier ZIP dans lequel les fichiers sont stockés non compressés et situés dans des limites de 4 Ko.

Les quatre fichiers d'un fichier APEX sont les 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 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 que 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 du package et des informations sur la version. Ces informations sont généralement également disponibles dans apex_manifest.json.

apex_manifest.json est recommandé à la place de AndroidManifest.xml pour le nouveau code et les systèmes qui traitent d'APEX. AndroidManifest.xml peut contenir des informations de ciblage supplémentaires pouvant être utilisées par les outils de publication d'applications existants.

apex_payload.img est une image de système de fichiers ext4 reposant sur dm-verity. L'image est montée au moment de l'exécution via un appareil 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 installé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é par la même entité qui signe le même APEX dans les partitions intégrées.

Consignes de dénomination pour APEX

Pour éviter les conflits de noms entre les nouveaux APEX à mesure que la plate-forme évolue, respectez les consignes de dénomination suivantes :

  • com.android.*
    • Réservé aux APEX AOSP. Elle n'est pas propre à toutes les entreprises ni à tous les appareils.
  • com.<companyname>.*
    • Réservé à une entreprise. Peut être utilisé par plusieurs appareils de cette entreprise.
  • com.<companyname>.<devicename>.*
    • Réservé pour les 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 est prêt au début de la séquence de démarrage. Les fichiers APEX sont normalement préinstallés sur l'appareil sous /system/apex. Par défaut, le gestionnaire d'apex utilise ces packages 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.

  1. Un fichier APEX est téléchargé via une application d'installation de package, ADB ou une autre source.
  2. Le gestionnaire de paquets lance la procédure d'installation. Lorsqu'il reconnaît que le fichier est un APEX, le gestionnaire de paquets transfère le contrôle au gestionnaire APEX.
  3. Le gestionnaire APEX vérifie le fichier APEX.
  4. Si le fichier APEX est validé, la base de données interne du gestionnaire APEX est mise à jour pour indiquer que le fichier APEX est activé au prochain démarrage.
  5. Le demandeur d'installation reçoit une annonce une fois la vérification du package réussie.
  6. Pour continuer l'installation, vous devez redémarrer le système.
  7. 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é :

    1. Vérifie le fichier APEX.
    2. Crée un appareil de bouclage à partir du fichier APEX.
    3. Crée un appareil de mappage d'appareils sur l'appareil de bouclage.
    4. Monte le périphérique de blocage du mappeur d'appareils 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 de liaison permettant aux autres composants système d'interroger des informations sur les fichiers APEX installés. Par exemple, les autres composants 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 d'accéder aux fichiers.

Les fichiers APEX sont des fichiers APK

Les fichiers APEX sont des fichiers APK valides, car ils sont des 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 pour les fichiers APK, tels qu'une application d'installation de packages, l'utilitaire de signature et le gestionnaire de packages.

Le fichier AndroidManifest.xml d'un fichier APEX est minimal et se compose du package name, versionCode, ainsi que des éléments facultatifs targetSdkVersion, minSdkVersion et maxSdkVersion pour le ciblage précis. Ces informations permettent de distribuer les fichiers APEX via des canaux existants tels que les applications d'installation de packages et ADB.

Types de fichiers compatibles

Le format APEX accepte 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é. Ensuite, l'APEX entier est signé à l'aide du schéma de signature des fichiers APK v3. Deux clés différentes sont utilisées dans ce processus.

Côté 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 vérifier les APEX qui doivent être installés. Chaque APEX doit être signé avec des clés différentes et est appliqué 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 installés directement sur l'appareil 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 nouvelle version de l'APEX installée n'est activée qu'après le redémarrage.

Exigences du noyau

Pour prendre en charge les modules principaux APEX sur un appareil Android, les fonctionnalités de 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 valide le module APEX.

Les performances du pilote de bouclage et de dm-verity sont importantes pour obtenir de bonnes performances système lors de l'utilisation de modules APEX.

Versions de noyau compatibles

Les modules principaux APEX sont compatibles avec les appareils utilisant les versions de noyau 4.4 ou ultérieures. Les nouveaux appareils lancés avec Android 10 ou version ultérieure doivent utiliser la version 4.9 ou ultérieure du noyau pour être compatibles avec 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 compatibles avec APEX, utilisez la dernière version de l'arborescence commune Android.

Version de kernel 4.4

Cette version n'est compatible qu'avec les appareils mis à niveau d'Android 9 à Android 10 et qui souhaitent prendre en charge les modules APEX. Pour obtenir les correctifs requis, nous vous recommandons vivement de procéder à une fusion descendante à partir de la branche android-4.4. Voici une liste des correctifs individuels requis pour la version 4.4 du noyau.

  • UPSTREAM: loop: add ioctl pour changer la taille de bloc logique (4.4)
  • BACKPORT: bloc/boucle: définit hw_sectors (4.4)
  • UPSTREAM: boucle: ajoute LOOP_SET_BLOCK_SIZE dans ioctl compatible (4.4)
  • ANDROID : mnt : correction de next_descendent (4.4)
  • ANDROID : mnt : la nouvelle installation doit se propager aux esclaves des esclaves (4.4)
  • ANDROID: mnt: propage la réinstallation correctement (4.4)
  • Rétablissement de "ANDROID: dm verity: add minimum prefetch size" (ANDROID : dm verity : ajouter la taille de préchargement minimale) (4.4)
  • UPSTREAM: boucle: suppression des caches si offset ou block_size sont modifiés (4.4)

Versions du noyau 4.9/4.14/4.19

Pour obtenir les correctifs requis pour les versions de kernel 4.9/4.14/4.19, 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 (*) correspondent aux exigences existantes d'Android 9 et 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éfini
  • loop.max_part doit être inférieur ou égal à 8.

Créer un APEX

Cette section explique comment compiler 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 pour 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 le bras traduit en x86)
Fichiers exécutables /bin
Bibliothèques Java /javalib
Prédéfinis /etc

Dépendances transitives

Les fichiers APEX incluent automatiquement les dépendances transitives des bibliothèques partagées natives ou des exécutables. Par exemple, si libFoo dépend de libBar, les deux bibliothèques sont incluses lorsque seule libFoo est répertoriée 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 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 ajouter un contrôle ultraprécis sur les ABI des bibliothèques natives et des binaires, 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 du paramètre par défaut pour les fichiers binaires.
  • lib32 : correspond à l'ABI 32 bits de l'appareil, le cas échéant.
  • lib64 : correspond à l'ABI 64 bits de l'appareil, compatible.
  • prefer32: correspond à l'ABI 32 bits de l'appareil, si compatible. Si l'ABI 32 bits n'est pas compatible, correspond à l'ABI 64 bits.
  • both: correspond aux deux ABI. Il s'agit de la valeur par défaut pour native_shared_libraries.

Les propriétés java, libraries et prebuilts sont indépendantes des ABI.

Cet exemple s'applique à un appareil compatible avec 32/64 et qui ne préfère pas 32 :

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 l'apex à l'aide de la clé. La clé publique est automatiquement incluse dans l'APEX avec le nom avb_pubkey.

# create an rsa key pair
openssl genrsa -out foo.pem 4096

# extract the public key from the key pair
avbtool extract_public_key --key foo.pem --output foo.avbpubkey

# in Android.bp
apex_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. Au moment de l'exécution, apexd valide l'APEX à l'aide d'une clé publique avec le même ID sur l'appareil.

Signature APEX

Signez les fichiers 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 trois manières différentes :

  • 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 aucune option n'est définie, le chemin d'accès est défini par défaut sur build/target/product/security/testkey.
  • <name> : l'APEX est signé avec le certificat <name> dans le même répertoire que PRODUCT_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, tous les services qu'il contient ont été arrêtés), un nouvel APEX peut être installé sans redémarrage à l'aide de l'indicateur --force-non-staged.

adb install --force-non-staged apex_file_name

Utiliser un APEX

Après le redémarrage, l'apex est installé 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 d'installation, celui qui correspond à la dernière version est installé via la liaison sur /apex/<apex_name>.

Les clients peuvent utiliser le chemin d'accès monté par liaison pour lire ou exécuter des fichiers à partir d'APEX.

Les apex sont généralement utilisés comme suit:

  1. Un OEM ou un ODM précharge un APEX sous /system/apex lorsque l'appareil est expédié.
  2. Les fichiers de l'apex sont accessibles via le chemin d'accès /apex/<apex_name>/.
  3. 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:

  1. Marquez le service dans la partition système comme pouvant être mis à jour. Ajoutez l'option updatable à la définition de service.

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. Créez un fichier .rc pour le service mis à jour. Utilisez l'option override 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 compatibles avec 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 qu'il accepte 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éaliste de mettre à jour l'ancien noyau pour qu'il prenne pleinement en charge APEX. Par exemple, le noyau peut avoir été créé sans CONFIG_BLK_DEV_LOOP=Y, ce qui est essentiel pour installer l'image du système de fichiers dans un APEX.

Flattened APEX est un APEX spécialement conçu qui peut être activé sur les appareils dotés d'un ancien noyau. Les fichiers d'un fichier APEX aplati sont directement installés dans un répertoire sous la partition intégrée. Par exemple, lib/libFoo.so dans un élément APEX my.apex aplati est installé dans /system/apex/my.apex/lib/libFoo.so.

L'activation d'un APEX aplati n'implique pas l'appareil de boucle. L'ensemble du répertoire /system/apex/my.apex est directement monté en liaison avec /apex/name@ver.

Les APEX aplatis ne peuvent pas être mis à jour 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 aplaties ne peuvent être mises à jour que via une mise à jour OTA standard.

La configuration par défaut est l'APEX aplati. Cela signifie que tous les apex sont par défaut aplatis, sauf si vous configurez explicitement votre appareil pour créer des apex non aplatis afin de prendre en charge les mises à jour des apex (comme expliqué ci-dessus).

Le mélange d'APEX aplatis et non aplatis dans un appareil n'est PAS pris en charge. Les APEX d'un appareil doivent tous être non aplatis ou tous aplatis. Cela est particulièrement important lorsque vous envoyez des APEX prédéfinis pour des projets tels que Mainline. Les APEX qui ne sont pas présignés (c'est-à-dire créés à partir de la source) ne doivent pas être aplatis et doivent être signés avec les clés appropriées. L'appareil doit hériter de updatable_apex.mk, comme expliqué dans la section Mettre à jour un service avec un APEX.

Apex compressés

Android 12 et versions ultérieures proposent la compression APEX pour réduire l'impact sur le stockage des packages APEX pouvant être mis à jour. Une fois qu'une mise à jour d'un APEX est 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 hautement compressé de fichiers APEX sur des partitions en lecture seule (comme la partition /system). Android 12 et versions ultérieures utilisent un algorithme de compression ZIP DEFLATE.

La compression n'offre pas d'optimisation pour les éléments suivants :

  • Les apex d'amorçage qui doivent être installés très tôt dans la séquence de démarrage

  • APEX non actualisables. La compression n'est utile que si une version mise à jour d'un élément APEX est installée sur la partition /data. La liste complète des APEX pouvant être mis à jour est disponible sur la page Composants système modulaires.

  • APEXes de bibliothèques partagées dynamiques. Étant donné que apexd active toujours les deux versions de ces APEX (préinstallées et mises à niveau), les compresser n'a aucune utilité.

Format de fichier APEX compressé

Il s'agit du format d'un fichier APEX compressé.

Schéma illustrant le format d&#39;un fichier APEX compressé

Figure 2. Format de fichier APEX compressé

Au niveau supérieur, un fichier APEX compressé est un fichier ZIP contenant le fichier apex d'origine sous sa forme déformée avec un niveau de compression de 9, ainsi que d'autres fichiers stockés non compressés.

Un fichier APEX se compose de quatre fichiers :

  • original_apex : dégonflé avec un niveau de compression de 9. Il s'agit du fichier APEX d'origine non compressé.
  • apex_manifest.pb: stocké uniquement
  • AndroidManifest.xml: stocké uniquement
  • apex_pubkey : stocké uniquement

Les fichiers apex_manifest.pb, AndroidManifest.xml et apex_pubkey sont des copies des 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é dans system/apex/tools.

Plusieurs paramètres liés à la compression APEX sont disponibles dans le système de compilation.

Dans Android.bp, la propriété compressible permet de contrôler si un fichier APEX est 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 locaux, vous pouvez forcer une compilation à compresser les 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 portent 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é résultant est lié au répertoire /data/apex/active.

Considérez l'exemple suivant comme une illustration du processus décrit ci-dessus.

Considérez /system/apex/com.android.foo.capex comme un APEX compressé en cours d'activation, avec le code de version 37.

  1. Le fichier original_apex dans /system/apex/com.android.foo.capex est décompressé dans /data/apex/decompressed/com.android.foo@37.apex.
  2. restorecon /data/apex/decompressed/com.android.foo@37.apex est exécuté pour vérifier qu'il dispose d'un libellé SELinux correct.
  3. Des vérifications sont effectuées sur /data/apex/decompressed/com.android.foo@37.apex pour s'assurer de sa validité : apexd vérifie la clé publique groupée dans /data/apex/decompressed/com.android.foo@37.apex pour s'assurer qu'elle est égale à celle groupée dans /system/apex/com.android.foo.capex.
  4. Le fichier /data/apex/decompressed/com.android.foo@37.apex est lié au répertoire /data/apex/active/com.android.foo@37.apex.
  5. La logique d'activation standard des fichiers APEX non compressés est exécutée sur /data/apex/active/com.android.foo@37.apex.

Interaction avec OTA

Les fichiers APEX compressés ont des conséquences sur la diffusion OTA et l'application. É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 de l'appareil pour appliquer une mise à jour OTA.

Pour prendre en charge le système OTA, apexd expose ces deux API de liaison:

  • calculateSizeForCompressedApex : calcule la taille requise pour décompresser les fichiers AAPEX dans un package OTA. Cela permet de vérifier qu'un appareil dispose d'assez 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 par apexd pour décompresser les fichiers APEX compressés dans le package OTA.

Dans le cas d'une mise à jour OTA A/B, apexd tente de décompresser en arrière-plan dans la routine OTA post-installation. Si la décompression échoue, apexd effectue la décompression pendant le démarrage qui applique la mise à jour OTA.

Alternatives envisagées lors du développement d'APEX

Voici quelques options que l'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 des paquets standards

Les distributions Linux disposent de systèmes de gestion de paquets tels que dpkg et rpm, qui sont puissants, matures et robustes. Cependant, 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 paquets installés, sans être détectés. 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 falsification des composants du système doit être interdite ou être 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 l'installation des partitions. Pour offrir le même niveau de sécurité aux fichiers, tous les fichiers d'un rapport APEX sont stockés dans une image du système de fichiers associée à une arborescence 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 vérification 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 parvient à accéder à la partition /data, il ne peut plus bénéficier d'une protection supplémentaire. Il s'agit là aussi d'une régression par rapport à chaque composant système de la partition /system. L'arborescence de hachage d'un fichier APEX avec 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 empaquetés dans un APEX sont accessibles via de nouveaux chemins d'accès tels que /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 plate-forme) doit utiliser les nouveaux chemins. Vous devrez peut-être mettre à jour le code existant en raison de ce changement de chemin d'accès.

Bien qu'une méthode permettant d'éviter le changement de chemin d'accès consiste à superposer le contenu d'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 (et éventuellement empilés les uns sur les autres) augmente.

Une autre option consistait à pirater des fonctions d'accès aux fichiers telles que open, stat et readlink, de sorte que les chemins commençant par /system soient redirigés vers leurs chemins correspondants sous /apex. L'équipe Android a supprimé cette option, car il est impossible de modifier toutes les fonctions qui acceptent les chemins. Par exemple, certaines applications associent de manière statique Bionic, qui implémente les fonctions. Dans ce cas, ces applications ne sont pas redirigées.