Punto de control de datos del usuario

Android 10 introduce el punto de control de datos del usuario (UDC), que permite a Android revertir al estado anterior cuando falla una actualización inalámbrica (OTA) de Android. Con UDC, si falla una actualización de OTA de Android, el dispositivo puede revertir de forma segura a su estado anterior. Si bien las actualizaciones A/B resuelven este problema para el inicio temprano, no se admite la reversión cuando se modifica la partición de datos del usuario (que se monta en /data).

La UDC permite que el dispositivo revierta la partición de datos del usuario incluso después de que se haya modificado. La función UDC logra esto con capacidades de puntos de control para el sistema de archivos, una implementación alternativa cuando el sistema de archivos no admite puntos de control, integración con el mecanismo de bootloader A/B y compatibilidad con actualizaciones que no son A/B, y compatibilidad con la vinculación de versiones de claves y la prevención de reversión de claves.

Impacto en los usuarios

La función UDC mejora la experiencia de actualización OTA para los usuarios, ya que menos usuarios pierden sus datos cuando falla una actualización OTA. Esto puede reducir la cantidad de llamadas de asistencia técnica de los usuarios que tienen problemas durante el proceso de actualización. Sin embargo, cuando falla una actualización OTA, es posible que los usuarios noten que el dispositivo se reinicia varias veces.

Cómo funciona

Funcionalidad de puntos de control en diferentes sistemas de archivos

Para el sistema de archivos F2FS, UDC agrega la funcionalidad de punto de control al kernel de Linux 4.20 upstream y la agrega a todos los kernels comunes compatibles con los dispositivos que ejecutan Android 10.

Para otros sistemas de archivos, UDC usa un dispositivo virtual de Device Mapper llamado dm_bow para la funcionalidad de puntos de control. dm_bow se encuentra entre el dispositivo y el sistema de archivos. Cuando se activa una partición, se emite un comando TRIM que hace que el sistema de archivos emita comandos TRIM en todos los bloques libres. dm_bow intercepta estos cortes y los usa para configurar una lista de bloqueo gratuita. Luego, las lecturas y escrituras se envían al dispositivo sin modificaciones, pero, antes de permitir una escritura, se crea una copia de seguridad de los datos necesarios para un restablecimiento en un bloque libre.

Proceso de punto de control

Cuando se activa una partición con la marca checkpoint=fs/block, Android llama a restoreCheckpoint en la unidad para permitir que el dispositivo restablezca cualquier punto de control actual. Luego, init llama a la función needsCheckpoint para determinar si el dispositivo está en un estado de bootloader A/B o si se estableció el recuento de reintentos de actualización. Si alguna de las dos condiciones es verdadera, Android llama a createCheckpoint para agregar marcas de montaje o compilar un dispositivo dm_bow.

Después de que se activa la partición, se llama al código del punto de control para emitir recortes. Luego, el proceso de inicio continúa con normalidad. En LOCKED_BOOT_COMPLETE, Android llama a commitCheckpoint para confirmar el punto de control actual y la actualización continúa con normalidad.

Administra las claves de KeyMint (anteriormente Keymaster)

Las claves de KeyMint se usan para la encriptación del dispositivo o para otros fines. Para administrar estas claves, Android retrasa las llamadas de eliminación de claves hasta que se confirma el punto de control.

Supervisar la salud

Un daemon de estado verifica que haya suficiente espacio en el disco para crear un punto de control. El daemon de estado se encuentra en cp_healthDaemon en Checkpoint.cpp.

El daemon de estado tiene los siguientes comportamientos que se pueden configurar:

APIs de Checkpoint

Las APIs de puntos de control se usan en la función de UDC. Para otras APIs que usa UDC, consulta IVold.aidl.

void startCheckpoint(int retry)

Crea un punto de control.

El framework llama a este método cuando está listo para iniciar una actualización. El punto de control se crea antes de que los sistemas de archivos con puntos de control, como userdata, se monten con acceso de lectura y escritura después del reinicio. Si el recuento de reintentos es positivo, la API controla los reintentos de seguimiento y el actualizador llama a needsRollback para verificar si se requiere una reversión de la actualización. Si el recuento de reintentos es -1, la API se remite al criterio del bootloader A/B.

No se llama a este método cuando se realiza una actualización normal de la prueba A/B.

void commitChanges()

Confirma los cambios.

El framework llama a este método después de reiniciar el dispositivo cuando los cambios están listos para confirmarse. Se llama a este método antes de que se escriban datos (como fotos, videos, SMS o recibos de recepción del servidor) en userdata y antes de BootComplete.

Si no existe ninguna actualización con puntos de control activa, este método no tiene efecto.

abortChanges()

Fuerza el reinicio y revierte al punto de control. Abandona todas las modificaciones de datos del usuario desde el primer reinicio.

El framework llama a este método después del reinicio, pero antes de commitChanges. retry_counter disminuye cuando se llama a este método. Se generan entradas de registro.

bool needsRollback()

Determina si se requiere una reversión.

En los dispositivos que no son de punto de control, devuelve false. En los dispositivos con puntos de control, devuelve true durante un inicio sin punto de control.

Implementa la UDC

Implementación de referencia

Para ver un ejemplo de cómo se puede implementar la UDC, consulta dm-bow.c. Para obtener documentación adicional sobre la función, consulta dm-bow.txt.

Configuración

En on fs en tu archivo init.hardware.rc, asegúrate de tener lo siguiente:

mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --early

En on late-fs en tu archivo init.hardware.rc, asegúrate de tener lo siguiente:

mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late

En tu archivo fstab.hardware, asegúrate de que /data esté etiquetado como latemount.

/dev/block/bootdevice/by-name/userdata              /data              f2fs
noatime,nosuid,nodev,discard,reserve_root=32768,resgid=1065,fsync_mode=nobarrier
latemount,wait,check,fileencryption=ice,keydirectory=/metadata/vold/metadata_encryption,quota,formattable,sysfs_path=/sys/devices/platform/soc/1d84000.ufshc,reservedsize=128M,checkpoint=fs

Agrega una partición de metadatos

UDC requiere una partición de metadatos para almacenar el recuento de reintentos y las claves que no son del cargador de arranque. Configura una partición de metadatos y móntala de forma anticipada en /metadata.

En tu archivo fstab.hardware, asegúrate de que /metadata esté etiquetado como earlymount o first_stage_mount.

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

Inicializa la partición en ceros.

Agrega las siguientes líneas a BoardConfig.mk:

BOARD_USES_METADATA_PARTITION := true
BOARD_ROOT_EXTRA_FOLDERS := existing_folders metadata

Actualiza los sistemas

Sistemas F2FS

En el caso de los sistemas que usan F2FS para formatear datos, asegúrate de que tu versión de F2FS admita puntos de control. Para obtener más información, consulta Funcionalidad de puntos de control en diferentes sistemas de archivos.

Agrega la marca checkpoint=fs a la sección <fs_mgr_flags> de fstab para el dispositivo que se encuentra en /data.

Sistemas que no son F2FS

En los sistemas que no son F2FS, se debe habilitar dm-bow en la configuración del kernel.

Agrega la marca checkpoint=block a la sección <fs_mgr_flags> de fstab para el dispositivo que se encuentra en /data.

Verifica los registros

Las entradas de registro se generan cuando se llama a las APIs de Checkpoint.

Validación

Para probar tu implementación de UDC, ejecuta el conjunto de pruebas de VTS VtsKernelCheckpointTest.