Aggiornamenti di sistema dinamici

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

Requisiti del kernel

Consulta Implementazione delle partizioni dinamiche per i requisiti del kernel.

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

  • CONFIG_DM_VERITY=y
  • CONFIG_DM_VERITY_FEC=y

Requisiti di partizione

A partire da Android 11, la DSU richiede l'/data per utilizzare il file system F2FS o ext4. F2FS offre prestazioni migliori viene consigliato, ma la differenza non dovrebbe essere significativa.

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

  • Con 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: encryption=ice
  • Utilizzo di ext4:
    • 135s, utente 8G, sistema 867M, tipo di file system: ext4: crittografia=aes-256-xts:aes-256-cts

Se sulla tua piattaforma richiede molto più tempo, ti consigliamo di controllare se il supporto contiene qualsiasi flag che comporti una scrittura "sync", oppure puoi specificare un flag "async" segnala in modo esplicito per ottenere prestazioni migliori.

Per archiviare i dati relativi alla partizione metadata è necessaria una partizione di 16 MB o superiore alle immagini installate. Deve essere montato durante il montaggio del primo stadio.

La partizione userdata deve utilizzare un file system F2FS o ext4. Quando utilizzi F2FS, includere tutte le patch relative a F2FS disponibili nel Keril comune di Android.

DSU è stato sviluppato e testato con kernel/common 4.9. Ti consigliamo di utilizzare kernel 4.9 e successivi per questa funzione.

Comportamento HAL del fornitore

Weaver HAL

Weaver HAL offre un numero fisso di slot per l'archiviazione delle chiavi utente. La DSU utilizza due slot di chiave aggiuntivi. Se un OEM dispone di Weaver HAL, deve disporre abbastanza slot per un'immagine di sistema generica (GSI) e un'immagine host.

Gatekeeper HAL

Gatekeeper HAL deve supporta valori USER_ID grandi, perché GSI compensa gli UID nell'HAL +1000000.

Verifica avvio

Se vuoi supportare l'avvio delle immagini GSI per sviluppatori in stato BLOCCATO senza disattivazione avvio verificato, includi le chiavi GSI dello sviluppatore aggiungendo la riga seguente al file device/<device_name>/device.mk:

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

Protezione rollback

Quando si utilizza DSU, l'immagine di sistema Android scaricata deve essere più recente della l'immagine di sistema attuale sul dispositivo. Per farlo, confronta le patch di sicurezza livelli nel Avvio verificato di Android (AVB) Descrittore proprietà AVB di entrambe le immagini di sistema: Prop: com.android.build.system.security_patch -> '2019-04-05'.

Per i dispositivi che non utilizzano AVB, inserisci il livello patch di sicurezza del sistema attuale nella cartella cmdline del 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 archiviare GSI.img (1~1,5 G)
  • Una partizione /data vuota da 8 GB come sandbox per l'esecuzione di GSI

Ti consigliamo di prenotare almeno 10 GB di spazio libero prima di lanciare una DSU in esecuzione in un'istanza Compute Engine. DSU supporta anche l'allocazione da una scheda SD. Se la scheda SD viene presente, ha la priorità più alta per l'allocazione. Il supporto della scheda SD è è fondamentale per i dispositivi a basso consumo che potrebbero non avere abbastanza memoria interna. Se è presente una scheda SD, assicurati che non sia adottata. DSU non supporta adottate le schede SD.

Frontend disponibili

Puoi avviare la DSU utilizzando adb, un'app OEM o il caricatore DSU con un solo clic (in Android 11 o versioni successive).

Avviare la DSU utilizzando ADB

Per avviare la DSU utilizzando 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

Avviare la DSU utilizzando un'app

Il punto di accesso principale alla 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. Poiché DynamicSystemClient è un'API di sistema, non puoi creare l'app con la SDK e non potrai pubblicarla 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. Richiama DynamicSystemClient.start in questo modo:

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

L'URL rimanda a un file immagine di sistema in formato 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 deve avere 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 solo clic

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

Avvio del caricatore DSU

Figura 1. Avvio del caricatore DSU

Quando lo sviluppatore fa clic sul pulsante DSU Loader, recupera una pagina descrittore JSON DSU dal web e visualizza tutte le immagini applicabili nel menu mobile. Seleziona un'immagine per avviare l'installazione della DSU e lo stato di avanzamento viene visualizzata sulla barra delle notifiche.

Avanzamento dell&#39;installazione dell&#39;immagine DSU

Figura 2. Avanzamento dell'installazione dell'immagine DSU

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

Flag funzionalità

