Resumen virtual A/B

Android tiene dos mecanismos de actualización: actualizaciones A/B (ininterrumpidas) y actualizaciones no A/B. Para reducir la complejidad del código y mejorar el proceso de actualización, en Android 11 los dos mecanismos se unifican a través de A/B virtual para brindar actualizaciones sin inconvenientes a todos los dispositivos con un costo de almacenamiento mínimo. Android 12 ofrece la opción de compresión A/B virtual para comprimir particiones instantáneas. Tanto en Android 11 como en Android 12, se aplica lo siguiente:

  • Las actualizaciones virtuales A/B son perfectas como las actualizaciones A/B. Las actualizaciones virtuales A/B minimizan el tiempo que un dispositivo está fuera de línea e inutilizable.
  • Las actualizaciones virtuales A/B se pueden revertir . Si el nuevo sistema operativo no se inicia, los dispositivos retroceden automáticamente a la versión anterior.
  • Las actualizaciones virtuales A/B usan un mínimo de espacio adicional al duplicar solo las particiones que usa el gestor de arranque. Se capturan instantáneas de otras particiones actualizables.

Antecedentes y terminología

Esta sección define la terminología y describe la tecnología que admite A/B virtual.

mapeador de dispositivos

Device-mapper es una capa de bloque virtual de Linux que se usa a menudo en Android. Con particiones dinámicas , las particiones como /system son una pila de dispositivos en capas:

  • En la parte inferior de la pila se encuentra la superpartición física (por ejemplo, /dev/block/by-name/super ).
  • En el medio hay un dispositivo dm-linear , que especifica qué bloques en la súper partición forman la partición dada. Aparece como /dev/block/mapper/system_[a|b] en un dispositivo A/B o /dev/block/mapper/system en un dispositivo que no es A/B.
  • En la parte superior reside un dispositivo dm-verity , creado para particiones verificadas. Este dispositivo verifica que los bloques en el dispositivo dm-linear estén firmados correctamente. Aparece como /dev/block/mapper/system-verity y es la fuente del punto de montaje /system .

La Figura 1 muestra cómo se ve la pila debajo del punto de montaje /system .

Partition stacking underneath system

Figura 1. Pila debajo del punto de montaje /system

dm-instantánea

Virtual A/B se basa en dm-snapshot , un módulo mapeador de dispositivos para tomar instantáneas del estado de un dispositivo de almacenamiento. Al usar dm-snapshot , hay cuatro dispositivos en juego:

  • El dispositivo base es el dispositivo del que se toma una instantánea. En esta página, el dispositivo base siempre es una partición dinámica, como un sistema o un proveedor.
  • El dispositivo de copia en escritura (COW), para registrar cambios en el dispositivo base. Puede ser de cualquier tamaño, pero debe ser lo suficientemente grande para acomodar todos los cambios en el dispositivo base.
  • El dispositivo de instantánea se crea utilizando el destino snapshot . Las escrituras en el dispositivo de instantáneas se escriben en el dispositivo COW. Las lecturas del dispositivo de instantánea se leen desde el dispositivo base o desde el dispositivo COW, dependiendo de si la instantánea ha cambiado los datos a los que se accede.
  • El dispositivo de origen se crea utilizando el destino snapshot-origin . Las lecturas en el dispositivo de origen se leen directamente desde el dispositivo base. Escribe en el dispositivo de origen escribe directamente en el dispositivo base, pero los datos originales se respaldan escribiendo en el dispositivo COW.

Device mapping for dm-snapshot

Figura 2. Asignación de dispositivos para dm-snapshot

Instantáneas comprimidas

En Android 12 y versiones posteriores, debido a que los requisitos de espacio en la partición /data pueden ser altos, puede habilitar instantáneas comprimidas en su compilación para abordar los requisitos de espacio más altos de la partición /data .

Las instantáneas comprimidas virtuales A/B se basan en los siguientes componentes que están disponibles en Android 12 y versiones posteriores:

  • dm-user , un módulo del núcleo similar a FUSE que permite que el espacio de usuario implemente dispositivos de bloque.
  • snapuserd , un demonio de espacio de usuario para implementar un nuevo formato de instantánea.

Estos componentes permiten la compresión. Los otros cambios necesarios realizados para implementar las capacidades de instantáneas comprimidas se proporcionan en las siguientes secciones: formato COW para instantáneas comprimidas , dm-user y Snapuserd .

Formato COW para instantáneas comprimidas

