Implementar una prueba A/B virtual

Para implementar A/B virtual en un dispositivo nuevo o actualizar un dispositivo lanzado, debes realizar cambios en el código específico del dispositivo.

Marcas de compilación

Los dispositivos que usan A/B virtual deben configurarse como un dispositivo A/B y deben inicio con particiones dinámicas.

Para los dispositivos que se inician con A/B virtual, configúralos para que hereden la configuración básica del dispositivo A/B virtual:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Los dispositivos que se lanzan con A/B virtual necesitan solo la mitad del tamaño de placa para BOARD_SUPER_PARTITION_SIZE porque las ranuras B ya no están en super. Es decir, BOARD_SUPER_PARTITION_SIZE debe ser mayor o igual que suma(tamaño de grupos de actualización) + sobrecarga, que, a su vez, debe ser mayor o igual que suma(tamaño de las particiones) + sobrecarga.

En Android 13 y versiones posteriores, para habilitar instantáneas comprimidas con A/B virtual, hereda la siguiente configuración base:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/vabc_features.mk)

Esto habilita instantáneas del espacio de usuario con A/B virtual mientras se usa un método de compresión sin operaciones. Luego, puedes configurar el método de compresión en uno de los métodos compatibles, zstd y lz4. En Android 15, la compresión se puede personalizar aún más para que coincida con las necesidades del dispositivo. Para obtener más información, consulta Ajuste fino de la compresión.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4
PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Para Android 12, para habilitar instantáneas comprimidas con A/B virtual, hereda la siguiente configuración base:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

Compresión XOR

En el caso de los dispositivos que se actualizan a Android 13 y versiones posteriores, la función de compresión XOR no está habilitada de forma predeterminada. Para habilitar la compresión XOR, agrega lo siguiente al archivo .mk del dispositivo.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

La compresión XOR está habilitada de forma predeterminada para los dispositivos que se heredan de android_t_baseline.mk.

Combinación de espacio del usuario

En la versión moderna de A/B virtual (Android T y versiones posteriores), el proceso de combinación de instantáneas ocurre por completo en el espacio del usuario. Este cambio es posible gracias a Snapuserd y dm-user. Los dispositivos que se inician con Android 13 y versiones posteriores tienen habilitada la combinación de espacio de usuario de forma predeterminada y, para los dispositivos más antiguos que se actualizan, esta propiedad se puede establecer con lo siguiente:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

HAL del control de inicio

La HAL de control de inicio proporciona una interfaz para que los clientes inalámbricos controlen las ranuras de inicio. El A/B virtual requiere una actualización de versión menor del HAL de control de inicio, ya que se necesitan APIs adicionales para garantizar que el bootloader esté protegido durante el proceso de actualización de firmware o el restablecimiento de la configuración de fábrica. Consulta IBootControl.hal y types.hal para obtener la versión más reciente de la definición de HAL.

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Cambios en fstab

La integridad de la partición de metadatos es esencial para el proceso de inicio, especialmente después de aplicar una actualización OTA. Por lo tanto, se debe verificar la partición de metadatos antes de que first_stage_init la active. Para garantizar que esto suceda, agrega la marca fs_mgr de check a la entrada de /metadata. A continuación, se proporciona un ejemplo:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Requisitos del kernel

Para habilitar las instantáneas, establece CONFIG_DM_SNAPSHOT en true.

Para los dispositivos que usan F2FS, incluye el parche del kernel f2fs: export FS_NOCOW_FL to user para corregir el bloqueo de archivos. También incluye el parche del kernel f2fs: support aligned pinned file.

La A/B virtual se basa en funciones agregadas en la versión 4.3 del kernel: el bit de estado de overflow en los destinos snapshot y snapshot-merge. Todos los dispositivos que se lanzan con Android 9 y versiones posteriores ya deben tener la versión de kernel 4.4 o una posterior.

Para habilitar las instantáneas comprimidas, la versión mínima del kernel compatible es 4.19. Establece CONFIG_DM_USER=m o CONFIG_DM_USER=y. Si usas el primero (un módulo), este se debe cargar en el disco RAM de la primera etapa. Para ello, agrega la siguiente línea al archivo Make del dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Cambios en las herramientas de Fastboot