La funzione DSU è sotto il flag funzione settings_dynamic_android. Prima del giorno usando DSU, accertati che il flag di funzione corrispondente sia abilitato.

Attivazione del flag della funzionalità in corso...

Figura 3. Attivazione del flag della funzionalità

La UI del flag di funzionalità potrebbe non essere disponibile su un dispositivo che esegue una build utente. Nella in questo caso, usa invece il comando adb:

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

Immagini di sistema host del fornitore su GCE (facoltative)

Una delle possibili posizioni di archiviazione per le immagini di sistema è di Compute Engine (GCE). L'amministratore delle release utilizza dalla console di archiviazione Google Cloud aggiungi/elimina/modifica l'immagine di sistema rilasciata.

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

Accesso pubblico in GCE

Figura 4. Accesso pubblico in GCE

La procedura per rendere un elemento pubblico è disponibile in documentazione di Google Cloud.

DSU a partizione multipla nel file ZIP

A partire da Android 11, la DSU può avere più di una della partizione di testo. Ad esempio, può contenere un valore product.img oltre ai system.img. All'avvio del dispositivo, la prima fase init rileva ha installato partizioni DSU e sostituisce temporaneamente la partizione sul dispositivo, la DSU installata sia abilitata. Il pacchetto DSU può contenere una partizione a una partizione corrispondente sul dispositivo.

Processo DSU con più partizioni

Figura 5. Processo DSU con più partizioni

DSU firmato dall'OEM

Per assicurarti che tutte le immagini in esecuzione sul dispositivo siano autorizzate dal dispositivo stesso produttore, tutte le immagini all'interno di un pacchetto DSU devono essere firmate. Ad esempio: supponiamo che esista un pacchetto DSU che contiene due immagini di partizione come quelle riportate di seguito:

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

