Aggiornamenti dinamici del sistema

Gli aggiornamenti dinamici del sistema (DSU) consentono di creare un'immagine del sistema Android che gli utenti possono scaricare da Internet e provare senza il rischio di danneggiare l'immagine del sistema corrente. Questo documento descrive come supportare DSU.

Requisiti del kernel

Vedere Implementazione dinamica partizioni per i requisiti del kernel.

Inoltre, DSU si basa sulla funzionalità del kernel device-mapper-verity (dm-verity) per verificare l'immagine del sistema Android. Quindi devi abilitare le seguenti configurazioni del kernel:

  • CONFIG_DM_VERITY=y
  • CONFIG_DM_VERITY_FEC=y

Requisiti di partizione

A partire dal 11 Android, DSU richiede l' /data partizione da utilizzare i f2fs o file system ext4. F2FS offre prestazioni migliori ed è consigliato, ma la differenza dovrebbe essere insignificante.

Ecco alcuni esempi di quanto tempo impiega un aggiornamento dinamico del sistema con un dispositivo Pixel:

  • Usando F2FS:
    • 109s, utente 8G, sistema 867M, tipo di file system: F2FS: crittografia=aes-256-xts:aes-256-cts
    • 104s, utente 8G, sistema 867M, tipo di file system: F2FS: crittografia=ghiaccio
  • Usando ext4:
    • 135s, utente 8G, sistema 867M, tipo di file system: ext4: crittografia=aes-256-xts:aes-256-cts

Se ci vuole molto più tempo sulla tua piattaforma, potresti voler controllare se il flag di montaggio contiene un flag che fa scrivere "sync" oppure puoi specificare un flag "async" in modo esplicito per ottenere prestazioni migliori.

Il metadata è richiesto partizione (16 MB o superiore) per la memorizzazione dei dati relativi alle immagini installate. Deve essere montato durante il montaggio della prima fase.

userdata partizione deve utilizzare f2fs o il file system ext4. Quando si utilizza f2fs, includere tutti i f2fs patch relative disponibile nel Android kernel comuni .

DSU è stato sviluppato e testato con kernel/common 4.9. Si consiglia di utilizzare il kernel 4.9 e versioni successive per questa funzionalità.

Comportamento HAL del fornitore

Tessitore HAL

L'HAL del tessitore fornisce un numero fisso di slot per la memorizzazione delle chiavi utente. La DSU consuma due slot chiave aggiuntivi. Se un OEM dispone di un HAL weaver, deve disporre di slot sufficienti per un'immagine di sistema generica (GSI) e un'immagine host.

Guardiano HAL

Il Gatekeeper HAL ha bisogno di supportare grandi USER_ID valori, perché UID il GSI offset per l'HAL da 1.000.000.

Verifica avvio

Se si vuole supportare l'avvio sviluppatori GSI Immagini in stato di blocco senza disabilitare l'avvio verificato, includere sviluppatori chiavi GSI aggiungendo la seguente riga al file device/<device_name>/device.mk :

$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)

Protezione contro il rollback

Quando si utilizza DSU, l'immagine del sistema Android scaricata deve essere più recente dell'immagine del sistema corrente sul dispositivo. Questo viene fatto confrontando i livelli di patch di sicurezza in Android Avvio verificato (AVB) AVB proprietà del descrittore di entrambe le immagini di sistema: Prop: com.android.build.system.security_patch -> '2019-04-05' .

Per i dispositivi che non utilizzano AVB, mettere il livello di patch di sicurezza dell'immagine del sistema corrente nella cmdline kernel o bootconfig con il bootloader: androidboot.system.security_patch=2019-04-05 .

Requisiti hardware

Quando avvii un'istanza DSU, vengono allocati due file temporanei:

  • Una partizione logica per memorizzare GSI.img (1 ~ 1,5 G)
  • 8 GB vuoto /data partizione sandbox per l'esecuzione del GSI

Ti consigliamo di riservare almeno 10 GB di spazio libero prima di avviare un'istanza DSU. DSU supporta anche l'allocazione da una scheda SD. Quando è presente una scheda SD, ha la massima priorità per l'allocazione. Il supporto della scheda SD è fondamentale per i dispositivi a bassa potenza che potrebbero non disporre di spazio di archiviazione interno sufficiente. Quando è presente una scheda SD, assicurati che non sia adottata. DSU non supporta le schede SD adottati .

