Implementar Virtual A/B

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

Construir banderas

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

Para los dispositivos que se inician con A/B virtual, configúrelos para que hereden la configuración base del dispositivo A/B virtual:

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

Los dispositivos que se inician con A/B virtual solo necesitan la mitad del tamaño de la 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 sum(size of update groups) + overhead , que, a su vez, debe ser mayor o igual que sum(size of partitions) + overhead .

Para Android 13 y versiones posteriores, para habilitar instantáneas comprimidas con Virtual A/B, herede 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/android_t_baseline.mk)

Esto habilita instantáneas del espacio de usuario con Virtual A/B mientras se usa un método de compresión sin operaciones. A continuación, puede configurar el método de compresión en uno de los métodos admitidos, gz y brotli .

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := gz

Para Android 12, para habilitar instantáneas comprimidas con Virtual A/B, herede 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

Para 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, agregue 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 heredan de android_t_baseline.mk .

Fusión de espacio de usuario

Para los dispositivos que se actualizan a Android 13 y versiones posteriores, el proceso de fusión del espacio de usuario como se describe en Capas del mapeador de dispositivos no está habilitado de manera predeterminada. Para habilitar la fusión del espacio de usuario, agregue la siguiente línea al archivo .mk del dispositivo:

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

La combinación de espacio de usuario está habilitada de forma predeterminada en los dispositivos que se inician con 13 y superior.

Control de arranque HAL

La HAL de control de inicio proporciona una interfaz para que los clientes OTA controlen las ranuras de inicio. Virtual A/B requiere una actualización de la versión menor de la HAL de control de arranque porque se necesitan API adicionales para garantizar que el cargador de arranque esté protegido durante el restablecimiento de fábrica/parpadeo. Consulte 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 arranque, especialmente justo después de aplicar una actualización OTA. Por lo tanto, la partición de metadatos debe verificarse antes de first_stage_init la monte. Para asegurarse de que esto suceda, agregue el indicador check fs_mgr a la entrada de /metadata . Lo siguiente proporciona un ejemplo:

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

Requisitos del núcleo

Para habilitar la creación de instantáneas, establezca CONFIG_DM_SNAPSHOT en true .

Para los dispositivos que usan F2FS, incluya el indicador f2fs: export FS_NOCOW_FL al parche del kernel del usuario para corregir la fijación de archivos. Incluya el f2fs: también admite el parche del kernel de archivos anclados alineados .

Virtual A/B se basa en las funciones agregadas en la versión 4.3 del kernel: el bit de estado de desbordamiento en la snapshot y los objetivos snapshot-merge . Todos los dispositivos que se inicien con Android 9 y versiones posteriores ya deberían tener la versión de kernel 4.4 o posterior.

Para habilitar las instantáneas comprimidas, la versión de kernel mínima admitida es 4.19. Establezca CONFIG_DM_USER=m o CONFIG_DM_USER=y . Si usa el primero (un módulo), el módulo debe cargarse en el ramdisk de primera etapa. Esto se puede lograr agregando la siguiente línea al Makefile del dispositivo:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Actualización en dispositivos que se actualicen a Android 11

Al actualizar a Android 11, los dispositivos que se lanzaron con particiones dinámicas pueden actualizar opcionalmente A/B virtual. El proceso de actualización es prácticamente el mismo que para los dispositivos que se inician con A/B virtual, con algunas diferencias menores:

  • Ubicación de los archivos COW : para los dispositivos de lanzamiento, el cliente OTA usa todo el espacio vacío disponible en la súper partición antes de usar el espacio en /data . Para dispositivos actualizados, siempre hay suficiente espacio en la súper partición para que el archivo COW nunca se cree en /data .

  • Indicadores de características en tiempo de construcción : para los dispositivos que actualizan A/B virtual, tanto PRODUCT_VIRTUAL_AB_OTA como PRODUCT_VIRTUAL_AB_OTA_RETROFIT se establecen en true , como se muestra a continuación:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Tamaño de superpartición : los dispositivos que se inician con A/B virtual pueden reducir BOARD_SUPER_PARTITION_SIZE a la mitad porque las ranuras B no están en la superpartición. Los dispositivos que actualizan A/B virtual mantienen el tamaño de superpartición antiguo, por lo que BOARD_SUPER_PARTITION_SIZE es mayor o igual a 2 * sum(tamaño de los grupos de actualización) + sobrecarga , que a su vez es mayor o igual a 2 * sum(tamaño de las particiones) + sobrecarga .

Cambios en el cargador de arranque

Durante el paso de fusión de una actualización, /data contiene la única instancia completa del sistema operativo Android. Una vez que comienza la migración, las particiones product , vendor y system nativo están incompletas hasta que finaliza la copia. Si el dispositivo se restablece de fábrica durante este proceso, ya sea por recuperación o a través del cuadro de diálogo de configuración del sistema, entonces el dispositivo no se podrá iniciar.

