Implementare il test A/B virtuale

Per implementare i test A/B virtuali su un nuovo dispositivo o per adattare un dispositivo lanciato, devi apportare modifiche al codice specifico del dispositivo.

Creare flag

I dispositivi che utilizzano A/B virtuale devono essere configurati come dispositivi A/B e devono essere avviati con partizioni dinamiche.

Per i dispositivi che vengono lanciati con A/B virtuale, impostali in modo che ereditino la configurazione di base del dispositivo A/B virtuale:

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

I dispositivi lanciati con A/B virtuale richiedono solo la metà delle dimensioni della scheda per BOARD_SUPER_PARTITION_SIZE perché gli slot B non sono più in super. ovvero BOARD_SUPER_PARTITION_SIZE deve essere maggiore o uguale a sum(size of update groups) + overhead, che a sua volta deve essere maggiore o uguale a sum(size of partitions) + overhead.

Per Android 13 e versioni successive, per attivare gli snapshot compressi con Virtual A/B, eredita la seguente configurazione di base:

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

In questo modo vengono abilitati gli snapshot userspace con Virtual A/B utilizzando un metodo di compressione no-op. A questo punto, puoi configurare il metodo di compressione su uno dei metodi supportati,zstd e lz4. Per Android 15, la compressione può essere ulteriormente personalizzata in base alle esigenze del dispositivo. Per ulteriori informazioni, consulta Ottimizzazione della compressione.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Per Android 12, per attivare gli snapshot compressi con Virtual A/B, eredita la seguente configurazione di base:

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

Compressione XOR

Per i dispositivi che eseguono l'upgrade ad Android 13 e versioni successive, la funzionalità di compressione XOR non è attivata per impostazione predefinita. Per attivare la compressione XOR, aggiungi quanto segue al file .mk del dispositivo.

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

La compressione XOR è attiva per impostazione predefinita per i dispositivi che ereditano da android_t_baseline.mk.

Unione dello spazio utente

Nella versione moderna di Virtual A/B (Android T e versioni successive), il processo di unione degli snapshot avviene interamente nello spazio utente. Questa modifica è resa possibile da snapuserd e dm-user. I dispositivi lanciati con Android 13 e versioni successive hanno l'unione dello spazio utente attivata per impostazione predefinita e per i dispositivi meno recenti che eseguono l'upgrade, questa proprietà può essere impostata con quanto segue:

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

Boot control HAL

L'HAL di controllo dell'avvio fornisce un'interfaccia per i client OTA per controllare gli slot di avvio. Virtual A/B richiede un upgrade della versione secondaria dell'HAL di controllo dell'avvio perché sono necessarie API aggiuntive per garantire che il bootloader sia protetto durante il flashing o il ripristino dei dati di fabbrica. Consulta IBootControl.hal e types.hal per la versione più recente della definizione 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
}

Modifiche a fstab

L'integrità della partizione dei metadati è essenziale per il processo di avvio, soprattutto subito dopo l'applicazione di un aggiornamento OTA. Pertanto, la partizione di metadati deve essere controllata prima che first_stage_init la monti. Per assicurarti che ciò avvenga, aggiungi il flag check fs_mgr alla voce per /metadata. Di seguito è riportato un esempio:

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

Requisiti del kernel

Per attivare la creazione di snapshot, imposta CONFIG_DM_SNAPSHOT su true.

Per i dispositivi che utilizzano F2FS, includi la patch del kernel f2fs: export FS_NOCOW_FL flag to user per correggere il blocco dei file. Includi anche la patch del kernel f2fs: support aligned pinned file.

Virtual A/B si basa sulle funzionalità aggiunte nella versione 4.3 del kernel: il bit di stato overflow nei target snapshot e snapshot-merge. Tutti i dispositivi lanciati con Android 9 e versioni successive dovrebbero già avere la versione del kernel 4.4 o successive.

Per abilitare gli snapshot compressi, la versione minima del kernel supportata è 4.19. Imposta CONFIG_DM_USER=m o CONFIG_DM_USER=y. Se utilizzi il primo (un modulo), il modulo deve essere caricato nel ramdisk della prima fase. Per farlo, aggiungi la seguente riga al Makefile del dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Modifiche agli strumenti Fastboot

