Checkpoint dei dati utente

Android 10 introduce la funzionalità User Data Checkpoint (UDC), che consente ad Android di eseguire il rollback allo stato precedente quando un aggiornamento over-the-air (OTA) di Android non va a buon fine. In questo caso, il dispositivo può eseguire il rollback in modo sicuro allo stato precedente. Sebbene gli aggiornamenti A/B risolvano il problema per la fase iniziale di avvio, il rollback non è supportato quando viene modificata la partizione dei dati utente (montata su /data).

L'UDC consente al dispositivo di ripristinare la partizione dei dati utente anche dopo che è stata modificata. Ciò avviene tramite le funzionalità di checkpoint del file system: un'implementazione alternativa se il file system non supporta i checkpoint, l'integrazione con il meccanismo A/B del bootloader supportando anche gli aggiornamenti non A/B, il supporto del binding della versione delle chiavi e la prevenzione del rollback delle chiavi.

Impatto sugli utenti

La funzionalità UDC migliora l'esperienza di aggiornamento OTA per gli utenti, in quanto meno utenti perdono i propri dati quando un aggiornamento OTA non va a buon fine. In questo modo si riduce il numero di chiamate di assistenza da parte degli utenti che riscontrano problemi durante la procedura di aggiornamento. Tuttavia, quando un aggiornamento OTA non va a buon fine, gli utenti potrebbero notare che il dispositivo si riavvia più volte.

Come funziona

Funzionalità di checkpoint in diversi file system

Per il file system F2FS, l'UDC aggiunge la funzionalità di checkpoint al kernel Linux 4.20 upstream e ne esegue il backporting in tutti i kernel comuni supportati dai dispositivi con Android 10.

Per gli altri file system, utilizza un dispositivo virtuale di mappatura dei dispositivi chiamato dm_bow per la funzionalità di checkpoint. dm_bow si trova tra il dispositivo e il file system. Quando una partizione viene montata, viene emesso un trim che fa sì che il file system emetta comandi trim in tutti i blocchi liberi. dm_bow intercetta i trim e li utilizza per configurare un elenco di blocchi liberi. Le letture e le scritture vengono quindi inviate al dispositivo senza modifiche, ma prima che venga eseguita una scrittura, viene effettuato un backup dei dati necessari per il ripristino in un blocco libero.

Procedura di checkpoint

Quando viene montata una partizione con il flag checkpoint=fs/block, Android chiama restoreCheckpoint sull'unità del dispositivo per consentire il ripristino di eventuali checkpoint correnti. init chiama quindi la funzione needsCheckpoint per determinare se il dispositivo si trova in uno stato bootloader A/B o ha impostato il conteggio dei tentativi di aggiornamento. Se una delle due condizioni è vera, Android chiama createCheckpoint per aggiungere flag di montaggio o creare un dispositivo dm_bow.

Dopo il montaggio della partizione, viene chiamato il codice del checkpoint per emettere i trim. La procedura di avvio continua normalmente. Con LOCKED_BOOT_COMPLETE, Android chiama commitCheckpoint per eseguire il commit del checkpoint corrente e l'aggiornamento continua normalmente.

Gestisci le chiavi KeyMint (in precedenza Keymaster)

Le chiavi KeyMint vengono utilizzate per la crittografia del dispositivo o per altri scopi. Per gestire le chiavi, Android ritarda le chiamate di eliminazione delle chiavi finché il checkpoint non viene eseguito.

Monitora lo stato

Un daemon di monitoraggio dello stato verifica che ci sia spazio su disco sufficiente per creare un checkpoint. Il daemon di monitoraggio della stato si trova in cp_healthDaemon in Checkpoint.cpp.

Il daemon di monitoraggio della stato include i seguenti comportamenti configurabili:

  • ro.sys.cp_msleeptime: controlla la frequenza con cui il dispositivo verifica l'utilizzo del disco.
  • ro.sys.cp_min_free_bytes: controlla il valore minimo cercato dal daemon di monitoraggio dello stato.
  • ro.sys.cp_commit_on_full: controlla se il daemon di monitoraggio dello stato riavvia il dispositivo o esegue il commit del checkpoint e continua quando il disco è pieno.

