Implementa A/B virtuale

Per implementare l'A/B virtuale su un nuovo dispositivo o per aggiornare un dispositivo lanciato, è necessario apportare modifiche al codice specifico del dispositivo.

Costruisci bandiere

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

Per i dispositivi avviati 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 avviati 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. Cioè, BOARD_SUPER_PARTITION_SIZE deve essere maggiore o uguale a sum(dimensione dei gruppi di aggiornamento) + sovraccarico , che, a sua volta, deve essere maggiore o uguale a sum(dimensione delle partizioni) + sovraccarico .

Per Android 13 e versioni successive, per abilitare 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/android_t_baseline.mk)

Ciò consente snapshot dello spazio utente con Virtual A/B utilizzando un metodo di compressione no-op. È quindi possibile configurare il metodo di compressione su uno dei metodi supportati, gz , zstd e lz4 .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

Per Android 12, per abilitare 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'aggiornamento ad Android 13 e versioni successive, la funzionalità di compressione XOR non è abilitata per impostazione predefinita. Per abilitare la compressione XOR, aggiungi quanto segue al file .mk del dispositivo.

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

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

Unione dello spazio utente

Per i dispositivi che eseguono l'aggiornamento ad Android 13 e versioni successive, il processo di unione dello spazio utente descritto in Stratificazione del mapping dei dispositivi non è abilitato per impostazione predefinita. Per abilitare l'unione dello spazio utente, aggiungi la seguente riga al file .mk del dispositivo:

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

L'unione dello spazio utente è abilitata per impostazione predefinita sui dispositivi che si avviano con 13 e versioni successive.

Controllo di avvio HAL

L' HAL di controllo di avvio fornisce un'interfaccia per i client OTA per controllare gli slot di avvio. L'A/B virtuale richiede un aggiornamento della versione minore dell'HAL di controllo di avvio poiché sono necessarie API aggiuntive per garantire che il bootloader sia protetto durante il flashing/il ripristino delle impostazioni di fabbrica. Vedere IBootControl.hal etypes.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
}

Fstab cambia

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

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

Requisiti del kernel

Per abilitare lo snapshot, impostare CONFIG_DM_SNAPSHOT su true .

Per i dispositivi che utilizzano F2FS, includere il flag f2fs: export FS_NOCOW_FL nella patch del kernel dell'utente per correggere il blocco dei file. Includi f2fs: supporta anche la patch del kernel del file bloccato allineato .

L'A/B virtuale si basa sulle funzionalità aggiunte nella versione 4.3 del kernel: il bit di stato di overflow nelle destinazioni snapshot e snapshot-merge . Tutti i dispositivi avviati con Android 9 e versioni successive dovrebbero già avere la versione del kernel 4.4 o successiva.

Per abilitare gli snapshot compressi, la versione minima del kernel supportata è 4.19. Impostare CONFIG_DM_USER=m o CONFIG_DM_USER=y . Se si utilizza il primo (un modulo), il modulo deve essere caricato nel ramdisk del primo stadio. Ciò può essere ottenuto aggiungendo la seguente riga al Makefile del dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Retrofit sui dispositivi che stanno aggiornando ad Android 11

Quando si esegue l'aggiornamento ad Android 11, i dispositivi avviati con partizioni dinamiche possono facoltativamente eseguire il retrofit A/B virtuale. Il processo di aggiornamento è sostanzialmente lo stesso dell'avvio dei dispositivi con A/B virtuale, con alcune piccole differenze:

  • Posizione dei file COW : per i dispositivi di avvio, il client OTA utilizza tutto lo spazio vuoto disponibile nella super partizione prima di utilizzare lo spazio in /data . Per i dispositivi retrofit, c'è sempre spazio sufficiente nella super partizione in modo che il file COW non venga mai creato su /data .

  • Flag funzionalità in fase di creazione : per i dispositivi che eseguono il retrofit di A/B virtuale, sia PRODUCT_VIRTUAL_AB_OTA che PRODUCT_VIRTUAL_AB_OTA_RETROFIT sono impostati su true , come mostrato di seguito:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Dimensioni della super partizione : i dispositivi avviati con A/B virtuale possono dimezzare BOARD_SUPER_PARTITION_SIZE perché gli slot B non si trovano nella super partizione. I dispositivi che eseguono il retrofit A/B virtuale mantengono la vecchia dimensione della super partizione, quindi BOARD_SUPER_PARTITION_SIZE è maggiore o uguale a 2 * sum(dimensione dei gruppi di aggiornamento) + sovraccarico , che a sua volta è maggiore o uguale a 2 * sum(dimensione delle partizioni) + sopraelevato .

Modifiche al bootloader

Durante la fase di unione di un aggiornamento, /data contiene l'unica istanza intera del sistema operativo Android. Una volta avviata la migrazione, le partizioni native system , vendor e product saranno incomplete fino al termine della copia. Se durante questo processo vengono ripristinate le impostazioni di fabbrica del dispositivo, tramite ripristino o tramite la finestra di dialogo Impostazioni di sistema, il dispositivo non sarà avviabile.

