Производители оригинального оборудования (OEM) и поставщики SoC, желающие внедрить A/B-обновления системы, должны убедиться, что их загрузчик реализует HAL boot_control и передает правильные параметры ядру.
Реализуйте HAL управления загрузкой.
Загрузчики с поддержкой A/B должны реализовывать HAL boot_control расположенный в файле hardware/libhardware/include/hardware/boot_control.h . Проверить реализацию можно с помощью утилиты system/extras/bootctl и system/extras/tests/bootloader/ .
Вам также необходимо реализовать конечный автомат, показанный ниже:

Настройте ядро
Для внедрения A/B-тестирования обновлений системы:
- При необходимости выберите следующую серию патчей ядра:
- Если загрузка осуществляется без ramdisk и используется режим "загрузка в режиме восстановления", выберите соответствующий пункт в списке возможных вариантов: android-review.googlesource.com/#/c/158491/ .
- Чтобы настроить dm-verity без ramdisk, выполните cherrypick android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18 .
- Убедитесь, что аргументы командной строки ядра содержат следующие дополнительные параметры:
...где значениеskip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"<public-key-id>— это идентификатор открытого ключа, используемого для проверки подписи таблицы достоверности (подробнее см. dm-verity ). - Добавьте сертификат .X509, содержащий открытый ключ, в системное хранилище ключей:
- Скопируйте сертификат .X509 в формате
.derв корневой каталогkernel. Если сертификат .X509 имеет формат.pem, используйте следующую командуopensslдля преобразования из формата.pemв формат.der:openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
- Создайте
zImage, включив сертификат в состав системного связки ключей. Для проверки проверьте записьprocfs(требуется включитьKEYS_CONFIG_DEBUG_PROC_KEYS): Успешное включение сертификата .X509 указывает на наличие открытого ключа в системном хранилище ключей (выделено идентификатором открытого ключа).angler:/# cat /proc/keys 1c8a217e I------ 1 perm 1f010000 0 0 asymmetri Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f [] 2d454e3e I------ 1 perm 1f030000 0 0 keyring .system_keyring: 1/4
- Замените пробел на
#и передайте его как<public-key-id>в командной строке ядра. Например, вместо<public-key-id>передайтеAndroid:#7e4333f9bba00adfe0ede979e28ed1920492b40f.
- Скопируйте сертификат .X509 в формате
Задайте переменные сборки
Загрузчики с поддержкой A/B-тестирования должны соответствовать следующим критериям переменных сборки:
| Необходимо определить целевую группу A/B. |
/device/google/marlin/+/android-7.1.0_r1/device-common.mk . При желании вы можете выполнить шаг dex2oat после установки (но до перезагрузки), описанный в разделе «Компиляция» . |
|---|---|
| Настоятельно рекомендуется для A/B-тестирования. |
|
| Невозможно задать целевую группу для A/B-тестирования. |
|
| Необязательно для отладочных сборок | PRODUCT_PACKAGES_DEBUG += update_engine_client |
Задать разделы (слоты)
Устройствам A/B не требуется раздел восстановления или раздел кэша, поскольку Android больше не использует эти разделы. Раздел данных теперь используется для загруженного OTA-пакета, а код образа восстановления находится в загрузочном разделе. Все разделы, используемые в режиме A/B, должны быть названы следующим образом (слоты всегда называются a , b и т. д.): boot_a , boot_b , system_a , system_b , vendor_a , vendor_b .
Кэш
Для обновлений, не использующих A/B-тестирование, раздел кэша использовался для хранения загруженных OTA-пакетов и для временного сохранения блоков во время применения обновлений. Оптимального размера раздела кэша не существовало: его размер зависел от того, какие обновления вы хотели применить. В худшем случае размер раздела кэша соответствовал размеру образа системы. При A/B-обновлениях нет необходимости сохранять блоки (поскольку запись всегда происходит в раздел, который в данный момент не используется), а при потоковой A/B-обновлениях нет необходимости загружать весь OTA-пакет перед его применением.
Восстановление
Теперь диск восстановления в оперативной памяти находится в файле boot.img . При переходе в режим восстановления загрузчик не может добавить параметр skip_initramfs в командную строку ядра.
Для обновлений, отличных от A/B, раздел восстановления содержит код, используемый для применения обновлений. Обновления A/B применяются движком update_engine работающим в обычном загруженном образе системы. Режим восстановления по-прежнему используется для сброса заводских настроек и загрузки пакетов обновлений (отсюда и название «восстановление»). Код и данные для режима восстановления хранятся в обычном загрузочном разделе в оперативной памяти (ramdisk); для загрузки образа системы загрузчик указывает ядру пропустить ramdisk (в противном случае устройство загружается в режим восстановления). Режим восстановления небольшой (и большая его часть уже находилась в загрузочном разделе), поэтому размер загрузочного раздела не увеличивается.
Фстаб
Аргумент slotselect должен находиться в строке, предназначенной для A/B-разделов. Например:
<path-to-block-device>/vendor /vendor ext4 ro wait,verify=<path-to-block-device>/metadata,slotselect
Разделу с именем vendor не следует присваивать имя. Вместо этого будет выбран раздел vendor_a или vendor_b , который будет смонтирован в точке монтирования /vendor .
Аргументы слота ядра
Текущий суффикс слота должен передаваться либо через конкретный узел дерева устройств (DT) ( /firmware/android/slot_suffix ), либо через командную строку ядра androidboot.slot_suffix или аргумент bootconfig.
По умолчанию fastboot прошивает текущий слот на устройстве A/B. Если пакет обновления также содержит образы для другого, не текущего слота, fastboot прошивает и эти образы. Доступные параметры:
-
--slot SLOT. Переопределяет поведение по умолчанию и предлагает fastboot выполнить прошивку слота, переданного в качестве аргумента. -
--set-active [ SLOT ]. Устанавливает слот в качестве активного. Если не указан необязательный аргумент, то активным устанавливается текущий слот. -
fastboot --help. Получить подробную информацию о командах.
Если загрузчик реализует fastboot, он должен поддерживать команду set_active <slot> , которая устанавливает текущий активный слот на заданный слот (это также должно сбросить флаг невозможности загрузки для этого слота и установить счетчик повторных попыток на значения по умолчанию). Загрузчик также должен поддерживать следующие переменные:
-
has-slot:<partition-base-name-without-suffix>. Возвращает «yes», если указанный раздел поддерживает слоты, «no» в противном случае. -
current-slot. Возвращает суффикс слота, с которого будет выполнена следующая загрузка. -
slot-count. Возвращает целое число, представляющее количество доступных слотов. В настоящее время поддерживаются два слота, поэтому это значение равно2. -
slot-successful:<slot-suffix>. Возвращает "yes", если указанный слот помечен как успешно загруженный, "no" в противном случае. -
slot-unbootable:<slot-suffix>. Возвращает «yes», если данный слот помечен как незагружаемый, и «no» в противном случае. -
slot-retry-count:<slot-suffix>. Количество оставшихся попыток загрузки указанного слота.
Чтобы просмотреть все переменные, выполните команду fastboot getvar all .
Создание OTA-пакетов
Инструменты для создания OTA-пакетов используют те же команды, что и команды для устройств, не поддерживающих протокол A/B. Файл target_files.zip необходимо сгенерировать, определив переменные сборки для целевого устройства A/B. Инструменты для создания OTA-пакетов автоматически идентифицируют и генерируют пакеты в формате, подходящем для обновления A/B.
Примеры:
- Для генерации полного обновления OTA:
./build/make/tools/releasetools/ota_from_target_files \ dist_output/tardis-target_files.zip \ ota_update.zip - Для создания инкрементального обновления OTA:
./build/make/tools/releasetools/ota_from_target_files \ -i PREVIOUS-tardis-target_files.zip \ dist_output/tardis-target_files.zip \ incremental_ota_update.zip
Настройка разделов
Функция update_engine может обновлять любую пару разделов A/B, определенных на одном диске. Пара разделов имеет общий префикс (например, system или boot ) и суффикс для каждого слота (например, _a ). Список разделов, для которых генератор полезной нагрузки определяет обновление, настраивается переменной make AB_OTA_PARTITIONS .
Например, если включены пара разделов bootloader_a и booloader_b ( _a и _b — суффиксы слотов), вы можете обновить эти разделы, указав следующее в конфигурации продукта или платы:
AB_OTA_PARTITIONS := \ boot \ system \ bootloader
Все разделы, обновляемые функцией update_engine не должны изменяться остальной частью системы. Во время инкрементальных или дельта- обновлений двоичные данные из текущего слота используются для генерации данных в новом слоте. Любое изменение может привести к тому, что данные нового слота не пройдут проверку в процессе обновления, и, следовательно, обновление завершится неудачей.
Настройка после установки
Для каждого обновленного раздела можно настроить этап postinstall по-разному, используя набор пар ключ-значение. Чтобы запустить программу, расположенную по адресу /system/usr/bin/postinst в новом образе, укажите путь относительно корня файловой системы в системном разделе.
Например, usr/bin/postinst — это system/usr/bin/postinst (если не используется RAM-диск). Дополнительно укажите тип файловой системы, который будет передан системному вызову mount(2) . Добавьте следующее в файлы .mk продукта или устройства (если применимо):
AB_OTA_POSTINSTALL_CONFIG += \ RUN_POSTINSTALL_system=true \ POSTINSTALL_PATH_system=usr/bin/postinst \ FILESYSTEM_TYPE_system=ext4
Компиляция приложений
Приложения можно компилировать в фоновом режиме перед перезагрузкой с новым образом системы. Для компиляции приложений в фоновом режиме добавьте следующее в конфигурацию устройства продукта (в файл device.mk продукта):
- Включите в сборку нативные компоненты, чтобы гарантировать компиляцию скрипта компиляции и бинарных файлов, а также их включение в образ системы.
# A/B OTA dexopt package PRODUCT_PACKAGES += otapreopt_script
- Подключите скрипт компиляции к
update_engineтаким образом, чтобы он запускался в качестве шага после установки.# A/B OTA dexopt update_engine hookup AB_OTA_POSTINSTALL_CONFIG += \ RUN_POSTINSTALL_system=true \ POSTINSTALL_PATH_system=system/bin/otapreopt_script \ FILESYSTEM_TYPE_system=ext4 \ POSTINSTALL_OPTIONAL_system=true
Для получения помощи по установке предварительно настроенных файлов во второй неиспользуемый системный раздел обратитесь к разделу «Установка файлов DEX_PREOPT при первой загрузке» .