Sia system.img sia product.img devono essere firmati dalla chiave dell'OEM prima di poter vengono inseriti nel file ZIP. È prassi comune utilizzare una query asimmetrica dell'algoritmo, ad esempio RSA, in cui la chiave segreta viene utilizzata per firmare il pacchetto e chiave pubblica utilizzata per verificarla. Il ramdisk della prima fase deve includere il paring chiave pubblica, ad esempio /avb/*.avbpubkey. Se il dispositivo ha già adottato AVB, la procedura di firma esistente. Le seguenti sezioni illustrano la processo di firma ed evidenzia il posizionamento della chiave pubkey AVB utilizzata verificare le immagini nel pacchetto DSU.

Descrittore JSON DSU

Il descrittore JSON DSU descrive i pacchetti DSU. Supporta due primitive. Innanzitutto, la primitiva include include descrittori o reindirizzamenti JSON aggiuntivi il caricatore DSU in una nuova posizione. Ad esempio:

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

La seconda, la primitiva image, viene utilizzata per descrivere i pacchetti DSU rilasciati. Interno ci sono diversi attributi:

  • Gli attributi name e details sono stringhe che vengono mostrate la finestra di dialogo da selezionare.

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

  • L'attributo facoltativo pubkey descrive il pubblico che viene accoppiata con la chiave segreta utilizzata per firmare il pacchetto DSU. Quando è specificato, il servizio DSU può verificare se il dispositivo ha la chiave utilizzata per verificare il pacchetto DSU. In questo modo si evita l'installazione di una DSU non riconosciuta. ad esempio l'installazione di una DSU firmata da OEM-A su un dispositivo realizzato OEM-B.

  • L'attributo facoltativo tos rimanda a un file di testo che descrive i Termini di servizio del pacchetto DSU corrispondente. Quando uno sviluppatore seleziona un pacchetto DSU con l'attributo termini di servizio specificato, si apre la finestra di dialogo mostrata nella Figura 6, in cui viene chiesto allo sviluppatore di accettare i termini prima di installare il pacchetto DSU.

    Finestra di dialogo Termini di servizio

    Figura 6. Finestra di dialogo Termini di servizio

Come 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à

Vengono utilizzati diversi attributi 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 la proprietà di sistema ro.product.cpu.abi. I loro valori devono corrispondere esattamente.

  • os_version è un numero intero facoltativo che specifica una release di Android. Per ad esempio, per Android 10, os_version è 10 e per Android 11, os_version è 11. Quando questo , deve essere uguale o superiore al valore ro.system.build.version.release proprietà di sistema. Questo controllo viene utilizzato per impedire l'avvio di un'immagine GSI di Android 10 su Android 11 del fornitore, che al momento non è supportato. È consentito l'avvio di un'immagine GSI di Android 11 su un dispositivo Android 10.

  • vndk è un array facoltativo che specifica tutti i VNDK inclusi del pacchetto DSU. Quando viene specificato, il caricatore DSU controlla se il numero estratta dalla proprietà di sistema ro.vndk.version.

Revocare le chiavi DSU per la sicurezza

Nel caso estremamente raro in cui la coppia di chiavi RSA utilizzata per firmare le immagini DSU venga compromesso, il ramdisk dovrebbe essere aggiornato il prima possibile per rimuovere della chiave compromessa. Oltre ad aggiornare la partizione di avvio, puoi bloccare compromesse utilizzando un elenco di revoche delle chiavi DSU (lista nera delle chiavi) da un protocollo URL.

L'elenco di revoche delle chiavi DSU contiene un elenco delle chiavi pubbliche AVB revocate. Durante l'installazione della DSU, le chiavi pubbliche all'interno delle immagini DSU vengono convalidate con l'elenco delle revoche. Se le immagini contengono un nome pubblico revocato viene interrotta la procedura di installazione della DSU.

L'URL dell'elenco di revoche delle chiavi deve essere un URL HTTPS per garantire la 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 delle revoche per le chiavi GSI rilasciate da Google. Questa stringa di risorse può essere sovrapposti e personalizzati, in modo che gli OEM che adottano la funzione DSU possano fornire mantenere la propria lista bloccata. In questo modo, l'OEM può bloccare alcune chiavi pubbliche senza aggiornare l'immagine ramdisk del dispositivo.

Il formato dell'elenco revoche è:

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

Procedure DSU

Questa sezione descrive come eseguire diverse procedure di configurazione DSU.

Genera una nuova coppia di chiavi

Usa il comando openssl per generare una coppia di chiavi pubbliche/private RSA in .pem (ad esempio, con dimensione 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 e viene conservata solo in una modulo di sicurezza hardware (HSM). In questo caso, potrebbe essere disponibile un certificato di chiave pubblica x509 dopo la chiave di classificazione. Consulta la sezione Aggiunta del pubkey di accoppiamento al ramdisk per istruzioni su come 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

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

Aggiungi la Pubkey di accoppiamento al ramdisk

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

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

Quindi, includi la chiave pubblica nel ramdisk della prima fase seguendo questi passaggi.

  1. Aggiungi un modulo predefinito per copiare avbpubkey. Ad esempio, aggiungi device/<company>/<board>/oem_cert.avbpubkey e device/<company>/<board>/avb/Android.mk con contenuti come questi:

    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. Fai in modo che il target droidcore dipenda dal valore oem_cert.avbpubkey aggiunto:

    droidcore: oem_cert.avbpubkey
    

Genera l'attributo pubkey AVB nel descrittore JSON

oem_cert.avbpubkey è nel formato binario della chiave pubblica AVB. Utilizza SHA-1 per rendilo leggibile prima di inserirlo nel descrittore JSON:

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

Questi saranno i contenuti dell'attributo pubkey del descrittore JSON.

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

Firmare un pacchetto DSU

Per firmare un pacchetto DSU, utilizza uno dei seguenti metodi:

  • Metodo 1: riutilizza l'artefatto creato dal processo di firma AVB originale per creare un pacchetto DSU. Un approccio alternativo è quello di estrarre le informazioni immagini dal pacchetto di rilascio e usare le immagini estratte per creare il file ZIP .

  • Metodo 2: utilizza i seguenti comandi per firmare le partizioni DSU se sia 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 tramite avbtool, consulta Utilizzo di avbtool.

Verificare il pacchetto DSU a livello locale

Ti consigliamo di verificare tutte le immagini locali rispetto alla chiave pubblica di accoppiamento 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 sarà simile al seguente:

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

L'esempio seguente crea un pacchetto DSU che contiene system.img e un oggetto product.img:

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

Dopo aver firmato entrambe le immagini, 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 -

Personalizzare la DSU con un clic

Per impostazione predefinita, il caricatore DSU rimanda ai metadati delle immagini GSI, https://...google.com/.../gsi-src.json.

Gli OEM possono sovrascrivere l'elenco definendo il persist.sys.fflag.override.settings_dynamic_system.list che punta al proprio descrittore JSON. Ad esempio, un OEM potrebbe fornisci metadati JSON che includano GSI e immagini di proprietà dell'OEM, ad esempio le seguenti:

{
    "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"
      },

}

Un OEM può concatenare i metadati DSU pubblicati, come mostrato nella Figura 7.

Concatenamento dei metadati DSU pubblicati

Figura 7. Concatenamento dei metadati DSU pubblicati