Android 11 apporta le seguenti modifiche al protocollo fastboot:

  • getvar snapshot-update-status: restituisce il valore che l'HAL di controllo dell'avvio ha comunicato al bootloader:
    • Se lo stato è MERGING, il bootloader deve restituire merging.
    • Se lo stato è SNAPSHOTTED, il bootloader deve restituire snapshotted.
    • In caso contrario, il bootloader deve restituire none.
  • snapshot-update merge: completa un'operazione di unione, avviando il sistema operativo di ripristino/fastbootd, se necessario. Questo comando è valido solo se snapshot-update-status è merging ed è supportato solo in fastbootd.
  • snapshot-update cancel: imposta lo stato di unione dell'HAL di controllo dell'avvio su CANCELLED. Questo comando non è valido quando il dispositivo è bloccato.
  • erase o wipe: un erase o wipe di metadata, userdata o una partizione che contiene lo stato di unione per l'HAL di controllo dell'avvio deve controllare lo stato di unione dello snapshot. Se lo stato è MERGING o SNAPSHOTTED, il dispositivo deve interrompere l'operazione.
  • set_active: un comando set_active che cambia lo slot attivo deve controllare lo stato dell'unione degli snapshot. Se lo stato è MERGING, il dispositivo deve interrompere l'operazione. Lo slot può essere modificato in sicurezza nello stato SNAPSHOTTED.

Queste modifiche sono progettate per evitare di rendere accidentalmente un dispositivo non avviabile, ma possono interrompere gli strumenti automatizzati. Quando i comandi vengono utilizzati come componente del flashing di tutte le partizioni, ad esempio l'esecuzione di fastboot flashall, è consigliabile utilizzare il seguente flusso:

  1. Query getvar snapshot-update-status.
  2. Se merging o snapshotted, problema snapshot-update cancel.
  3. Procedi con i passaggi per il flashing.

Ridurre i requisiti di spazio di archiviazione

I dispositivi a cui non è stato allocato lo spazio di archiviazione A/B completo in super e che prevedono di utilizzare /data in base alle necessità sono caldamente invitati a utilizzare lo strumento di mappatura dei blocchi. Lo strumento di mappatura dei blocchi mantiene l'allocazione dei blocchi coerente tra le build, riducendo le scritture non necessarie nello snapshot. Questo è documentato in Riduzione delle dimensioni OTA.

Algoritmi di compressione OTA

I pacchetti OTA possono essere ottimizzati per diverse metriche di rendimento. Android fornisce diversi metodi di compressione supportati (lz4, zstd e none) che presentano compromessi tra tempo di installazione, utilizzo dello spazio COW, tempo di avvio e tempo di unione degli snapshot. L'opzione predefinita abilitata per l'ab virtuale con compressione è lz4 compression method.

Ottimizzazione della compressione

Gli algoritmi di compressione possono essere ulteriormente personalizzati tramite due metodi: (livello di compressione) (la quantità di compressione ottenuta a scapito della velocità) e (fattore di compressione) (la dimensione massima della finestra comprimibile). Il livello di compressione è disponibile per alcuni algoritmi come zstd e la modifica del livello comporta un compromesso tra velocità e rapporto di compressione. Il fattore di compressione descrive le dimensioni massime della finestra di compressione utilizzate durante l'installazione OTA. Il valore predefinito è 64 k, ma può essere sostituito personalizzando il parametro di build PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR. Fattori di compressione supportati: 4k, 8k, 16k, 32k, 64k, 128k e 256k.

PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Aggiornamento OTA incrementale su Pixel 8 Pro

Install time w/o postinstall phase Utilizzo dello spazio COW Tempo di avvio post-OTA Tempo di unione degli snapshot
lz4 18 min 15 sec 2,5 GB 32,7 sec 98,6 sec
zstd 24 min 49s 2,05 GB 36,3 sec 133,2 sec
nessuno 16 min 42 sec 4,76 GB 28,7 sec 76,6 sec

OTA completa su Pixel 8 Pro

Install time w/o postinstall phase Utilizzo dello spazio COW Tempo di avvio post-OTA Tempo di unione degli snapshot
lz4 15 min 11 sec 4,16 GB 17,6 sec 82,2 sec
zstd 16 min 19s 3,46 GB 21,0 sec 106,3 sec
nessuno 13 min 33 sec 6,39 GB 18,5 sec 92,5 sec