Google si impegna a promuovere l'equità razziale per le comunità nere. Vedi come.
This page was translated by the Cloud Translation API.
Switch to English

Aggiornamenti di sistema A / B (senza interruzioni)

Gli aggiornamenti del sistema A / B, noti anche come aggiornamenti continui, assicurano che un sistema di avvio funzionante rimanga sul disco durante un aggiornamento over-the-air (OTA) . Questo approccio riduce la probabilità di un dispositivo inattivo dopo un aggiornamento, il che significa un minor numero di sostituzioni e riflessioni del dispositivo nei centri di riparazione e garanzia. Anche altri sistemi operativi di livello commerciale come ChromeOS utilizzano correttamente gli aggiornamenti A / B.

Per ulteriori informazioni sugli aggiornamenti del sistema A / B e su come funzionano, vedere Selezione delle partizioni (slot) .

Gli aggiornamenti del sistema A / B offrono i seguenti vantaggi:

  • Gli aggiornamenti OTA possono verificarsi mentre il sistema è in esecuzione, senza interrompere l'utente. Gli utenti possono continuare a utilizzare i propri dispositivi durante un OTA: l'unico tempo di inattività durante un aggiornamento è il riavvio del dispositivo nella partizione del disco aggiornata.
  • Dopo un aggiornamento, il riavvio non richiede più di un normale riavvio.
  • Se un OTA non si applica (ad esempio a causa di un flash difettoso), l'utente non sarà interessato. L'utente continuerà a eseguire il vecchio sistema operativo e il client è libero di riprovare l'aggiornamento.
  • Se viene applicato un aggiornamento OTA ma non si avvia, il dispositivo si riavvierà nella vecchia partizione e rimarrà utilizzabile. Il client è libero di riprovare l'aggiornamento.
  • Eventuali errori (come errori I / O) riguardano solo il set di partizioni inutilizzato e possono essere ritentati. Tali errori diventano anche meno probabili perché il carico di I / O è volutamente basso per evitare di degradare l'esperienza dell'utente.
  • Gli aggiornamenti possono essere trasmessi in streaming ai dispositivi A / B, eliminando la necessità di scaricare il pacchetto prima di installarlo. Lo streaming significa che non è necessario che l'utente disponga di spazio libero sufficiente per archiviare il pacchetto di aggiornamento su /data o /cache .
  • La partizione cache non viene più utilizzata per archiviare i pacchetti di aggiornamento OTA, quindi non è necessario assicurarsi che la partizione cache sia sufficientemente grande per gli aggiornamenti futuri.
  • dm-verity garantisce che un dispositivo avvierà un'immagine non corrotta. Se un dispositivo non si avvia a causa di un problema OTA o dm-verity errato, il dispositivo può riavviarsi in una vecchia immagine. (Android Verified Boot non richiede aggiornamenti A / B.)

Informazioni sugli aggiornamenti del sistema A / B

Gli aggiornamenti A / B richiedono modifiche sia al client che al sistema. Il server di pacchetti OTA, tuttavia, non dovrebbe richiedere modifiche: i pacchetti di aggiornamento sono ancora offerti su HTTPS. Per i dispositivi che utilizzano l'infrastruttura OTA di Google, le modifiche al sistema sono tutte in AOSP e il codice client è fornito dai servizi di Google Play. Gli OEM che non utilizzano l'infrastruttura OTA di Google saranno in grado di riutilizzare il codice di sistema AOSP ma dovranno fornire il proprio cliente.

