Las actualizaciones dinámicas del sistema (DSU) le permiten crear una imagen del sistema Android que los usuarios pueden descargar de Internet y probar sin el riesgo de dañar la imagen del sistema actual. Este documento describe cómo admitir DSU.
Requisitos del núcleo
Consulte Implementación de particiones dinámicas para conocer los requisitos del kernel.
Además, DSU se basa en la función del kernel device-mapper-verity (dm-verity) para verificar la imagen del sistema Android. Por lo tanto, debe habilitar las siguientes configuraciones del kernel:
-
CONFIG_DM_VERITY=y
-
CONFIG_DM_VERITY_FEC=y
Requisitos de partición
A partir de Android 11, DSU requiere la partición /data
para usar el sistema de archivos F2FS o ext4. F2FS ofrece un mejor rendimiento y se recomienda, pero la diferencia debería ser insignificante.
Estos son algunos ejemplos de cuánto tarda una actualización dinámica del sistema con un dispositivo Pixel:
- Usando F2FS:
- 109s, usuario 8G, sistema 867M, tipo de sistema de archivos: F2FS: cifrado=aes-256-xts:aes-256-cts
- 104s, usuario 8G, sistema 867M, tipo de sistema de archivos: F2FS: cifrado = hielo
- Usando ext4:
- 135s, usuario 8G, sistema 867M, tipo de sistema de archivos: ext4: cifrado=aes-256-xts:aes-256-cts
Si lleva mucho más tiempo en su plataforma, es posible que desee verificar si el indicador de montaje contiene algún indicador que haga que la escritura sea "sincronizada", o puede especificar un indicador "asincrónico" explícitamente para obtener un mejor rendimiento.
La partición de metadata
(16 MB o más) es necesaria para almacenar datos relacionados con las imágenes instaladas. Debe montarse durante el montaje de la primera etapa.
La partición de datos de userdata
debe utilizar el sistema de archivos F2FS o ext4. Cuando use F2FS, incluya todos los parches relacionados con F2FS disponibles en el kernel común de Android .
DSU fue desarrollado y probado con kernel/common 4.9. Se recomienda utilizar el kernel 4.9 y superior para esta función.
Comportamiento de HAL del proveedor
Tejedor HAL
El tejedor HAL proporciona un número fijo de ranuras para almacenar claves de usuario. La DSU consume dos ranuras para llaves adicionales. Si un OEM tiene una HAL weaver, debe tener suficientes ranuras para una imagen de sistema genérica (GSI) y una imagen de host.
HAL guardián
Gatekeeper HAL necesita admitir valores de USER_ID
grandes, porque GSI compensa los UID con HAL en +1000000.
Verificar arranque
Si desea admitir el arranque de imágenes GSI del desarrollador en estado BLOQUEADO sin deshabilitar el arranque verificado, incluya las claves GSI del desarrollador agregando la siguiente línea al archivo device/<device_name>/device.mk
:
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
protección contra reversión
Al usar DSU, la imagen del sistema Android descargada debe ser más reciente que la imagen del sistema actual en el dispositivo. Esto se hace comparando los niveles de parches de seguridad en el descriptor de propiedades AVB de Android Verified Boot (AVB) de ambas imágenes del sistema: Prop: com.android.build.system.security_patch -> '2019-04-05'
.
Para dispositivos que no usan AVB, coloque el nivel de parche de seguridad de la imagen actual del sistema en la línea de comandos del kernel o bootconfig con el gestor de arranque: androidboot.system.security_patch=2019-04-05
.
Requisitos de hardware
Cuando inicia una instancia de DSU, se asignan dos archivos temporales:
- Una partición lógica para almacenar
GSI.img
(1~1.5 G) - Una partición
/data
vacía de 8 GB como sandbox para ejecutar el GSI
Recomendamos reservar al menos 10 GB de espacio libre antes de iniciar una instancia de DSU. DSU también admite la asignación desde una tarjeta SD. Cuando hay una tarjeta SD presente, tiene la prioridad más alta para la asignación. La compatibilidad con la tarjeta SD es fundamental para los dispositivos de menor potencia que pueden no tener suficiente almacenamiento interno. Cuando haya una tarjeta SD presente, asegúrese de que no se adopte. DSU no admite tarjetas SD adoptadas .
Interfaces disponibles
Puede iniciar DSU usando adb
, una aplicación OEM o el cargador de DSU con un solo clic (en Android 11 o superior).
Lanzamiento de DSU usando adb
Para iniciar DSU usando adb, ingrese estos comandos:
$ 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
Iniciar DSU usando una aplicación
El principal punto de entrada a DSU es la 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);
}
Debe agrupar/preinstalar esta aplicación en el dispositivo. Debido a que DynamicSystemClient
es una API del sistema, no puede compilar la aplicación con la API SDK normal y no puede publicarla en Google Play. El propósito de esta aplicación es:
- Obtenga una lista de imágenes y la URL correspondiente con un esquema definido por el proveedor.
- Haga coincidir las imágenes de la lista con el dispositivo y muestre imágenes compatibles para que el usuario las seleccione.
Invoque
DynamicSystemClient.start
así:DynamicSystemClient aot = new DynamicSystemClient(...) aot.start( ...URL of the selected image..., ...uncompressed size of the selected image...);
La URL apunta a un archivo de imagen del sistema comprimido con gzip, no disperso, que puede crear con los siguientes comandos:
$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz
El nombre del archivo debe seguir este formato:
<android version>.<lunch name>.<user defined title>.raw.gz
Ejemplos:
-
o.aosp_taimen-userdebug.2018dev.raw.gz
-
p.aosp_taimen-userdebug.2018dev.raw.gz
Cargador de DSU con un solo clic
Android 11 presenta el cargador de DSU con un solo clic, que es una interfaz en la configuración del desarrollador.
Figura 1. Inicio del cargador de DSU
Cuando el desarrollador hace clic en el botón DSU Loader , obtiene un descriptor DSU JSON preconfigurado de la web y muestra todas las imágenes aplicables en el menú flotante. Seleccione una imagen para iniciar la instalación de DSU y el progreso se muestra en la barra de notificaciones.
Figura 2. Progreso de la instalación de la imagen de DSU
De forma predeterminada, el cargador de DSU carga un descriptor JSON que contiene las imágenes GSI. Las siguientes secciones muestran cómo crear paquetes de DSU firmados por OEM y cargarlos desde el cargador de DSU.
Indicador de característica
La función DSU está bajo el indicador de función settings_dynamic_android
. Antes de usar DSU, asegúrese de que el indicador de función correspondiente esté habilitado.
Figura 3. Activación del indicador de función
Es posible que la interfaz de usuario del indicador de función no esté disponible en un dispositivo que ejecuta una compilación de usuario. En este caso, utilice el comando adb
en su lugar:
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
Imágenes del sistema host del proveedor en GCE (opcional)
Una de las posibles ubicaciones de almacenamiento para las imágenes del sistema es el depósito de Google Compute Engine (GCE). El administrador de la versión usa la consola de almacenamiento de GCP para agregar, eliminar o cambiar la imagen del sistema publicada.
Las imágenes deben ser de acceso público, como se muestra aquí:
Figura 4. Acceso público en GCE
El procedimiento para hacer público un elemento está disponible en la documentación de Google Cloud .
DSU de múltiples particiones en archivo ZIP
A partir de Android 11, DSU puede tener más de una partición. Por ejemplo, puede contener product.img
además de system.img
. Cuando el dispositivo arranca, la primera etapa init
detecta las particiones de DSU instaladas y reemplaza la partición en el dispositivo temporalmente, cuando la DSU instalada está habilitada. El paquete DSU puede contener una partición que no tiene una partición correspondiente en el dispositivo.
Figura 5. Proceso de DSU con varias particiones
DSU firmado por OEM
Para asegurarse de que todas las imágenes que se ejecutan en el dispositivo estén autorizadas por el fabricante del dispositivo, todas las imágenes dentro de un paquete de DSU deben estar firmadas. Por ejemplo, suponga que hay un paquete de DSU que contiene dos imágenes de partición como la siguiente:
dsu.zip {
- system.img
- product.img
}
Tanto system.img
como product.img
deben estar firmados por la clave OEM antes de colocarse en el archivo ZIP. La práctica común es usar un algoritmo asimétrico, por ejemplo, RSA, donde la clave secreta se usa para firmar el paquete y la clave pública se usa para verificarlo. El ramdisk de la primera etapa debe incluir la clave pública de emparejamiento, por ejemplo, /avb/*.avbpubkey
. Si el dispositivo ya adoptó AVB, el procedimiento de firma existente será suficiente. Las siguientes secciones ilustran el proceso de firma y resaltan la ubicación de la clave pública AVB que se usa para verificar las imágenes en el paquete DSU.
Descriptor JSON de ESD
El descriptor JSON de DSU describe los paquetes de DSU. Admite dos primitivas. En primer lugar, la primitiva de include
incluye descriptores JSON adicionales o redirige el cargador de DSU a una nueva ubicación. Por ejemplo:
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
En segundo lugar, la image
primitiva se utiliza para describir los paquetes DSU publicados. Dentro de la imagen primitiva hay varios atributos:
Los atributos de
name
ydetails
son cadenas que se muestran en el cuadro de diálogo para que el usuario las seleccione.Los
cpu_api
,vndk
yos_version
se utilizan para las comprobaciones de compatibilidad, que se describen en la siguiente sección.El atributo
pubkey
opcional describe la clave pública que se empareja con la clave secreta que se usa para firmar el paquete DSU. Cuando se especifica, el servicio DSU puede verificar si el dispositivo tiene la clave utilizada para verificar el paquete DSU. Esto evita instalar un paquete DSU no reconocido, por ejemplo, instalar un DSU firmado por OEM-A en un dispositivo fabricado por OEM-B.El atributo
tos
opcional apunta a un archivo de texto que describe los términos de servicio para el paquete de DSU correspondiente. Cuando un desarrollador selecciona un paquete de DSU con el atributo de términos de servicio especificado, se abre el cuadro de diálogo que se muestra en la Figura 6, que le pide al desarrollador que acepte los términos de servicio antes de instalar el paquete de DSU.Figura 6. Cuadro de diálogo Condiciones de servicio
Como referencia, aquí hay un descriptor DSU JSON para 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"
}
]
}
Gestión de compatibilidad
Se utilizan varios atributos para especificar la compatibilidad entre un paquete DSU y el dispositivo local:
cpu_api
es una cadena que describe la arquitectura del dispositivo. Este atributo es obligatorio y se compara con la propiedad del sistemaro.product.cpu.abi
. Sus valores deben coincidir exactamente.os_version
es un entero opcional que especifica una versión de Android. Por ejemplo, para Android 10,os_version
es10
y para Android 11,os_version
es11
. Cuando se especifica este atributo, debe ser igual o mayor que la propiedad del sistemaro.system.build.version.release
. Esta verificación se usa para evitar el arranque de una imagen GSI de Android 10 en un dispositivo de proveedor de Android 11, que actualmente no es compatible. Se permite iniciar una imagen GSI de Android 11 en un dispositivo con Android 10.vndk
es una matriz opcional que especifica todos los VNDK que se incluyen en el paquete DSU. Cuando se especifica, el cargador de DSU comprueba si se incluye el número extraído de la propiedad del sistemaro.vndk.version
.
Revocación de claves DSU por seguridad
En el caso extremadamente raro de que el par de claves RSA utilizado para firmar las imágenes DSU se vea comprometida, el ramdisk debe actualizarse lo antes posible para eliminar la clave comprometida. Además de actualizar la partición de arranque, puede bloquear las claves comprometidas mediante una lista de revocación de claves DSU (lista negra de claves) desde una URL HTTPS.
La lista de revocación de claves DSU contiene una lista de claves públicas AVB revocadas. Durante la instalación de DSU, las claves públicas dentro de las imágenes de DSU se validan con la lista de revocación. Si se encuentra que las imágenes contienen una clave pública revocada, el proceso de instalación de DSU se detiene.
La URL de la lista de revocación de claves debe ser una URL HTTPS para garantizar la solidez de la seguridad y se especifica en una cadena de recursos:
frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url
El valor de la cadena es https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json
, que es una lista de revocación de claves GSI publicadas por Google. Esta cadena de recursos se puede superponer y personalizar, de modo que los OEM que adopten la función DSU puedan proporcionar y mantener su propia lista negra de claves. Esto proporciona una forma para que el OEM bloquee ciertas claves públicas sin actualizar la imagen ramdisk del dispositivo.
El formato de la lista de revocación es:
{
"entries":[
{
"public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
"status":"REVOKED",
"reason":"Key revocation test key"
},
{
"public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
"status":"REVOKED",
"reason":"Key revocation test key"
}
]
}
-
public_key
es el resumen SHA-1 de la clave revocada, en el formato descrito en la sección de generación de la clave pública AVB . -
status
indica el estado de revocación de la clave. Actualmente, el único valor admitido esREVOKED
. -
reason
es una cadena opcional que describe el motivo de la revocación.
Procedimientos ESD
Esta sección describe cómo realizar varios procedimientos de configuración de DSU.
Generación de un nuevo par de claves
Utilice el comando openssl
para generar un par de claves pública/privada RSA en formato .pem
(por ejemplo, con un tamaño de 2048 bits):
$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem
Es posible que no se pueda acceder a la clave privada y solo se guarda en un módulo de seguridad de hardware (HSM) . En este caso, podría haber un certificado de clave pública x509 disponible después de la generación de la clave. Consulte la sección Adición de la clave pública de emparejamiento al ramdisk para obtener instrucciones sobre cómo generar la clave pública AVB a partir de un certificado x509.
Para convertir un certificado x509 a formato PEM:
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
Omita este paso si el certificado ya es un archivo PEM.
Agregar la clave pública de emparejamiento al ramdisk
El oem_cert.avbpubkey
debe colocarse en /avb/*.avbpubkey
para verificar el paquete DSU firmado. Primero, convierta la clave pública en formato PEM a formato de clave pública AVB:
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
Luego incluya la clave pública en el ramdisk de la primera etapa con los siguientes pasos.
Agregue un módulo precompilado para copiar
avbpubkey
. Por ejemplo, agreguedevice/<company>/<board>/oem_cert.avbpubkey
ydevice/<company>/<board>/avb/Android.mk
con contenido como este: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)
Haga que el objetivo de droidcore dependa del
oem_cert.avbpubkey
agregado:droidcore: oem_cert.avbpubkey
Generación del atributo pubkey AVB en el descriptor JSON
oem_cert.avbpubkey
está en formato binario de clave pública AVB. Use SHA-1 para que sea legible antes de colocarlo en el descriptor JSON:
$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20
Este será el contenido del atributo pubkey
del descriptor JSON.
"images":[
{
...
"pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
...
},
Firmar un paquete de DSU
Utilice uno de estos métodos para firmar un paquete DSU:
Método 1: reutilizar el artefacto creado por el proceso de firma AVB original para crear un paquete DSU. Un enfoque alternativo es extraer las imágenes ya firmadas del paquete de lanzamiento y usar las imágenes extraídas para crear el archivo ZIP directamente.
Método 2: use los siguientes comandos para firmar particiones DSU si la clave privada está disponible. Cada
img
dentro de un paquete DSU (el archivo ZIP) se firma por separado:$ 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
Para obtener más información sobre cómo agregar add_hashtree_footer
mediante avbtool
, consulte Uso de avbtool .
Verificación del paquete DSU localmente
Se recomienda verificar todas las imágenes locales con la clave pública de emparejamiento con estos comandos:
for partition in system product; do
avbtool verify_image --image ${OUT}/${partition}.img --key oem_cert_pub.pem
done
El resultado esperado se ve así:
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
Hacer un paquete de DSU
El siguiente ejemplo crea un paquete DSU que contiene un system.img
y un product.img
:
dsu.zip {
- system.img
- product.img
}
Después de que ambas imágenes estén firmadas, use el siguiente comando para crear el archivo ZIP:
$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -
Personalización de la DSU de un clic
De forma predeterminada, el cargador de DSU apunta a un metadato de imágenes GSI que es https://...google.com/.../gsi-src.json
.
Los OEM pueden sobrescribir la lista definiendo la propiedad persist.sys.fflag.override.settings_dynamic_system.list
que apunta a su propio descriptor JSON. Por ejemplo, un OEM puede proporcionar metadatos JSON que incluyen GSI, así como imágenes patentadas de OEM como esta:
{
"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"
},
}
Es posible que un OEM encadene metadatos de DSU publicados como se muestra en la Figura 7.
Figura 7. Encadenamiento de metadatos de DSU publicados
,Las actualizaciones dinámicas del sistema (DSU) le permiten crear una imagen del sistema Android que los usuarios pueden descargar de Internet y probar sin el riesgo de dañar la imagen del sistema actual. Este documento describe cómo admitir DSU.
Requisitos del núcleo
Consulte Implementación de particiones dinámicas para conocer los requisitos del kernel.
Además, DSU se basa en la función del kernel device-mapper-verity (dm-verity) para verificar la imagen del sistema Android. Por lo tanto, debe habilitar las siguientes configuraciones del kernel:
-
CONFIG_DM_VERITY=y
-
CONFIG_DM_VERITY_FEC=y
Requisitos de partición
A partir de Android 11, DSU requiere la partición /data
para usar el sistema de archivos F2FS o ext4. F2FS ofrece un mejor rendimiento y se recomienda, pero la diferencia debería ser insignificante.
Estos son algunos ejemplos de cuánto tarda una actualización dinámica del sistema con un dispositivo Pixel:
- Usando F2FS:
- 109s, usuario 8G, sistema 867M, tipo de sistema de archivos: F2FS: cifrado=aes-256-xts:aes-256-cts
- 104s, usuario 8G, sistema 867M, tipo de sistema de archivos: F2FS: cifrado = hielo
- Usando ext4:
- 135s, usuario 8G, sistema 867M, tipo de sistema de archivos: ext4: cifrado=aes-256-xts:aes-256-cts
Si lleva mucho más tiempo en su plataforma, es posible que desee verificar si el indicador de montaje contiene algún indicador que haga que la escritura sea "sincronizada", o puede especificar un indicador "asincrónico" explícitamente para obtener un mejor rendimiento.
La partición de metadata
(16 MB o más) es necesaria para almacenar datos relacionados con las imágenes instaladas. Debe montarse durante el montaje de la primera etapa.
La partición de datos de userdata
debe utilizar el sistema de archivos F2FS o ext4. Cuando use F2FS, incluya todos los parches relacionados con F2FS disponibles en el kernel común de Android .
DSU fue desarrollado y probado con kernel/common 4.9. Se recomienda utilizar el kernel 4.9 y superior para esta función.
Comportamiento de HAL del proveedor
Tejedor HAL
El tejedor HAL proporciona un número fijo de ranuras para almacenar claves de usuario. La DSU consume dos ranuras para llaves adicionales. Si un OEM tiene una HAL weaver, debe tener suficientes ranuras para una imagen de sistema genérica (GSI) y una imagen de host.
HAL guardián
Gatekeeper HAL necesita admitir valores de USER_ID
grandes, porque GSI compensa los UID con HAL en +1000000.
Verificar arranque
Si desea admitir el arranque de imágenes GSI del desarrollador en estado BLOQUEADO sin deshabilitar el arranque verificado, incluya las claves GSI del desarrollador agregando la siguiente línea al archivo device/<device_name>/device.mk
:
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
protección contra reversión
Al usar DSU, la imagen del sistema Android descargada debe ser más reciente que la imagen del sistema actual en el dispositivo. Esto se hace comparando los niveles de parches de seguridad en el descriptor de propiedades AVB de Android Verified Boot (AVB) de ambas imágenes del sistema: Prop: com.android.build.system.security_patch -> '2019-04-05'
.
Para dispositivos que no usan AVB, coloque el nivel de parche de seguridad de la imagen actual del sistema en la línea de comandos del kernel o bootconfig con el gestor de arranque: androidboot.system.security_patch=2019-04-05
.
Requisitos de hardware
Cuando inicia una instancia de DSU, se asignan dos archivos temporales:
- Una partición lógica para almacenar
GSI.img
(1~1.5 G) - Una partición
/data
vacía de 8 GB como sandbox para ejecutar el GSI
Recomendamos reservar al menos 10 GB de espacio libre antes de iniciar una instancia de DSU. DSU también admite la asignación desde una tarjeta SD. Cuando hay una tarjeta SD presente, tiene la prioridad más alta para la asignación. La compatibilidad con la tarjeta SD es fundamental para los dispositivos de menor potencia que pueden no tener suficiente almacenamiento interno. Cuando haya una tarjeta SD presente, asegúrese de que no se adopte. DSU no admite tarjetas SD adoptadas .
Interfaces disponibles
Puede iniciar DSU usando adb
, una aplicación OEM o el cargador de DSU con un solo clic (en Android 11 o superior).
Lanzamiento de DSU usando adb
Para iniciar DSU usando adb, ingrese estos comandos:
$ 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
Iniciar DSU usando una aplicación
El principal punto de entrada a DSU es la 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);
}
Debe agrupar/preinstalar esta aplicación en el dispositivo. Debido a que DynamicSystemClient
es una API del sistema, no puede compilar la aplicación con la API SDK normal y no puede publicarla en Google Play. El propósito de esta aplicación es:
- Obtenga una lista de imágenes y la URL correspondiente con un esquema definido por el proveedor.
- Haga coincidir las imágenes de la lista con el dispositivo y muestre imágenes compatibles para que el usuario las seleccione.
Invoque
DynamicSystemClient.start
así:DynamicSystemClient aot = new DynamicSystemClient(...) aot.start( ...URL of the selected image..., ...uncompressed size of the selected image...);
La URL apunta a un archivo de imagen del sistema comprimido con gzip, no disperso, que puede crear con los siguientes comandos:
$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz
El nombre del archivo debe seguir este formato:
<android version>.<lunch name>.<user defined title>.raw.gz
Ejemplos:
-
o.aosp_taimen-userdebug.2018dev.raw.gz
-
p.aosp_taimen-userdebug.2018dev.raw.gz
Cargador de DSU con un solo clic
Android 11 presenta el cargador de DSU con un solo clic, que es una interfaz en la configuración del desarrollador.
Figura 1. Inicio del cargador de DSU
Cuando el desarrollador hace clic en el botón DSU Loader , obtiene un descriptor DSU JSON preconfigurado de la web y muestra todas las imágenes aplicables en el menú flotante. Seleccione una imagen para iniciar la instalación de DSU y el progreso se muestra en la barra de notificaciones.
Figura 2. Progreso de la instalación de la imagen de DSU
De forma predeterminada, el cargador de DSU carga un descriptor JSON que contiene las imágenes GSI. Las siguientes secciones muestran cómo crear paquetes de DSU firmados por OEM y cargarlos desde el cargador de DSU.
Indicador de característica
La función DSU está bajo el indicador de función settings_dynamic_android
. Antes de usar DSU, asegúrese de que el indicador de función correspondiente esté habilitado.
Figura 3. Activación del indicador de función
Es posible que la interfaz de usuario del indicador de función no esté disponible en un dispositivo que ejecuta una compilación de usuario. En este caso, utilice el comando adb
en su lugar:
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
Imágenes del sistema host del proveedor en GCE (opcional)
Una de las posibles ubicaciones de almacenamiento para las imágenes del sistema es el depósito de Google Compute Engine (GCE). El administrador de la versión usa la consola de almacenamiento de GCP para agregar, eliminar o cambiar la imagen del sistema publicada.
Las imágenes deben ser de acceso público, como se muestra aquí:
Figura 4. Acceso público en GCE
El procedimiento para hacer público un elemento está disponible en la documentación de Google Cloud .
DSU de múltiples particiones en archivo ZIP
A partir de Android 11, DSU puede tener más de una partición. Por ejemplo, puede contener product.img
además de system.img
. Cuando el dispositivo arranca, la primera etapa init
detecta las particiones de DSU instaladas y reemplaza la partición en el dispositivo temporalmente, cuando la DSU instalada está habilitada. El paquete DSU puede contener una partición que no tiene una partición correspondiente en el dispositivo.
Figura 5. Proceso de DSU con varias particiones
DSU firmado por OEM
Para asegurarse de que todas las imágenes que se ejecutan en el dispositivo estén autorizadas por el fabricante del dispositivo, todas las imágenes dentro de un paquete de DSU deben estar firmadas. Por ejemplo, suponga que hay un paquete de DSU que contiene dos imágenes de partición como la siguiente:
dsu.zip {
- system.img
- product.img
}
Tanto system.img
como product.img
deben estar firmados por la clave OEM antes de colocarse en el archivo ZIP. La práctica común es usar un algoritmo asimétrico, por ejemplo, RSA, donde la clave secreta se usa para firmar el paquete y la clave pública se usa para verificarlo. El ramdisk de la primera etapa debe incluir la clave pública de emparejamiento, por ejemplo, /avb/*.avbpubkey
. Si el dispositivo ya adoptó AVB, el procedimiento de firma existente será suficiente. Las siguientes secciones ilustran el proceso de firma y resaltan la ubicación de la clave pública AVB que se usa para verificar las imágenes en el paquete DSU.
Descriptor JSON de ESD
El descriptor JSON de DSU describe los paquetes de DSU. Admite dos primitivas. En primer lugar, la primitiva de include
incluye descriptores JSON adicionales o redirige el cargador de DSU a una nueva ubicación. Por ejemplo:
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
En segundo lugar, la image
primitiva se utiliza para describir los paquetes DSU publicados. Dentro de la imagen primitiva hay varios atributos:
Los atributos de
name
ydetails
son cadenas que se muestran en el cuadro de diálogo para que el usuario las seleccione.Los
cpu_api
,vndk
yos_version
se utilizan para las comprobaciones de compatibilidad, que se describen en la siguiente sección.El atributo
pubkey
opcional describe la clave pública que se empareja con la clave secreta que se usa para firmar el paquete DSU. Cuando se especifica, el servicio DSU puede verificar si el dispositivo tiene la clave utilizada para verificar el paquete DSU. Esto evita instalar un paquete DSU no reconocido, por ejemplo, instalar un DSU firmado por OEM-A en un dispositivo fabricado por OEM-B.El atributo
tos
opcional apunta a un archivo de texto que describe los términos de servicio para el paquete de DSU correspondiente. Cuando un desarrollador selecciona un paquete de DSU con el atributo de términos de servicio especificado, se abre el cuadro de diálogo que se muestra en la Figura 6, que le pide al desarrollador que acepte los términos de servicio antes de instalar el paquete de DSU.Figura 6. Cuadro de diálogo Condiciones de servicio
Como referencia, aquí hay un descriptor DSU JSON para 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"
}
]
}
Gestión de compatibilidad
Se utilizan varios atributos para especificar la compatibilidad entre un paquete DSU y el dispositivo local:
cpu_api
es una cadena que describe la arquitectura del dispositivo. Este atributo es obligatorio y se compara con la propiedad del sistemaro.product.cpu.abi
. Sus valores deben coincidir exactamente.os_version
es un entero opcional que especifica una versión de Android. Por ejemplo, para Android 10,os_version
es10
y para Android 11,os_version
es11
. Cuando se especifica este atributo, debe ser igual o mayor que la propiedad del sistemaro.system.build.version.release
. Esta verificación se usa para evitar el arranque de una imagen GSI de Android 10 en un dispositivo de proveedor de Android 11, que actualmente no es compatible. Se permite iniciar una imagen GSI de Android 11 en un dispositivo con Android 10.vndk
es una matriz opcional que especifica todos los VNDK que se incluyen en el paquete DSU. Cuando se especifica, el cargador de DSU comprueba si se incluye el número extraído de la propiedad del sistemaro.vndk.version
.
Revocación de claves DSU por seguridad
En el caso extremadamente raro de que el par de claves RSA utilizado para firmar las imágenes DSU se vea comprometida, el ramdisk debe actualizarse lo antes posible para eliminar la clave comprometida. Además de actualizar la partición de arranque, puede bloquear las claves comprometidas mediante una lista de revocación de claves DSU (lista negra de claves) desde una URL HTTPS.
La lista de revocación de claves DSU contiene una lista de claves públicas AVB revocadas. Durante la instalación de DSU, las claves públicas dentro de las imágenes de DSU se validan con la lista de revocación. Si se encuentra que las imágenes contienen una clave pública revocada, el proceso de instalación de DSU se detiene.
La URL de la lista de revocación de claves debe ser una URL HTTPS para garantizar la solidez de la seguridad y se especifica en una cadena de recursos:
frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url
El valor de la cadena es https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json
, que es una lista de revocación de claves GSI publicadas por Google. Esta cadena de recursos se puede superponer y personalizar, de modo que los OEM que adopten la función DSU puedan proporcionar y mantener su propia lista negra de claves. Esto proporciona una forma para que el OEM bloquee ciertas claves públicas sin actualizar la imagen ramdisk del dispositivo.
El formato de la lista de revocación es:
{
"entries":[
{
"public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
"status":"REVOKED",
"reason":"Key revocation test key"
},
{
"public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
"status":"REVOKED",
"reason":"Key revocation test key"
}
]
}
-
public_key
es el resumen SHA-1 de la clave revocada, en el formato descrito en la sección de generación de la clave pública AVB . -
status
indica el estado de revocación de la clave. Actualmente, el único valor admitido esREVOKED
. -
reason
es una cadena opcional que describe el motivo de la revocación.
Procedimientos ESD
Esta sección describe cómo realizar varios procedimientos de configuración de DSU.
Generación de un nuevo par de claves
Utilice el comando openssl
para generar un par de claves pública/privada RSA en formato .pem
(por ejemplo, con un tamaño de 2048 bits):
$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem
Es posible que no se pueda acceder a la clave privada y solo se guarda en un módulo de seguridad de hardware (HSM) . En este caso, podría haber un certificado de clave pública x509 disponible después de la generación de la clave. Consulte la sección Adición de la clave pública de emparejamiento al ramdisk para obtener instrucciones sobre cómo generar la clave pública AVB a partir de un certificado x509.
Para convertir un certificado x509 a formato PEM:
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
Omita este paso si el certificado ya es un archivo PEM.
Agregar la clave pública de emparejamiento al ramdisk
El oem_cert.avbpubkey
debe colocarse en /avb/*.avbpubkey
para verificar el paquete DSU firmado. Primero, convierta la clave pública en formato PEM a formato de clave pública AVB:
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
Luego incluya la clave pública en el ramdisk de la primera etapa con los siguientes pasos.
Agregue un módulo precompilado para copiar
avbpubkey
. Por ejemplo, agreguedevice/<company>/<board>/oem_cert.avbpubkey
ydevice/<company>/<board>/avb/Android.mk
con contenido como este: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)
Haga que el objetivo de droidcore dependa del
oem_cert.avbpubkey
agregado:droidcore: oem_cert.avbpubkey
Generación del atributo pubkey AVB en el descriptor JSON
oem_cert.avbpubkey
está en formato binario de clave pública AVB. Use SHA-1 para que sea legible antes de colocarlo en el descriptor JSON:
$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20
Este será el contenido del atributo pubkey
del descriptor JSON.
"images":[
{
...
"pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
...
},
Firmar un paquete de DSU
Utilice uno de estos métodos para firmar un paquete DSU:
Método 1: reutilizar el artefacto creado por el proceso de firma AVB original para crear un paquete DSU. Un enfoque alternativo es extraer las imágenes ya firmadas del paquete de lanzamiento y usar las imágenes extraídas para crear el archivo ZIP directamente.
Método 2: use los siguientes comandos para firmar particiones DSU si la clave privada está disponible. Cada
img
dentro de un paquete DSU (el archivo ZIP) se firma por separado:$ 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
Para obtener más información sobre cómo agregar add_hashtree_footer
mediante avbtool
, consulte Uso de avbtool .
Verificación del paquete DSU localmente
Se recomienda verificar todas las imágenes locales con la clave pública de emparejamiento con estos comandos:
for partition in system product; do
avbtool verify_image --image ${OUT}/${partition}.img --key oem_cert_pub.pem
done
El resultado esperado se ve así:
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
Hacer un paquete de DSU
El siguiente ejemplo crea un paquete DSU que contiene un system.img
y un product.img
:
dsu.zip {
- system.img
- product.img
}
Después de que ambas imágenes estén firmadas, use el siguiente comando para crear el archivo ZIP:
$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -
Personalización de la DSU de un clic
De forma predeterminada, el cargador de DSU apunta a un metadato de imágenes GSI que es https://...google.com/.../gsi-src.json
.
Los OEM pueden sobrescribir la lista definiendo la propiedad persist.sys.fflag.override.settings_dynamic_system.list
que apunta a su propio descriptor JSON. Por ejemplo, un OEM puede proporcionar metadatos JSON que incluyen GSI, así como imágenes patentadas de OEM como esta:
{
"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"
},
}
Es posible que un OEM encadene metadatos de DSU publicados como se muestra en la Figura 7.
Figura 7. Encadenamiento de metadatos de DSU publicados