En Android 12 y versiones posteriores, las instantáneas comprimidas usan un formato COW. De manera similar al formato integrado del kernel que se usa para las instantáneas sin comprimir, el formato COW para las instantáneas comprimidas tiene secciones alternas de metadatos y datos. Los metadatos del formato original solo se permiten para operaciones de reemplazo : Reemplace el bloque X en la imagen base con el contenido del bloque Y en la instantánea. El formato COW de instantáneas comprimidas es más expresivo y admite las siguientes operaciones:

  • Copia : el bloque X en el dispositivo base debe reemplazarse con el bloque Y en el dispositivo base.
  • Reemplazar : el bloque X en el dispositivo base debe reemplazarse con el contenido del bloque Y en la instantánea. Cada uno de estos bloques está comprimido en gz.
  • Cero : el bloque X en el dispositivo base debe reemplazarse con ceros.
  • XOR : el dispositivo COW almacena bytes comprimidos XOR entre el bloque X y el bloque Y. (Disponible en Android 13 y superior).

Las actualizaciones OTA completas consisten únicamente en operaciones de reemplazo y puesta a cero . Las actualizaciones incrementales de OTA también pueden tener operaciones de copia .

dm-usuario en Android 12

El módulo de kernel dm-user permite que userspace implemente dispositivos de bloque mapeador de dispositivos. Una entrada de la tabla dm-user crea un dispositivo misceláneo en /dev/dm-user/<control-name> . Un proceso userspace puede sondear el dispositivo para recibir solicitudes de lectura y escritura del kernel. Cada solicitud tiene un búfer asociado para que el espacio de usuario se complete (para una lectura) o se propague (para una escritura).

El módulo de kernel dm-user proporciona una nueva interfaz visible para el usuario para el kernel que no forma parte de la base de código upstream kernel.org. Hasta que lo sea, Google se reserva el derecho de modificar la interfaz dm-user en Android.

Snapusuario

El componente de espacio de usuario snapuserd para dm-user implementa la compresión Virtual A/B.

En la versión sin comprimir de Virtual A/B (ya sea en Android 11 y versiones anteriores, o en Android 12 sin la opción de instantánea comprimida), el dispositivo COW es un archivo sin formato. Cuando la compresión está habilitada, COW funciona como un dispositivo dm-user , que está conectado a una instancia del daemon snapuserd .

El kernel no usa el nuevo formato COW. Entonces, el componente snapuserd traduce las solicitudes entre el formato COW de Android y el formato integrado del kernel:

Snapuserd component translating requests between Android COW format and kernel built-in format

Figura 3. Diagrama de flujo de snapuserd como traductor entre los formatos Android y Kernel COW

Esta traducción y descompresión nunca ocurre en el disco. El componente snapuserd intercepta las lecturas y escrituras COW que ocurren en el kernel y las implementa usando el formato COW de Android.

compresión XOR

Para los dispositivos que se inician con Android 13 y versiones posteriores, la función de compresión XOR, que está habilitada de forma predeterminada, permite que las instantáneas del espacio de usuario almacenen bytes comprimidos XOR entre bloques antiguos y bloques nuevos. Cuando solo se cambian unos pocos bytes en un bloque en una actualización Virtual A/B, el esquema de almacenamiento de compresión XOR usa menos espacio que el esquema de almacenamiento predeterminado porque las instantáneas no almacenan 4K bytes completos. Esta reducción en el tamaño de la instantánea es posible porque los datos XOR contienen muchos ceros y son más fáciles de comprimir que los datos de bloque sin formato. En los dispositivos Pixel, la compresión XOR reduce el tamaño de la instantánea entre un 25 % y un 40 %.

Para los dispositivos que se actualizan a Android 13 y versiones posteriores, la compresión XOR debe estar habilitada. Para obtener más información, consulte Compresión XOR .

Procesos de compresión A/B virtual

Esta sección proporciona detalles sobre el proceso de compresión Virtual A/B que se usa en Android 13 y Android 12.

Lectura de metadatos (Android 12)

Los metadatos son construidos por un daemon snapuserd . Los metadatos son principalmente un mapeo de dos ID, de 8 bytes cada uno, que representan los sectores que se fusionarán. En dm-snapshot se llama disk_exception .

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

Se utiliza una excepción de disco cuando una parte antigua de datos se reemplaza por una nueva.

Un demonio snapuserd lee el archivo COW interno a través de la biblioteca COW y construye los metadatos para cada una de las operaciones COW presentes en el archivo COW.

Las lecturas de metadatos se inician desde dm-snapshot en el kernel cuando se crea el dispositivo dm- snapshot .

La siguiente figura proporciona un diagrama de secuencia para la ruta de E/S para la construcción de metadatos.

Sequence diagram, IO path for metadata construction

