Virtual A/B è il meccanismo di aggiornamento principale di Android. La funzionalità A/B virtuale si basa sugli aggiornamenti A/B legacy (vedi Aggiornamenti di sistema A/B) e non A/B, che è deprecata nella versione 15 per ridurre l'overhead di spazio degli aggiornamenti.
Il test A/B virtuale non ha in realtà uno slot aggiuntivo per le partizioni dinamiche, vedi partizioni dinamiche. Il delta viene invece scritto in uno snapshot e poi unito alla partizione di base dopo la conferma di un avvio riuscito. Il test A/B virtuale utilizza un formato di snapshot specifico per Android. Consulta Formato COW per snapshot compressi, che consente di comprimere gli snapshot e ridurre al minimo l'utilizzo dello spazio su disco. In un aggiornamento OTA completo, le dimensioni dello snapshot vengono ridotte di circa il 45% con la compressione, mentre in un aggiornamento OTA incrementale vengono ridotte di circa il 55%.
Android 12 offre l'opzione di compressione A/B virtuale per comprimere le partizioni di snapshot. Virtual A/B offre quanto segue:
- Gli aggiornamenti A/B virtuali sono istantanei (l'aggiornamento avviene interamente in background mentre il dispositivo è operativo) come gli aggiornamenti A/B. Gli aggiornamenti A/B virtuali riducono al minimo il tempo in cui un dispositivo è offline e inutilizzabile.
- Gli aggiornamenti A/B virtuali possono essere annullati. Se il nuovo sistema operativo non si avvia, i dispositivi eseguono automaticamente il rollback alla versione precedente.
- Gli aggiornamenti A/B virtuali utilizzano uno spazio aggiuntivo minimo duplicando solo le partizioni utilizzate dal bootloader. Le altre partizioni aggiornabili vengono snapshotate.
Background e terminologia
Questa sezione definisce la terminologia e descrive la tecnologia che supporta il test A/B virtuale. Durante l'installazione OTA, i nuovi dati del sistema operativo vengono scritti nel nuovo slot per le partizioni fisiche o in un dispositivo COW specifico per Android. Dopo il riavvio del dispositivo, i dati della partizione dinamica vengono nuovamente uniti al dispositivo di base tramite l'utilizzo dei daemon dm-user e snapuserd. Questo processo avviene interamente nello spazio utente.
Device-mapper
Device-mapper è un livello di blocchi virtuali Linux utilizzato spesso in Android. Con le
partizioni dinamiche, le partizioni come
/system
sono uno stack di dispositivi a più livelli:
- Nella parte inferiore dello stack si trova la partizione super fisica (ad esempio,
/dev/block/by-name/super
). - Al centro si trova un dispositivo
dm-linear
, che specifica quali blocchi nella superpartizione formano la partizione dinamica specificata. Viene visualizzato come/dev/block/mapper/system_[a|b]
su un dispositivo A/B o/dev/block/mapper/system
su un dispositivo non A/B. - In alto si trova un dispositivo
dm-verity
, creato per le partizioni verificate. Questo dispositivo verifica che i blocchi sul dispositivodm-linear
siano firmati correttamente. Viene visualizzato come/dev/block/mapper/system-verity
ed è l'origine del punto di montaggio/system
.
La Figura 1 mostra l'aspetto dello stack sotto il punto di montaggio /system
.
Figura 1. Stack sotto il punto di montaggio /system
Snapshot compressi
In Android 12 e versioni successive, poiché i requisiti di spazio nella partizione /data
possono essere elevati, puoi attivare gli snapshot compressi nella build per soddisfare i requisiti di spazio più elevati della partizione /data
.
Gli snapshot compressi A/B virtuali sono basati sui seguenti componenti disponibili in Android 12 e versioni successive:
dm-user
, un modulo kernel simile a FUSE che consente allo spazio utente di implementare dispositivi a blocchi.snapuserd
, un daemon userspace per implementare un nuovo formato di snapshot.
Questi componenti consentono la compressione. Le altre modifiche necessarie apportate per implementare le funzionalità degli snapshot compressi sono riportate nelle sezioni successive: formato COW per gli snapshot compressi, dm-user e snapuserd.
Formato COW per gli snapshot compressi
In Android 12 e versioni successive, gli snapshot compressi utilizzano un formato COW specifico di Android. Il formato COW contiene metadati sull'OTA e buffer distinti contenenti operazioni COW e nuovi dati del sistema operativo. Rispetto al formato snapshot del kernel che consentiva solo operazioni di sostituzione (sostituzione del blocco X nell'immagine di base con i contenuti del blocco Y nello snapshot), il formato COW degli snapshot compressi di Android è più espressivo e supporta le seguenti operazioni:
- Copia: il blocco X nel dispositivo base deve essere sostituito con il blocco Y nel dispositivo base.
- Sostituisci: il blocco X nel dispositivo di base deve essere sostituito con i contenuti del blocco Y nello snapshot. Ciascuno di questi blocchi è compresso con gz.
- Zero: il blocco X nel dispositivo base deve essere sostituito con tutti zeri.
- XOR: il dispositivo COW memorizza i byte compressi XOR tra il blocco X e il blocco Y. (Disponibile su Android 13 e versioni successive.)
Gli aggiornamenti OTA completi sono costituiti solo da operazioni di sostituzione e zero. Gli aggiornamenti OTA incrementali possono inoltre includere operazioni di copia.
Il layout completo dello snapshot sul disco è il seguente:
Figura 2. Formato COW di Android sul disco
dm-user
Il modulo del kernel dm-user consente a userspace
di implementare dispositivi a blocchi di Device Mapper. Una voce della tabella dm-user crea un dispositivo generico in
/dev/dm-user/<control-name>
. Un processo userspace
può eseguire il polling del dispositivo per
ricevere richieste di lettura e scrittura dal kernel. Ogni richiesta ha un buffer associato per lo spazio utente da compilare (per una lettura) o propagare (per una scrittura).
Il modulo kernel dm-user
fornisce una nuova interfaccia visibile all'utente per il kernel
che non fa parte della base di codice upstream di kernel.org. Fino ad allora, Google
si riserva il diritto di modificare l'interfaccia di dm-user
in Android.
snapuserd
Il componente userspace snapuserd
per dm-user
implementa la compressione A/B virtuale. Snapuserd è un daemon userspace responsabile della scrittura e della lettura
dei dispositivi COW Android. Tutti gli I/O allo snapshot devono passare attraverso questo servizio.
Durante l'installazione OTA, i nuovi dati del sistema operativo vengono scritti nello snapshot da
snapuserd (con compressione). Qui viene gestita anche l'analisi dei metadati e l'estrazione dei nuovi
dati dei blocchi.
Compressione XOR
Per i dispositivi lanciati con Android 13 e versioni successive, la funzionalità di compressione XOR, abilitata per impostazione predefinita, consente agli snapshot di spazio utente di archiviare i byte compressi XOR tra i blocchi precedenti e quelli nuovi. Quando solo pochi byte di un blocco vengono modificati in un aggiornamento A/B virtuale, lo schema di archiviazione con compressione XOR utilizza meno spazio rispetto allo schema di archiviazione predefinito perché gli snapshot non memorizzano 4096 byte completi. Questa riduzione delle dimensioni dello snapshot è possibile perché i dati XOR contengono molti zeri e sono più facili da comprimere rispetto ai dati grezzi dei blocchi. Sui dispositivi Pixel, la compressione XOR riduce le dimensioni degli snapshot del 25-40%.
Per i dispositivi che eseguono l'upgrade ad Android 13 e versioni successive, la compressione XOR deve essere attivata. Per maggiori dettagli, vedi Compressione XOR.
Unione degli snapshot
Per i dispositivi lanciati con Android 13 e versioni successive, i processi di snapshot e unione degli snapshot nella compressione A/B virtuale vengono eseguiti dal componente userspace snapuserd
. Per i dispositivi che eseguono l'upgrade ad Android
13 e versioni successive, questa funzionalità deve essere abilitata. Per
maggiori dettagli, vedi Unione
dello spazio utente.
Di seguito viene descritta la procedura di compressione A/B virtuale:
- Il framework monta la partizione
/system
su un dispositivodm-verity
, che è impilato sopra un dispositivodm-user
. Ciò significa che ogni I/O dal file system root viene indirizzato adm-user
. dm-user
instrada l'I/O al daemonsnapuserd
userspace, che gestisce la richiesta di I/O.- Al termine dell'operazione di unione, il framework comprime
dm-verity
sopradm-linear
(system_base
) e rimuovedm-user
.
Figura 3. Procedura di compressione A/B virtuale
Il processo di unione degli snapshot può essere interrotto. Se il dispositivo viene riavviato durante il processo di unione, quest'ultimo riprende dopo il riavvio.
Init transitions
Quando si avvia il sistema con snapshot compressi, init di primo livello deve avviare
snapuserd
per montare le partizioni. Ciò pone un problema: quando sepolicy
viene caricato
e applicato, snapuserd
viene inserito nel contesto sbagliato e le sue richieste di lettura
non vanno a buon fine, con errori di SELinux.
Per risolvere il problema, snapuserd
esegue la transizione in modo sincrono con init
, come segue:
- La fase 1
init
avviasnapuserd
dal ramdisk e salva un descrittore di file aperto in una variabile di ambiente. - La prima fase di
init
sposta il file system root nella partizione di sistema, quindi esegue la copia di sistema diinit
. - La copia di sistema di
init
legge sepolicy combinato in una stringa. Init
richiamamlock()
su tutte le pagine supportate da ext4. Quindi disattiva tutte le tabelle device-mapper per i dispositivi snapshot e arrestasnapuserd
. Dopo questa operazione, è vietato leggere dalle partizioni, poiché ciò causa un deadlock.- L'utilizzo del descrittore aperto per la copia ramdisk di
snapuserd
,init
riavvia il daemon con il contesto SELinux corretto. Le tabelle di Device Mapper per i dispositivi snapshot vengono riattivate. - Init richiama
munlockall()
: è sicuro eseguire di nuovo l'I/O.
Utilizzo dello spazio
La tabella seguente fornisce un confronto dell'utilizzo dello spazio per diversi meccanismi OTA utilizzando le dimensioni del sistema operativo e degli aggiornamenti OTA di Pixel.
Impatto delle dimensioni | non-A/B | A/B | Virtual A/B | Test A/B virtuale (compresso) |
---|---|---|---|---|
Immagine di fabbrica originale | 4,5 GB super (immagine da 3,8 GB + 700 MB riservati)1 | 9 GB super (3,8 GB + 700 MB riservati, per due slot) | 4,5 GB super (immagine da 3,8 GB + 700 MB riservati) | 4,5 GB super (immagine da 3,8 GB + 700 MB riservati) |
Altre partizioni statiche | /cache | Nessuno | Nessuno | Nessuno |
Spazio di archiviazione aggiuntivo durante l'OTA (spazio restituito dopo l'applicazione dell'OTA) | 1,4 GB su /data | 0 | 3,8 GB2 su /data | 2,1 GB2 su /data |
Spazio di archiviazione totale necessario per applicare l'aggiornamento OTA | 5,9 GB3 (super e dati) | 9GB (super) | 8,3 GB3 (super e dati) | 6,6 GB3 (super e dati) |
1Indica il layout presunto in base alla mappatura di Pixel.
2Presuppone che la nuova immagine di sistema abbia le stesse dimensioni dell'originale.
3Il requisito di spazio è temporaneo fino al riavvio.
Android 11 Virtual A/B
Android 11 di Virtual A/B ha scritto nella partizione dinamica utilizzando il formato Kernel COW. Alla fine è stato ritirato perché il formato COW del kernel non supporta la compressione.
Virtual A/B di Android 12
In Android 12, la compressione è supportata sotto forma di formato COW specifico per Android. Questa versione di Virtual A/B richiedeva la conversione del COW specifico per Android nel formato COW del kernel. Alla fine è stato sostituito in Android
13, che ha rimosso la dipendenza dal formato COW del kernel e anche dm-snapshot
.
Per implementare Virtual A/B o utilizzare le funzionalità di snapshot compressi, consulta Implementazione di Virtual A/B.