Antes de borrar /data , finalice la combinación en recuperación o reversión según el estado del dispositivo:

  • Si la nueva compilación se inició correctamente antes, finalice la migración.
  • De lo contrario, retroceda a la ranura anterior:
    • Para particiones dinámicas, retroceda al estado anterior.
    • Para particiones estáticas, establezca la ranura activa en la ranura anterior.

Tanto el gestor de arranque como fastbootd pueden borrar la partición /data si el dispositivo está desbloqueado. Si bien fastbootd puede forzar la finalización de la migración, el gestor de arranque no puede. El cargador de arranque no sabe si una combinación está en progreso o no, o qué bloques en /data constituyen las particiones del sistema operativo. Los dispositivos deben evitar que el usuario inutilice el dispositivo sin saberlo (bloqueo) al hacer lo siguiente:

  1. Implemente el control de arranque HAL para que el gestor de arranque pueda leer el valor establecido por el método setSnapshotMergeStatus() .
  2. Si el estado de fusión es MERGING , o si el estado de fusión es SNAPSHOTTED y la ranura ha cambiado a la ranura recién actualizada, las solicitudes para borrar userdata , metadata o la partición que almacena el estado de fusión deben rechazarse en el gestor de arranque.
  3. Implemente el comando fastboot snapshot-update cancel para que los usuarios puedan indicarle al cargador de arranque que desean omitir este mecanismo de protección.
  4. Modifique las herramientas o secuencias de comandos de flasheo personalizadas para fastboot snapshot-update cancel cuando se flashea todo el dispositivo. Esto es seguro de emitir porque flashear todo el dispositivo elimina la OTA. Las herramientas pueden detectar este comando en tiempo de ejecución implementando fastboot getvar snapshot-update-status . Este comando ayuda a diferenciar entre condiciones de error.

Ejemplo

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Cambios en las herramientas de Fastboot

Android 11 realiza los siguientes cambios en el protocolo fastboot:

  • getvar snapshot-update-status — Devuelve el valor que el HAL de control de arranque comunicó al gestor de arranque:
    • Si el estado es MERGING , el gestor de arranque debe devolver merging .
    • Si el estado es SNAPSHOTTED , el gestor de arranque debe devolver snapshotted .
    • De lo contrario, el gestor de arranque debe devolver none .
  • snapshot-update merge : completa una operación de fusión, arrancando en recuperación/arranque rápido si es necesario. Este comando solo es válido si snapshot-update-status se está merging y solo se admite en fastbootd.
  • snapshot-update cancel : establece el estado de combinación de HAL de control de inicio en CANCELLED . Este comando no es válido cuando el dispositivo está bloqueado.
  • erase o wipe : un erase o wipe de metadata , userdata o una partición que contiene el estado de fusión para el control de arranque HAL debe verificar el estado de fusión de la instantánea. Si el estado es MERGING o SNAPSHOTTED , el dispositivo debe cancelar la operación.
  • set_active : un comando set_active que cambia la ranura activa debe verificar el estado de fusión de la instantánea. Si el estado es MERGING , el dispositivo debe cancelar 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 accidentalmente, pero pueden interrumpir las herramientas automatizadas. Cuando los comandos se usan como un componente del flasheo de todas las particiones, como ejecutar fastboot flashall , se recomienda usar el siguiente flujo:

  1. Consulta getvar snapshot-update-status .
  2. Si merging o snapshotted , emita snapshot-update cancel .
  3. Continúe con los pasos intermitentes.

Reducir los requisitos de almacenamiento

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

Métodos de compresión OTA

Los paquetes Ota se pueden ajustar para diferentes métricas de rendimiento. Actualmente, Android proporciona algunos métodos de compresión admitidos ( gz , lz4 y none ) que tienen compensaciones entre el tiempo de instalación, el uso del espacio COW, el tiempo de arranque y el tiempo de combinación de instantáneas. La opción predeterminada habilitada para ab virtual con compresión es el gz compression method . (Nota: el rendimiento relativo entre los métodos de compresión varía según la velocidad de la CPU y el rendimiento del almacenamiento, que puede cambiar según el dispositivo. Todos los paquetes OTA generados a continuación tienen PostInstall desactivado, lo que ralentizará ligeramente el tiempo de arranque. El tamaño total de la partición dinámica de un ota completo sin compresión es de 4,81 GB ).

OTA incremental en Pixel 6 Pro

Tiempo de instalación sin fase posterior a la instalación Uso del espacio vaca Tiempo de arranque posterior a OTA Tiempo de fusión de instantáneas
gz 24 minutos 1,18 GB 40.2 seg 45,5 seg
lz4 13 minutos 1,49GB 37.4 seg 37.1 seg
ninguno 13 minutos 2,90GB 37.6 seg 40.7 seg

OTA completo en Pixel 6 Pro

Tiempo de instalación sin fase posterior a la instalación Uso del espacio VACA Tiempo de arranque posterior a OTA Tiempo de fusión de instantáneas
gz 23 minutos 2,79 GB 24,9 seg 41.7 seg
lz4 12 minutos 3,46GB 20,0 seg 25,3 seg
ninguno 10 minutos 4,85GB 20,6 seg 29.8 seg