Prima di cancellare /data , completa l'unione in ripristino o rollback a seconda dello stato del dispositivo:

  • Se la nuova build è stata avviata correttamente in precedenza, completa la migrazione.
  • Altrimenti, torna al vecchio slot:
    • Per le partizioni dinamiche, ripristina lo stato precedente.
    • Per le partizioni statiche, imposta lo slot attivo sul vecchio slot.

Sia il bootloader che fastbootd possono cancellare la partizione /data se il dispositivo è sbloccato. Mentre fastbootd può forzare il completamento della migrazione, il bootloader non può. Il bootloader non sa se è in corso o meno un'unione o quali blocchi in /data costituiscono le partizioni del sistema operativo. I dispositivi devono impedire all'utente di rendere inconsapevolmente il dispositivo inutilizzabile (bricking) effettuando le seguenti operazioni:

  1. Implementare l'HAL del controllo di avvio in modo che il bootloader possa leggere il valore impostato dal metodo setSnapshotMergeStatus() .
  2. Se lo stato di unione è MERGING o se lo stato di unione è SNAPSHOTTED e lo slot è cambiato nello slot appena aggiornato, le richieste di cancellazione userdata , metadata o della partizione che memorizza lo stato di unione devono essere rifiutate nel bootloader.
  3. Implementa il comando fastboot snapshot-update cancel in modo che gli utenti possano segnalare al bootloader che desiderano bypassare questo meccanismo di protezione.
  4. Modifica gli strumenti o gli script di flashing personalizzati per fastboot snapshot-update cancel durante il flashing dell'intero dispositivo. Questo è sicuro perché il flashing dell'intero dispositivo rimuove l'OTA. Gli strumenti possono rilevare questo comando in fase di esecuzione implementando fastboot getvar snapshot-update-status . Questo comando aiuta a distinguere tra le condizioni di errore.

Esempio

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()));
}

Modifiche agli strumenti di avvio rapido

Android 11 apporta le seguenti modifiche al protocollo fastboot:

  • getvar snapshot-update-status — Restituisce il valore che l'HAL di controllo di avvio ha comunicato al bootloader:
    • Se lo stato è MERGING , il bootloader deve restituire merging .
    • Se lo stato è SNAPSHOTTED , il bootloader deve restituire snapshotted .
    • Altrimenti il ​​bootloader deve restituire none .
  • snapshot-update merge — Completa un'operazione di unione, avviando tramite recovery/fastbootd se necessario. Questo comando è valido solo se snapshot-update-status sta merging ed è supportato solo in fastbootd.
  • snapshot-update cancel — Imposta lo stato di unione dell'HAL di controllo di avvio su CANCELLED . Questo comando non è valido quando il dispositivo è bloccato.
  • erase o wipe : una erase o wipe di metadata , userdata o una partizione che mantiene lo stato di unione per l'HAL di controllo di avvio dovrebbe controllare lo stato di unione dello snapshot. Se lo stato è MERGING o SNAPSHOTTED , il dispositivo dovrebbe interrompere l'operazione.
  • set_active : un comando set_active che modifica lo slot attivo dovrebbe verificare lo stato di unione degli snapshot. Se lo stato è MERGING , il dispositivo dovrebbe interrompere l'operazione. Lo slot può essere modificato in sicurezza nello stato SNAPSHOTTED .

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

  1. Interroga getvar snapshot-update-status .
  2. In caso di merging o snapshotted , emettere snapshot-update cancel .
  3. Procedere con i passaggi lampeggianti.

Ridurre i requisiti di archiviazione

Si consiglia vivamente ai dispositivi che non dispongono di spazio di archiviazione A/B completo allocato in super e che prevedono di utilizzare /data secondo necessità, di utilizzare lo strumento di mappatura dei blocchi. Lo strumento di mappatura dei blocchi mantiene coerente l'allocazione dei blocchi tra le build, riducendo le scritture non necessarie sullo snapshot. Ciò è documentato in Riduzione delle dimensioni OTA .

Metodi di compressione OTA

I pacchetti OTA possono essere ottimizzati per diversi parametri di prestazione. Android fornisce diversi metodi di compressione supportati ( gz , 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 ab virtuale con compressione è il gz compression method . (Nota: le prestazioni relative tra i metodi di compressione variano a seconda della velocità della CPU e del throughput di archiviazione, che può variare a seconda del dispositivo. Tutti i pacchetti OTA generati di seguito hanno PostInstall disabilitato, il che rallenterà leggermente il tempo di avvio. La dimensione totale della partizione dinamica di un ota completo senza compressione è 4,81 GB ).

OTA incrementale su Pixel 6 Pro

Tempo di installazione senza fase postinstallazione Utilizzo dello spazio MUCCA Orario di avvio post OTA Ora di unione delle istantanee
gz 24 minuti 1,18 GB 40,2 secondi 45,5 secondi
lz4 13 minuti 1,49GB 37,4 secondi 37,1 secondi
nessuno 13 minuti 2,90GB 37,6 secondi 40,7 secondi

OTA completo su Pixel 6 Pro

Tempo di installazione senza fase postinstallazione Utilizzo dello spazio MUCCA Orario di avvio post OTA Ora di unione delle istantanee
gz 23 minuti 2,79GB 24,9 secondi 41,7 secondi
lz4 12 minuti 3,46GB 20,0 secondi 25,3 secondi
nessuno 10 minuti 4,85 GB 20,6 secondi 29,8 secondi