Figura 4. Flujo de secuencia para la ruta de E/S en la construcción de metadatos

Fusión (Android 12)

Una vez que se completa el proceso de inicio, el motor de actualización marca la ranura como un inicio exitoso e inicia la combinación cambiando el destino dm-snapshot al destino dm-snapshot-merge .

dm-snapshot recorre los metadatos e inicia una E/S de combinación para cada excepción de disco. A continuación se muestra una descripción general de alto nivel de la ruta de E/S de combinación.

Merge IO path

Figura 5. Descripción general de la ruta Merge IO

Si el dispositivo se reinicia durante el proceso de combinación, la combinación se reanuda en el próximo reinicio y la combinación se completa.

Capas de mapeador de dispositivos

Para los dispositivos que se inician con Android 13 y versiones posteriores, el componente de espacio de usuario snapuserd realiza los procesos de instantánea y combinación de instantáneas en la compresión Virtual A/B. Para los dispositivos que se actualizan a Android 13 y versiones posteriores, esta función debe estar habilitada. Para obtener más información, consulte Combinación de espacio de usuario .

A continuación se describe el proceso de compresión Virtual A/B:

  1. El marco monta la partición /system fuera de un dispositivo dm-verity , que se apila encima de un dispositivo dm-user . Esto significa que cada E/S del sistema de archivos raíz se enruta a dm-user .
  2. dm-user enruta la E/S al demonio snapuserd del espacio de usuario, que maneja la solicitud de E/S.
  3. Cuando se completa la operación de combinación, el marco colapsa dm-verity sobre dm-linear ( system_base ) y elimina dm-user .

Proceso de compresión virtual A/B

Figura 6. Proceso de compresión A/B virtual

El proceso de combinación de instantáneas se puede interrumpir. Si el dispositivo se reinicia durante el proceso de combinación, el proceso de combinación se reanuda después del reinicio.

transiciones de inicio

Al arrancar con instantáneas comprimidas, el init de primera etapa debe iniciar snapuserd para montar particiones. Esto plantea un problema: cuando se carga y aplica sepolicy , snapuserd se coloca en el contexto incorrecto y sus solicitudes de lectura fallan, con denegaciones de selinux.

Para abordar esto, las transiciones snapuserd están sincronizadas con init , de la siguiente manera:

  1. init de la primera etapa inicia snapuserd desde el ramdisk y guarda un descriptor de archivo abierto en una variable de entorno.
  2. init de primera etapa cambia el sistema de archivos raíz a la partición del sistema y luego ejecuta la copia del sistema de init .
  3. La copia del sistema de init lee la política combinada en una cadena.
  4. Init invoca mlock() en todas las páginas respaldadas por ext4. A continuación, desactiva todas las tablas del mapeador de dispositivos para dispositivos de instantáneas y detiene snapuserd . Después de esto, está prohibido leer de las particiones, ya que al hacerlo se produce un interbloqueo.
  5. Usando el descriptor abierto de la copia ramdisk de snapuserd , init relanza el daemon con el contexto selinux correcto. Se reactivan las tablas del mapeador de dispositivos para dispositivos de instantáneas.
  6. Init invoca munlockall() - es seguro realizar IO nuevamente.

uso del espacio

La siguiente tabla proporciona una comparación del uso del espacio para diferentes mecanismos de OTA que usan el sistema operativo de Pixel y los tamaños de OTA.

Impacto de tamaño no-A/B A/B A/B virtuales A/B virtual (comprimido)
Imagen original de fábrica Super de 4,5 GB (imagen de 3,8 G + 700 M reservados) 1 Super de 9GB (3.8G + 700M reservados, para dos ranuras) Super de 4,5 GB (imagen de 3,8 G + 700 M reservados) Super de 4,5 GB (imagen de 3,8 G + 700 M reservados)
Otras particiones estáticas /cache Ninguno Ninguno Ninguno
Almacenamiento adicional durante OTA (espacio devuelto después de aplicar OTA) 1,4 GB en/datos 0 3.8GB 2 en /datos 2.1GB 2 en /datos
Almacenamiento total requerido para aplicar OTA 5.9GB 3 (súper y datos) 9 GB (súper) 8.3GB 3 (súper y datos) 6.6GB 3 (súper y datos)

1 Indica el diseño asumido basado en el mapeo de píxeles.

2 Supone que la nueva imagen del sistema tiene el mismo tamaño que la original.

3 El requisito de espacio es transitorio hasta que se reinicia.

Para implementar Virtual A/B, o para usar capacidades de instantáneas comprimidas, consulte Implementación de Virtual A/B