Implémenter un test A/B virtuel

Pour implémenter des tests A/B virtuels sur un nouvel appareil ou pour adapter un appareil déjà lancé, vous devez modifier le code spécifique à l'appareil.

Indicateurs de compilation

Les appareils qui utilisent le partitionnement virtuel A/B doivent être configurés comme des appareils A/B et doivent être lancés avec des partitions dynamiques.

Pour les appareils lancés avec A/B virtuel, configurez-les pour qu'ils héritent de la configuration de base de l'appareil A/B virtuel :

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Les appareils lancés avec A/B virtuel n'ont besoin que de la moitié de la taille de la carte pour BOARD_SUPER_PARTITION_SIZE, car les emplacements B ne sont plus en super. Autrement dit, BOARD_SUPER_PARTITION_SIZE doit être supérieur ou égal à sum(taille des groupes de mise à jour) + overhead, qui doit lui-même être supérieur ou égal à sum(taille des partitions) + overhead.

Pour Android 13 et versions ultérieures, afin d'activer les snapshots compressés avec Virtual A/B, héritez de la configuration de base suivante :

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)

Cela permet les instantanés de l'espace utilisateur avec Virtual A/B tout en utilisant une méthode de compression no-op. Vous pouvez ensuite configurer la méthode de compression sur l'une des méthodes compatibles,zstd et lz4. Pour Android 15, la compression peut être davantage personnalisée pour répondre aux besoins de l'appareil. Pour en savoir plus, consultez Affiner la compression.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Pour Android 12, afin d'activer les instantanés compressés avec Virtual A/B, héritez de la configuration de base suivante :

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

Compression XOR

Pour les appareils qui passent à Android 13 ou version ultérieure, la fonctionnalité de compression XOR n'est pas activée par défaut. Pour activer la compression XOR, ajoutez ce qui suit au fichier .mk de l'appareil.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

La compression XOR est activée par défaut pour les appareils qui héritent de android_t_baseline.mk.

Fusion de l'espace utilisateur

Dans la version moderne de Virtual A/B (Android T et versions ultérieures), le processus de fusion des instantanés se déroule entièrement dans l'espace utilisateur. Cette modification est rendue possible par snapuserd et dm-user. Les appareils lancés avec Android 13 ou version ultérieure ont la fusion de l'espace utilisateur activée par défaut. Pour les appareils plus anciens qui sont mis à niveau, cette propriété peut être définie avec les éléments suivants :

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

HAL de contrôle du démarrage

La HAL de contrôle du démarrage fournit une interface permettant aux clients OTA de contrôler les emplacements de démarrage. La fonctionnalité A/B virtuel nécessite une mise à niveau de la version mineure du HAL de contrôle du démarrage, car des API supplémentaires sont nécessaires pour s'assurer que le bootloader est protégé lors du flashage ou du retour aux paramètres d'usine. Consultez IBootControl.hal et types.hal pour obtenir la dernière version de la définition HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Modifications apportées à fstab

L'intégrité de la partition de métadonnées est essentielle au processus de démarrage, en particulier juste après l'application d'une mise à jour OTA. La partition de métadonnées doit donc être vérifiée avant que first_stage_init ne la monte. Pour ce faire, ajoutez l'indicateur check fs_mgr à l'entrée pour /metadata. Voici un exemple :

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Exigences concernant le noyau

Pour activer la création d'instantanés, définissez CONFIG_DM_SNAPSHOT sur true.

Pour les appareils utilisant F2FS, incluez le correctif du noyau f2fs: export FS_NOCOW_FL flag to user pour résoudre le problème d'épinglage de fichiers. Incluez également le correctif du noyau f2fs: support aligned pinned file.

La fonctionnalité A/B virtuel repose sur des fonctionnalités ajoutées dans la version 4.3 du noyau : le bit d'état overflow dans les cibles snapshot et snapshot-merge. Tous les appareils lancés avec Android 9 ou version ultérieure devraient déjà être équipés du noyau 4.4 ou version ultérieure.

Pour activer les instantanés compressés, la version minimale du noyau compatible est la version 4.19. Définissez CONFIG_DM_USER=m ou CONFIG_DM_USER=y. Si vous utilisez l'ancien (un module), le module doit être chargé dans le ramdisk de première étape. Pour ce faire, ajoutez la ligne suivante au fichier Makefile de l'appareil :

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Modifications apportées à l'outil Fastboot

Android 11 apporte les modifications suivantes au protocole fastboot :

  • getvar snapshot-update-status : renvoie la valeur que le HAL de contrôle du démarrage a communiquée au bootloader :
    • Si l'état est MERGING, le bootloader doit renvoyer merging.
    • Si l'état est SNAPSHOTTED, le bootloader doit renvoyer snapshotted.
    • Sinon, le bootloader doit renvoyer none.
  • snapshot-update merge : termine une opération de fusion et démarre en mode Recovery/fastbootd si nécessaire. Cette commande n'est valide que si snapshot-update-status est défini sur merging et n'est compatible qu'avec fastbootd.
  • snapshot-update cancel : définit l'état de fusion du HAL de contrôle du démarrage sur CANCELLED. Cette commande n'est pas valide lorsque l'appareil est verrouillé.
  • erase ou wipe : un erase ou un wipe de metadata, userdata ou une partition contenant l'état de fusion pour le HAL de contrôle du démarrage doivent vérifier l'état de fusion de l'instantané. Si l'état est MERGING ou SNAPSHOTTED, l'appareil doit abandonner l'opération.
  • set_active : une commande set_active qui modifie l'emplacement actif doit vérifier l'état de la fusion de l'instantané. Si l'état est MERGING, l'appareil doit abandonner l'opération. L'emplacement peut être modifié sans risque dans l'état SNAPSHOTTED.

Ces modifications visent à éviter qu'un appareil ne devienne involontairement non amorçable, mais elles peuvent perturber les outils automatisés. Lorsque les commandes sont utilisées comme composant du flashage de toutes les partitions, comme l'exécution de fastboot flashall, il est recommandé d'utiliser le flux suivant :

  1. Requête getvar snapshot-update-status.
  2. Si merging ou snapshotted, émettez snapshot-update cancel.
  3. Poursuivez la procédure de flashage.

Réduire les besoins de stockage

Il est fortement recommandé aux appareils qui ne disposent pas d'un stockage A/B complet alloué dans le super et qui prévoient d'utiliser /data si nécessaire d'utiliser l'outil de mappage de blocs. L'outil de mappage des blocs assure une allocation cohérente des blocs entre les versions, ce qui réduit les écritures inutiles dans l'instantané. Cette opération est décrite dans la section Réduire la taille des mises à jour OTA.

Algorithmes de compression OTA

Les packages OTA peuvent être ajustés pour différentes métriques de performances. Android fournit plusieurs méthodes de compression compatibles (lz4, zstd et none) qui présentent des compromis entre le temps d'installation, l'utilisation de l'espace COW, le temps de démarrage et le temps de fusion des instantanés. L'option lz4 compression method est activée par défaut pour l'abdominale virtuelle avec compression.

Compression d'affinage

Les algorithmes de compression peuvent être personnalisés davantage grâce à deux méthodes : le niveau de compression (le degré de compression obtenu au détriment de la vitesse) et le facteur de compression (la taille maximale de la fenêtre compressible). Le niveau de compression est disponible pour certains algorithmes tels que zstd. Le fait de modifier le niveau entraîne un compromis entre la vitesse et le taux de compression. Le facteur de compression décrit la taille maximale de la fenêtre de compression utilisée lors de l'installation OTA. La valeur par défaut est de 64 ko, mais vous pouvez la remplacer en personnalisant le paramètre de compilation PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR. Facteurs de compression compatibles : 4k, 8k, 16k, 32k, 64k, 128k et 256k.

PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Mise à jour OTA incrémentielle sur le Pixel 8 Pro

Temps d'installation sans la phase post-installation Utilisation de l'espace COW Temps de démarrage après la mise à jour OTA Heure de fusion de l'instantané
lz4 18 min 15 s 2,5 Go 32,7 s 98,6 s
zstd 24 min 49 s 2,05 Go 36.3 sec 133.2 sec
none 16 min 42 s 4,76 Go 28.7 sec 76,6 s

OTA complet sur le Pixel 8 Pro

Temps d'installation sans la phase post-installation Utilisation de l'espace COW Temps de démarrage après la mise à jour OTA Heure de fusion de l'instantané
lz4 15 min 11 s 4,16 Go 17,6 s 82,2 s
zstd 16 min 19 s 3,46 Go 21.0 sec 106,3 s
none 13 min 33 s 6,39 Go 18,5 s 92,5 s