API Checkpoint

Le API Checkpoint vengono utilizzate dalla funzionalità UDC. Per altre API utilizzate dall'UDC, vedi IVold.aidl.

void startCheckpoint(int retry)

Crea un checkpoint.

Il framework chiama questo metodo quando è pronto per avviare un aggiornamento. Il checkpoint viene creato prima che i file system soggetti a checkpoint, come la partizione dei dati utente, vengano montati in lettura/scrittura dopo il riavvio. Se il conteggio dei tentativi è positivo, l'API gestisce i tentativi di monitoraggio e l'updater chiama needsRollback per verificare se è necessario un rollback dell'aggiornamento. Se il conteggio dei tentativi è -1, l'API si affida al giudizio del bootloader A/B.

Questo metodo non viene chiamato quando viene eseguito un normale aggiornamento A/B.

void commitChanges()

Esegue il commit delle modifiche.

Il framework chiama questo metodo dopo il riavvio quando le modifiche sono pronte per il commit. La chiamata avviene prima che i dati (ad esempio immagini, video, SMS, conferme di ricezione del server) vengano scritti nella partizione dei dati utente e prima di BootComplete.

Se non esiste un aggiornamento con checkpoint attivo, questo metodo non funziona.

abortChanges()

Forza il riavvio e ripistina il checkpoint. Annulla tutte le modifiche ai dati utente dal primo riavvio.

Il framework chiama questo metodo dopo il riavvio, ma prima di commitChanges. Il numero di tentativi registrato da retry_counter diminuisce quando viene chiamato questo metodo. Vengono generate le voci di log.

bool needsRollback()

Determina se è necessario un rollback.

Sui dispositivi senza checkpoint, restituisce false. Sui dispositivi con checkpoint, restituisce true durante un avvio non di checkpoint.

Implementa l'UDC

Implementazione di riferimento

Per un esempio di come implementare UDC, consulta dm-bow.c. Per ulteriore documentazione sulla funzionalità, consulta dm-bow.txt.

Configura

In on fs nel file init.hardware.rc, assicurati di avere:

mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --early

In on late-fs nel file init.hardware.rc, assicurati di avere:

mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

Nel file fstab.hardware, assicurati che /data sia taggato come latemount.

/dev/block/bootdevice/by-name/userdata              /data              f2fs
noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier
latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M,checkpoint=fs

Aggiungi una partizione di metadati

L'UDC richiede una partizione di metadati per archiviare il conteggio dei tentativi non bootloader e le chiavi. Configura una partizione di metadati e montala in anticipo in /metadata.

Nel file fstab.hardware, assicurati che /metadata sia taggato come earlymount o first_stage_mount.

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

Inizializza la partizione con tutti zeri.

Aggiungi le seguenti righe a BoardConfig.mk:

BOARD_USES_METADATA_PARTITION := true
BOARD_ROOT_EXTRA_FOLDERS := existing_folders metadata

Aggiorna i sistemi

Sistemi F2FS

Per i sistemi che utilizzano F2FS per formattare i dati, assicurati che la tua versione di F2FS supporti i checkpoint. Per maggiori informazioni, consulta Funzionalità di checkpoint in diversi file system.

Aggiungi il flag checkpoint=fs alla sezione <fs_mgr_flags> di fstab per il dispositivo montato in /data.

Sistemi non F2FS

Per i sistemi non F2FS, dm-bow deve essere abilitato nella configurazione del kernel.

Aggiungi il flag checkpoint=block alla sezione <fs_mgr_flags> di fstab per il dispositivo montato in /data.

Controlla i log

Le voci di log vengono generate quando vengono chiamate le API Checkpoint.

Convalida

Per testare l'implementazione dell'UDC, esegui il set di test VTS VtsKernelCheckpointTest.