Implementa actualizaciones A/B

Los OEM y proveedores de SoC que quieran implementar actualizaciones del sistema A/B deben asegurarse de que su bootloader implementa la HAL de boot_control y pasa los parámetros correctos al kernel.

Implementa la HAL del control de inicio

Los bootloaders compatibles con A/B deben implementar la HAL de boot_control en hardware/libhardware/include/hardware/boot_control.h Puedes probar las implementaciones system/extras/bootctl utilidad y system/extras/tests/bootloader/

También debes implementar la máquina de estados que se muestra a continuación:

Figura 1: Máquina de estado del bootloader

Cómo configurar el kernel

Para implementar actualizaciones del sistema A/B, haz lo siguiente:

  1. Selecciona los siguientes parches de kernel (si es necesario):
  2. Asegúrate 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>"
    ... donde el valor <public-key-id> es el ID de la clave pública que se usa para verificarás la firma de la tabla de verity (para obtener más información, consulta dm-verity).
  3. Agrega el certificado .X509 que contiene la clave pública al llavero de claves del sistema:
    1. Copia el certificado .X509 con formato .der en la raíz del archivo kernel. Si el certificado .X509 tiene el formato .pem, usa el siguiente comando openssl para convertir desde Formato .pem a .der:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. Compila el zImage para incluir el certificado como parte del llavero de claves del sistema. Para verificarlo,comprueba la entrada procfs (requiere KEYS_CONFIG_DEBUG_PROC_KEYS que se habilitarán):
      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 correcta del certificado .X509 indica la presencia de la clave pública. en el llavero de claves del sistema (el punto destacado denota el ID de la clave pública)
    3. Reemplaza el espacio por # y pásalo como <public-key-id> en la línea de comandos del kernel. Por ejemplo, pasa Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f en lugar de <public-key-id>

Cómo establecer variables de compilación

Los bootloaders compatibles con A/B deben cumplir con los siguientes criterios de variables de compilación:

Se debe definir para el objetivo A/B.
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \ de
      boot \
      system \
      vendor
    y otras particiones actualizadas a través de update_engine (radio, bootloader, etc.)
  • PRODUCT_PACKAGES += \
      update_engine \
      update_verifier
Para ver un ejemplo, consulta /device/google/marlin/+/android-7.1.0_r1/device-common.mk De manera opcional, puedes realizar el paso de dex2oat posterior a la instalación (pero antes del reinicio) que se describe en Compilación.
Muy recomendado para objetivos A/B
  • Definir TARGET_NO_RECOVERY := true
  • Definir BOARD_USES_RECOVERY_AS_BOOT := true
  • No definir BOARD_RECOVERYIMAGE_PARTITION_SIZE
No se puede definir para la orientación A/B
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
Opcional para las compilaciones de depuración PRODUCT_PACKAGES_DEBUG += update_engine_client

Cómo configurar particiones (ranuras)

Los dispositivos A/B no necesitan una partición de recuperación ni una partición de caché porque Android ya no usa estas particiones. La partición de datos ahora se usa para el paquete inalámbrico descargado, y la el código de imagen de recuperación está en la partición de inicio. Todas las particiones que sean A/B-ed deben tener un nombre de la siguiente manera (las ranuras siempre se denominan a, b, etc.): boot_a, boot_b, system_a, system_b y vendor_a, vendor_b

Caché

En el caso de las actualizaciones que no son A/B, la partición de caché se utilizó para almacenar los paquetes inalámbricos descargados y para bloquear temporalmente los bloqueos durante la aplicación de actualizaciones Nunca hubo un buen tamaño de la caché partición: el tamaño necesario para depender de las actualizaciones que deseaba aplicar. Lo peor sería una partición de caché del tamaño de la imagen del sistema. Con las actualizaciones A/B, no es necesario para almacenar bloques (porque siempre escribes en una partición que no está en uso) y con la transmisión A/B, no es necesario descargar todo el paquete inalámbrico antes de aplicarlo.

Recuperación

El disco RAM de recuperación ahora se encuentra en el archivo boot.img. Al entrar en la recuperación, el bootloader no puede colocar la opción skip_initramfs en la línea de comandos del kernel.

En el caso de las actualizaciones que no son A/B, la partición de recuperación contiene el código que se usa para aplicar las actualizaciones. A/B update_engine aplica las actualizaciones que se ejecutan en la imagen del sistema iniciada normal. Aún se usa un modo de recuperación para implementar el restablecimiento de la configuración de fábrica y la transferencia de actualizaciones paquetes (de donde provino el nombre "recuperación"). El código y los datos del Modo de recuperación [Recovery mode] se almacena en la partición de inicio normal en un disco RAM; para iniciar en la imagen del sistema, El bootloader le indica al kernel que omita el ramdisk (de lo contrario, el dispositivo se iniciará en el modo de recuperación). . El modo de recuperación es pequeño (y gran parte ya estaba en la partición de inicio), por lo que no aumenta de tamaño.

