Gli aggiornamenti di sistema dinamici (DSU) ti consentono di creare un'immagine di sistema Android che gli utenti possono scaricare da internet e provare senza il rischio di danneggiare l'immagine di sistema corrente. Questo documento descrive come supportare la DSU.
Requisiti del kernel
Per i requisiti del kernel, consulta Implementazione delle partizioni dinamiche.
Inoltre, DSU si basa sulla funzionalità del kernel device-mapper-verity (dm-verity) per verificare l'immagine di sistema Android. Pertanto, devi attivare le seguenti configurazioni del kernel:
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_FEC=y
Requisiti delle partizioni
A partire da Android 11, DSU richiede che la partizione /data
utilizzi il file system F2FS o ext4. F2FS offre prestazioni migliori ed è consigliato, ma la differenza dovrebbe essere irrilevante.
Ecco alcuni esempi della durata di un aggiornamento di sistema dinamico su un dispositivo Pixel:
- Utilizzo di F2FS:
- 109 s, 8 G utente, 867 M sistema, tipo di file system: F2FS: encryption=aes-256-xts:aes-256-cts
- 104s, 8G user, 867M system, file system type: F2FS: encryption=ice
- Utilizzo di ext4:
- 135 s, 8 G utente, 867 M sistema, tipo di file system: ext4: encryption=aes-256-xts:aes-256-cts
Se la tua piattaforma impiega molto più tempo, ti consigliamo di controllare se il flag mount contiene un flag che esegue la scrittura "sync" oppure puoi specificare esplicitamente un flag "async" per migliorare le prestazioni.
La partizione metadata
(da 16 MB in su) è necessaria per archiviare i dati relativi alle immagini installate. Deve essere montato durante il primo montaggio.
La partizione userdata
deve utilizzare il file system F2FS o ext4. Quando utilizzi F2FS,
includere tutte le patch relative a F2FS disponibili nel
kernel comune di Android.
DSU è stato sviluppato e testato con kernel/common 4.9. Per questa funzionalità è consigliabile utilizzare il kernel 4.9 e versioni successive.
Comportamento dell'HAL del fornitore
HAL Weaver
L'HAL Weaver fornisce un numero fisso di slot per l'archiviazione delle chiavi utente. Il DSU consuma due slot per chiavi aggiuntivi. Se un OEM ha un HAL Weaver, deve avere abbastanza slot per un'immagine di sistema generica (GSI) e un'immagine host.
HAL Gatekeeper
L'HAL Gatekeeper deve supportare valori USER_ID
di grandi dimensioni, perché GSI compensa gli UID nell'HAL di più di 1000000.
Avvio verificato
Se vuoi supportare l'avvio di immagini GSI per sviluppatori
in stato BLOccato senza disattivare
l'avvio verificato, includi le chiavi GSI per sviluppatori 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 utilizzi DSU, l'immagine di sistema Android scaricata deve essere più recente dell'immagine di sistema corrente sul dispositivo. Questo viene fatto confrontando i livelli delle patch di sicurezza nel descrittore della proprietà AVB di Avvio verificato Android (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 della patch di sicurezza dell'immagine di sistema corrente in cmdline o bootconfig del kernel 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 del GSI
Ti consigliamo di riservare almeno 10 GB di spazio libero prima di lanciare un'istanza DSU. DSU supporta anche l'allocazione da una scheda SD. Se è presente una scheda SD, ha la priorità più alta per l'allocazione. Il supporto della scheda SD è fondamentale per i dispositivi meno potenti che potrebbero non avere memoria interna sufficiente. Se è presente una scheda SD, assicurati che non sia adottata. DSU non supporta le schede SD adottate.
Frontend disponibili
Puoi avviare DSU utilizzando adb
, un'app OEM o il caricatore DSU con un solo clic (in Android 11 o versioni successive).
Avvia DSU utilizzando adb
Per avviare 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 ingresso principale a DSU è l'API android.os.image.DynamicSystemClient.java
:
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 normale
API SDK e non puoi pubblicarla su Google Play. Lo scopo di questa app è:
- Recupera un elenco di immagini e l'URL corrispondente con uno schema definito dal fornitore.
- Abbina le immagini nell'elenco al dispositivo e mostra quelle compatibili da selezionare dall'utente.
Richiama
DynamicSystemClient.start
nel seguente 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 non sparso compresso con gzip, 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 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 solo clic
Android 11 introduce il caricatore DSU con un solo clic, che è un frontend nelle impostazioni sviluppatore.
Figura 1. Avvio del caricatore DSU
Quando lo sviluppatore fa clic sul pulsante DSU Loader, viene recuperato un descrittore JSON DSU preconfigurato dal web e vengono visualizzate tutte le immagini applicabili nel menu popup. Seleziona un'immagine per avviare l'installazione del DSU e lo stato di avanzamento viene visualizzato nella barra delle notifiche.
Figura 2. Avanzamento dell'installazione dell'immagine DSU
Per impostazione predefinita, il caricatore DSU carica un descrittore JSON contenente le immagini GSI. Le sezioni seguenti mostrano come creare pacchetti DSU firmati dall'OEM e caricarli dal caricatore DSU.
Flag funzionalità
La funzionalità DSU è inclusa nel flag funzionalità settings_dynamic_android
. Prima di usare DSU, assicurati che il flag della funzionalità corrispondente sia attivato.
Figura 3. Attivazione del flag funzionalità
L'interfaccia utente dei flag di funzionalità potrebbe non essere disponibile su un dispositivo su cui è in esecuzione una build utente. In questo caso, utilizza il comando adb
:
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
(Facoltativo) Il fornitore ospita le immagini di sistema su GCE
Uno dei possibili percorsi di archiviazione per le immagini di sistema è il bucket Google Compute Engine (GCE). L'amministratore delle release utilizza la console di archiviazione Google Cloud per aggiungere/eliminare/modificare l'immagine di sistema rilasciata.
Le immagini devono essere di dominio pubblico, come mostrato di seguito:
Figura 4. Accesso pubblico in GCE
La procedura per rendere pubblico un elemento è disponibile nella documentazione di Google Cloud.
DSU con più partizioni in file ZIP
A partire da Android 11, la DSU può avere più di una partizione. Ad esempio, può contenere un product.img
oltre al
system.img
. Quando il dispositivo si avvia, la prima fase init
rileva le partizioni DSU installate e sostituisce temporaneamente la partizione sul dispositivo quando il DSU installato è abilitato. Il pacchetto DSU potrebbe contenere una partizione che non ha una partizione corrispondente sul dispositivo.
Figura 5. Processo DSU con più partizioni
DSU firmato dall'OEM
Per assicurarti che tutte le immagini in esecuzione sul dispositivo siano autorizzate dal produttore, tutte le immagini all'interno di un pacchetto DSU devono essere firmate. Ad esempio, supponiamo che esista un pacchetto DSU contenente due immagini di partizione come mostrato di seguito:
dsu.zip {
- system.img
- product.img
}
Sia system.img
che product.img
devono essere firmati dalla chiave OEM prima di essere inseriti nel file ZIP. La pratica comune è utilizzare un algoritmo asimmetrico, ad esempio RSA, in cui la chiave segreta viene utilizzata per firmare il pacchetto e la chiave pubblica per verificarlo. Il ramdisk della prima fase deve includere la chiave pubblica di accoppiamento, ad esempio /avb/*.avbpubkey
. Se il dispositivo ha già adottato AVB, sarà sufficiente la procedura di firma esistente. Le sezioni seguenti illustrano la procedura di firma e mettono in evidenza il posizionamento della chiave pubblica AVB utilizzata per verificare le immagini nel pacchetto DSU.
Descrittore JSON DSU
Il descrittore JSON DSU descrive i pacchetti DSU. Supporta due primitive.
Innanzitutto, l'elemento primitivo include
include descrittori JSON aggiuntivi o reindirizza il caricatore DSU a una nuova posizione. Ad esempio:
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
In secondo luogo, la primitiva image
viene utilizzata per descrivere i pacchetti DSU rilasciati. All'interno della primitiva immagine sono presenti diversi attributi:
Gli attributi
name
edetails
sono stringhe mostrate nella finestra di dialogo per la selezione da parte dell'utente.Gli attributi
cpu_api
,vndk
eos_version
vengono utilizzati per i controlli di compatibilità, descritti nella sezione successiva.L'attributo facoltativo
pubkey
descrive la chiave pubblica abbinata alla chiave segreta utilizzata per firmare il pacchetto DSU. Se è specificato, il servizio DSU può verificare se il dispositivo ha la chiave utilizzata per verificare il pacchetto DSU. In questo modo si evita di installare un pacchetto DSU non riconosciuto, ad esempio un DSU firmato da OEM-A su un dispositivo prodotto da OEM-B.L'attributo facoltativo
tos
fa riferimento 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 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.Figura 6. Finestra di dialogo Termini di servizio
Come riferimento, di seguito è riportato un descrittore JSON DSU per la 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à
Per specificare la compatibilità tra un pacchetto DSU e il dispositivo locale vengono utilizzati diversi attributi:
cpu_api
è una stringa che descrive l'architettura del dispositivo. Questo attributo è obbligatorio e viene confrontato con la proprietà di sistemaro.product.cpu.abi
. I valori devono corrispondere esattamente.os_version
è un numero intero facoltativo che specifica una release di Android. Ad esempio, per Android 10,os_version
è10
e per Android 11,os_version
è11
. Quando questo attributo è specificato, deve essere uguale o superiore alla proprietà di sistemaro.system.build.version.release
. Questo controllo viene utilizzato per impedire l'avvio di un'immagine GSI di Android 10 su un dispositivo del fornitore con Android 11, 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 nel pacchetto DSU. Se è specificato, il caricatore DSU controlla se il numero estratto dalla proprietà di sistemaro.vndk.version
è incluso.
Revocare le 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, la ramdisk deve essere aggiornata il prima possibile per rimuovere la chiave compromessa. Oltre ad aggiornare la partizione di avvio, puoi bloccare le chiavi compromesse utilizzando un elenco di revoca delle chiavi DSU (lista nera delle chiavi) da un URL HTTPS.
L'elenco di revoca delle chiavi DSU contiene un elenco di chiavi pubbliche AVB revocate. Durante l'installazione del DSU, le chiavi pubbliche all'interno delle immagini DSU vengono convalidate con l'elenco di revoca. Se le immagini contengono una chiave pubblica revocata, la procedura di installazione del DSU si interrompe.
L'URL dell'elenco di revoca delle chiavi deve essere un URL HTTPS per garantire un elevato livello di sicurezza e viene 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 rilasciate da Google. Questa stringa di risorse può essere sovrapposta e personalizzata, in modo che gli OEM che adottano la funzionalità DSU possano fornire e gestire la propria lista nera di chiavi. In questo modo, l'OEM può bloccare determinate chiavi pubbliche senza aggiornare l'immagine del ramdisk del dispositivo.
Il formato dell'elenco 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
è il digest SHA-1 della chiave revocata, nel formato descritto nella sezione Generare la chiave pubblica AVB.status
indica lo stato di revoca della chiave. Al momento, l'unico valore supportato èREVOKED
.reason
è una stringa facoltativa che descrive il motivo della revoca.
Procedure DSU
Questa sezione descrive come eseguire diverse procedure di configurazione del DSU.
Genera una nuova coppia di chiavi
Utilizza il comando openssl
per generare una coppia di chiavi privata/pubblica RSA in formato .pem
(ad esempio, con una dimensione di 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 è conservata solo in un modulo di sicurezza hardware (HSM). In questo caso, dopo la generazione della chiave potrebbe essere disponibile un certificato della chiave pubblica x509. Consulta la sezione Aggiunta della chiave pubblica di accoppiamento alla 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
Salta questo passaggio se il certificato è già un file PEM.
Aggiungi la chiave pubblica di accoppiamento al ramdisk
oem_cert.avbpubkey
deve essere inserito in /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
Poi, includi la chiave pubblica nel ramdisk della prima fase seguendo i passaggi riportati di seguito.
Aggiungi un modulo predefinito per copiare il
avbpubkey
. Ad esempio, aggiungidevice/<company>/<board>/oem_cert.avbpubkey
edevice/<company>/<board>/avb/Android.mk
con contenuti come: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)
Fai in modo che il target droidcore dipenda dal
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
renderlo 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
Utilizza uno dei seguenti metodi per firmare un pacchetto DSU:
Metodo 1: riutilizza l'elemento creato dalla procedura di firma AVB originale per creare un pacchetto DSU. Un approccio alternativo è estrarre le immagini già firmate dal pacchetto di rilascio e utilizzarle per creare direttamente il file ZIP.
Metodo 2: utilizza 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 distintamente:$ 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
, consulta
Utilizzo di avbtool.
Verificare il pacchetto DSU localmente
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 è il 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
Crea un pacchetto DSU
L'esempio seguente crea un pacchetto DSU contenente un system.img
e un
product.img
:
dsu.zip {
- system.img
- product.img
}
Dopo aver firmato entrambe le immagini, utilizza 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 solo clic
Per impostazione predefinita, il caricatore DSU rimanda ai metadati delle immagini GSI, ovvero
https://...google.com/.../gsi-src.json
.
Gli OEM possono sovrascrivere l'elenco definendo la proprietà persist.sys.fflag.override.settings_dynamic_system.list
che rimanda al proprio descrittore JSON. Ad esempio, un OEM può fornire metadati JSON che includono GSI e immagini proprietarie dell'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 mettere in catena i metadati DSU pubblicati come mostrato nella Figura 7.
Figura 7. Collegamento in catena dei metadati DSU pubblicati