Frontend disponibili

È possibile avviare DSU usando adb , un'applicazione OEM, o con un solo clic loader DSU (in Android 11 o superiore).

Avvio di DSU utilizzando adb

Per avviare DSU usando adb, inserisci questi comandi:

$ simg2img out/target/product/.../system.img system.raw
$ gzip -c system.raw > system.raw.gz
$ adb push system.raw.gz /storage/emulated/0/Download
$ adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity  \
-a android.os.image.action.START_INSTALL    \
-d file:///storage/emulated/0/Download/system.raw.gz  \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1)  \
--el KEY_USERDATA_SIZE 8589934592

Avvio di DSU utilizzando un'app

Il punto di ingresso principale per DSU è android.os.image.DynamicSystemClient.java API:

public class DynamicSystemClient {


...
...

     /**
     * Start installing DynamicSystem from URL with default userdata size.
     *
     * @param systemUrl A network URL or a file URL to system image.
     * @param systemSize size of system image.
     */
    public void start(String systemUrl, long systemSize) {
        start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
    }

Devi raggruppare/preinstallare questa app sul dispositivo. Perché DynamicSystemClient è un'API di sistema, non si può costruire l'applicazione con il regolare API SDK e non è possibile pubblicare su Google Play. Lo scopo di questa app è:

  1. Recupera un elenco di immagini e l'URL corrispondente con uno schema definito dal fornitore.
  2. Abbina le immagini nell'elenco al dispositivo e mostra le immagini compatibili che l'utente può selezionare.
  3. Richiamare DynamicSystemClient.start in questo modo:

    DynamicSystemClient aot = new DynamicSystemClient(...)
       aot.start(
            ...URL of the selected image...,
            ...uncompressed size of the selected image...);
    
    

L'URL punta a un file di immagine di sistema compresso con gzip, non sparso, che puoi creare con i seguenti comandi:

$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz

Il nome del file dovrebbe seguire questo formato:

<android version>.<lunch name>.<user defined title>.raw.gz

Esempi:

  • o.aosp_taimen-userdebug.2018dev.raw.gz
  • p.aosp_taimen-userdebug.2018dev.raw.gz

Caricatore DSU con un clic

Android 11 introduce il caricatore DSU con un clic, che è un frontend nelle impostazioni dello sviluppatore.

Avvio del caricatore DSU

Figura 1. Avvio del caricatore DSU

Quando lo sviluppatore fa clic sul pulsante DSU Loader, si va a prendere un pre-configurati DSU JSON descrittore dal web e visualizza tutte le immagini applicabili nel menu mobile. Seleziona un'immagine per avviare l'installazione di DSU e l'avanzamento viene visualizzato nella barra di notifica.

Avanzamento dell'installazione dell'immagine DSU

Figura 2. DSU avanzamento dell'installazione immagine

Per impostazione predefinita, il caricatore DSU carica un descrittore JSON che contiene le immagini GSI. Le sezioni seguenti mostrano come creare pacchetti DSU firmati dall'OEM e caricarli dal caricatore DSU.

Bandiera caratteristica

La caratteristica DSU è sotto il settings_dynamic_android bandiera funzione. Prima di utilizzare DSU, assicurarsi che il flag della funzione corrispondente sia abilitato.

Abilitazione del flag della funzione.

Figura 3. Abilitando la funzione bandiera

L'interfaccia utente del flag della funzionalità potrebbe non essere disponibile su un dispositivo che esegue una build utente. In questo caso, utilizzare adb comando invece:

$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1

Immagini del sistema host del fornitore su GCE (facoltativo)

Una delle possibili posizioni di archiviazione per le immagini di sistema è il bucket di Google Compute Engine (GCE). L'amministratore di rilascio utilizza la console di storage GCP per aggiungere / cancellare / modificare l'immagine del sistema rilasciato.

Le immagini devono essere di pubblico accesso, come mostrato qui:

Accesso pubblico in GCE

Accesso figura 4. pubblici a GCE

La procedura per creare un pubblico elemento è disponibile nella documentazione di Google Cloud .

DSU a più partizioni in file ZIP

A partire da Android 11, DSU può avere più di una partizione. Ad esempio, può contenere un product.img oltre al system.img . All'avvio del dispositivo, la prima fase init rileva le partizioni DSU installati e sostituisce la partizione sul dispositivo temporaneo, quando il DSU installato è abilitato. Il pacchetto DSU può contenere una partizione che non dispone di una partizione corrispondente sul dispositivo.

Processo DSU con più partizioni

Processo Figura 5. DSU con più partizioni

DSU firmato OEM

Per assicurarsi che tutte le immagini in esecuzione sul dispositivo siano autorizzate dal produttore del dispositivo, tutte le immagini all'interno di un pacchetto DSU devono essere firmate. Ad esempio, supponiamo che ci sia un pacchetto DSU che contiene due immagini di partizione come di seguito:

dsu.zip {
    - system.img
    - product.img
}

Sia system.img e product.img devono essere firmati dal tasto OEM prima di essere inserite in un file ZIP. La pratica comune consiste nell'utilizzare un algoritmo asimmetrico, ad esempio RSA, in cui la chiave segreta viene utilizzata per firmare il pacchetto e la chiave pubblica per verificarlo. La prima fase ramdisk deve includere la chiave pubblica sbucciatura, per esempio, /avb/*.avbpubkey . Se il dispositivo ha già adottato l'AVB, sarà sufficiente la procedura di firma esistente. Le sezioni seguenti illustrano il processo di firma ed evidenziano il posizionamento della chiave pub AVB utilizzata per verificare le immagini nel pacchetto DSU.

Descrittore DSU JSON

Il descrittore DSU JSON descrive i pacchetti DSU. Supporta due primitive. In primo luogo, la include primitivo include descrittori JSON aggiuntivi o reindirizza il caricatore DSU in una nuova posizione. Per esempio:

{
    "include": ["https://.../gsi-release/gsi-src.json"]
}

In secondo luogo, l' image primitiva è utilizzata per descrivere pacchetti DSU rilasciati. All'interno della primitiva dell'immagine ci sono diversi attributi:

  • Il name e details attributi sono stringhe che vengono visualizzati nella finestra di dialogo per l'utente di selezionare.

  • I cpu_api , vndk e os_version attributi vengono utilizzati per controlli di compatibilità, descritti nella sezione successiva.

  • L'invio facoltativo pubkey attributo descrive la chiave pubblica che le coppie con la chiave segreta che viene utilizzato per firmare il pacchetto DSU. Quando è specificato, il servizio DSU può verificare se il dispositivo dispone della chiave utilizzata per verificare il pacchetto DSU. Ciò evita l'installazione di un pacchetto DSU non riconosciuto, ad esempio l'installazione di una DSU firmata da OEM-A su un dispositivo realizzato da OEM-B.

  • I opzionali tos attribuiscono punti in un file di testo che descrive i termini di servizio per il corrispondente pacchetto DSU. Quando uno sviluppatore seleziona un pacchetto DSU con l'attributo dei termini di servizio specificato, si apre la finestra di dialogo mostrata nella Figura 6, che chiede allo sviluppatore di accettare i termini di servizio prima di installare il pacchetto DSU.

    Finestra di dialogo Termini di servizio

    Figura 6. Condizioni di finestra di dialogo di servizio

Per riferimento, ecco un descrittore JSON DSU per GSI:

{
   "images":[
      {
         "name":"GSI+GMS x86",
         "os_version":"10",
         "cpu_abi": "x86",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_x86-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI+GMS ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
         "uri":"https://.../gsi/gsi_gms_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI ARM64",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_arm64-exp-QP1A.190711.020.C4-5928301.zip"
      },
      {
         "name":"GSI x86_64",
         "os_version":"10",
         "cpu_abi": "x86_64",
         "details":"exp-QP1A.190711.020.C4-5928301",
         "vndk":[
            27,
            28,
            29
         ],
         "pubkey":"",
         "uri":"https://.../gsi/aosp_x86_64-exp-QP1A.190711.020.C4-5928301.zip"
      }
   ]
}

Gestione della compatibilità

Diversi attributi vengono utilizzati per specificare la compatibilità tra un pacchetto DSU e il dispositivo locale:

  • cpu_api è una stringa che descrive l'architettura del dispositivo. Questo attributo è obbligatorio e viene confrontato con il ro.product.cpu.abi proprietà di sistema. I loro valori devono corrispondere esattamente.

  • os_version è un intero opzionale che specifica una versione di Android. Ad esempio, per Android 10, os_version è 10 e per Android 11, os_version è 11 . Quando viene specificato questo attributo, deve essere uguale o maggiore della ro.system.build.version.release proprietà di sistema. Questo controllo viene utilizzato per impedire l'avvio di un'immagine GSI Android 10 su un dispositivo del fornitore Android 11, che attualmente non è supportato. È consentito l'avvio di un'immagine GSI Android 11 su un dispositivo Android 10.

  • vndk è un array facoltativo che specifica tutti VNDKs che sono inclusi nel pacchetto DSU. Quando è specificato, i controlli caricatore DSU se il numero estratto dal ro.vndk.version è incluso proprietà di sistema.

Revoca delle chiavi DSU per motivi di sicurezza

Nel caso estremamente raro in cui la coppia di chiavi RSA utilizzata per firmare le immagini DSU sia compromessa, il ramdisk dovrebbe essere aggiornato il prima possibile per rimuovere la chiave compromessa. Oltre ad aggiornare la partizione di avvio, è possibile bloccare le chiavi compromesse utilizzando un elenco di revoche di chiavi DSU (key blacklist) da un URL HTTPS.

L'elenco di revoche di chiavi DSU contiene un elenco di chiavi pubbliche AVB revocate. Durante l'installazione di DSU, le chiavi pubbliche all'interno delle immagini DSU vengono convalidate con l'elenco di revoche. Se si rileva che le immagini contengono una chiave pubblica revocata, il processo di installazione di DSU si interrompe.

L'URL dell'elenco di revoche di chiavi deve essere un URL HTTPS per garantire il livello di sicurezza ed è specificato in una stringa di risorse:

frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url

Il valore della stringa è https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json , che è un elenco di revoca per le chiavi GSI Google-rilasciati. Questa stringa di risorse può essere sovrapposta e personalizzata, in modo che gli OEM che adottano la funzione DSU possano fornire e mantenere la propria lista nera di chiavi. Ciò consente all'OEM di bloccare determinate chiavi pubbliche senza aggiornare l'immagine del ramdisk del dispositivo.

Il formato della lista di revoca è:

{
   "entries":[
      {
         "public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      },
      {
         "public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
         "status":"REVOKED",
         "reason":"Key revocation test key"
      }
   ]
}
  • public_key è SHA-1 digest della chiave revocata, nel formato descritto nella generazione del CGA pubkey sezione.
  • status indica lo stato di revoca della chiave. Attualmente, il valore unico supportato è REVOKED .
  • reason è una stringa opzionale che descrive il motivo della revoca.

Procedure DSU

Questa sezione descrive come eseguire diverse procedure di configurazione DSU.

Generazione di una nuova coppia di chiavi

Utilizzare openssl comando per generare una RSA private / coppia di chiavi pubblica in .pem formato (ad esempio, con dimensioni 2048 bit):

$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem

La chiave privata potrebbe non essere accessibile ed è mantenuta solo in un modulo di sicurezza hardware (HSM) . In questo caso, potrebbe essere disponibile un certificato di chiave pubblica x509 dopo la generazione della chiave. Vedi l' aggiunta del pubkey abbinamento al ramdisk sezione per istruzioni per generare la chiave pubblica AVB da un certificato x509.

Per convertire un certificato x509 in formato PEM:

$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem

Salta questo passaggio se il certificato è già un file PEM.

Aggiunta del pairing pubkey al ramdisk

oem_cert.avbpubkey deve essere messo sotto /avb/*.avbpubkey per verificare il pacchetto DSU firmato. Innanzitutto, converti la chiave pubblica in formato PEM in formato chiave pubblica AVB:

$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey

Quindi includi la chiave pubblica nel ramdisk della prima fase con i seguenti passaggi.

  1. Aggiungere un modulo precompilato per copiare avbpubkey . Ad esempio, aggiungere device/<company>/<board>/oem_cert.avbpubkey e device/<company>/<board>/avb/Android.mk con contenuti di questo tipo:

    include $(CLEAR_VARS)
    
    LOCAL_MODULE := oem_cert.avbpubkey
    LOCAL_MODULE_CLASS := ETC
    LOCAL_SRC_FILES := $(LOCAL_MODULE)
    ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true)
    LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb
    else
    LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb
    endif
    
    include $(BUILD_PREBUILT)
    
  2. Fare l'obiettivo droidcore dipenderà dalla aggiunto oem_cert.avbpubkey :

    droidcore: oem_cert.avbpubkey
    

Generazione dell'attributo pubkey AVB nel descrittore JSON

oem_cert.avbpubkey è nel CGA formato binario chiave pubblica. Usa SHA-1 per renderlo leggibile prima di inserirlo nel descrittore JSON:

$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20

Questo sarà il contenuto del pubkey attributo del descrittore JSON.

   "images":[
      {
         ...
         "pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
         ...
      },

Firmare un pacchetto DSU

Utilizzare uno di questi metodi per firmare un pacchetto DSU:

  • Metodo 1: riutilizzare l'artefatto creato dal processo di firma AVB originale per creare un pacchetto DSU. Un approccio alternativo consiste nell'estrarre le immagini già firmate dal pacchetto di rilascio e utilizzare le immagini estratte per creare direttamente il file ZIP.

  • Metodo 2: utilizzare i seguenti comandi per firmare le partizioni DSU se la chiave privata è disponibile. Ogni img all'interno di un pacchetto DSU (il file ZIP) è firmato separatamente:

    $ key_len=$(openssl rsa -in oem_cert_pri.pem -text | grep Private-Key | sed -e 's/.*(\(.*\) bit.*/\1/')
    $ for partition in system product; do
        avbtool add_hashtree_footer \
            --image ${OUT}/${partition}.img \
            --partition_name ${partition} \
            --algorithm SHA256_RSA${key_len} \
            --key oem_cert_pri.pem
    done
    

Per ulteriori informazioni sull'aggiunta di add_hashtree_footer utilizzando avbtool , vedere Utilizzando avbtool .

Verifica del pacchetto DSU in locale

Si consiglia di verificare tutte le immagini locali rispetto alla chiave pubblica di associazione con questi comandi:


for partition in system product; do
    avbtool verify_image --image ${OUT}/${partition}.img  --key oem_cert_pub.pem
done

L'output previsto è simile a questo:

Verifying image dsu/system.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/system.img
: Successfully verified sha1 hashtree of dsu/system.img for image of 898494464 bytes

Verifying image dsu/product.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/product.img
: Successfully verified sha1 hashtree of dsu/product.img for image of 905830400 bytes

Creare un pacchetto DSU

Il seguente esempio fa un pacchetto DSU contenente uno system.img e un product.img :

dsu.zip {
    - system.img
    - product.img
}

Dopo che entrambe le immagini sono state firmate, usa il seguente comando per creare il file ZIP:

$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -

Personalizzazione della DSU con un clic

Per default, i punti loader DSU ad una metadati di immagini GSI che è https://...google.com/.../gsi-src.json .

Gli OEM possono sovrascrivere la lista definendo la persist.sys.fflag.override.settings_dynamic_system.list proprietà che punti alla propria descrittore JSON. Ad esempio, un OEM può fornire metadati JSON che includono GSI e immagini proprietarie OEM come questa:

{
    "include": ["https://dl.google.com/.../gsi-src.JSON"]
    "images":[
      {
         "name":"OEM image",
         "os_version":"10",
         "cpu_abi": "arm64-v8a",
         "details":"...",
         "vndk":[
            27,
            28,
            29
         ],
         "spl":"...",
         "pubkey":"",
         "uri":"https://.../....zip"
      },

}

È possibile per un OEM concatenare i metadati DSU pubblicati come mostrato nella Figura 7.

Concatenamento dei metadati DSU pubblicati

Figura 7. concatenamento pubblicato metadati DSU