Virtual A/B es el principal mecanismo de actualización de Android. A/B virtual se basa en las actualizaciones A/B heredadas (consulta Actualizaciones del sistema A/B) y las que no son A/B, que se dejaron de usar en la versión 15 para reducir la sobrecarga de espacio de las actualizaciones.
En realidad, Virtual A/B no tiene una ranura adicional para las particiones dinámicas. Consulta particiones dinámicas. En cambio, el delta se escribe en una instantánea y, luego, se combina con la partición base después de confirmar un inicio correcto. A/B virtual usa un formato de instantáneas específico de Android. Consulta Formato COW para instantáneas comprimidas, que permite comprimir instantáneas y minimizar el uso del espacio en disco. En una OTA completa, el tamaño de la instantánea se reduce en alrededor de un 45% con la compresión, y en una OTA incremental, se reduce en alrededor de un 55%.
Android 12 ofrece la opción de compresión de A/B virtual para comprimir particiones con instantáneas. Las actualizaciones de A/B virtuales ofrecen lo siguiente:
- Las actualizaciones de A/B virtuales son sin interrupciones (la actualización se realiza por completo en segundo plano mientras el dispositivo está en funcionamiento), al igual que las actualizaciones de A/B. Las actualizaciones de A/B virtual minimizan el tiempo que un dispositivo está sin conexión y no se puede usar.
- Las actualizaciones de A/B virtuales se pueden revertir. Si el nuevo SO no se inicia, los dispositivos revierten automáticamente a la versión anterior.
- Las actualizaciones virtuales de A/B usan un mínimo de espacio adicional, ya que solo duplican las particiones que usa el bootloader. Se crean instantáneas de otras particiones actualizables.
Información general y terminología
En esta sección, se define la terminología y se describe la tecnología que admite las pruebas A/B virtuales. Durante la instalación OTA, los datos nuevos del sistema operativo se escriben en su nueva ranura para particiones físicas o en un dispositivo COW específico de Android. Después de reiniciar el dispositivo, los datos de la partición dinámica se vuelven a combinar en su dispositivo base a través del uso de dm-user y el daemon snapuserd. Este proceso se realiza por completo en el espacio del usuario.
Device-mapper
Device-mapper es una capa de bloques virtuales de Linux que se usa con frecuencia en Android. Con las particiones dinámicas, las particiones como /system
son una pila de dispositivos en capas:
- En la parte inferior de la pila, se encuentra la partición física super (por ejemplo,
/dev/block/by-name/super
). - En el medio, hay un dispositivo
dm-linear
que especifica qué bloques de la superpartición forman la partición dinámica determinada. Aparece como/dev/block/mapper/system_[a|b]
en un dispositivo A/B o como/dev/block/mapper/system
en un dispositivo que no es A/B. - En la parte superior, se encuentra un dispositivo
dm-verity
, creado para particiones verificadas. Este dispositivo verifica que los bloques del dispositivodm-linear
estén firmados correctamente. Aparece como/dev/block/mapper/system-verity
y es la fuente del punto de activación/system
.
En la figura 1, se muestra cómo se ve la pila debajo del punto de activación /system
.
Figura 1: Pila debajo del punto de activación /system
Instantáneas comprimidas
En Android 12 y versiones posteriores, debido a que los requisitos de espacio en la partición /data
pueden ser altos, puedes habilitar instantáneas comprimidas en tu compilación para abordar los requisitos de espacio más altos de la partición /data
.
Las instantáneas comprimidas de A/B virtual se compilan sobre los siguientes componentes disponibles en Android 12 y versiones posteriores:
dm-user
, un módulo de kernel similar a FUSE que permite que el espacio del usuario implemente dispositivos de bloqueo.snapuserd
, un daemon de espacio de usuario para implementar un nuevo formato de instantánea.
Estos componentes habilitan la compresión. Los otros cambios necesarios que se realizaron para implementar las capacidades de instantáneas comprimidas se indican 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 específico de Android. El formato COW contiene metadatos sobre la OTA y tiene búferes distintos que contienen operaciones COW y datos nuevos del sistema operativo. En comparación con el formato de instantáneas del kernel, que solo permitía operaciones de reemplazo (reemplazar el bloque X en la imagen base por el contenido del bloque Y en la instantánea), el formato COW de instantáneas comprimidas de Android es más expresivo y admite las siguientes operaciones:
- Copia: El bloque X del dispositivo base se debe reemplazar por el bloque Y del dispositivo base.
- Reemplazar: El bloque X del dispositivo base se debe reemplazar por el contenido del bloque Y de la instantánea. Cada uno de estos bloques está comprimido con gz.
- Cero: El bloqueo X en el dispositivo base debe reemplazarse por ceros.
- XOR: El dispositivo COW almacena bytes comprimidos con XOR entre el bloque X y el bloque Y. (Disponible en Android 13 y versiones posteriores)
Las actualizaciones OTA completas solo constan de operaciones de reemplazo y cero. Las actualizaciones OTA incrementales también pueden tener operaciones de copia.
El diseño completo de la instantánea en el disco se ve de la siguiente manera:
Figura 2: Formato COW de Android en el disco
dm-user
El módulo del kernel dm-user permite que userspace
implemente dispositivos de bloques de device-mapper. Una entrada de la tabla dm-user crea un dispositivo diverso 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 del usuario lo complete (para una lectura) o lo propague (para una escritura).
El módulo del kernel dm-user
proporciona una nueva interfaz visible para el usuario en el kernel que no forma parte de la base de código de kernel.org upstream. Hasta entonces, Google se reserva el derecho de modificar la interfaz de dm-user
en Android.
snapuserd
El componente de espacio de usuario snapuserd
para dm-user
implementa la compresión A/B virtual. Snapuserd es un daemon de espacio de usuario encargado de escribir y leer los dispositivos COW de Android. Todas las E/S a la instantánea deben pasar por este servicio.
Durante la instalación de OTA, snapuserd escribe los datos del nuevo sistema operativo en la instantánea (con compresión). Aquí también se maneja el análisis de los metadatos y el desempaquetado de los datos de bloques nuevos.
Compresión XOR
En el caso de los dispositivos que se lanzan con Android 13 y versiones posteriores, la función de compresión XOR, que está habilitada de forma predeterminada, permite que los resúmenes del espacio del usuario almacenen bytes comprimidos con XOR entre bloques antiguos y bloques nuevos. Cuando solo se cambian unos pocos bytes en un bloque en una actualización de Virtual A/B, el esquema de almacenamiento de compresión XOR usa menos espacio que el esquema de almacenamiento predeterminado, ya que las instantáneas no almacenan bytes completos de 4 K. 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 procesar. En los dispositivos Pixel, la compresión XOR reduce el tamaño del resumen entre un 25% y un 40%.
En el caso de los dispositivos que se actualizan a Android 13 y versiones posteriores, se debe habilitar la compresión XOR. Para obtener más información, consulta Compresión XOR.
Fusión de instantáneas
En el caso de los dispositivos que se lanzan con Android 13 y versiones posteriores, los procesos de instantánea y combinación de instantáneas en la compresión A/B virtual se realizan con el componente de espacio de usuario snapuserd
. Esta función debe habilitarse en los dispositivos que se actualicen a Android 13 y versiones posteriores. Para obtener más información, consulta Combinación del espacio del usuario.
A continuación, se describe el proceso de compresión de Virtual A/B:
- El framework monta la partición
/system
desde un dispositivodm-verity
, que se apila sobre un dispositivodm-user
. Esto significa que cada E/S del sistema de archivos raíz se dirige adm-user
. dm-user
enruta la E/S al daemonsnapuserd
del espacio del usuario, que controla la solicitud de E/S.- Cuando se completa la operación de combinación, el framework contrae
dm-verity
sobredm-linear
(system_base
) y quitadm-user
.
Figura 3: Proceso de compresión de A/B virtual
Se puede interrumpir el proceso de combinación de instantáneas. Si se reinicia el dispositivo durante el proceso de combinación, este se reanudará después del reinicio.
Transiciones de inicialización
Cuando se inicia con snapshots comprimidos, 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 este problema, snapuserd
realiza la transición en sincronía con init
, de la siguiente manera:
- La etapa 1 de
init
iniciasnapuserd
desde el disco RAM y guarda un descriptor de archivo abierto en él en una variable de entorno. init
de primera etapa cambia el sistema de archivos raíz a la partición del sistema y, luego, ejecuta la copia del sistema deinit
.- La copia del sistema de
init
lee la política de seguridad combinada en una cadena. Init
invocamlock()
en todas las páginas respaldadas por ext4. Luego, desactiva todas las tablas de device-mapper para los dispositivos de instantáneas y detienesnapuserd
. Después de esto, está prohibido leer desde las particiones, ya que esto provoca un bloqueo.- Con el descriptor abierto para la copia de
snapuserd
en el disco RAM,init
reinicia el daemon con el contexto de SELinux correcto. Se reactivan las tablas de device-mapper para los dispositivos de instantáneas. - Init invoca
munlockall()
, por lo que es seguro volver a realizar E/S.
Uso del espacio
En la siguiente tabla, se proporciona una comparación del uso del espacio para diferentes mecanismos de OTA con los tamaños del SO y de la OTA de Pixel.
Impacto en el tamaño | non-A/B | A/B | A/B virtual | A/B virtual (comprimido) |
---|---|---|---|---|
Imagen original de fábrica | 4.5 GB súper (3.8 GB de imagen y 700 MB reservados)1 | 9 GB de memoria súper (3.8 GB + 700 M reservados, para dos ranuras) | 4.5 GB súper (imagen de 3.8 GB + 700 M reservados) | 4.5 GB súper (imagen de 3.8 GB + 700 M reservados) |
Otras particiones estáticas | /cache | Ninguno | Ninguno | Ninguno |
Almacenamiento adicional durante la OTA (espacio que se recupera después de aplicar la OTA) | 1.4 GB en /data | 0 | 3.8 GB2 en /data | 2.1 GB2 en /data |
Almacenamiento total necesario para aplicar la OTA | 5.9 GB3 (súper y datos) | 9 GB (súper) | 8.3 GB3 (súper y datos) | 6.6 GB3 (súper y datos) |
1Indica el diseño supuesto según la asignación de píxeles.
2Supone que la nueva imagen del sistema tiene el mismo tamaño que la original.
3El requisito de espacio es transitorio hasta el reinicio.
Actualizaciones A/B virtuales en Android 11
Android 11 de Virtual A/B escribió en la partición dinámica con el formato COW del kernel. Finalmente, se dejó de usar porque el formato COW del kernel no admite la compresión.
Actualizaciones A/B virtuales en Android 12
En Android 12, la compresión se admite en forma de un formato COW específico de Android. Esta versión de A/B virtual requería una traducción del COW específico de Android al formato COW del kernel. Finalmente, se reemplazó en Android 13, que quitó la dependencia del formato COW del kernel y también dm-snapshot
.
Para implementar A/B virtual o usar las capacidades de instantáneas comprimidas, consulta Implementación de A/B virtual.