A/B virtuale è il principale meccanismo di aggiornamento di Android. Build A/B virtuali si basano su aggiornamenti A/B legacy (vedi Aggiornamenti di sistema A/B) e non A/B, che sono deprecati nella versione 15 per ridurre l'overhead di spazio degli aggiornamenti.
A/B virtuale non dispone di uno slot 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. A/B virtuale utilizza un formato snapshot 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 compressione A/B virtuale per comprimere le partizioni acquisite tramite 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 minimo di spazio aggiuntivo 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 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 c'è 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 è l'origine 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 nella partizione /data
possono essere elevati, puoi abilitare snapshot compressi nella build 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 kernel simile a FUSE che consente allo spazio utente di implementare dispositivi a blocchi.snapuserd
, un demone dello spazio utente 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 snapshot compressi
In Android 12 e versioni successive, gli snapshot compressi usano 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 avere anche operazioni di copia.
Il layout dello snapshot completo sul disco è il seguente:
Figura 2. Formato Android COW su 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 al kernel una nuova interfaccia visibile all'utente
che non fa parte del codebase upstream 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
i dettagli, consulta Unione
dello spazio utente.
Di seguito viene descritto il processo di compressione A/B virtuale:
- Il framework monta la partizione
/system
di 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 il processo di unione, questo riprende dopo il riavvio.
Transizioni di inizializzazione
Durante l'avvio con snapshot compressi, l'init della prima fase deve avviare
snapuserd
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 supportate da ext4. Quindi disattiva tutte le tabelle di mappatura dei dispositivi per i dispositivi snapshot e interrompesnapuserd
. Dopodiché, non è più possibile leggere dalle partizioni, poiché ciò causa un deadlock.- Utilizzando il descrittore aperto nella copia ramdisk di
snapuserd
,init
riavvia il daemon con il contesto selinux corretto. Le tabelle di mapping dei dispositivi 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) | 4,5 GB super (immagine 3,8 GB + 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 su /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 Partendo dal presupposto che la nuova immagine di sistema sia delle stesse dimensioni dell'originale.
3 Il requisito di spazio è temporaneo fino al riavvio.
Virtual A/B di Android 11
L'androide 11 di Virtual A/B ha scritto su una partizione dinamica utilizzando il formato Kernel COW. Questo formato è stato infine deprecato perché il formato Kernel COW 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 Kernel COW. 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