Русский
Русский
English
Статистика
Реклама

Бесшовные AB-обновления в Android как они устроены

image

Всем привет.

В SberDevices наша команда занимается разработкой различных железок прошивок и для них на базе AOSP.

Начиная с Android 8 (у некоторых вендоров с 7.1) в системе появился новый механизм накатки OTA-обновлений, т. н. Seamless A/B OTA Updates бесшовные обновления. В этом посте я опишу общие принципы его работы, рассмотрю механизм с точки зрения разработчика, а также проведу сравнение со старым (будем его называть recovery-based) подходом применения обновлений. Всё нижесказанное будет справедливо только для чистого AOSP, т. к. конкретная реализация зависит от вендора.

Recovery-based OTA


Обновления для Android поставляются в виде zip-архива с образами обновляемых разделов (block-based updates). Во времена KitKat это был просто набор файлов, которые копировались на устройство прилагаемым скриптом. Я не стану подробно останавливаться на этом режиме, кратко опишу основные принципы его работы:

  • zip-архив скачивается системой на устройство;
  • система перезагружается в режим recovery;
  • проверяется совместимость обновления с устройством, его подпись;
  • если всё OK, выполняется updater-script из zip-архива;
  • в процессе обновления устройство может несколько раз перезагрузиться (например, для обновления device tree);
  • если всё прошло успешно, загружаемся в новую прошивку.

Какие минусы в данной схеме?

  • Необходимость резервировать достаточное количество встроенной памяти для OTA-архива. Для этого служит раздел /cache. Некоторые вендоры используют /data, но это редкость. В итоге пользователю остаётся меньше места (да, приложения всё ещё могут использовать место в разделе /cache, но с некоторыми ограничениями).
  • Перезагрузка и применение обновления занимает время, что может быть критично для некоторых видов устройств, например, для Smart TV.
  • Прерывание процесса обновления может привести к boot loop.
  • Нет возможности откатиться на старую версию прошивки.

Эти неудобства позволяет обойти способ бесшовного обновления. Давайте посмотрим, как он устроен.

Seamless A/B OTA


Ключевые компоненты и механизмы, необходимые для реализации бесшовных A/B-обновлений:

  • слотовая разметка флеш-памяти;
  • взаимодействие с загрузчиком, управлениесостоянием слотов;
  • системный демон update_engine;
  • генерация zip-архива с обновлением. В рамках данной статьи этот аспект рассматриваться не будет.

Слотирование


Основным принципом работы A/B OTA являетсяслотирование.Все разделы, которые необходимо обновлять (это могут быть любые разделы, а не только системные),должны находиться в двух копиях или, иначе, в слотах. В Android-реализации поддерживается 2 слота,которыеименуются соответственно A и B. Система загружается и работает изтекущего слота, второй используется только в момент обновления.К имени раздела добавляется суффикс с именем слота.

Ниже приведена таблица сравнения двух вариантов организации разделов на устройстве.
image

Все слотируемые разделыпомечаютсяопциеймонтированияslotselect, чтобы системамоглавыбратьправильный слот.В зависимости от того, где они описаны, это может быть fstab либо dts.

Изменения в таблице разделов


  • В /сache большенет необходимости.Теперьобновлениеможет сохраняться либов /data,либосразупрошиваться внеактивныйслот(обэтом ниже).
  • Раздел recovery также больше не используется.Однакорежимrecoveryвсё ещё существует, оннеобходим, например, для сброса устройства на заводские настройки (к этому может привестиrescueparty). Или для т. н. ручного обновления (sideload) через adb.Recovery ramdiskтеперьлежит внутриboot-раздела,ядро общее.
  • Для переключения режима загрузки (android/recovery) появилась новая опция в cmdline skip_initramfs.

На первый взгляд кажется, что такая схема не оптимальна, т. к. под систему необходимо выделить в два раза больше места. Но ведь мы избавились от/cache,а значит уже сэкономили большое количествопамяти. Таким образом,система будет заниматьнемногобольше, чем в варианте с recovery.

Главным достоинством A/B-обновлений является возможностьстриминга прошивки. Именно она обеспечивает бесшовность и прозрачность обновлений для пользователя: для обновления устройству достаточно перезагрузиться в новый слот. В этом режиме нет необходимости заранее скачивать zip-архив, занимая место в /data. Вместо этого система сразу пишет блоки данных из специально подготовленного файла (payload, см. ниже) в каждый разделнеактивногослота. С точки зрения реализации нет разницы, скачиваем ли мы предварительно обновление либо сразу стримим его в слот.

Слоты имеют следующие состояния:

  • active активный слот, из него будет загружена система при следующей перезагрузке;
  • bootable обновление успешно прошито в слот, прошло валидацию, совпали хеш-суммы и т. д.;
  • successful система смогла успешно загрузиться в новый слот;
  • unbootable слот поврежден. Система всегда помечает слот как unbootable перед началом процесса обновления.

