Google is committed to advancing racial equity for Black communities. See how.
Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Implementazione degli aggiornamenti A / B

OEM e fornitori di SoC che desiderano implementare aggiornamenti di sistema A / B devono assicurarsi che il loro bootloader implementi il ​​boot_control HAL e passi i parametri corretti al kernel.

Implementazione del controllo di avvio HAL

I bootloader compatibili con A / B devono implementare boot_control HAL in hardware/libhardware/include/hardware/boot_control.h . È possibile testare le implementazioni utilizzando l'utility system/extras/bootctl e system/extras/tests/bootloader/ .

È inoltre necessario implementare la macchina a stati mostrata di seguito:

Figura 1. Bootloader state machine

Configurazione del kernel

Per implementare gli aggiornamenti di sistema A / B:

  1. Scegli la seguente serie di patch del kernel (se necessario):
  2. Assicurarsi che gli argomenti della riga di comando del kernel contengano i seguenti argomenti aggiuntivi:
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... dove il valore <public-key-id> è l'ID della chiave pubblica utilizzata per verificare la firma della tabella di verity (per i dettagli, vedere dm-verity ).
  3. Aggiungere il certificato .X509 contenente la chiave pubblica al portachiavi di sistema:
    1. Copiare il certificato .X509 formattato nel formato .der nella radice della directory del kernel . Se il certificato .X509 è formattato come un .pem file, utilizzare il seguente openssl comando per convertire da .pem a .der formato:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. zImage la zImage per includere il certificato come parte del portachiavi di sistema. Per verificare, controllare la voce procfs (richiede che KEYS_CONFIG_DEBUG_PROC_KEYS sia abilitato):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      L'inclusione corretta del certificato .X509 indica la presenza della chiave pubblica nel portachiavi di sistema (l'evidenziazione indica l'ID della chiave pubblica).
    3. Sostituisci lo spazio con # e passalo come <public-key-id> nella riga di comando del kernel. Ad esempio, passa Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f al posto di <public-key-id> .

Impostazione delle variabili di compilazione

I bootloader compatibili con A / B devono soddisfare i seguenti criteri delle variabili di build:

Deve definire per il target A / B
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
    boot \
    system \
    vendor
    e altre partizioni aggiornate tramite update_engine (radio, bootloader, ecc.)
  • PRODUCT_PACKAGES += \
    update_engine \
    update_verifier
Per un esempio, fare riferimento a /device/google/marlin/+/android-7.1.0_r1/device-common.mk . Facoltativamente, è possibile eseguire il passaggio dex2oat post-installazione (ma pre-riavvio) descritto in Compilazione .
Fortemente consigliato per target A / B
  • Definisci TARGET_NO_RECOVERY := true
  • Definisci BOARD_USES_RECOVERY_AS_BOOT := true
  • Non definire BOARD_RECOVERYIMAGE_PARTITION_SIZE
Impossibile definire per target A / B
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
Facoltativo per build di debug PRODUCT_PACKAGES_DEBUG += update_engine_client

Impostazione delle partizioni (slot)

I dispositivi A / B non necessitano di una partizione di ripristino o di una partizione cache perché Android non utilizza più queste partizioni. La partizione dati viene ora utilizzata per il pacchetto OTA scaricato e il codice dell'immagine di ripristino si trova sulla partizione di avvio. Tutte le partizioni A / B dovrebbero essere denominate come segue (gli slot sono sempre denominati a , b , ecc.): boot_a , boot_b , system_a , system_b , vendor_a , vendor_b .

Cache

Per gli aggiornamenti non A / B, la partizione della cache è stata utilizzata per memorizzare i pacchetti OTA scaricati e per nascondere temporaneamente i blocchi durante l'applicazione degli aggiornamenti. Non c'è mai stato un buon modo per dimensionare la partizione della cache: quanto grande doveva dipendere dagli aggiornamenti che si desideravano applicare. Il caso peggiore sarebbe una partizione della cache grande quanto l'immagine del sistema. Con gli aggiornamenti A / B non è necessario memorizzare i blocchi (perché stai sempre scrivendo su una partizione che non è attualmente utilizzata) e con lo streaming A / B non è necessario scaricare l'intero pacchetto OTA prima di applicarlo.

Recupero

Il disco RAM di ripristino è ora contenuto nel file boot.img . Quando si va in ripristino, il bootloader non può mettere l'opzione skip_initramfs sulla riga di comando del kernel.

