В Android 10 добавлена контрольная точка пользовательских данных (UDC), которая позволяет откатить систему до предыдущего состояния, если обновление по беспроводной сети (OTA) завершилось неудачно. Если беспроводное обновление Android не удается, UDC позволяет безопасно откатить устройство к предыдущему состоянию. Хотя A/B-обновления решают эту проблему для ранней загрузки, откат не поддерживается, если раздел пользовательских данных (подключенный к /data) изменен.
UDC позволяет устройству восстанавливать раздел с данными пользователя даже после того, как он был изменен. Функция UDC реализует это с помощью контрольных точек в файловой системе, альтернативной реализации, если файловая система не поддерживает контрольные точки, интеграции с механизмом A/B загрузчика, а также поддержки обновлений, не относящихся к A/B, привязки версии ключа и предотвращения отката ключа.
Последствия для пользователя
Благодаря UDC меньше пользователей теряют данные, если беспроводное обновление не удается. Это может уменьшить количество обращений в службу поддержки от пользователей, у которых возникли проблемы в процессе обновления. Однако при сбое обновления по беспроводной сети пользователи могут заметить, что устройство перезагружается несколько раз.
Принцип работы
Функциональность контрольных точек в разных файловых системах
Для файловой системы F2FS UDC добавляет функцию контрольной точки в ядро Linux 4.20 и переносит ее во все распространенные ядра, поддерживаемые устройствами с Android 10.
Для других файловых систем UDC использует виртуальное устройство сопоставления устройств под названием dm_bow для функции контрольной точки. dm_bow находится между устройством и файловой системой. Когда раздел подключен, выполняется команда TRIM, в результате чего файловая система отправляет команды TRIM для всех свободных блоков. dm_bow перехватывает эти обрезки и использует их для создания бесплатного списка блокировки. Затем операции чтения и записи отправляются на устройство без изменений, но перед разрешением записи данные, необходимые для восстановления, копируются в свободный блок.
Процесс проверки
Когда раздел с флагом checkpoint=fs/block смонтирован, Android вызывает restoreCheckpoint на диске, чтобы устройство могло восстановить текущую контрольную точку. Затем init вызывает функцию needsCheckpoint, чтобы определить, находится ли устройство в состоянии загрузчика A/B или задано ли количество повторных попыток обновления. Если хотя бы одно из этих условий выполняется, Android вызывает createCheckpoint, чтобы добавить флаги монтирования или создать устройство dm_bow.
После монтирования раздела вызывается код контрольной точки для выдачи усечений.
Затем процесс загрузки продолжится в обычном режиме. В точке LOCKED_BOOT_COMPLETE ОС Android вызывает функцию commitCheckpoint, чтобы зафиксировать текущую контрольную точку, и обновление продолжается в обычном режиме.
Управление ключами KeyMint (ранее – Keymaster)
Ключи KeyMint используются для шифрования устройства или других целей. Чтобы управлять этими ключами, Android задерживает вызовы удаления ключей до фиксации контрольной точки.
Как следить за здоровьем
Демон проверки работоспособности проверяет, достаточно ли места на диске для создания контрольной точки. Демон здоровья находится в
cp_healthDaemon
в Checkpoint.cpp.
У демона состояния есть следующие настраиваемые функции:
ro.sys.cp_msleeptime: управляет тем, как часто устройство проверяет использование диска.ro.sys.cp_min_free_bytes: Управляет минимальным значением, которое ищет демон здоровья.ro.sys.cp_commit_on_full: Указывает, перезагружает ли демон состояния устройство или сохраняет контрольную точку и продолжает работу, когда диск заполнен.
API контрольных точек
Функция UDC использует API контрольных точек. Информацию о других API, используемых UDC, можно найти в IVold.aidl.
void startCheckpoint(int retry)
Создает контрольную точку.
Фреймворк вызывает этот метод, когда готов начать обновление. Контрольная точка создается до того, как файловые системы, для которых создаются контрольные точки, например userdata, будут смонтированы в режиме чтения и записи после перезагрузки. Если количество повторных попыток положительное, API обрабатывает повторные попытки отслеживания, а программа обновления вызывает needsRollback, чтобы проверить, требуется ли откат обновления. Если количество повторных попыток равно -1, API полагается на решение загрузчика A/B.
Этот метод не вызывается при обычном A/B-обновлении.
void commitChanges()
Применяет изменения.
Фреймворк вызывает этот метод после перезагрузки, когда изменения готовы к фиксации. Этот метод вызывается до того, как данные (например, изображения, видео, SMS, подтверждение получения от сервера) записываются в раздел userdata и до вызова BootComplete.
Если активное обновление с контрольной точкой отсутствует, этот метод не действует.
abortChanges()
Принудительно перезагружает устройство и возвращает его к контрольной точке. Отменяет все изменения пользовательских данных, внесенные с момента первой перезагрузки.
Платформа вызывает этот метод после перезагрузки, но до commitChanges.
retry_counter уменьшается при вызове этого метода. Создаются записи в журнале.
bool needsRollback()
Определяет, требуется ли откат.
На устройствах, не поддерживающих контрольные точки, возвращает значение false. На устройствах с контрольными точками возвращает значение true
во время запуска без контрольной точки.
Как реализовать сбор данных, предоставленных пользователями
Пример реализации
Пример реализации пользовательских данных конфигурации можно найти на странице dm-bow.c.
Дополнительную информацию об этой функции можно найти в dm-bow.txt.
Настроить
В разделе on fs файла init.hardware.rc убедитесь, что у вас есть:
mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --early
В разделе on late-fs файла init.hardware.rc убедитесь, что у вас есть:
mount_all /vendor/etc/fstab.${ro.boot.hardware.platform} --late
В файле fstab.hardware убедитесь, что /data помечен как 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
Добавить сегмент метаданных
Для UDC требуется раздел метаданных, в котором будут храниться ключи и количество попыток, не связанных с загрузчиком. Настройте раздел метаданных и смонтируйте его на раннем этапе в /metadata.
В файле fstab.hardware убедитесь, что /metadata помечен как earlymount или first_stage_mount.
/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount
Инициализируйте раздел, заполнив его нулями.
Добавьте в файл BoardConfig.mk следующие строки:
BOARD_USES_METADATA_PARTITION := true BOARD_ROOT_EXTRA_FOLDERS := existing_folders metadata
Обновление систем
Системы F2FS
Если для форматирования данных используется F2FS, убедитесь, что ваша версия F2FS поддерживает контрольные точки. Подробнее о контрольных точках в разных файловых системах…
Добавьте флаг checkpoint=fs в раздел <fs_mgr_flags> файла fstab для устройства, смонтированного в /data.
Системы, не использующие F2FS
В системах, отличных от F2FS, dm-bow необходимо включить в конфигурации ядра.
Добавьте флаг checkpoint=block в раздел <fs_mgr_flags> файла fstab для устройства, смонтированного в /data.
Проверьте журналы
Записи в журнале создаются при вызове API контрольных точек.
Проверка
Чтобы проверить реализацию UDC, запустите набор тестов VTS VtsKernelCheckpointTest.