Los fabricantes de equipos originales y los proveedores de SoC que deseen implementar actualizaciones del sistema A/B deben asegurarse de que su cargador de arranque implemente boot_control HAL y pase los parámetros correctos al kernel.
Implementando el control de arranque HAL
Los cargadores de arranque compatibles con A/B deben implementar boot_control
HAL en hardware/libhardware/include/hardware/boot_control.h
. Puede probar las implementaciones usando la utilidad system/extras/bootctl
y system/extras/tests/bootloader/
.
También debe implementar la máquina de estado que se muestra a continuación:
Configurando el núcleo
Para implementar actualizaciones del sistema A/B:
- Elija la siguiente serie de parches del kernel (si es necesario):
- Si arranca sin ramdisk y usa "arranque como recuperación", seleccione android-review.googlesource.com/#/c/158491/ .
- Para configurar dm-verity sin ramdisk, elija android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18 .
- Asegúrese de que los argumentos de la línea de comandos del kernel contengan los siguientes argumentos adicionales:
skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
<public-key-id>
es el ID de la clave pública utilizada para verificar la firma de la tabla de verity (para obtener detalles, consulte dm-verity ) . - Agregue el certificado .X509 que contiene la clave pública al conjunto de claves del sistema:
- Copie el certificado .X509 formateado en formato
.der
en la raíz del directorio delkernel
. Si el certificado .X509 tiene formato de archivo.pem
, use el siguiente comandoopenssl
para convertir el formato.pem
a.der
:openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
- Genere
zImage
para incluir el certificado como parte del conjunto de claves del sistema. Para verificar, verifique la entrada deprocfs
(requiere queKEYS_CONFIG_DEBUG_PROC_KEYS
esté habilitado):angler:/# cat /proc/keys 1c8a217e I------ 1 perm 1f010000 0 0 asymmetri Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f [] 2d454e3e I------ 1 perm 1f030000 0 0 keyring .system_keyring: 1/4
La inclusión exitosa del certificado .X509 indica la presencia de la clave pública en el conjunto de claves del sistema (el resaltado indica el ID de la clave pública). - Reemplace el espacio con
#
y páselo como<public-key-id>
en la línea de comando del kernel. Por ejemplo, paseAndroid:#7e4333f9bba00adfe0ede979e28ed1920492b40f
en lugar de<public-key-id>
.
- Copie el certificado .X509 formateado en formato
Configuración de variables de compilación
Los cargadores de arranque compatibles con A/B deben cumplir con los siguientes criterios de variables de compilación:
Debe definirse para el objetivo A/B |
/device/google/marlin/+/android-7.1.0_r1/device-common.mk . Opcionalmente, puede realizar el paso de dex2oat posterior a la instalación (pero previo al reinicio) que se describe en Compilación . |
---|---|
Altamente recomendado para objetivos A/B |
|
No se puede definir para el objetivo A/B |
|
Opcional para compilaciones de depuración | PRODUCT_PACKAGES_DEBUG += update_engine_client |
Configuración de particiones (ranuras)
Los dispositivos A/B no necesitan una partición de recuperación o una partición de caché porque Android ya no usa estas particiones. La partición de datos ahora se usa para el paquete OTA descargado y el código de la imagen de recuperación está en la partición de arranque. Todas las particiones que son A/B-ed deben nombrarse de la siguiente manera (las ranuras siempre se denominan a
, b
, etc.): boot_a
, boot_b
, system_a
, system_b
, vendor_a
, vendor_b
.
Cache
Para las actualizaciones que no son A/B, la partición de caché se utilizó para almacenar paquetes OTA descargados y para ocultar bloques temporalmente mientras se aplicaban las actualizaciones. Nunca hubo una buena manera de dimensionar la partición del caché: el tamaño que debía tener dependía de las actualizaciones que deseaba aplicar. El peor de los casos sería una partición de caché tan grande como la imagen del sistema. Con las actualizaciones A/B no hay necesidad de almacenar bloques (porque siempre está escribiendo en una partición que no se usa actualmente) y con la transmisión A/B no hay necesidad de descargar todo el paquete OTA antes de aplicarlo.
Recuperación
El disco RAM de recuperación ahora está contenido en el archivo boot.img
. Al entrar en recuperación, el gestor de arranque no puede poner la opción skip_initramfs
en la línea de comandos del kernel.
Para las actualizaciones que no son A/B, la partición de recuperación contiene el código utilizado para aplicar las actualizaciones. Las actualizaciones A/B se aplican mediante update_engine
ejecutándose en la imagen del sistema arrancado normal. Todavía hay un modo de recuperación que se usa para implementar el restablecimiento de datos de fábrica y la carga lateral de paquetes de actualización (que es de donde proviene el nombre "recuperación"). El código y los datos para el modo de recuperación se almacenan en la partición de arranque normal en un ramdisk; para arrancar en la imagen del sistema, el cargador de arranque le dice al núcleo que omita el ramdisk (de lo contrario, el dispositivo arranca en modo de recuperación. El modo de recuperación es pequeño (y gran parte ya estaba en la partición de arranque), por lo que la partición de arranque no aumenta en tamaño.
Fstab
El argumento slotselect
debe estar en la línea para las particiones A/B-ed. Por ejemplo:
<path-to-block-device>/vendor /vendor ext4 ro wait,verify=<path-to-block-device>/metadata,slotselect
Ninguna partición debe tener el nombre vendor
. En su lugar, se seleccionará y vendor_b
la partición vendor_a
o proveedor_b en el punto de montaje /vendor
.
Argumentos de la ranura del kernel
El sufijo de ranura actual debe pasarse a través de un nodo de árbol de dispositivos (DT) específico ( /firmware/android/slot_suffix
) o a través de la línea de comando del kernel androidboot.slot_suffix
o el argumento bootconfig.
De forma predeterminada, fastboot muestra la ranura actual en un dispositivo A/B. Si el paquete de actualización también contiene imágenes para la otra ranura no actual, fastboot también muestra esas imágenes. Las opciones disponibles incluyen:
-
--slot SLOT
. Anule el comportamiento predeterminado y solicite a fastboot que actualice la ranura que se pasa como argumento. -
--set-active [ SLOT ]
. Establecer la ranura como activa. Si no se especifica ningún argumento opcional, la ranura actual se establece como activa. -
fastboot --help
. Obtenga detalles sobre los comandos.
Si el gestor de arranque implementa fastboot, debe admitir el comando set_active <slot>
que establece la ranura activa actual en la ranura dada (esto también debe borrar el indicador de no arranque para esa ranura y restablecer el recuento de reintentos a los valores predeterminados). El gestor de arranque también debe admitir las siguientes variables:
-
has-slot:<partition-base-name-without-suffix>
. Devuelve "sí" si la partición dada admite ranuras, "no" de lo contrario. -
current-slot
. Devuelve el sufijo de la ranura desde la que se iniciará a continuación. -
slot-count
. Devuelve un número entero que representa el número de ranuras disponibles. Actualmente, se admiten dos ranuras, por lo que este valor es2
. -
slot-successful:<slot-suffix>
. Devuelve "sí" si la ranura dada se ha marcado como un arranque exitoso, "no" de lo contrario. -
slot-unbootable:<slot-suffix>
. Devuelve "sí" si la ranura dada está marcada como no arrancable, "no" de lo contrario. -
slot-retry-count
. Número de reintentos restantes para intentar iniciar la ranura dada.
Para ver todas las variables, ejecute fastboot getvar all
.
Generación de paquetes OTA
Las herramientas del paquete OTA siguen los mismos comandos que los comandos para dispositivos que no son A/B. El archivo target_files.zip
debe generarse definiendo las variables de compilación para el destino A/B. Las herramientas de paquetes OTA identifican y generan automáticamente paquetes en el formato para el actualizador A/B.
Ejemplos:
- Para generar una OTA completa:
./build/make/tools/releasetools/ota_from_target_files \ dist_output/tardis-target_files.zip \ ota_update.zip
- Para generar una OTA incremental:
./build/make/tools/releasetools/ota_from_target_files \ -i PREVIOUS-tardis-target_files.zip \ dist_output/tardis-target_files.zip \ incremental_ota_update.zip
Configuración de particiones
update_engine
puede actualizar cualquier par de particiones A/B definidas en el mismo disco. Un par de particiones tiene un prefijo común (como system
o boot
) y un sufijo por ranura (como _a
). La lista de particiones para las que el generador de carga útil define una actualización está configurada por la variable make AB_OTA_PARTITIONS
.
Por ejemplo, si se incluyen un par de particiones bootloader_a
y booloader_b
( _a
y _b
son los sufijos de las ranuras), puede actualizar estas particiones especificando lo siguiente en la configuración del producto o placa:
AB_OTA_PARTITIONS := \ boot \ system \ bootloader
Todas las particiones actualizadas por update_engine
no deben ser modificadas por el resto del sistema. Durante las actualizaciones incrementales o delta , los datos binarios de la ranura actual se utilizan para generar los datos en la nueva ranura. Cualquier modificación puede hacer que los nuevos datos de la ranura no superen la verificación durante el proceso de actualización y, por lo tanto, la actualización falle.
Configuración posterior a la instalación
Puede configurar el paso posterior a la instalación de manera diferente para cada partición actualizada mediante un conjunto de pares clave-valor. Para ejecutar un programa ubicado en /system/usr/bin/postinst
en una nueva imagen, especifique la ruta relativa a la raíz del sistema de archivos en la partición del sistema.
Por ejemplo, usr/bin/postinst
es system/usr/bin/postinst
(si no se usa un disco RAM). Además, especifique el tipo de sistema de archivos para pasar a la llamada del sistema mount(2)
. Agregue lo siguiente a los archivos .mk
del producto o dispositivo (si corresponde):
AB_OTA_POSTINSTALL_CONFIG += \ RUN_POSTINSTALL_system=true \ POSTINSTALL_PATH_system=usr/bin/postinst \ FILESYSTEM_TYPE_system=ext4
Compilando
Por motivos de seguridad, system_server
no puede utilizar la compilación justo a tiempo (JIT) . Esto significa que debe compilar con anticipación los archivos odex para system_server
y sus dependencias como mínimo; cualquier otra cosa es opcional.
Para compilar aplicaciones en segundo plano, debe agregar lo siguiente a la configuración del dispositivo del producto (en el archivo device.mk del producto):
- Incluya los componentes nativos en la compilación para garantizar que el script de compilación y los archivos binarios se compilen e incluyan en la imagen del sistema.
# A/B OTA dexopt package PRODUCT_PACKAGES += otapreopt_script
- Conecte el script de compilación a
update_engine
para que se ejecute como un paso posterior a la instalación.# A/B OTA dexopt update_engine hookup AB_OTA_POSTINSTALL_CONFIG += \ RUN_POSTINSTALL_system=true \ POSTINSTALL_PATH_system=system/bin/otapreopt_script \ FILESYSTEM_TYPE_system=ext4 \ POSTINSTALL_OPTIONAL_system=true
Para obtener ayuda con la instalación de los archivos preoptados en la segunda partición del sistema no utilizada, consulte Primera instalación de arranque de archivos DEX_PREOPT .