Per gli aggiornamenti non A / B, la partizione di ripristino contiene il codice utilizzato per applicare gli aggiornamenti. Gli aggiornamenti A / B vengono applicati da update_engine esecuzione nella normale immagine di sistema avviata. Esiste ancora una modalità di ripristino utilizzata per implementare il ripristino dei dati di fabbrica e il sideload dei pacchetti di aggiornamento (da cui deriva il nome "ripristino"). Il codice ei dati per la modalità di ripristino sono archiviati nella normale partizione di avvio in un ramdisk; per eseguire l'avvio nell'immagine di sistema, il bootloader dice al kernel di saltare il ramdisk (altrimenti il ​​dispositivo si avvia in modalità di ripristino. La modalità di ripristino è piccola (e gran parte di essa era già sulla partizione di avvio), quindi la partizione di avvio non aumenta in misura.

Fstab

L'argomento slotselect deve essere sulla riga per le partizioni A / B-ed. Per esempio:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

Nessuna partizione dovrebbe essere denominata vendor . Invece, la partizione vendor_a o vendor_b verrà selezionata e montata sul punto di montaggio /vendor .

Argomenti dello slot del kernel

Il suffisso dello slot corrente deve essere passato tramite un nodo DT (Device Tree) specifico ( /firmware/android/slot_suffix ) o tramite l'argomento della riga di comando androidboot.slot_suffix .

Per impostazione predefinita, fastboot lampeggia lo slot corrente su un dispositivo A / B. Se il pacchetto di aggiornamento contiene anche immagini per l'altro slot non corrente, fastboot lampeggia anche quelle immagini. Le opzioni disponibili includono:

  • --slot SLOT . Ignorare il comportamento predefinito e richiedere a fastboot di eseguire il flashing dello slot passato come argomento.
  • --set-active [ SLOT ] . Imposta lo slot come attivo. Se non viene specificato alcun argomento facoltativo, lo slot corrente viene impostato come attivo.
  • fastboot --help . Ottieni dettagli sui comandi.

Se il bootloader implementa il fastboot, dovrebbe supportare il comando set_active <slot> che imposta lo slot attivo corrente sullo slot dato (questo deve anche cancellare il flag non avviabile per quello slot e ripristinare il conteggio dei tentativi ai valori predefiniti). Il bootloader dovrebbe supportare anche le seguenti variabili:

  • has-slot:<partition-base-name-without-suffix> . Restituisce "sì" se la partizione data supporta gli slot, "no" in caso contrario.
  • current-slot . Restituisce il suffisso dello slot che verrà avviato dal successivo.
  • slot-count . Restituisce un numero intero che rappresenta il numero di slot disponibili. Attualmente, sono supportati due slot, quindi questo valore è 2 .
  • slot-successful:<slot-suffix> . Restituisce "sì" se lo slot specificato è stato contrassegnato come avviato correttamente, "no" in caso contrario.
  • slot-unbootable:<slot-suffix> . Restituisce "sì" se lo slot specificato è contrassegnato come non avviabile, "no" in caso contrario.
  • slot-retry-count . Numero di tentativi rimanenti per tentare di avviare lo slot specificato.

Per visualizzare tutte le variabili, eseguire fastboot getvar all .

Generazione di pacchetti OTA

Gli strumenti del pacchetto OTA seguono gli stessi comandi dei comandi per i dispositivi non A / B. Il file target_files.zip deve essere generato definendo le variabili di build per il target A / B. Gli strumenti dei pacchetti OTA identificano e generano automaticamente i pacchetti nel formato per l'aggiornamento A / B.

Esempi:

  • Per generare un OTA completo:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • Per generare un'OTA incrementale:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

Configurazione delle partizioni

update_engine può aggiornare qualsiasi coppia di partizioni A / B definite nello stesso disco. Una coppia di partizioni ha un prefisso comune (come system o boot ) e un suffisso per slot (come _a ). L'elenco delle partizioni per le quali il generatore di payload definisce un aggiornamento è configurato dalla variabile make AB_OTA_PARTITIONS .

Ad esempio, se sono incluse una coppia di partizioni bootloader_a e booloader_b ( _a e _b sono i suffissi degli slot), è possibile aggiornare queste partizioni specificando quanto segue nella configurazione del prodotto o della scheda:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

Tutte le partizioni aggiornate da update_engine non devono essere modificate dal resto del sistema. Durante gli aggiornamenti incrementali o delta , i dati binari dallo slot corrente vengono utilizzati per generare i dati nel nuovo slot. Qualsiasi modifica potrebbe causare la mancata verifica dei dati del nuovo slot durante il processo di aggiornamento e quindi il mancato aggiornamento.

Configurazione post-installazione

È possibile configurare la fase di post-installazione in modo diverso per ciascuna partizione aggiornata utilizzando un set di coppie chiave-valore. Per eseguire un programma che si trova in /system/usr/bin/postinst in una nuova immagine, specificare il percorso relativo alla radice del filesystem nella partizione di sistema.

Ad esempio, usr/bin/postinst è system/usr/bin/postinst (se non si utilizza un disco RAM). Inoltre, specifica il tipo di filesystem da passare alla chiamata di sistema mount(2) . Aggiungere quanto segue ai file .mk del prodotto o del dispositivo (se applicabile):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

Compilazione

Per motivi di sicurezza, system_server non può utilizzare la system_server just-in-time (JIT) . Ciò significa che è necessario compilare in anticipo i file system_server per system_server e le sue dipendenze come minimo; qualsiasi altra cosa è facoltativa.

Per compilare app in background, è necessario aggiungere quanto segue alla configurazione del dispositivo del prodotto (in device.mk del prodotto):

  1. Includere i componenti nativi nella build per garantire che lo script di compilazione e i file binari siano compilati e inclusi nell'immagine di sistema.
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. Collega lo script di compilazione a update_engine modo che update_engine eseguito come passaggio di post-installazione.
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

Per assistenza sull'installazione dei file preoptati nella seconda partizione di sistema inutilizzata, fare riferimento a Prima installazione di avvio dei file DEX_PREOPT .