Implementazione dell'A/B virtuale

Per implementare l'A/B virtuale su un nuovo dispositivo o per eseguire il retrofit di un dispositivo avviato, è necessario apportare modifiche al codice specifico del dispositivo.

Costruisci bandiere

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 si avviano 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 che si avviano 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(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 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ò abilita le istantanee dello spazio utente con Virtual A/B mentre si utilizza un metodo di compressione no-op. È quindi possibile configurare il metodo di compressione su uno dei metodi supportati, gz e brotli .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := gz

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 funzione 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 .

Fusione dello spazio utente

Per i dispositivi che eseguono l'aggiornamento ad Android 13 e versioni successive, il processo di unione dello spazio utente come descritto in Stratificazione device-mapper 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. Virtual A/B richiede un aggiornamento della versione minore dell'HAL di controllo di avvio perché sono necessarie API aggiuntive per garantire la protezione del bootloader durante il flashing/ripristino delle impostazioni di fabbrica. Vedere IBootControl.hal e types.hal per l'ultima versione 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. Quindi, la partizione dei metadati deve essere controllata prima che first_stage_init la monti. Per assicurarti che ciò accada, aggiungi il flag check fs_mgr alla voce per /metadata . Quanto segue fornisce 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, imposta CONFIG_DM_SNAPSHOT su true .

Per i dispositivi che utilizzano F2FS, includi 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 dei file bloccati allineati .

Virtual A/B 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 che si avviano con Android 9 e versioni successive dovrebbero già disporre della versione del kernel 4.4 o successiva.

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

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Retrofit su dispositivi che eseguono l'aggiornamento ad Android 11

Quando si esegue l'aggiornamento ad Android 11, i dispositivi avviati con partizioni dinamiche possono facoltativamente aggiornare A/B virtuale. Il processo di aggiornamento è sostanzialmente lo stesso dei dispositivi che si avviano 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 delle funzionalità in fase di compilazione : per i dispositivi che aggiornano 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 che si avviano con A/B virtuale possono dimezzare BOARD_SUPER_PARTITION_SIZE perché gli slot B non si trovano nella super partizione. I dispositivi che aggiornano l'A/B virtuale mantengono la vecchia dimensione della super partizione, quindi BOARD_SUPER_PARTITION_SIZE è maggiore o uguale a 2 * sum(size of update groups) + overhead , che a sua volta è maggiore o uguale a 2 * sum(size of partitions) + spese generali .

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 del system nativo , vendor e product sono incomplete fino al termine della copia. Se il dispositivo viene ripristinato alle impostazioni di fabbrica durante questo processo, 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, terminare la migrazione.
  • Altrimenti, esegui il rollback al vecchio slot:
    • Per le partizioni dinamiche, eseguire il rollback allo stato precedente.
    • Per le partizioni statiche, impostare 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 no. 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 inutilizzabile il dispositivo (bricking) procedendo come segue:

  1. Implementare l'HAL di 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 cancellare userdata , metadata o la 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 vogliono ignorare questo meccanismo di protezione.
  4. Modifica gli strumenti o gli script di flashing personalizzati per eseguire fastboot snapshot-update cancel durante il flashing dell'intero dispositivo. Questo è sicuro da emettere 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 differenziare 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 Fastboot

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 .
    • In caso contrario, il bootloader deve restituire none .
  • snapshot-update merge — Completa un'operazione di unione, avviando in recovery/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 di avvio su CANCELLED . Questo comando non è valido quando il dispositivo è bloccato.
  • erase or wipe — Una erase o wipe di metadata , userdata o una partizione contenente 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 controllare lo stato di unione delle istantanee. Se lo stato è MERGING , il dispositivo dovrebbe interrompere l'operazione. Lo slot può essere tranquillamente modificato nello stato SNAPSHOTTED .

Queste modifiche sono progettate per evitare di rendere accidentalmente un dispositivo non avviabile, ma possono essere dannose per 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. Query getvar snapshot-update-status .
  2. In caso di merging o snapshotted , emettere snapshot-update cancel .
  3. Procedere con passaggi lampeggianti.

Riduzione dei requisiti di archiviazione

I dispositivi che non dispongono di spazio di archiviazione A/B completo allocato in super e prevedono di utilizzare /data se necessario, sono vivamente consigliati di 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 sullo snapshot. Questo è documentato in Riduzione delle dimensioni OTA .

Metodi di compressione OTA

I pacchetti Ota possono essere ottimizzati per diverse metriche delle prestazioni. Android attualmente fornisce alcuni metodi di compressione supportati ( gz , lz4 e none ) che presentano compromessi tra tempo di installazione, utilizzo dello spazio della mucca, tempo di avvio e tempo di unione delle istantanee. 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 possono variare a seconda del dispositivo. Tutti i pacchetti OTA generati di seguito sono con 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 )

1. OTA incrementale su Pixel 6 Pro

Tempo di installazione senza fase di postinstallazione Uso dello spazio della mucca Dopo il tempo di avvio OTA Ora unione istantanee
gz 24 min 1,18GB 40,2 sec 45,5 sec
z4 13 min 1,49GB 37,4 sec 37,1 sec
nessuno 13 min 2,90GB 37,6 sec 40,7 sec

2. OTA completo su Pixel 6 Pro

Tempo di installazione senza fase di postinstallazione Uso dello spazio della mucca Dopo il tempo di avvio OTA Ora unione istantanee
gz 23 min 2,79GB 24,9 sec 41,7 sec
z4 12 min 3,46GB 20,0 sec 25,3 sec
nessuno 10 minuti 4,85GB 20,6 sec 29,8 sec