Les mises à jour système dynamiques (DSU) vous permettent de créer une image système Android que les utilisateurs peuvent télécharger sur Internet et essayer sans risque de corrompre l'image système actuelle. Ce document explique comment prendre en charge le mode de paiement par défaut.
Exigences du noyau
Consultez la page Implémenter des partitions dynamiques pour connaître les exigences concernant le noyau.
De plus, le DSU s'appuie sur la fonctionnalité de noyau device-mapper-verity (dm-verity) pour vérifier l'image système Android. Vous devez donc activer les configurations de noyau suivantes:
CONFIG_DM_VERITY=y
CONFIG_DM_VERITY_FEC=y
Exigences concernant les partitions
À partir d'Android 11, DSU nécessite que la partition /data
utilise le système de fichiers F2FS ou ext4. F2FS offre de meilleures performances et est recommandé, mais la différence ne devrait pas être importante.
Voici quelques exemples de la durée d'une mise à jour système dynamique avec un appareil Pixel :
- À l'aide de F2FS :
- 109 s, 8 Go utilisateur, 867 Mo système, type de système de fichiers : F2FS : encryption=aes-256-xts:aes-256-cts
- 104 s, utilisateur 8G, système 867M, type de système de fichiers: F2FS: encryption=ice
- Avec ext4 :
- 135s, utilisateur 8G, système 867M, type de système de fichiers: ext4 : chiffrement=aes-256-xts:aes-256-cts
Si l'opération prend beaucoup plus de temps sur votre plate-forme, vous pouvez vérifier si l'indicateur d'installation contient un indicateur qui effectue l'écriture "sync", ou spécifier explicitement un indicateur "async" pour obtenir de meilleures performances.
La partition metadata
(16 Mo ou plus) est requise pour stocker les données liées aux images installées. Il doit être installé lors du premier montage.
La partition userdata
doit utiliser le système de fichiers F2FS ou ext4. Lorsque vous utilisez F2FS, incluez tous les correctifs liés à F2FS disponibles dans le kernel commun Android.
DSU a été développé et testé avec kernel/common 4.9. Nous vous recommandons d'utiliser le kernel 4.9 ou une version ultérieure pour cette fonctionnalité.
Comportement des fournisseurs HAL
HAL Weaver
Le HAL de Weaver fournit un nombre fixe d'emplacements pour stocker les clés utilisateur. Le DSU consomme deux emplacements de clé supplémentaires. Si un OEM dispose d'un HAL Weaver, il doit disposer d'assez d'emplacements pour une image système générique (GSI) et une image hôte.
Opérateur HAL
Le HAL Gatekeeper doit accepter les valeurs USER_ID
élevées, car le GSI décale les UID vers le HAL de +1 000 000.
Vérifier le démarrage
Si vous souhaitez prendre en charge le démarrage des images GSI de développement en état LOCKED sans désactiver le démarrage validé, incluez les clés GSI de développement en ajoutant la ligne suivante au fichier device/<device_name>/device.mk
:
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
Protection contre le rollback
Lorsque vous utilisez le DSU, l'image système Android téléchargée doit être plus récente que l'image système actuelle sur l'appareil. Pour ce faire, comparez les niveaux du correctif de sécurité dans le descripteur de propriété AVB du démarrage validé Android (AVB) des deux images système: Prop: com.android.build.system.security_patch ->
'2019-04-05'
.
Pour les appareils qui n'utilisent pas AVB, placez le niveau du correctif de sécurité de l'image système actuelle dans la ligne de commande du noyau ou dans le fichier de configuration de démarrage avec le bootloader : androidboot.system.security_patch=2019-04-05
.
Configuration matérielle requise
Lorsque vous lancez une instance DSU, deux fichiers temporaires sont alloués :
- Une partition logique pour stocker
GSI.img
(1 à 1,5 Go) - Une partition
/data
vide de 8 Go servant de bac à sable pour exécuter le GSI
Nous vous recommandons de réserver au moins 10 Go d'espace libre avant de lancer une instance DSU. DSU prend également en charge l'affectation à partir d'une carte SD. Lorsqu'une carte SD est présente, elle a la priorité la plus élevée pour l'allocation. La compatibilité avec les cartes SD est essentielle pour les appareils moins puissants qui ne disposent peut-être pas d'espace de stockage interne suffisant. Si une carte SD est présente, assurez-vous qu'elle n'est pas adoptée. Le DSU n'est pas compatible avec les cartes SD adoptées.
Interfaces disponibles
Vous pouvez lancer le DSU à l'aide de adb
, d'une application OEM ou du chargeur DSU en un clic (sous Android 11 ou version ultérieure).
Lancer DSU à l'aide d'adb
Pour lancer DSU à l'aide d'adb, saisissez ces commandes:
$ 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
Lancer une DSU à l'aide d'une application
Le principal point d'entrée de la DSU est 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);
}
Vous devez grouper/préinstaller cette application sur l'appareil. Étant donné que DynamicSystemClient
est une API système, vous ne pouvez pas compiler l'application avec l'API SDK standard et vous ne pouvez pas la publier sur Google Play. Objectif de cette application:
- Récupérez une liste d'images et l'URL correspondante à l'aide d'un schéma défini par le fournisseur.
- Faites correspondre les images de la liste avec l'appareil et affichez des images compatibles que l'utilisateur peut sélectionner.
Appelez
DynamicSystemClient.start
comme ceci:DynamicSystemClient aot = new DynamicSystemClient(...) aot.start( ...URL of the selected image..., ...uncompressed size of the selected image...);
L'URL pointe vers un fichier image système compressé et non creux, que vous pouvez créer à l'aide des commandes suivantes:
$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz
Le nom de fichier doit respecter le format suivant :
<android version>.<lunch name>.<user defined title>.raw.gz
Exemples :
o.aosp_taimen-userdebug.2018dev.raw.gz
p.aosp_taimen-userdebug.2018dev.raw.gz
Chargeur de DSU en un clic
Android 11 introduit le chargeur DSU en un clic, qui est une interface dans les paramètres pour les développeurs.
Figure 1 : Lancer le chargeur de DSU
Lorsque le développeur clique sur le bouton Chargeur DSU, celui-ci extrait sur le Web un descripteur JSON DSU préconfiguré et affiche toutes les images applicables dans le menu flottant. Sélectionnez une image pour lancer l'installation du DSU. La progression s'affiche dans la barre de notification.
Figure 2. Progression de l'installation de l'image DSU
Par défaut, le chargeur DSU charge un descripteur JSON contenant les images GSI. Les sections suivantes expliquent comment créer des packages DSU signés par l'OEM et les charger à partir du chargeur de DSU.
Commutateur de fonctionnalité
La fonctionnalité DSU est associée au flag de fonctionnalité settings_dynamic_android
. Avant d'utiliser DSU, assurez-vous que le flag de fonctionnalité correspondant est activé.
Figure 3. Activer le flag de fonctionnalité
L'UI du flag de fonctionnalité peut être indisponible sur un appareil exécutant un build utilisateur. Dans ce cas, utilisez plutôt la commande adb
:
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
Images système de l'hôte du fournisseur sur GCE (facultatif)
Le bucket Google Compute Engine (GCE) est l'un des emplacements de stockage possibles des images système. L'administrateur de la version utilise la console de stockage GCP pour ajouter/supprimer/modifier l'image système publiée.
Les images doivent être accessibles publiquement, comme indiqué ci-dessous:
Figure 4. Accès public dans GCE
La procédure à suivre pour rendre un élément public est disponible dans la documentation Google Cloud.
DSU multipartition dans un fichier ZIP
À partir d'Android 11, le DSU peut comporter plusieurs partitions. Par exemple, il peut contenir un product.img
en plus du system.img
. Lorsque l'appareil démarre, la première étape init
détecte les partitions DSU installées et remplace temporairement la partition sur l'appareil, lorsque la DSU installée est activée. Le package DSU peut contenir une partition qui n'a pas de partition correspondante sur l'appareil.
Figure 5. Processus DSU avec plusieurs partitions
DSU signée par l'OEM
Pour vous assurer que toutes les images exécutées sur l'appareil sont autorisées par le fabricant de l'appareil, toutes les images d'un package DSU doivent être signées. Par exemple, supposons qu'il existe un package DSU contenant deux images de partition comme ci-dessous :
dsu.zip {
- system.img
- product.img
}
Les éléments system.img
et product.img
doivent tous deux être signés par la clé OEM avant d'être intégrés au fichier ZIP. La pratique courante consiste à utiliser un algorithme asymétrique, par exemple RSA, dans lequel la clé secrète est utilisée pour signer le package et la clé publique pour la vérifier. Le premier étage ramdisk doit inclure la clé publique d'association, par exemple /avb/*.avbpubkey
. Si l'appareil a déjà adopté AVB, la procédure de signature existante suffit. Les sections suivantes illustrent le processus de signature et mettent en évidence l'emplacement de la clé publique AVB utilisée pour valider les images du package DSU.
Déscripteur JSON de la DSU
Le descripteur JSON DSU décrit les packages DSU. Il accepte deux primitives.
Tout d'abord, la primitive include
inclut des descripteurs JSON supplémentaires ou redirige le chargeur DSU vers un nouvel emplacement. Exemple :
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
Deuxièmement, la primitive image
sert à décrire les packages DSU publiés. La primitive d'image contient plusieurs attributs :
Les attributs
name
etdetails
sont des chaînes affichées dans la boîte de dialogue pour que l'utilisateur puisse les sélectionner.Les attributs
cpu_api
,vndk
etos_version
sont utilisés pour les vérifications de compatibilité, qui sont décrites dans la section suivante.L'attribut facultatif
pubkey
décrit la clé publique associée à la clé secrète utilisée pour signer le package DSU. Une fois spécifié, le service DSU peut vérifier si l'appareil dispose de la clé permettant de valider le package DSU. Cela évite d'installer un package DSU non reconnu, par exemple d'installer un DSU signé par OEM-A sur un appareil fabriqué par OEM-B.L'attribut
tos
facultatif pointe vers un fichier texte qui décrit les conditions d'utilisation du package DSU correspondant. Lorsqu'un développeur sélectionne un package DSU avec l'attribut conditions d'utilisation spécifié, la boîte de dialogue illustrée à la figure 6 s'ouvre et lui demande d'accepter les conditions d'utilisation avant d'installer le package DSU.Figure 6. Boîte de dialogue "Conditions d'utilisation"
Pour référence, voici un descripteur JSON DSU pour le 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"
}
]
}
Gestion de la compatibilité
Plusieurs attributs permettent de spécifier la compatibilité entre un package DSU et l'appareil local:
cpu_api
est une chaîne qui décrit l'architecture de l'appareil. Cet attribut est obligatoire et est comparé à la propriété systèmero.product.cpu.abi
. Leurs valeurs doivent correspondre exactement.os_version
est un entier facultatif qui spécifie une version Android. Par exemple, pour Android 10,os_version
est10
et pour Android 11,os_version
est11
. Lorsque cet attribut est spécifié, il doit être supérieur ou égal à la propriété systèmero.system.build.version.release
. Cette vérification permet d'empêcher le démarrage d'une image GSI Android 10 sur un appareil du fournisseur Android 11, qui n'est actuellement pas compatible. Le démarrage d'une image GSI Android 11 sur un appareil Android 10 est autorisé.vndk
est un tableau facultatif qui spécifie tous les VNDK inclus dans le package DSU. Lorsqu'il est spécifié, le chargeur DSU vérifie si le nombre extrait de la propriété systèmero.vndk.version
est inclus.
Révoquer les clés DSU pour des raisons de sécurité
Dans le cas extrêmement rare où la paire de clés RSA utilisée pour signer les images DSU est compromise, le ramdisk doit être mis à jour dès que possible pour supprimer la clé compromise. En plus de mettre à jour la partition de démarrage, vous pouvez bloquer les clés compromises à l'aide d'une liste de révocation de clés DSU (liste noire des clés) à partir d'une URL HTTPS.
La liste de révocation de clés DSU contient une liste de clés publiques AVB révoquées. Lors de l'installation du DSU, les clés publiques des images du DSU sont validées avec la liste de révocation. Si les images contiennent une clé publique révoquée, le processus d'installation du DSU s'arrête.
Pour garantir le niveau de sécurité, l'URL de la liste de révocation de clés doit être une URL HTTPS spécifiée dans une chaîne de ressource:
frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url
La valeur de la chaîne est https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json
, qui est une liste de révocation pour les clés GSI publiées par Google. Cette chaîne de ressources peut être superposée et personnalisée afin que les OEM qui adoptent la fonctionnalité DSU puissent fournir et gérer leur propre liste noire de clés. Cela permet à l'OEM de bloquer certaines clés publiques sans mettre à jour l'image ramdisk de l'appareil.
Le format de la liste de révocation est le suivant :
{
"entries":[
{
"public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
"status":"REVOKED",
"reason":"Key revocation test key"
},
{
"public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
"status":"REVOKED",
"reason":"Key revocation test key"
}
]
}
public_key
est le condensé SHA-1 de la clé révoquée, au format décrit dans la section Générer la clé publique AVB.status
indique l'état de révocation de la clé. Actuellement, la seule valeur acceptée estREVOKED
.reason
est une chaîne facultative décrivant le motif de la révocation.
Procédures DSU
Cette section explique comment effectuer plusieurs procédures de configuration du DSU.
Générer une nouvelle paire de clés
Utilisez la commande openssl
pour générer une paire de clés publique/privée RSA au format .pem
(par exemple, avec une taille de 2 048 bits) :
$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem
La clé privée peut ne pas être accessible et n'est conservée que dans un module de sécurité matérielle (HSM). Dans ce cas, un certificat de clé publique x509 peut être disponible après la génération de la clé. Consultez la section Ajouter la clé publique d'association au ramdisk pour savoir comment générer la clé publique AVB à partir d'un certificat X.509.
Pour convertir un certificat x509 au format PEM:
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
Ignorez cette étape si le certificat est déjà un fichier PEM.
Ajouter la clé publique d'association à la ramdisk
Le oem_cert.avbpubkey
doit être placé sous /avb/*.avbpubkey
pour valider le package DSU signé. Commencez par convertir la clé publique au format PEM au format de clé publique AVB :
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
Incluez ensuite la clé publique dans le ramdisk de la première étape en procédant comme suit :
Ajoutez un module prédéfini pour copier le
avbpubkey
. Par exemple, ajoutezdevice/<company>/<board>/oem_cert.avbpubkey
etdevice/<company>/<board>/avb/Android.mk
avec un contenu comme celui-ci :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)
Faites en sorte que la cible droidcore dépende du
oem_cert.avbpubkey
ajouté:droidcore: oem_cert.avbpubkey
Générer l'attribut de clé publique AVB dans le descripteur JSON
oem_cert.avbpubkey
est au format binaire de la clé publique AVB. Utilisez SHA-1 pour le rendre lisible avant de le placer dans le descripteur JSON :
$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20
Il s'agit du contenu de l'attribut pubkey
du descripteur JSON.
"images":[
{
...
"pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
...
},
Signer un package DSU
Utilisez l'une des méthodes suivantes pour signer un package de DSU:
Méthode 1 : Réutiliser l'artefact créé par le processus de signature AVB d'origine pour créer un package DSU Une autre approche consiste à extraire les images déjà signées du package de version et à les utiliser pour créer directement le fichier ZIP.
Méthode 2 : Utilisez les commandes suivantes pour signer les partitions DSU si la clé privée est disponible. Chaque
img
d'un package DSU (fichier ZIP) est signé séparément :$ 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
Pour en savoir plus sur l'ajout de add_hashtree_footer
à l'aide de avbtool
, consultez la section Utiliser avbtool.
Vérifier le package DSU localement
Nous vous recommandons de vérifier toutes les images locales par rapport à la clé publique d'association à l'aide des commandes suivantes:
for partition in system product; do
avbtool verify_image --image ${OUT}/${partition}.img --key oem_cert_pub.pem
done
Le résultat attendu se présente comme suit:
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
Créer un package DSU
L'exemple suivant crée un package DSU contenant un system.img
et un product.img
:
dsu.zip {
- system.img
- product.img
}
Une fois les deux images signées, créez le fichier ZIP à l'aide de la commande suivante:
$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -
Personnaliser le DSU en un clic
Par défaut, le chargeur DSU pointe vers des métadonnées d'images GSI, qui sont https://...google.com/.../gsi-src.json
.
Les OEM peuvent écraser la liste en définissant la propriété persist.sys.fflag.override.settings_dynamic_system.list
qui pointe vers leur propre descripteur JSON. Par exemple, un OEM peut fournir des métadonnées JSON incluant des GSI, ainsi que des images propriétaires OEM, comme ceci:
{
"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 peut associer les métadonnées DSU publiées, comme illustré dans la figure 7.
Figure 7. Relier des métadonnées de DSU publiées