fstab

El argumento slotselect debe estar en la línea de la dirección A/B. y particiones. Por ejemplo:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

Ninguna partición debe llamarse vendor. En su lugar, particiona vendor_a o Se seleccionará vendor_b y se activará en el punto de activación /vendor.

Argumentos de la ranura del kernel

El sufijo de ranura actual debe pasarse por un nodo del árbol de dispositivos (DT) específico (/firmware/android/slot_suffix) o a través de la Línea de comandos del kernel de androidboot.slot_suffix o argumento bootconfig.

De forma predeterminada, fastboot escribe en la memoria flash de la ranura actual de un dispositivo A/B. Si el paquete de actualización también contiene imágenes para la otra ranura no actual, fastboot también instala esas imágenes. Entre las opciones disponibles, se incluyen las siguientes:

  • --slot SLOT. Anula el comportamiento predeterminado y solicita a fastboot que escriba en la memoria flash la ranura que se pasa como un argumento.
  • --set-active [SLOT]. Configura el horario disponible como activo. Si no hay un argumento opcional se especifica, la ranura actual se establece como activa.
  • fastboot --help Obtén información detallada sobre los comandos.

Si el bootloader implementa fastboot, debería admitir el comando. set_active <slot>, que establece el espacio activo actual en el espacio determinado (este También debes borrar la marca de que no se puede iniciar para esa ranura y restablecer el recuento de reintentos a la configuración predeterminada. de salida). El bootloader también debe admitir las siguientes variables:

  • has-slot:<partition-base-name-without-suffix>. Devuelve “sí” si el valor especificado partición admite ranuras; de lo contrario, “no”.
  • current-slot Muestra el sufijo de la ranura que se iniciará a partir del siguiente elemento.
  • slot-count. Muestra un número entero que representa la cantidad de ranuras disponibles. Actualmente, se admiten dos ranuras, por lo que este valor es 2.
  • slot-successful:<slot-suffix>. Muestra "yes". si el espacio proporcionado se ha marcado como iniciado correctamente, "no" de lo contrario.
  • slot-unbootable:<slot-suffix>. Devuelve "yes" si el espacio proporcionado está marcado como imposible de arrancar, "no" de lo contrario.
  • slot-retry-count:<slot-suffix>. Cantidad de reintentos restantes para intentar iniciar la ranura en cuestión.

Para ver todas las variables, ejecuta fastboot getvar all

Cómo generar paquetes inalámbricos

Las herramientas de paquetes inalámbricos siguen los mismos comandos que para dispositivos que no son A/B. El archivo target_files.zip debe generarse definir las variables de compilación para el destino A/B. Las herramientas de paquetes OTA identifican automáticamente y generar 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 actualización inalámbrica incremental, haz lo siguiente:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

Configura 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 el sufijo por ranura (como _a). La lista de particiones para las cuales generator define que una actualización se configura mediante la variable make AB_OTA_PARTITIONS.

Por ejemplo, si un par de particiones bootloader_a y Se incluyen booloader_b (_a y _b son el espacio sufijos), puedes actualizar estas particiones especificando lo siguiente en el producto o la placa actual:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

El resto de las particiones no deben modificar las particiones actualizadas por update_engine en un sistema de archivos. Durante las actualizaciones incrementales o delta, los datos binarios de la ranura actual se que se usa para generar los datos en la nueva ranura. Cualquier modificación puede hacer que los nuevos datos de la ranura falla la verificación durante el proceso de actualización y, por lo tanto, falla la actualización.

Configurar posterior a la instalación

Puedes configurar el paso posterior a la instalación de manera diferente para cada partición actualizada con un conjunto de pares clave-valor. Para ejecutar un programa ubicado en /system/usr/bin/postinst en una nueva zona especifica la ruta de acceso relacionada con 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 es así) con un disco RAM). Además, especifica el tipo de sistema de archivos que se pasará al Llamada del sistema mount(2). Agregue la siguiente información al producto o dispositivo Archivos .mk (si corresponde):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

Compilar apps

Las apps se pueden compilar en segundo plano antes del reinicio con la nueva imagen del sistema. Para compilar apps en segundo plano, agrega lo siguiente a la configuración del dispositivo del producto (en el device.mk del producto):

  1. Incluye los componentes nativos en la compilación para garantizar que la secuencia de comandos y los objetos binarios de la compilación se compilarse y, luego, incluirse en la imagen del sistema.
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. Conecta la secuencia de comandos de compilación a update_engine de modo 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
    

Si necesitas ayuda para instalar los archivos preoptados en la segunda partición del sistema sin usar, consulta Primera instalación de inicio de archivos DEX_PREOPT.