Android 11 realiza los siguientes cambios en el protocolo de fastboot:

  • getvar snapshot-update-status: Muestra el valor que la HAL de control de inicio comunicó al bootloader:
    • Si el estado es MERGING, el bootloader debe mostrar merging.
    • Si el estado es SNAPSHOTTED, el bootloader debe mostrar snapshotted.
    • De lo contrario, el bootloader debe mostrar none.
  • snapshot-update merge: Completa una operación de combinación y, si es necesario, inicia en recovery/fastbootd. Este comando es válido solo si snapshot-update-status es merging y solo es compatible con fastbootd.
  • snapshot-update cancel: Establece el estado de combinación de la HAL del control de inicio en CANCELLED. Este comando no es válido cuando el dispositivo está bloqueado.
  • erase o wipe: Un objeto erase o wipe de metadata, userdata, o bien una partición que tenga el estado de combinación de la HAL de control de inicio debería verificar el estado de combinación de las instantáneas. Si el estado es MERGING o SNAPSHOTTED, el dispositivo debe abortar la operación.
  • set_active: Un comando set_active que cambia el espacio activo debería verificar el estado de combinación de instantáneas. Si el estado es MERGING, el dispositivo debe abortar la operación. La ranura se puede cambiar de forma segura en el estado SNAPSHOTTED.

Estos cambios están diseñados para evitar que un dispositivo no se pueda iniciar por accidente, pero pueden interrumpir las herramientas automatizadas. Cuando los comandos se usan como un componente para actualizar todas las particiones, como ejecutar fastboot flashall, se recomienda usar el siguiente flujo:

  1. Consulta getvar snapshot-update-status.
  2. Si es merging o snapshotted, muestra snapshot-update cancel.
  3. Continúa con los pasos para actualizar el firmware.

Reduce los requisitos de almacenamiento

Se recomienda que los dispositivos que no tienen almacenamiento A/B completo asignado en super y que esperan usar /data según sea necesario usen la herramienta de asignación de bloques. La herramienta de asignación de bloques mantiene la asignación de bloques coherente entre compilaciones, lo que reduce las escrituras innecesarias en la instantánea. Esto se documenta en Cómo reducir el tamaño de OTA.

Algoritmos de compresión OTA

Los paquetes OTA se pueden ajustar para diferentes métricas de rendimiento. Android proporciona varios métodos de compresión compatibles (lz4, zstd y none) que tienen compensaciones entre el tiempo de instalación, el uso de espacio de COW, el tiempo de inicio y el tiempo de combinación de instantáneas. La opción predeterminada habilitada para la ab virtual con compresión es lz4 compression method.

Cómo ajustar la compresión

Los algoritmos de compresión se pueden personalizar aún más mediante dos métodos: (nivel de compresión) (la cantidad de compresión que se logra a expensas de la velocidad) y (factor de compresión) (el tamaño máximo de ventana comprimible). El nivel de compresión está disponible para ciertos algoritmos, como zstd, y cambiar el nivel implica una compensación entre la velocidad y la relación de compresión. El factor de compresión describe el tamaño máximo de la ventana de compresión que se usa durante la instalación OTA. El valor predeterminado se establece en 64 K, pero se puede anular si se personaliza el parámetro de compilación PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR. Factores de compresión compatibles: 4K, 8K, 16K, 32K, 64K, 128K y 256K.

PRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 65536

Actualización inalámbrica incremental en el Pixel 8 Pro

Tiempo de instalación sin la fase de postinstalación Uso de espacio de COW Tiempo de inicio posterior a la actualización OTA Fecha y hora de combinación de instantáneas
LZ4 18 min y 15 s 2,5 GB 32.7 s 98.6 s
zstd 24 min 49 s 2.05 GB 36.3 s 133.2 s
none 16 min 42s 4.76 GB 28.7 s 76.6 s

Actualización inalámbrica completa en el Pixel 8 Pro

Tiempo de instalación sin la fase de postinstalación Uso de espacio de COW Tiempo de inicio posterior a la actualización OTA Fecha y hora de combinación de instantáneas
LZ4 15 min 11 s 4.16 GB 17.6 s 82.2 s
zstd 16 min 19 s 3.46 GB 21.0 s 106.3 s
none 13 min 33 s 6.39 GB 18.5 s 92.5 s