Per gli OEM che forniscono il proprio cliente, il cliente deve:

  • Decidi quando eseguire un aggiornamento. Poiché gli aggiornamenti A / B si verificano in background, non vengono più avviati dall'utente. Per evitare di disturbare gli utenti, si consiglia di pianificare gli aggiornamenti quando il dispositivo è in modalità di manutenzione inattiva, ad esempio durante la notte, e su Wi-Fi. Tuttavia, il cliente può utilizzare qualsiasi euristica desiderata.
  • Verificare con i server dei pacchetti OTA e determinare se è disponibile un aggiornamento. Questo dovrebbe essere per lo più lo stesso del tuo codice client esistente, tranne per il fatto che vorrai segnalare che il dispositivo supporta A / B. (Il client di Google include anche un pulsante Controlla ora per consentire agli utenti di verificare l'ultimo aggiornamento.)
  • Chiama update_engine con l'URL HTTPS per il tuo pacchetto di aggiornamento, supponendo che uno sia disponibile. update_engine aggiornerà i blocchi grezzi sulla partizione attualmente inutilizzata durante lo streaming del pacchetto di aggiornamento.
  • Segnala esiti update_engine all'installazione sui tuoi server, in base al codice risultato update_engine . Se l'aggiornamento viene applicato correttamente, update_engine indicherà al bootloader di avviarsi nel nuovo sistema operativo al successivo riavvio. Il bootloader eseguirà il fallback sul vecchio sistema operativo se il nuovo sistema operativo non si avvia, quindi non è necessario alcun lavoro da parte del client. Se l'aggiornamento non riesce, il client deve decidere quando (e se) riprovare, in base al codice di errore dettagliato. Ad esempio, un buon client potrebbe riconoscere che un pacchetto OTA parziale ("diff") fallisce e provare invece un pacchetto OTA completo.

Opzionalmente, il cliente può:

  • Mostra una notifica che chiede all'utente di riavviare. Se si desidera implementare una politica in cui l'utente è invitato ad aggiornare regolarmente, questa notifica può essere aggiunta al proprio client. Se il client non richiede agli utenti, gli utenti riceveranno comunque l'aggiornamento al successivo riavvio. (Il client di Google ha un ritardo configurabile per aggiornamento.)
  • Mostra una notifica che dice agli utenti se si sono avviati in una nuova versione del sistema operativo o se ci si aspettava che lo facessero, ma sono passati alla versione precedente del sistema operativo. (Il client di Google in genere non lo fa.)

Dal lato del sistema, gli aggiornamenti del sistema A / B influiscono su quanto segue:

  • Selezione della partizione (slot), demone update_engine e interazioni bootloader (descritte di seguito)
  • Creazione del processo di generazione e generazione di pacchetti di aggiornamento OTA (descritti in Implementazione degli aggiornamenti A / B )

Selezione della partizione (slot)

Gli aggiornamenti del sistema A / B utilizzano due serie di partizioni denominate slot (normalmente slot A e slot B). Il sistema funziona dallo slot corrente mentre le partizioni nello slot non utilizzato non sono accessibili dal sistema in esecuzione durante il normale funzionamento. Questo approccio rende gli aggiornamenti resistenti ai guasti mantenendo lo slot inutilizzato come fallback: se si verifica un errore durante o immediatamente dopo un aggiornamento, il sistema può eseguire il rollback al vecchio slot e continuare a disporre di un sistema funzionante. Per raggiungere questo obiettivo, nessuna partizione utilizzata dallo slot corrente deve essere aggiornata come parte dell'aggiornamento OTA (comprese le partizioni per le quali esiste una sola copia).

Ogni slot ha un attributo avviabile che indica se lo slot contiene un sistema corretto da cui il dispositivo può avviarsi. Lo slot corrente è avviabile quando il sistema è in esecuzione, ma l'altro slot potrebbe avere una versione precedente (ancora corretta) del sistema, una versione più recente o dati non validi. Indipendentemente da quale sia lo slot corrente , esiste uno slot che è lo slot attivo (quello che verrà avviato dal bootloader all'avvio successivo) o lo slot preferito .

Ogni slot ha anche un attributo di successo impostato dallo spazio utente, che è rilevante solo se lo slot è anche avviabile. Uno slot di successo dovrebbe essere in grado di avviarsi, eseguirsi e aggiornarsi. Uno slot di avvio che non è stato contrassegnato come riuscito (dopo diversi tentativi di avvio da esso) dovrebbe essere contrassegnato come non avviabile dal bootloader, inclusa la modifica dello slot attivo in un altro slot di avvio (normalmente nello slot in esecuzione immediatamente prima del tentativo di avvio nel nuovo, attivo). I dettagli specifici dell'interfaccia sono definiti in boot_control.h .

Aggiorna il daemon del motore

Gli aggiornamenti del sistema A / B utilizzano un demone in background chiamato update_engine per preparare l'avvio del sistema in una nuova versione aggiornata. Questo demone può eseguire le seguenti azioni:

  • Leggere dalle attuali partizioni A / B dello slot e scrivere tutti i dati nelle partizioni A / B dello slot non utilizzate come indicato dal pacchetto OTA.
  • Chiamare l'interfaccia boot_control in un flusso di lavoro predefinito.
  • Esegui un programma post-installazione dalla nuova partizione dopo aver scritto tutte le partizioni di slot inutilizzate, come indicato dal pacchetto OTA. (Per i dettagli, vedere Post-installazione ).

Poiché il demone update_engine non è coinvolto nel processo di avvio stesso, è limitato a ciò che può fare durante un aggiornamento dalle politiche e dalle funzionalità SELinux nello slot corrente (tali politiche e caratteristiche non possono essere aggiornate fino a quando il sistema non si avvia in un nuova versione). Per mantenere un sistema affidabile, il processo di aggiornamento non deve modificare la tabella delle partizioni, il contenuto delle partizioni nello slot corrente o il contenuto delle partizioni non A / B che non possono essere cancellate con un ripristino delle impostazioni di fabbrica.

Aggiorna la fonte del motore

La fonte update_engine si trova in system/update_engine . I file di dexopt OTA A / B sono suddivisi tra installd e un gestore pacchetti:

Per un esempio funzionante, consultare /device/google/marlin/device-common.mk .

Aggiorna i log del motore

Per le versioni di Android update_engine precedenti, i log update_engine sono disponibili in logcat e nella segnalazione dei bug. Per rendere disponibili i log update_engine nel file system, update_engine le seguenti modifiche alla build:

Queste modifiche salvano una copia del registro update_engine più recente in /data/misc/update_engine_log/update_engine. YEAR - TIME . Oltre al registro corrente, i cinque registri più recenti vengono salvati in /data/misc/update_engine_log/ . Gli utenti con l'ID del gruppo di registri saranno in grado di accedere ai registri del file system.

Interazioni bootloader

L'HAL boot_control viene utilizzato da update_engine (e possibilmente da altri demoni) per update_engine al bootloader da cosa avviare. Gli scenari di esempio comuni e i loro stati associati includono quanto segue:

  • Caso normale : il sistema è in esecuzione dal suo slot corrente, slot A o B. Finora non sono stati applicati aggiornamenti. Lo slot corrente del sistema è avviabile, di successo e lo slot attivo.
  • Aggiornamento in corso : il sistema è in esecuzione dallo slot B, quindi lo slot B è lo slot di avvio, di successo e attivo. Lo slot A è stato contrassegnato come non avviabile poiché i contenuti dello slot A vengono aggiornati ma non ancora completati. Un riavvio in questo stato dovrebbe continuare l'avvio dallo slot B.
  • Aggiornamento applicato, riavvio in sospeso : il sistema è in esecuzione dallo slot B, lo slot B è avviabile e ha esito positivo, ma lo slot A è stato contrassegnato come attivo (e quindi è contrassegnato come avviabile). Lo slot A non è ancora contrassegnato come riuscito e un certo numero di tentativi di avvio dallo slot A deve essere eseguito dal bootloader.
  • Il sistema è stato riavviato con un nuovo aggiornamento : il sistema è in esecuzione dallo slot A per la prima volta, lo slot B è ancora avviabile e ha esito positivo mentre lo slot A è solo avviabile, ma è ancora attivo ma non ha esito positivo. Un demone dello spazio utente, update_verifier , dovrebbe contrassegnare lo slot A come riuscito dopo aver effettuato alcuni controlli.

Supporto per l'aggiornamento in streaming

I dispositivi utente non hanno sempre abbastanza spazio su /data per scaricare il pacchetto di aggiornamento. Poiché né gli OEM né gli utenti vogliono sprecare spazio su una partizione /cache , alcuni utenti non hanno aggiornamenti perché il dispositivo non ha un posto dove archiviare il pacchetto di aggiornamento. Per risolvere questo problema, Android 8.0 ha aggiunto il supporto per lo streaming di aggiornamenti A / B che scrivono blocchi direttamente nella partizione B mentre vengono scaricati, senza dover archiviare i blocchi su /data . Gli aggiornamenti streaming A / B non richiedono quasi alcun archivio temporaneo e richiedono solo spazio sufficiente per circa 100 KiB di metadati.

Per abilitare gli aggiornamenti di streaming in Android 7.1, cherrypick le seguenti patch:

Queste patch sono necessarie per supportare gli aggiornamenti streaming A / B in Android 7.1 e versioni successive, sia utilizzando Google Mobile Services (GMS) o qualsiasi altro client di aggiornamento.

Durata di un aggiornamento A / B

Il processo di aggiornamento inizia quando è disponibile per il download un pacchetto OTA (indicato nel codice come payload ). I criteri nel dispositivo possono ritardare il download e l'applicazione del payload in base al livello della batteria, all'attività dell'utente, allo stato di carica o ad altri criteri. Inoltre, poiché l'aggiornamento viene eseguito in background, gli utenti potrebbero non sapere che è in corso un aggiornamento. Tutto ciò significa che il processo di aggiornamento potrebbe essere interrotto in qualsiasi momento a causa di politiche, riavvii imprevisti o azioni dell'utente.

Facoltativamente, i metadati nel pacchetto OTA stesso indicano che è possibile eseguire lo streaming dell'aggiornamento; lo stesso pacchetto può essere utilizzato anche per l'installazione non in streaming. Il server può utilizzare i metadati per comunicare al client lo streaming, in modo che il client distribuirà l'OTA per update_engine correttamente. I produttori di dispositivi con il proprio server e client possono abilitare gli aggiornamenti di streaming assicurandosi che il server identifichi che l'aggiornamento è in streaming (o presuppone che tutti gli aggiornamenti siano in streaming) e che il client effettui la chiamata corretta a update_engine per lo streaming. I produttori possono utilizzare il fatto che il pacchetto è della variante di streaming per inviare un flag al client per attivare la distribuzione sul lato framework come streaming.

Dopo che è disponibile un payload, il processo di aggiornamento è il seguente:

Passo attività
1 Lo slot corrente (o "slot sorgente") è contrassegnato come riuscito (se non già contrassegnato) con markBootSuccessful() .
2 Lo slot non utilizzato (o "slot di destinazione") è contrassegnato come non avviabile chiamando la funzione setSlotAsUnbootable() . Lo slot corrente viene sempre contrassegnato come riuscito all'inizio dell'aggiornamento per impedire al bootloader di ricadere nello slot inutilizzato, che presto avrà dati non validi. Se il sistema ha raggiunto il punto in cui può iniziare ad applicare un aggiornamento, lo slot corrente viene contrassegnato come riuscito anche se altri componenti principali sono rotti (come l'interfaccia utente in un loop di arresto anomalo) in quanto è possibile inviare un nuovo software per risolvere questi problemi i problemi.

Il payload di aggiornamento è un BLOB opaco con le istruzioni per l'aggiornamento alla nuova versione. Il payload di aggiornamento è costituito da:
  • Metadati . Una porzione relativamente piccola del payload di aggiornamento, i metadati contiene un elenco di operazioni per produrre e verificare la nuova versione nello slot di destinazione. Ad esempio, un'operazione potrebbe decomprimere un determinato BLOB e scriverlo su blocchi specifici in una partizione di destinazione oppure leggere da una partizione di origine, applicare una patch binaria e scrivere su determinati blocchi in una partizione di destinazione.
  • Dati extra Come massa del payload di aggiornamento, i dati extra associati alle operazioni sono costituiti dal BLOB compresso o dalla patch binaria in questi esempi.
3 I metadati del payload vengono scaricati.
4 Per ogni operazione definita nei metadati, nell'ordine, i dati associati (se presenti) vengono scaricati in memoria, l'operazione viene applicata e la memoria associata viene scartata.
5 Tutte le partizioni vengono rilette e verificate rispetto all'hash previsto.
6 Viene eseguito il passaggio post-installazione (se presente). In caso di errore durante l'esecuzione di qualsiasi passaggio, l'aggiornamento ha esito negativo e viene tentato di nuovo con un payload diverso. Se tutti i passaggi finora hanno avuto esito positivo, l'aggiornamento ha esito positivo e viene eseguito l'ultimo passaggio.
7 Lo slot inutilizzato viene contrassegnato come attivo chiamando setActiveBootSlot() . Contrassegnare lo slot inutilizzato come attivo non significa che finirà l'avvio. Il bootloader (o il sistema stesso) può ripristinare lo slot attivo se non legge correttamente.
8 La post-installazione (descritta di seguito) comporta l'esecuzione di un programma dalla versione "nuovo aggiornamento" mentre è ancora in esecuzione nella versione precedente. Se definito nel pacchetto OTA, questo passaggio è obbligatorio e il programma deve tornare con il codice di uscita 0 ; in caso contrario, l'aggiornamento non riesce.
9 Dopo che il sistema si avvia con successo abbastanza lontano nel nuovo slot e termina i controlli post-riavvio, lo slot corrente (in precedenza "slot di destinazione") viene contrassegnato come riuscito chiamando markBootSuccessful() .

Post installazione

Per ogni partizione in cui è definito un passaggio post-installazione, update_engine monta la nuova partizione in una posizione specifica ed esegue il programma specificato nell'OTA rispetto alla partizione montata. Ad esempio, se il programma post-installazione è definito come usr/bin/postinstall nella partizione di sistema, questa partizione dallo slot inutilizzato verrà montata in una posizione fissa (come /postinstall_mount ) e /postinstall_mount/usr/bin/postinstall viene eseguito il comando /postinstall_mount/usr/bin/postinstall .

Perché la post-installazione abbia successo, il vecchio kernel deve essere in grado di:

  • Montare il nuovo formato di file system . Il tipo di filesystem non può cambiare a meno che non ci sia supporto nel vecchio kernel, inclusi dettagli come l'algoritmo di compressione usato se si usa un filesystem compresso (cioè SquashFS).
  • Comprendi il formato del programma post-installazione della nuova partizione . Se si utilizza un binario Executable and Linkable Format (ELF), dovrebbe essere compatibile con il vecchio kernel (ad es. Un nuovo programma a 64 bit in esecuzione su un vecchio kernel a 32 bit se l'architettura passava da build da 32 a 64 bit). A meno che al loader ( ld ) venga richiesto di utilizzare altri percorsi o creare un binario statico, le librerie verranno caricate dall'immagine di sistema precedente e non da quella nuova.

Ad esempio, è possibile utilizzare uno script di shell come programma post-installazione interpretato dal binario della shell del vecchio sistema con un #! marker in alto), quindi impostare i percorsi della libreria dal nuovo ambiente per eseguire un programma binario post-installazione più complesso. In alternativa, è possibile eseguire il passaggio post-installazione da una partizione più piccola dedicata per consentire l'aggiornamento del formato del file system nella partizione di sistema principale senza incorrere in problemi di compatibilità con le versioni precedenti o aggiornamenti stepping-stone; ciò consentirebbe agli utenti di aggiornare direttamente all'ultima versione da un'immagine di fabbrica.

Il nuovo programma post-installazione è limitato dalle politiche SELinux definite nel vecchio sistema. Pertanto, la fase di post-installazione è adatta per eseguire le attività richieste dalla progettazione su un determinato dispositivo o altre attività di maggior sforzo (ad es. Aggiornamento del firmware o bootloader con supporto A / B, preparazione delle copie dei database per la nuova versione, ecc. ). Il passaggio post-installazione non è adatto a correzioni di bug una tantum prima del riavvio che richiedono autorizzazioni impreviste.

I selezionati programma viene eseguito postinstallazione nel postinstall contesto di SELinux. Tutti i file nella nuova partizione montata saranno taggati con postinstall_file , indipendentemente da quali siano i loro attributi dopo il riavvio in quel nuovo sistema. Le modifiche agli attributi SELinux nel nuovo sistema non influiranno sul passaggio post-installazione. Se il programma post-installazione necessita di autorizzazioni aggiuntive, è necessario aggiungerle al contesto post-installazione.

Dopo il riavvio

Dopo il riavvio, update_verifier avvia il controllo di integrità utilizzando dm-verity. Questo controllo inizia prima di zygote per evitare che i servizi Java apportino modifiche irreversibili che impedirebbero un rollback sicuro. Durante questo processo, il bootloader e il kernel possono anche attivare un riavvio se l'avvio verificato o dm-verity rilevano eventuali danni. Al termine del controllo, update_verifier segna l'avvio update_verifier .

update_verifier leggerà solo i blocchi elencati in /data/ota_package/care_map.txt , che è incluso in un pacchetto OTA A / B quando si usa il codice AOSP. Il client di aggiornamento del sistema Java, come GmsCore, estrae care_map.txt , imposta l'autorizzazione di accesso prima di riavviare il dispositivo ed elimina il file estratto dopo che il sistema si avvia correttamente nella nuova versione.