Оба слота могут бытьbootableиsuccessful, но только один active.

Алгоритм работы загрузчика при выборе слота:
image
  • Загрузчик определяет, что имеется один или более слотов с флагомbootable.
  • Из них выбирается активный слот (либо слот с наибольшим приоритетом).
  • Если система загрузилась успешно, слот помечается какsuccessfulиactive.
  • Иначе слот помечается как unbootable и система перезагружается.


Изменение состояний слотов во время обновления:
image

Необходимые компоненты для работы с Seamless A/B.


boot_control


Для поддержки A/B-обновлений вендор должен реализовать специальный HAL-интерфейс boot_control. Он позволяет изменять состояния слотов и получать о них информацию. Для внешней работы (например, через adb shell) используется утилита bootctl. Интерфейс используется как средство взаимодействия между ОС и загрузчиком.

update_engine


Основной компонент всей A/B-схемы. Занимается загрузкой, стримингом обновлений, проверкой подписи и многим другим. Изменяет состояния слотов через boot_control. Позволяет контролировать процесс обновления устройства: приостанавливать, возобновлять, отменять.
Компонент пришёл в Android из ChromeOS, где уже используется некоторое время.AOSP поддерживает update_engine в виде статической sideload-сборки. Именно она используется в recovery, т.к данный режим не поддерживает динамическую линковку.

Процесс работы данного компонента можно разделить на следующие шаги:

  • загрузка обновления в слот. Загружать можно как из предварительно скачанного пакета с обновлением, так и напрямую по Сети через http/https. В процессе загрузки проверяется подпись, открытый ключ уже находится на устройстве (/system/etc/update_engine/update-payload-key.pub.pem);
  • верификация загруженного обновления и сравнение хеш-сумм;
  • выполнение post-install скриптов.

Структура пакета обновления:
2009-01-01 00:00:00 .....          360          360  META-INF/com/android/metadata2009-01-01 00:00:00 .....          107          107  care_map.txt2009-01-01 00:00:00 .....    384690699    384690699  payload.bin2009-01-01 00:00:00 .....          154          154  payload_properties.txt2009-01-01 00:00:00 .....         1675          943  META-INF/com/android/otacert

  • care_map.txt используется update_verifier-ом (см. ниже);
  • payload_properties.txt содержит хеши и размеры данных внутри payload;
  • payload.bin пакет обновления, содержит блоки всех разделов, метаданные, подпись.


update_engine_client


Клиент для управления демоном update_engine. Может напрямую вызываться вендором для применения обновления.

update_verifier


Утилита для проверки целостности системы при первом запуске (слот с флагомactive, но еще неsuccessful). Контроль целостности реализуется с помощью модуля ядра dm-verity. Если проверка закончилась успешно, утилита помечает текущий слот какsuccessful. Иначе система перезагружается в старый слот. Верифицируются только блоки, указанные в файле care_map.txt.

UpdateEngineApi


Для реализации vendor-сервисов обновлений существует Java API. Также имеется пример реализации такого сервиса.

Рассмотрим пример сборки A/B update в AOSP. Для этого отредактируем Makefile целевой платформы:
#Включим поддержку A/BAB_OTA_UPDATER := true#Укажем необходимые разделы для слотирования:AB_OTA_PARTITIONS := boot system vendor#Добавим необходимые пакетыPRODUCT_PACKAGES := update_engine update_engine_client update_verifier#Отключим раздел recoveryTARGET_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.

Заключение


Плюсы нового механизма обновлений очевидны:
  • обновление системы происходит в фоне, не прерывая работу пользователя. Да, всё так же потребуется перезагрузка (в новый слот), но пройдёт оназначительнобыстрее, чем перезагрузка в recovery для применения обновления;
  • минимизируется вероятность boot loop (от ошибок в реализации никто не застрахован). Процесс обновления можно прерывать, наактивныйслот это никак не повлияет;
  • появляется возможность отката на предыдущую версию прошивки. Даже если по каким-то причинам обновление прошло неуспешно, система простовернётся к старой версии;
  • благодаря стримингу устройство обновится быстрее;
  • в зависимости от реализации можно полностью исключить пользователя из процесса обновления.

Из минусов я бы выделил два момента:
  • A/B OTA становится зависимой от текущей разметки диска, т. к. обновление происходит во время работы системы. Т. е. становится невозможно накатить обновление с изменёнными разделами;
  • относительная сложность реализации.

И все же, на мой взгляд, плюсы перевешивают. Кстати, в нашем недавно анонсированном устройстве мы используем A/B OTA обновления.
Источник: habr.com
К списку статей
Опубликовано: 29.09.2020 10:08:21
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Блог компании sberdevices

Блог компании сбер

Разработка под android

Android

Aosp

Ota

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru