Android 10 presenta el punto de control de datos del usuario (UDC), que permite a Android revertir a su estado anterior cuando falla una actualización inalámbrica (OTA) de Android. Con el UDC, si falla una actualización OTA de Android, el dispositivo puede revertir de forma segura a su estado anterior. Aunque las actualizaciones A/B resuelven este problema para el inicio anticipado, la reversión no se admite cuando se modifica la partición de datos del usuario (activada en /data
).
UDC permite que el dispositivo revierta la partición de datos del usuario incluso después de haberse modificado. La función UDC logra esto con capacidades de punto 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 A/B del bootloader y admite 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 la actualización inalámbrica para los usuarios, ya que menos usuarios pierden sus datos cuando falla una actualización inalámbrica. Esto puede reducir la cantidad de llamadas de asistencia de los usuarios que tienen problemas durante el proceso de actualización. Sin embargo, cuando falla una actualización inalámbrica, es posible que los usuarios noten que el dispositivo se reinicia varias veces.
Cómo funciona
Función de punto de control en diferentes sistemas de archivos
En el caso del sistema de archivos F2FS, la UDC agrega la función de punto de control al kernel de Linux 4.20 upstream y lo lleva a versiones anteriores para todos los kernels comunes compatibles con dispositivos que ejecutan Android 10.
Para otros sistemas de archivos, la UDC usa un dispositivo virtual del asignador de dispositivos llamado dm_bow
para la funcionalidad de punto de control. dm_bow
se encuentra entre el dispositivo y el sistema de archivos. Cuando se activa una partición, se emite un recorte que hace que el sistema de archivos emita comandos de recorte en todos los bloques libres. dm_bow
intercepta estos recortes y los usa para configurar una lista de bloqueo gratuito. Luego, las operaciones de lectura y escritura se envían al dispositivo sin modificaciones, pero antes de que se permita una operación de 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 alguno es verdadero, Android llama a createCheckpoint
para agregar marcas de activación o compilar un dispositivo dm_bow
.
Después de activar la partición, se llama al código de punto de control para emitir recortes.
Luego, el proceso de inicio continúa como de costumbre. En LOCKED_BOOT_COMPLETE
, Android llama a commitCheckpoint
para confirmar el punto de control actual y la actualización continúa como de costumbre.
Administra las claves de Keymaster
Las claves de Keymaster se usan para la encriptación del dispositivo y otros fines. Para administrar estas claves, Android retrasa las llamadas de eliminación de claves hasta que se confirme el punto de control.
Supervisa el estado
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:
ro.sys.cp_msleeptime
: Controla la frecuencia con la que el dispositivo verifica el uso del disco.ro.sys.cp_min_free_bytes
: Controla el valor mínimo que busca el daemon de estado.ro.sys.cp_commit_on_full
: Controla si el daemon de estado reinicia el dispositivo o confirma el punto de control y continúa cuando el disco está lleno.
API de punto de control
La función de UDC usa las APIs de punto de control. Para ver otras APIs que usa la UDC, consulta IVold.aidl
.
void startCheckpoint(reintento)
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 punto de control, como userdata, se activen en modo 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 aplaza el juicio del bootloader A/B.
No se llama a este método cuando se realiza una actualización A/B normal.
void commitChanges()
Confirma los cambios.
El framework llama a este método después del reinicio, cuando los cambios están listos para confirmarse. Se llama a esta función antes de que los datos (como imágenes, videos, SMS y recibos de recepción del servidor) se escriban en userdata y antes de BootComplete
.
Si no existe una actualización activa con punto de control, este método no tendrá efecto.
abortChanges()
Fuerza el reinicio y vuelve al punto de control. Abandona todas las modificaciones de userdata 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 needRollback()
Determina si se requiere una reversión.
En dispositivos que no son de punto de control, muestra false
. En los dispositivos de punto de control, muestra 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 UDC, consulta dm-bow.c. Para obtener documentación adicional sobre la función, consulta dm-bow.txt.
Configuración
En on fs
de 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
de tu archivo init.hardware.rc
, asegúrate de tener lo siguiente:
mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late
En el 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
Cómo agregar una partición de metadatos
La UDC requiere una partición de metadatos para almacenar el recuento de reintentos y las claves que no son del bootloader. Configura una partición de metadatos y actívala anticipadamente en /metadata
.
En el 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 con todos los 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 la 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 activado en /data
.
Sistemas que no son F2FS
Para los sistemas que no son F2FS, dm-bow
debe estar habilitado en la configuración del kernel.
Agrega la marca checkpoint=block
a la sección <fs_mgr_flags>
de fstab para el dispositivo activado 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 la UDC, ejecuta el conjunto de pruebas de VTS de VtsKernelCheckpointTest
.