OEM и поставщики процессоров, которые хотят реализовать обновления системы 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 и используется параметр "boot as recovery", выберите android-review.googlesource.com/#/c/158491/.
- Чтобы настроить dm-verity без ramdisk, выберите 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>– это идентификатор открытого ключа, который используется для проверки подписи таблицы verity (подробнее о dm-verity…). -
Добавьте сертификат X .509, содержащий открытый ключ, в системную связку ключей:
-
Скопируйте сертификат X .509 в формате
.derв корневой каталогkernel. Если сертификат X .509 имеет формат.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.
-
Скопируйте сертификат X .509 в формате
Как задать переменные сборки
Загрузчики операционной системы, поддерживающие 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, раздел кеша использовался для хранения скачанных пакетов беспроводного обновления и временного хранения блоков при применении обновлений. Размер раздела кеша всегда было сложно определить, поскольку он зависел от того, какие обновления вы хотели применить. В худшем случае размер раздела кеша будет равен размеру образа системы. При обновлении A/B не нужно сохранять блоки (поскольку запись всегда выполняется в раздел, который в данный момент не используется), а при потоковой передаче A/B не нужно скачивать весь пакет OTA перед его применением.
Восстановление
Теперь RAM-диск восстановления содержится в файле boot.img. При переходе в режим восстановления загрузчик не может добавить параметр skip_initramfs в командную строку ядра.
При обновлении без использования A/B-разделов раздел восстановления содержит код, который применяется для установки обновлений. Обновления A/B применяются update_engine, который работает в обычном загруженном образе системы.
Режим восстановления (Recovery mode) по-прежнему используется для сброса настроек до заводских и установки из неизвестного источника пакетов обновлений (отсюда и название). Код и данные для режима восстановления (Recovery mode) хранятся в обычном загрузочном разделе в RAM-диске. Чтобы загрузить образ системы, загрузчик операционной системы сообщает ядру, что RAM-диск нужно пропустить (иначе устройство загрузится в режиме восстановления (Recovery mode)). Раздел восстановления небольшой (и большая его часть уже находится в загрузочном разделе), поэтому размер загрузочного раздела не увеличивается.
Fstab
Аргумент 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.
Аргументы слота ядра
Суффикс текущего слота должен передаваться через узел дерева устройств (/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). Список разделов, для которых генератор полезной нагрузки определяет обновление, настраивается с помощью переменной AB_OTA_PARTITIONS.
Например, если включена пара разделов bootloader_a и booloader_b (_a и _b – суффиксы слотов), вы можете обновить эти разделы, указав в конфигурации продукта или платы следующее:
AB_OTA_PARTITIONS := \ boot \ system \ bootloader
Все разделы, обновленные update_engine, не должны изменяться остальными компонентами системы. При добавочном обновлении или дельта-обновлении двоичные данные из текущего рекламного места используются для создания данных в новом рекламном месте. Любые изменения могут привести к тому, что новые данные слота не пройдут проверку в процессе обновления и обновление не будет выполнено.
Настройка после установки
Вы можете настроить этап после установки для каждого обновленного раздела по-разному, используя набор пар "ключ-значение". Чтобы запустить программу, расположенную в каталоге /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 при первой загрузке.