Virtual A/B è il principale meccanismo di aggiornamento di Android. La sperimentazione A/B virtuale si basa sugli aggiornamenti A/B precedenti (consulta Aggiornamenti di sistema A/B) e non A/B, che sono stati ritirati nella versione 15 per ridurre l'overhead di spazio degli aggiornamenti.
La sperimentazione A/B virtuale non dispone di uno spazio aggiuntivo per le partizioni dinamiche, consulta partizioni dinamiche. Il delta viene invece scritto in uno snapshot e poi unito alla partizione di base dopo aver confermato un avvio riuscito. Virtual A/B utilizza un formato di istantanea specifico per Android. Consulta Formato COW per gli snapshot compressi, che consente di comprimere gli snapshot e riduce al minimo l'utilizzo dello spazio su disco. In un OTA completo, le dimensioni dello snapshot vengono ridotte di circa il 45% con la compressione e di circa il 55% con l'OTA incrementale.
Android 12 offre la possibilità di utilizzare la compressione A/B virtuale per comprimere le partizioni di cui è stato eseguito lo snapshot. La sperimentazione A/B virtuale offre quanto segue
- Gli aggiornamenti A/B virtuali sono seamless (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 ripristinati. Se il nuovo sistema operativo non si avvia, viene eseguito automaticamente il rollback alla versione precedente.
- Gli aggiornamenti A/B virtuali utilizzano un spazio aggiuntivo minimo duplicando solo le partizioni utilizzate dal bootloader. Per le altre partizioni aggiornabili viene eseguito un snapshot.
Informazioni generali e terminologia
Questa sezione definisce la terminologia e descrive la tecnologia che supporta il test A/B virtuale. Durante l'installazione OTA, i dati del nuovo 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 riuniti nuovamente nel suo dispositivo di base tramite l'utilizzo del daemon dm-user e snapuserd. Questo processo avviene interamente nello spazio utente.
Device-mapper
Device-mapper è un livello di blocco virtuale Linux spesso utilizzato in Android. Con le partizioni dinamiche, le partizioni come /system
sono una serie 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 è presente un dispositivo
dm-linear
che specifica quali blocchi della 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 è presente 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 è la fonte del punto di montaggio/system
.
La Figura 1 mostra l'aspetto della pila sotto il punto di montaggio /system
.
Figura 1. Impila sotto il punto di montaggio /system
Istantanee compresse
In Android 12 e versioni successive, poiché i requisiti di spazio per la partizione /data
possono essere elevati, puoi attivare gli snapshot compressi nella compilazione per soddisfare i requisiti di spazio più elevati della partizione /data
.
Gli snapshot compressi A/B virtuali si basano sui seguenti componenti disponibili in Android 12 e versioni successive:
dm-user
, un modulo del kernel simile a FUSE che consente allo spazio utente di implementare dispositivi di blocco.snapuserd
, un demone dello spazio utente per implementare un nuovo formato di snapshot.
Questi componenti attivano 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 per Android. Il formato COW contiene metadati sull'OTA e buffer distinti contenenti operazioni COW e nuovi dati del sistema operativo. Rispetto al formato dello snapshot del kernel che consentiva solo operazioni di sostituzione (Sostituisci il 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 di base deve essere sostituito con il blocco Y nel dispositivo di 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 di base deve essere sostituito con tutti gli zeri.
- XOR: il dispositivo COW memorizza i byte compressi XOR tra il blocco X e il blocco Y. (Disponibile in Android 13 e versioni successive).
Gli aggiornamenti OTA completi consistono solo in operazioni di sostituzione e zero. Gli aggiornamenti OTA incrementali possono includere anche operazioni di copia.
Il layout dello snapshot completo 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 di blocco device-mapper. Una voce della tabella dm-user crea un dispositivo di tipo diverso 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 da propagare (per una scrittura).
Il modulo del 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 a quel momento, Google si riserva il diritto di modificare l'interfaccia dm-user
in Android.
snapuserd
Il componente dello spazio utente snapuserd
per dm-user
implementa la compressione A/B virtuale. Snapuserd è un demone dello spazio utente responsabile della scrittura e della lettura dei dispositivi COW Android. Tutte le operazioni di I/O relative 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 vengono gestiti anche l'analisi dei metadati e lo scompattamento dei nuovi dati del blocco.
Compressione XOR
Per i dispositivi lanciati con Android 13 e versioni successive, la funzionalità di compressione XOR, abilitata per impostazione predefinita, consente agli snapshot dello spazio utente di memorizzare byte compressi XOR tra i vecchi blocchi e i nuovi blocchi. Quando solo alcuni byte in un blocco vengono modificati in un aggiornamento A/B virtuale, lo schema di archiviazione della compressione XOR utilizza meno spazio rispetto allo schema di archiviazione predefinito perché gli snapshot non memorizzano byte 4K completi. Questa riduzione delle dimensioni degli snapshot è possibile perché i dati XOR contengono molti zeri e sono più facili da comprimere rispetto ai dati dei blocchi non elaborati. Sui Pixel, la compressione XOR riduce le dimensioni degli istantanei dal 25% al 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 di snapshot
Per i dispositivi lanciati con Android 13 e versioni successive, le operazioni di unione di istantanee e istantanee nella compressione A/B virtuale vengono eseguite dal componente dello spazio utente snapuserd
. Per i dispositivi che eseguono l'upgrade ad Android 13 e versioni successive, questa funzionalità deve essere attivata. Per maggiori dettagli, consulta Unione dello spazio utente.
Di seguito viene descritta la procedura di compressione virtuale A/B:
- Il framework monta la partizione
/system
da un dispositivodm-verity
, che è sovrapposto a un dispositivodm-user
. Ciò significa che ogni I/O dal file system principale viene indirizzata adm-user
. dm-user
instrada l'I/O al daemonsnapuserd
nello spazio utente, che gestisce la richiesta 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 la procedura di unione, questa riprende dopo il riavvio.
Transizioni di inizializzazione
Quando si avvia con gli snapshot compressi, l'inizializzazione di primo livello deve essere avviatasnapuserd
per montare le partizioni. Questo 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 i rifiuti di selinux.
Per risolvere il problema, le transizioni di snapuserd
avvengono in modo sincrono con quelle di init
, come segue:
init
di primo livello avviasnapuserd
dalla ramdisk e salva un descrittore file aperto in una variabile di ambiente.- La prima fase di
init
passa il file system principale alla partizione di sistema, quindi esegue la copia di sistema diinit
. - La copia di sistema di
init
legge il file sepolicy combinato in una stringa. Init
richiamamlock()
su tutte le pagine basate su ext4. Disattiva quindi tutte le tabelle device-mapper per i dispositivi snapshot e interrompesnapuserd
. Dopodiché è vietato leggere dalle partizioni, poiché ciò causa un deadlock.- Utilizzando il descrittore aperto per la copia della ramdisk di
snapuserd
,init
riavvia il daemon con il contesto selinux corretto. Le tabelle Device-mapper per i dispositivi snapshot vengono riattivate. - Init invoca
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 dell'OTA di Pixel.
Impatto delle dimensioni | non A/B | A/B | A/B virtuale | Test A/B virtuale (compresso) |
---|---|---|---|---|
Immagine di fabbrica originale | Super da 4,5 GB (immagine da 3,8 GB + 700 MB riservati)1 | Super da 9 GB (3,8 G + 700 M riservati, per due slot) | Super da 4,5 GB (immagine da 3,8 G + 700 M riservati) | Super da 4,5 GB (immagine da 3,8 G + 700 M 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 in /data | 0 | 3,8 GB2 in /data | 2,1 GB2 in /data |
Spazio di archiviazione totale necessario per applicare l'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 dei pixel.
2 Si presume che la nuova immagine di sistema abbia le stesse dimensioni dell'originale.
3Il requisito di spazio è temporaneo fino al riavvio.
Virtual A/B di Android 11
Android 11 di Virtual A/B ha scritto nella partizione dinamica utilizzando il formato COW del kernel. Questo approccio è stato infine 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 una traduzione del COW specifico per Android nel formato COW del kernel. Alla fine, questo è stato sostituito in Android 13, che ha rimosso la dipendenza dal formato COW del kernel e anche da dm-snapshot
.
Per implementare il test A/B virtuale o utilizzare le funzionalità di snapshot compressi, consulta Implementazione del test A/B virtuale