Présentation des tests A/B virtuels

Virtual A/B est le principal mécanisme de mise à jour d'Android. La fonctionnalité de test A/B virtuel s'appuie sur les mises à jour A/B héritées (voir Mises à jour du système A/B) et non A/B, qui sont obsolètes dans la version 15 afin de réduire l'espace de stockage des mises à jour.

L'A/B virtuel ne dispose pas d'emplacement supplémentaire pour les partitions dynamiques. Pour en savoir plus, consultez Partitions dynamiques. Au lieu de cela, le delta est écrit dans un instantané, puis fusionné dans la partition de base après confirmation du démarrage réussi. Les tests A/B virtuels utilisent un format d'instantané spécifique à Android. Consultez la section Format COW pour les instantanés compressés, qui permet de compresser les instantanés et de minimiser l'utilisation de l'espace disque. Dans une mise à jour OTA complète, la taille de l'instantané est réduite d'environ 45 % grâce à la compression, et dans une mise à jour OTA incrémentielle, elle est réduite d'environ 55 %.

Android 12 propose l'option de compression A/B virtuelle pour compresser les partitions instantanées. Les tests A/B virtuels offrent les avantages suivants :

  • Les mises à jour A/B virtuelles sont fluides (elles se déroulent entièrement en arrière-plan pendant que l'appareil est opérationnel), comme les mises à jour A/B. Les mises à jour A/B virtuelles minimisent le temps pendant lequel un appareil est hors connexion et inutilisable.
  • Vous pouvez annuler les mises à jour A/B virtuelles. Si le nouvel OS ne parvient pas à démarrer, les appareils reviennent automatiquement à la version précédente.
  • Les mises à jour A/B virtuelles utilisent un minimum d'espace supplémentaire en ne dupliquant que les partitions utilisées par le bootloader. Les autres partitions pouvant être mises à jour sont instantanées.

Contexte et terminologie

Cette section définit la terminologie et décrit la technologie qui prend en charge les tests A/B virtuels. Lors de l'installation OTA, les nouvelles données du système d'exploitation sont écrites dans leur nouvel emplacement pour les partitions physiques ou dans un périphérique COW spécifique à Android. Une fois l'appareil redémarré, les données de partition dynamique sont fusionnées à nouveau dans son appareil de base à l'aide du démon dm-user et snapuserd. Ce processus se déroule entièrement dans l'espace utilisateur.

Device-mapper

Device-mapper est une couche de bloc virtuel Linux souvent utilisée dans Android. Avec les partitions dynamiques, les partitions telles que /system sont une pile d'appareils superposés :

  • En bas de la pile se trouve la partition physique super (par exemple, /dev/block/by-name/super).
  • Au milieu se trouve un appareil dm-linear, qui spécifie les blocs de la super-partition qui forment la partition dynamique donnée. /dev/block/mapper/system_[a|b] s'affiche sur un appareil A/B et /dev/block/mapper/system sur un appareil non-A/B.
  • En haut se trouve un appareil dm-verity, créé pour les partitions validées. Cet appareil vérifie que les blocs de l'appareil dm-linear sont correctement signés. Il s'affiche sous la forme /dev/block/mapper/system-verity et constitue la source du point d'installation /system.

La figure 1 montre à quoi ressemble la pile sous le point de montage /system.

Empilement des partitions sous le système

Figure 1 : Pile sous le point de montage /system

Instantanés compressés

Dans Android 12 et versions ultérieures, les exigences d'espace sur la partition /data peuvent être élevées. Vous pouvez donc activer les instantanés compressés dans votre build pour répondre à ces exigences./data

Les instantanés compressés A/B virtuels s'appuient sur les composants suivants, disponibles dans Android 12 et versions ultérieures :

  • dm-user, un module de noyau semblable à FUSE qui permet à l'espace utilisateur d'implémenter des périphériques de bloc.
  • snapuserd, un daemon de l'espace utilisateur pour implémenter un nouveau format d'instantané.

Ces composants permettent la compression. Les autres modifications nécessaires pour implémenter les fonctionnalités d'instantanés compressés sont présentées dans les sections suivantes : Format COW pour les instantanés compressés, dm-user et snapuserd.

Format COW pour les instantanés compressés

Dans Android 12 et versions ultérieures, les instantanés compressés utilisent un format COW spécifique à Android. Le format COW contient des métadonnées sur la mise à jour OTA et comporte des tampons distincts contenant les opérations COW et les nouvelles données du système d'exploitation. Par rapport au format d'instantané du noyau qui n'autorisait que les opérations replace (remplacer le bloc X dans l'image de base par le contenu du bloc Y dans l'instantané), le format COW des instantanés compressés Android est plus expressif et prend en charge les opérations suivantes :

  • Copier : le bloc X de l'appareil de base doit être remplacé par le bloc Y de l'appareil de base.
  • Remplacer : le bloc X de l'appareil de base doit être remplacé par le contenu du bloc Y dans l'instantané. Chacun de ces blocs est compressé au format gz.
  • Zéro : le bloc X de l'appareil de base doit être remplacé par des zéros.
  • XOR : l'appareil COW stocke les octets compressés XOR entre les blocs X et Y. (Disponible sur Android 13 et versions ultérieures)

Les mises à jour OTA complètes ne comportent que des opérations replace et zero. Les mises à jour OTA incrémentielles peuvent également comporter des opérations de copie.

La mise en page complète de l'instantané sur le disque se présente comme suit :

cow format

Figure 2. Format COW Android sur le disque

dm-user

Le module de noyau dm-user permet à userspace d'implémenter des périphériques de blocs device-mapper. Une entrée de table dm-user crée un périphérique divers sous /dev/dm-user/<control-name>. Un processus userspace peut interroger l'appareil pour recevoir les requêtes de lecture et d'écriture du noyau. Chaque requête est associée à un tampon que l'espace utilisateur doit remplir (pour une lecture) ou propager (pour une écriture).

Le module de noyau dm-user fournit une nouvelle interface visible par l'utilisateur au noyau qui ne fait pas partie de la base de code en amont de kernel.org. En attendant, Google se réserve le droit de modifier l'interface dm-user dans Android.

snapuserd

Le composant snapuserd de l'espace utilisateur vers dm-user implémente la compression A/B virtuelle. Snapuserd est un démon d'espace utilisateur chargé d'écrire et de lire les appareils COW Android. Toutes les E/S du snapshot doivent passer par ce service. Lors de l'installation OTA, de nouvelles données du système d'exploitation sont écrites dans l'instantané par snapuserd (avec compression). L'analyse des métadonnées et le décompactage des nouvelles données de bloc sont également gérés ici.

Compression XOR

Pour les appareils lancés avec Android 13 ou version ultérieure, la fonctionnalité de compression XOR, qui est activée par défaut, permet aux instantanés de l'espace utilisateur de stocker des octets compressés XOR entre les anciens blocs et les nouveaux blocs. Lorsqu'un petit nombre d'octets d'un bloc sont modifiés dans une mise à jour A/B virtuelle, le schéma de stockage de compression XOR utilise moins d'espace que le schéma de stockage par défaut, car les instantanés ne stockent pas des octets 4K complets. Cette réduction de la taille des instantanés est possible, car les données XOR contiennent de nombreux zéros et sont plus faciles à compresser que les données brutes des blocs. Sur les appareils Pixel, la compression XOR réduit la taille des instantanés de 25 % à 40 %.

Pour les appareils passant à Android 13 ou version ultérieure, la compression XOR doit être activée. Pour en savoir plus, consultez Compression XOR.

Fusion d'instantanés

Pour les appareils lancés avec Android 13 ou version ultérieure, les processus de fusion et d'instantané dans la compression Virtual A/B sont effectués par le composant espace utilisateur snapuserd. Pour les appareils qui passent à Android 13 ou version ultérieure, cette fonctionnalité doit être activée. Pour en savoir plus, consultez Fusion de l'espace utilisateur.

Le processus de compression A/B virtuelle est décrit ci-dessous :

  1. Le framework monte la partition /system à partir d'un périphérique dm-verity, qui est empilé sur un périphérique dm-user. Cela signifie que chaque E/S du système de fichiers racine est routée vers dm-user.
  2. dm-user achemine les E/S vers le daemon snapuserd de l'espace utilisateur, qui gère la requête d'E/S.
  3. Une fois l'opération de fusion terminée, le framework réduit dm-verity au-dessus de dm-linear (system_base) et supprime dm-user.

Processus de compression A/B virtuelle

Figure 3. Processus de compression A/B virtuel

Le processus de fusion des instantanés peut être interrompu. Si l'appareil est redémarré pendant le processus de fusion, celui-ci reprend après le redémarrage.

Transitions d'initialisation

Lors du démarrage avec des instantanés compressés, l'init de première étape doit démarrer snapuserd pour monter les partitions. Cela pose un problème : lorsque sepolicy est chargé et appliqué, snapuserd est placé dans le mauvais contexte et ses demandes de lecture échouent, avec des refus SELinux.

Pour résoudre ce problème, snapuserd évolue en même temps que init, comme suit :

  1. La première phase de init lance snapuserd à partir du ramdisk et enregistre un descripteur de fichier ouvert dans une variable d'environnement.
  2. La première étape de init consiste à basculer le système de fichiers racine vers la partition système, puis à exécuter la copie système de init.
  3. La copie système de init lit la sepolicy combinée dans une chaîne.
  4. Init appelle mlock() sur toutes les pages soutenues par ext4. Il désactive ensuite toutes les tables device-mapper pour les périphériques d'instantané et arrête snapuserd. Après cela, il est interdit de lire à partir des partitions, car cela provoque un blocage.
  5. L'utilisation du descripteur ouvert pour la copie ramdisk de snapuserd, init relance le daemon avec le contexte selinux approprié. Les tables device-mapper pour les périphériques d'instantané sont réactivées.
  6. Init invoque munlockall(). Vous pouvez à nouveau effectuer des E/S.

Utilisation de l'espace

Le tableau suivant compare l'utilisation de l'espace pour différents mécanismes OTA en utilisant la taille de l'OS et des OTA de Pixel.

Impact de la taille non-A/B A/B Tests A/B virtuels Test A/B virtuel (compressé)
Image d'usine d'origine 4,5 Go super (image de 3,8 Go + 700 Mo réservés)1 9 Go (3,8 Go + 700 Mo réservés, pour deux emplacements) 4,5 Go (3,8 Go pour l'image + 700 Mo réservés) 4,5 Go (3,8 Go pour l'image + 700 Mo réservés)
Autres partitions statiques /cache Aucun Aucun Aucun
Espace de stockage supplémentaire pendant la mise à jour OTA (espace libéré après l'application de la mise à jour OTA) 1,4 Go sur /data 0 3,8 Go2 sur /data 2,1 Go2 sur /data
Espace de stockage total requis pour appliquer la mise à jour OTA 5,9 Go3 (super et données) 9 Go (super) 8,3 Go3 (super et données) 6,6 Go3 (super et données)

1 Indique une disposition supposée basée sur le mappage Pixel.

2 : suppose que la nouvelle image système a la même taille que l'image d'origine.

3 L'espace requis est temporaire jusqu'au redémarrage.

Virtual A/B Android 11

Android 11 de Virtual A/B a écrit dans la partition dynamique au format Kernel COW. Il a finalement été abandonné, car le format COW du noyau n'est pas compatible avec la compression.

Tests A/B virtuels Android 12

Dans Android 12, la compression est compatible sous la forme d'un format COW spécifique à Android. Cette version de Virtual A/B nécessitait une traduction du COW spécifique à Android au format COW du noyau. Il a finalement été remplacé dans Android 13, qui a supprimé la dépendance au format COW du noyau et à dm-snapshot.

Pour implémenter Virtual A/B ou utiliser les fonctionnalités d'instantané compressé, consultez Implémenter Virtual A/B.