- PVSM.RU - https://www.pvsm.ru -
Всем привет. В SberDevices наша команда занимается разработкой различных железок и прошивок для них на базе AOSP.
Начиная с Android 8 (у некоторых вендоров с 7.1) в системе появился новый механизм накатки OTA-обновлений, т. н. Seamless A/B OTA Updates — бесшовные обновления. В этом посте я опишу общие принципы его работы, рассмотрю механизм с точки зрения разработчика, а также проведу сравнение со старым (будем его называть recovery-based) подходом применения обновлений. Всё нижесказанное будет справедливо только для чистого AOSP, т. к. конкретная реализация зависит от вендора.
Обновления для Android поставляются в виде zip-архива с образами обновляемых разделов (block-based updates). Во времена KitKat это был просто набор файлов, которые копировались на устройство прилагаемым скриптом. Я не стану подробно останавливаться на этом режиме [1], кратко опишу основные принципы его работы:
Какие минусы в данной схеме?
Эти неудобства позволяет обойти способ бесшовного обновления. Давайте посмотрим, как он устроен.
Ключевые компоненты и механизмы, необходимые для реализации бесшовных A/B-обновлений [2]:
Основным принципом работы A/B OTA является слотирование. Все разделы, которые необходимо обновлять (это могут быть любые разделы, а не только системные), должны находиться в двух копиях или, иначе, в слотах. В Android-реализации поддерживается 2 слота, которые именуются соответственно A и B. Система загружается и работает из текущего слота, второй используется только в момент обновления. К имени раздела добавляется суффикс с именем слота.
Ниже приведена таблица сравнения двух вариантов организации разделов на устройстве.
[3]
Все слотируемые разделы помечаются опцией монтирования slotselect, чтобы система могла выбрать правильный слот. В зависимости от того, где они описаны, это может быть fstab либо dts.
На первый взгляд кажется, что такая схема не оптимальна, т. к. под систему необходимо выделить в два раза больше места. Но ведь мы избавились от /cache, а значит уже сэкономили большое количество памяти. Таким образом, система будет занимать немного больше, чем в варианте с recovery.
Главным достоинством A/B-обновлений является возможность стриминга прошивки. Именно она обеспечивает бесшовность и прозрачность обновлений для пользователя: для обновления устройству достаточно перезагрузиться в новый слот. В этом режиме нет необходимости заранее скачивать zip-архив, занимая место в /data. Вместо этого система сразу пишет блоки данных из специально подготовленного файла (payload, см. ниже) в каждый раздел неактивного слота. С точки зрения реализации нет разницы, скачиваем ли мы предварительно обновление либо сразу стримим его в слот.
Слоты имеют следующие состояния:
Оба слота могут быть bootable и successful, но только один — active.
Алгоритм работы загрузчика при выборе слота:
[5]
Изменение состояний слотов во время обновления:
[6]
Для поддержки A/B-обновлений вендор должен реализовать специальный HAL-интерфейс — boot_control [7]. Он позволяет изменять состояния слотов и получать о них информацию. Для внешней работы (например, через adb shell) используется утилита – bootctl [8]. Интерфейс используется как средство взаимодействия между ОС и загрузчиком.
Основной компонент [9] всей A/B-схемы. Занимается загрузкой, стримингом обновлений, проверкой подписи и многим другим. Изменяет состояния слотов через boot_control. Позволяет контролировать процесс обновления устройства: приостанавливать, возобновлять, отменять.
Компонент пришёл в Android из ChromeOS, где уже используется некоторое время. AOSP поддерживает update_engine в виде статической sideload-сборки. Именно она используется в recovery, т.к данный режим не поддерживает динамическую линковку.
Процесс работы данного компонента можно разделить на следующие шаги:
Структура пакета обновления:
2009-01-01 00:00:00 ..... 360 360 META-INF/com/android/metadata
2009-01-01 00:00:00 ..... 107 107 care_map.txt
2009-01-01 00:00:00 ..... 384690699 384690699 payload.bin
2009-01-01 00:00:00 ..... 154 154 payload_properties.txt
2009-01-01 00:00:00 ..... 1675 943 META-INF/com/android/otacert
Клиент для управления демоном update_engine. Может напрямую вызываться вендором для применения обновления.
Утилита для проверки целостности системы при первом запуске (слот с флагом active, но еще не successful). Контроль целостности реализуется с помощью модуля ядра dm-verity [10]. Если проверка закончилась успешно, утилита помечает текущий слот как successful. Иначе система перезагружается в старый слот. Верифицируются только блоки, указанные в файле care_map.txt.
Для реализации vendor-сервисов обновлений существует Java API [11]. Также имеется пример реализации [12] такого сервиса.
Рассмотрим пример сборки A/B update в AOSP. Для этого отредактируем Makefile целевой платформы:
#Включим поддержку A/B
AB_OTA_UPDATER := true
#Укажем необходимые разделы для слотирования:
AB_OTA_PARTITIONS := boot system vendor
#Добавим необходимые пакеты
PRODUCT_PACKAGES := update_engine update_engine_client update_verifier
#Отключим раздел recovery
TARGET_NO_RECOVERY := true
#Убедимся, что НЕ определяются переменные для раздела cache:
#BOARD_CACHEIMAGE_PARTITION_SIZE := ...
#BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ...
После вызова make otapackage получаем zip-архив с обновлением. В таком виде он уже подходит для sideload-режима. Можем выполнить перезагрузку в recovery и вызвать adb sideload ota.zip. Этот способ удобен для отладки.
Применение обновления изнутри рабочей системы обычно определяется вендором. Самый простой способ — выложить payload.bin на http-сервер и напрямую вызвать update_engine_client.
Пример вызова:
update_engine_client
--payload=http://path/to/payload.bin
--update
--headers="
FILE_HASH=ozGgyQEddkI5Zax+Wbjo6I/PCR8PEZka9gGd0nWa+oY=
FILE_SIZE=282344983
METADATA_HASH=GLIKfE6KRwylWMHsNadG/Q8iy5f786WTatvMdBlpOPg=
METADATA_SIZE=26723"
В параметр headers передается содержимое файла payload_properties.txt. В logcat можно наблюдать прогресс обновления. Если передать ключ --follow, прогресс будет дублироваться в stdout.
Плюсы нового механизма обновлений очевидны:
Из минусов я бы выделил два момента:
И все же, на мой взгляд, плюсы перевешивают. Кстати, в нашем недавно анонсированном устройстве [13] мы используем A/B OTA обновления.
Автор: Меняев Константин
Источник [14]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android/357405
Ссылки в тексте:
[1] этом режиме: https://source.android.com/devices/tech/ota/nonab
[2] бесшовных A/B-обновлений: https://source.android.com/devices/tech/ota/ab
[3] Image: https://habrastorage.org/webt/0h/5o/fz/0h5ofzon-7tbjo-yu09aiwzimpc.png
[4] rescue party: https://source.android.com/devices/tech/debug/rescue-party
[5] Image: https://habrastorage.org/webt/8u/q4/9x/8uq49xpfsieqyjpebw96yxwigfq.png
[6] Image: https://habrastorage.org/webt/-r/7s/4u/-r7s4ucdozhivxpw9jkv-sjyqcm.png
[7] boot_control: https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/boot_control.h
[8] bootctl: https://android.googlesource.com/platform/system/extras/+/master/bootctl/
[9] компонент: https://android.googlesource.com/platform/system/update_engine/
[10] dm-verity: https://source.android.com/security/verifiedboot/dm-verity
[11] Java API: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/UpdateEngine.java
[12] пример реализации: https://android.googlesource.com/platform/packages/apps/Car/SystemUpdater/+/refs/heads/master
[13] устройстве: https://www.sber.ru/salute/sberportal
[14] Источник: https://habr.com/ru/post/521036/?utm_source=habrahabr&utm_medium=rss&utm_campaign=521036
Нажмите здесь для печати.