Implémenter l'A/B virtuel

Pour implémenter l'A/B virtuel sur un nouvel appareil ou pour moderniser un appareil lancé, vous devez apporter des modifications au code spécifique à l'appareil.

Construire des drapeaux

Les appareils qui utilisent l'A/B virtuel doivent être configurés en tant qu'appareil 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 des appareils A/B virtuels :

$(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(size of update groups) + Overhead , qui, à son tour, doit être supérieur ou égal à sum(size of partitions) + Overhead .

Pour Android 13 et versions ultérieures, pour 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/android_t_baseline.mk)

Cela permet d'obtenir des instantanés de l'espace utilisateur avec Virtual A/B tout en utilisant une méthode de compression sans opération. Vous pouvez ensuite configurer la méthode de compression sur l'une des méthodes prises en charge, gz , zstd et lz4 .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

Pour Android 12, pour 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 mis à niveau vers Android 13 et versions ultérieures, 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

Pour les appareils mis à niveau vers Android 13 et versions ultérieures, le processus de fusion de l’espace utilisateur tel que décrit dans Superposition de mappeurs d’appareils n’est pas activé par défaut. Pour activer la fusion de l'espace utilisateur, ajoutez la ligne suivante au fichier .mk de l'appareil :

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

La fusion de l'espace utilisateur est activée par défaut sur les appareils lancés avec 13 et versions ultérieures.

Contrôle de démarrage HAL

Le HAL de contrôle de démarrage fournit une interface permettant aux clients OTA de contrôler les emplacements de démarrage. Virtual A/B nécessite une mise à niveau mineure de la version du HAL de contrôle de démarrage, car des API supplémentaires sont nécessaires pour garantir que le chargeur de démarrage est protégé pendant le flashage/la réinitialisation d'usine. Voir IBootControl.hal et types.hal pour 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 de 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. Ainsi, la partition de métadonnées doit être vérifiée avant que first_stage_init la monte. Pour vous assurer que cela se produit, ajoutez l'indicateur check fs_mgr à l'entrée pour /metadata . Ce qui suit fournit un exemple :

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

Exigences du noyau

Pour activer la capture instantanée, définissez CONFIG_DM_SNAPSHOT sur true .

Pour les appareils utilisant F2FS, incluez l' indicateur f2fs: export FS_NOCOW_FL vers le correctif du noyau utilisateur pour corriger l'épinglage des fichiers. Incluez également le f2fs: prend en charge le correctif du noyau de fichiers épinglés alignés .

Virtual A/B s'appuie sur des fonctionnalités ajoutées dans la version 4.3 du noyau : le bit d'état de débordement dans les cibles snapshot et snapshot-merge . Tous les appareils lancés avec Android 9 et versions ultérieures devraient déjà disposer de la version 4.4 ou ultérieure du noyau.

Pour activer les instantanés compressés, la version minimale du noyau prise en charge est 4.19. Définissez CONFIG_DM_USER=m ou CONFIG_DM_USER=y . Si vous utilisez le premier (un module), le module doit être chargé dans le disque virtuel de premier étage. Ceci peut être réalisé en ajoutant la ligne suivante au Makefile du périphérique :

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Mise à niveau sur les appareils mis à niveau vers Android 11

Lors de la mise à niveau vers Android 11, les appareils lancés avec des partitions dynamiques peuvent éventuellement mettre à niveau l'A/B virtuel. Le processus de mise à jour est essentiellement le même que pour les appareils lancés avec A/B virtuel, avec quelques différences mineures :

  • Emplacement des fichiers COW — Pour les périphériques de lancement, le client OTA utilise tout l'espace vide disponible dans la super partition avant d'utiliser l'espace dans /data . Pour les appareils modernisés, il y a toujours suffisamment d'espace dans la super partition pour que le fichier COW ne soit jamais créé sur /data .

  • Indicateurs de fonctionnalité au moment de la construction — Pour les appareils modernisant l'A/B virtuel, PRODUCT_VIRTUAL_AB_OTA et PRODUCT_VIRTUAL_AB_OTA_RETROFIT sont définis sur true , comme indiqué ci-dessous :

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Taille de la super partition — Les appareils lancés avec A/B virtuel peuvent réduire BOARD_SUPER_PARTITION_SIZE de moitié car les emplacements B ne sont pas dans la super partition. Les appareils modernisant l'A/B virtuel conservent l'ancienne taille de super partition, donc BOARD_SUPER_PARTITION_SIZE est supérieur ou égal à 2 * somme (taille des groupes de mise à jour) + surcharge , qui à son tour est supérieure ou égale à 2 * somme (taille des partitions) + frais généraux .

Modifications du chargeur de démarrage

Lors de l'étape de fusion d'une mise à jour, /data contient la seule instance complète du système d'exploitation Android. Une fois la migration démarrée, les partitions natives system , vendor et product sont incomplètes jusqu'à la fin de la copie. Si le périphérique est réinitialisé aux paramètres d'usine au cours de ce processus, soit par récupération, soit via la boîte de dialogue Paramètres système, le périphérique ne pourra plus démarrer.

Avant d'effacer /data , terminez la fusion en récupération ou en restauration selon l'état de l'appareil :

  • Si la nouvelle version a démarré avec succès auparavant, terminez la migration.
  • Sinon, revenez à l'ancien emplacement :
    • Pour les partitions dynamiques, revenez à l'état précédent.
    • Pour les partitions statiques, définissez l'emplacement actif sur l'ancien emplacement.

Le chargeur de démarrage et fastbootd peuvent effacer la partition /data si le périphérique est déverrouillé. Alors que fastbootd peut forcer la migration à se terminer, le chargeur de démarrage ne le peut pas. Le chargeur de démarrage ne sait pas si une fusion est en cours ou non, ni quels blocs dans /data constituent les partitions du système d'exploitation. Les appareils doivent empêcher l'utilisateur de rendre l'appareil inutilisable (bricking) sans le savoir en procédant comme suit :

  1. Implémentez le HAL de contrôle de démarrage afin que le chargeur de démarrage puisse lire la valeur définie par la méthode setSnapshotMergeStatus() .
  2. Si l'état de fusion est MERGING , ou si l'état de fusion est SNAPSHOTTED et que l'emplacement a été remplacé par l'emplacement nouvellement mis à jour, alors les demandes d'effacement userdata , metadata ou de la partition stockant l'état de fusion doivent être rejetées dans le chargeur de démarrage.
  3. Implémentez la commande fastboot snapshot-update cancel afin que les utilisateurs puissent signaler au chargeur de démarrage qu'ils souhaitent contourner ce mécanisme de protection.
  4. Modifiez les outils ou scripts de flashage personnalisés pour émettre fastboot snapshot-update cancel lors du flashage de l'ensemble du périphérique. Ce problème peut être émis en toute sécurité, car le flashage de l'ensemble de l'appareil supprime l'OTA. Les outils peuvent détecter cette commande au moment de l'exécution en implémentant fastboot getvar snapshot-update-status . Cette commande permet de différencier les conditions d'erreur.

Exemple

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Modifications des outils Fastboot

Android 11 apporte les modifications suivantes au protocole fastboot :

  • getvar snapshot-update-status — Renvoie la valeur que le HAL de contrôle de démarrage a communiquée au chargeur de démarrage :
    • Si l'état est MERGING , le chargeur de démarrage doit renvoyer merging .
    • Si l'état est SNAPSHOTTED , le chargeur de démarrage doit renvoyer snapshotted .
    • Sinon, le chargeur de démarrage doit renvoyer none .
  • snapshot-update merge — Termine une opération de fusion, en démarrant sur recovery/fastbootd si nécessaire. Cette commande n'est valide que si snapshot-update-status est merging et n'est prise en charge que dans fastbootd.
  • snapshot-update cancel — Définit l'état de fusion du contrôle de démarrage HAL sur CANCELLED . Cette commande n'est pas valide lorsque l'appareil est verrouillé.
  • erase ou wipe - Un erase ou wipe des metadata , userdata ou d'une partition contenant l'état de fusion pour le contrôle de démarrage HAL doit vérifier l'état de fusion des instantanés. 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 fusion des instantanés. Si l'état est MERGING , l'appareil doit abandonner l'opération. L'emplacement peut être modifié en toute sécurité dans l'état SNAPSHOTTED .

Ces modifications sont conçues pour éviter de rendre accidentellement un périphérique impossible à démarrer, mais elles peuvent perturber les outils automatisés. Lorsque les commandes sont utilisées comme composant du flashage de toutes les partitions, par exemple en exécutant fastboot flashall , il est recommandé d'utiliser le flux suivant :

  1. Requête getvar snapshot-update-status .
  2. En cas merging ou snapshotted , exécutez snapshot-update cancel .
  3. Procédez aux étapes clignotantes.

Réduisez les besoins de stockage

Il est fortement recommandé aux appareils qui ne disposent pas d'un stockage A/B complet alloué dans super et qui prévoient d'utiliser /data si nécessaire d'utiliser l'outil de mappage de blocs. L'outil de mappage de blocs maintient l'allocation de blocs cohérente entre les builds, réduisant ainsi les écritures inutiles sur l'instantané. Ceci est documenté sous Réduire la taille de l’OTA .

Méthodes de compression OTA

Les packages OTA peuvent être optimisés pour différentes mesures de performances. Android propose plusieurs méthodes de compression prises en charge ( gz , 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 par défaut activée pour l'ab virtuel avec compression est la gz compression method . (Remarque : les performances relatives entre les méthodes de compression varient en fonction de la vitesse du processeur et du débit de stockage, qui peuvent changer en fonction du périphérique. Tous les packages OTA générés ci-dessous sont avec PostInstall désactivé, ce qui ralentira légèrement le temps de démarrage. La taille totale de la partition dynamique d'un ota complet sans compression est de 4,81 Go ).

OTA incrémentielle sur le Pixel 6 Pro

Temps d'installation sans phase de post-installation Utilisation de l'espace COW Temps de démarrage post-OTA Heure de fusion des instantanés
gz 24 minutes 1,18 Go 40,2 secondes 45,5 secondes
lz4 13 minutes 1,49 Go 37,4 secondes 37,1 secondes
aucun 13 minutes 2,90 Go 37,6 secondes 40,7 secondes

OTA complet sur le Pixel 6 Pro

Temps d'installation sans phase de post-installation Utilisation de l'espace COW Temps de démarrage post-OTA Heure de fusion des instantanés
gz 23 minutes 2,79 Go 24,9 secondes 41,7 secondes
lz4 12 minutes 3,46 Go 20,0 secondes 25,3 secondes
aucun 10 minutes 4,85 Go 20,6 secondes 29,8 secondes