Динамические обновления системы (DSU) позволяют создавать образ системы Android, который пользователи могут загрузить из интернета и протестировать без риска повреждения текущего образа системы. В этом документе описывается, как поддерживать DSU.
Требования ядра
Требования к ядру см. в разделе «Реализация динамических разделов» .
Кроме того, DSU использует функцию ядра device-mapper-verity (dm-verity) для проверки образа системы Android. Поэтому необходимо включить следующие параметры конфигурации ядра:
-
CONFIG_DM_VERITY=y -
CONFIG_DM_VERITY_FEC=y
Требования к разделению
Начиная с Android 11, DSU требует, чтобы раздел /data использовал файловую систему F2FS или ext4. F2FS обеспечивает лучшую производительность и рекомендуется, но разница должна быть незначительной.
Вот несколько примеров того, сколько времени занимает динамическое обновление системы на устройствах Pixel:
- Использование F2FS:
- 109s, 8G пользователей, 867M систем, тип файловой системы: F2FS: шифрование=aes-256-xts:aes-256-cts
- 104 с, 8 ГБ пользовательского трафика, 867 МБ системных данных, тип файловой системы: F2FS: шифрование = ice
- Используется файловая система ext4:
- 135s, 8G пользователь, 867M система, тип файловой системы: ext4: encryption=aes-256-xts:aes-256-cts
Если на вашей платформе это занимает гораздо больше времени, возможно, стоит проверить, содержит ли флаг монтирования какой-либо флаг, который заставляет запись выполняться в режиме «синхронно», или же можно явно указать флаг «асинхронно» для повышения производительности.
Раздел metadata (16 МБ или больше) необходим для хранения данных, относящихся к установленным образам. Его необходимо смонтировать на первом этапе монтирования.
Раздел userdata должен использовать файловую систему F2FS или ext4. При использовании F2FS необходимо включить все доступные в ядре Android патчи, связанные с F2FS.
DSU был разработан и протестирован с ядром kernel/common 4.9. Для этой функции рекомендуется использовать ядро версии 4.9 и выше.
Поведение HAL поставщика
Уивер ХАЛ
Интерфейс Weaver HAL предоставляет фиксированное количество слотов для хранения пользовательских ключей. Модуль DSU занимает два дополнительных слота для ключей. Если у OEM-производителя есть Weaver HAL, ему необходимо достаточно слотов для универсального образа системы (GSI) и образа хоста.
Привратник HAL
HAL Gatekeeper должен поддерживать большие значения USER_ID , поскольку GSI смещает UID относительно HAL на +1000000.
Проверьте загрузку
Если вы хотите обеспечить загрузку образов Developer GSI в заблокированном состоянии без отключения проверенной загрузки, добавьте ключи Developer GSI, добавив следующую строку в файл device/<device_name>/device.mk :
$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)
защита от отката
При использовании DSU загруженный образ системы Android должен быть новее текущего образа системы на устройстве. Это достигается путем сравнения уровней исправлений безопасности в дескрипторе свойства AVB ( Android Verified Boot ) обоих образов системы: Prop: com.android.build.system.security_patch -> '2019-04-05' .
Для устройств, не использующих AVB, укажите уровень исправления безопасности текущего образа системы в командной строке ядра или в bootconfig с помощью загрузчика: androidboot.system.security_patch=2019-04-05 .
Требования к оборудованию
При запуске экземпляра DSU выделяются два временных файла:
- Логический раздел для хранения файлов
GSI.img(1–1,5 ГБ) - Пустой раздел
/dataразмером 8 ГБ используется в качестве песочницы для запуска GSI.
Мы рекомендуем зарезервировать не менее 10 ГБ свободного места перед запуском экземпляра DSU. DSU также поддерживает выделение памяти с SD-карты. При наличии SD-карты она имеет наивысший приоритет при выделении памяти. Поддержка SD-карт критически важна для маломощных устройств, у которых может быть недостаточно внутренней памяти. Если SD-карта присутствует, убедитесь, что она не используется в качестве временной карты. DSU не поддерживает использование временных SD-карт .
Доступные интерфейсы
Запустить DSU можно с помощью adb , приложения от производителя или загрузчика DSU в один клик (в Android 11 и выше).
Запустите DSU с помощью adb.
Для запуска DSU с помощью adb введите следующие команды:
$ simg2img out/target/product/.../system.img system.raw
$ gzip -c system.raw > system.raw.gz
$ adb push system.raw.gz /storage/emulated/0/Download
$ adb shell am start-activity \
-n com.android.dynsystem/com.android.dynsystem.VerificationActivity \
-a android.os.image.action.START_INSTALL \
-d file:///storage/emulated/0/Download/system.raw.gz \
--el KEY_SYSTEM_SIZE $(du -b system.raw|cut -f1) \
--el KEY_USERDATA_SIZE 8589934592
Запустите DSU с помощью приложения.
Основной точкой входа в DSU является API-интерфейс android.os.image.DynamicSystemClient.java :
public class DynamicSystemClient {
...
...
/**
* Start installing DynamicSystem from URL with default userdata size.
*
* @param systemUrl A network URL or a file URL to system image.
* @param systemSize size of system image.
*/
public void start(String systemUrl, long systemSize) {
start(systemUrl, systemSize, DEFAULT_USERDATA_SIZE);
}
Необходимо предварительно установить это приложение на устройство. Поскольку DynamicSystemClient — это системный API, вы не можете собрать приложение с использованием обычного API SDK и не можете опубликовать его в Google Play. Назначение этого приложения:
- Получите список изображений и соответствующие URL-адреса, используя схему, определенную поставщиком.
- Сопоставьте изображения в списке с устройством и покажите пользователю совместимые изображения для выбора.
Вызовите метод
DynamicSystemClient.startследующим образом:DynamicSystemClient aot = new DynamicSystemClient(...) aot.start( ...URL of the selected image..., ...uncompressed size of the selected image...);
URL-адрес указывает на сжатый в формате gzip, неразреженный, образ системы, который можно создать с помощью следующих команд:
$ simg2img ${OUT}/system.img ${OUT}/system.raw
$ gzip ${OUT}/system.raw
$ ls ${OUT}/system.raw.gz
Имя файла должно соответствовать следующему формату:
<android version>.<lunch name>.<user defined title>.raw.gz
Примеры:
-
o.aosp_taimen-userdebug.2018dev.raw.gz -
p.aosp_taimen-userdebug.2018dev.raw.gz
Загрузчик DSU в один клик
В Android 11 появилась функция загрузки DSU в один клик, представляющая собой интерфейс в настройках для разработчиков.

Рисунок 1. Запуск погрузчика DSU.
Когда разработчик нажимает кнопку DSU Loader , программа загружает из интернета предварительно настроенный JSON-дескриптор DSU и отображает все подходящие образы во всплывающем меню. Выберите образ, чтобы начать установку DSU, и ход выполнения будет отображаться в панели уведомлений.

Рисунок 2. Ход установки образа DSU.
По умолчанию загрузчик DSU загружает JSON-дескриптор, содержащий образы GSI. В следующих разделах показано, как создавать пакеты DSU с OEM-подписью и загружать их из загрузчика DSU.
Флаг функции
Функция DSU находится в настройках с помощью флага settings_dynamic_android . Перед использованием DSU убедитесь, что соответствующий флаг функции включен.

Рисунок 3. Включение флага функции.
На устройстве с пользовательской сборкой может быть недоступен пользовательский интерфейс для отображения флагов функций. В этом случае используйте команду adb :
$ adb shell setprop persist.sys.fflag.override.settings_dynamic_system 1
Образы хост-систем поставщика на GCE (необязательно)
Одним из возможных мест хранения образов системы является хранилище Google Compute Engine (GCE). Администратор релиза использует консоль хранилища GCP для добавления/удаления/изменения выпущенных образов системы.
Изображения должны быть в открытом доступе, как показано здесь:

Рисунок 4. Общедоступный доступ в GCE.
Процедура публикации элемента описана в документации Google Cloud .
Многораздельный DSU в ZIP-файле
Начиная с Android 11, DSU может иметь более одного раздела. Например, он может содержать файл product.img в дополнение к system.img . При загрузке устройства init на первом этапе обнаруживает установленные разделы DSU и временно заменяет раздел на устройстве, когда установленный DSU включен. Пакет DSU может содержать раздел, которому не соответствует раздел на устройстве.

Рисунок 5. Процесс DSU с несколькими разделами.
DSU, подписанный производителем оборудования
Чтобы гарантировать авторизацию всех образов, работающих на устройстве, производителем устройства, все образы в пакете DSU должны быть подписаны. Например, предположим, что существует пакет DSU, содержащий два образа разделов, как показано ниже:
dsu.zip {
- system.img
- product.img
}
Файлы system.img и product.img должны быть подписаны OEM-ключом до того, как они будут помещены в ZIP-архив. Обычно используется асимметричный алгоритм, например, RSA, где секретный ключ используется для подписи пакета, а открытый ключ — для его проверки. На первом этапе создания образа в оперативной памяти (ramdisk) должен содержаться парный открытый ключ, например, /avb/*.avbpubkey . Если устройство уже поддерживает AVB, достаточно существующей процедуры подписи. В следующих разделах описан процесс подписи и показано расположение открытого ключа AVB, используемого для проверки образов в пакете DSU.
Дескриптор DSU в формате JSON
JSON-дескриптор DSU описывает пакеты DSU. Он поддерживает два примитива. Во-первых, примитив include включает дополнительные JSON-дескрипторы или перенаправляет загрузчик DSU в новое местоположение. Например:
{
"include": ["https://.../gsi-release/gsi-src.json"]
}
Во-вторых, примитив image используется для описания выпущенных пакетов DSU. Внутри примитива образа находится несколько атрибутов:
Атрибуты
nameиdetailsпредставляют собой строки, которые отображаются в диалоговом окне для выбора пользователем.Атрибуты
cpu_api,vndkиos_versionиспользуются для проверок совместимости, которые описаны в следующем разделе.Необязательный атрибут
pubkeyописывает открытый ключ, который используется в паре с секретным ключом для подписи пакета DSU. Если он указан, служба DSU может проверить, есть ли у устройства ключ, используемый для проверки пакета DSU. Это позволяет избежать установки нераспознанного пакета DSU, например, установки пакета DSU, подписанного OEM-A, на устройство, произведенное OEM-B.Необязательный атрибут
tosуказывает на текстовый файл, описывающий условия обслуживания для соответствующего пакета DSU. Когда разработчик выбирает пакет DSU с указанным атрибутом terms of service, открывается диалоговое окно, показанное на рисунке 6, в котором разработчику предлагается принять условия обслуживания перед установкой пакета DSU.
Рисунок 6. Диалоговое окно «Условия предоставления услуг».
Для справки, вот JSON-дескриптор DSU для GSI:
{
"images":[
{
"name":"GSI+GMS x86",
"os_version":"10",
"cpu_abi": "x86",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
"uri":"https://.../gsi/gsi_gms_x86-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI+GMS ARM64",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"tos": "https://dl.google.com/developers/android/gsi/gsi-tos.txt",
"uri":"https://.../gsi/gsi_gms_arm64-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI ARM64",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"uri":"https://.../gsi/aosp_arm64-exp-QP1A.190711.020.C4-5928301.zip"
},
{
"name":"GSI x86_64",
"os_version":"10",
"cpu_abi": "x86_64",
"details":"exp-QP1A.190711.020.C4-5928301",
"vndk":[
27,
28,
29
],
"pubkey":"",
"uri":"https://.../gsi/aosp_x86_64-exp-QP1A.190711.020.C4-5928301.zip"
}
]
}
Управление совместимостью
Для определения совместимости пакета DSU с локальным устройством используется несколько атрибутов:
cpu_api— это строка, описывающая архитектуру устройства. Этот атрибут является обязательным и сравнивается с системным свойствомro.product.cpu.abi. Их значения должны точно совпадать.os_version— это необязательное целое число, указывающее на версию Android. Например, для Android 10os_versionравно10, а для Android 11 —os_versionравно11Если этот атрибут указан, он должен быть равен или больше значения системного свойстваro.system.build.version.release. Эта проверка используется для предотвращения загрузки образа GSI Android 10 на устройстве производителя Android 11, что в настоящее время не поддерживается. Загрузка образа GSI Android 11 на устройстве Android 10 разрешена.vndk— это необязательный массив, указывающий все VNDK, включенные в пакет DSU. Если он указан, загрузчик DSU проверяет, включено ли число, извлеченное из системного свойстваro.vndk.version.
Отозвать ключи DSU в целях безопасности.
В крайне редких случаях, когда пара ключей RSA, используемая для подписи образов DSU, скомпрометирована, следует как можно скорее обновить ramdisk, чтобы удалить скомпрометированный ключ. Помимо обновления загрузочного раздела, можно заблокировать скомпрометированные ключи, используя список аннулированных ключей DSU (черный список ключей) по HTTPS-адресу.
Список аннулированных ключей DSU содержит перечень аннулированных открытых ключей AVB. Во время установки DSU открытые ключи внутри образов DSU проверяются по списку аннулированных ключей. Если в образах обнаруживается аннулированный открытый ключ, процесс установки DSU останавливается.
Для обеспечения надежности безопасности URL-адрес списка аннулированных ключей должен быть HTTPS-адресом и указываться в строке ресурса:
frameworks/base/packages/DynamicSystemInstallationService/res/values/strings.xml@key_revocation_list_url
Значение строки — https://dl.google.com/developers/android/gsi/gsi-keyblacklist.json , это список аннулированных ключей GSI, выпущенных Google. Эта строка ресурса может быть наложена и настроена, так что производители оборудования, использующие функцию DSU, могут предоставлять и поддерживать собственные черные списки ключей. Это позволяет производителю блокировать определенные открытые ключи без обновления образа оперативной памяти устройства.
Формат списка аннулированных аккаунтов следующий:
{
"entries":[
{
"public_key":"bf14e439d1acf231095c4109f94f00fc473148e6",
"status":"REVOKED",
"reason":"Key revocation test key"
},
{
"public_key":"d199b2f29f3dc224cca778a7544ea89470cbef46",
"status":"REVOKED",
"reason":"Key revocation test key"
}
]
}
public_key— это дайджест SHA-1 отозванного ключа в формате, описанном в разделе «Генерация открытого ключа AVB» .-
statusуказывает на статус отзыва ключа. В настоящее время поддерживается только значениеREVOKED. -
reason— необязательная строка, описывающая причину отзыва.
процедуры DSU
В этом разделе описывается, как выполнить несколько процедур настройки DSU.
Сгенерируйте новую пару ключей.
Используйте команду openssl для генерации пары закрытого и открытого ключей RSA в формате .pem (например, размером 2048 бит):
$ openssl genrsa -out oem_cert_pri.pem 2048
$ openssl rsa -in oem_cert_pri.pem -pubout -out oem_cert_pub.pem
Закрытый ключ может быть недоступен и хранится только в аппаратном модуле безопасности (HSM) . В этом случае после генерации ключа может быть доступен сертификат открытого ключа x509. Инструкции по генерации открытого ключа AVB из сертификата x509 см. в разделе «Добавление сопряженного открытого ключа на ramdisk» .
Для преобразования сертификата x509 в формат PEM:
$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem
Пропустите этот шаг, если сертификат уже является файлом PEM.
Добавьте открытый ключ сопряжения на виртуальный диск в оперативной памяти.
Для проверки подписанного пакета DSU файл oem_cert.avbpubkey необходимо поместить в каталог /avb/*.avbpubkey . Сначала преобразуйте открытый ключ из формата PEM в формат открытого ключа AVB:
$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey
Затем добавьте открытый ключ на первый этап создания образа ramdisk, выполнив следующие шаги.
Добавьте предварительно собранный модуль для копирования
avbpubkey. Например, добавьтеdevice/<company>/<board>/oem_cert.avbpubkeyиdevice/<company>/<board>/avb/Android.mkсо следующим содержимым:include $(CLEAR_VARS) LOCAL_MODULE := oem_cert.avbpubkey LOCAL_MODULE_CLASS := ETC LOCAL_SRC_FILES := $(LOCAL_MODULE) ifeq ($(BOARD_USES_RECOVERY_AS_BOOT),true) LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/first_stage_ramdisk/avb else LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT)/avb endif include $(BUILD_PREBUILT)Сделайте так, чтобы целевая платформа droidcore зависела от добавленного файла
oem_cert.avbpubkey:droidcore: oem_cert.avbpubkey
Сгенерируйте атрибут открытого ключа AVB в JSON-дескрипторе.
Файл oem_cert.avbpubkey находится в двоичном формате открытого ключа AVB. Используйте SHA-1, чтобы сделать его читаемым, прежде чем добавлять в JSON-дескриптор:
$ sha1sum oem_cert.avbpubkey | cut -f1 -d ' '
3e62f2be9d9d813ef5........866ac72a51fd20
Это будет содержимое атрибута pubkey в JSON-дескрипторе.
"images":[
{
...
"pubkey":"3e62f2be9d9d813ef5........866ac72a51fd20",
...
},
Подпишите пакет DSU
Для подписи пакета DSU используйте один из следующих методов:
Метод 1: Повторное использование артефакта, созданного в процессе первоначальной подписи AVB, для создания пакета DSU. Альтернативный подход заключается в извлечении уже подписанных образов из релизного пакета и использовании извлеченных образов для непосредственного создания ZIP-файла.
Метод 2: Используйте следующие команды для подписи разделов DSU, если доступен закрытый ключ. Каждый
imgв пакете DSU (ZIP-архив) подписывается отдельно:$ key_len=$(openssl rsa -in oem_cert_pri.pem -text | grep Private-Key | sed -e 's/.*(\(.*\) bit.*/\1/') $ for partition in system product; do avbtool add_hashtree_footer \ --image ${OUT}/${partition}.img \ --partition_name ${partition} \ --algorithm SHA256_RSA${key_len} \ --key oem_cert_pri.pem done
Для получения дополнительной информации о добавлении add_hashtree_footer с помощью avbtool см. раздел «Использование avbtool» .
Проверьте целостность пакета DSU локально.
Рекомендуется проверить все локальные образы по открытому ключу сопряжения с помощью следующих команд:
for partition in system product; do
avbtool verify_image --image ${OUT}/${partition}.img --key oem_cert_pub.pem
done
Ожидаемый результат выглядит следующим образом:
Verifying image dsu/system.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/system.img
: Successfully verified sha1 hashtree of dsu/system.img for image of 898494464 bytes
Verifying image dsu/product.img using key at oem_cert_pub.pem
vbmeta: Successfully verified footer and SHA256_RSA2048 vbmeta struct in dsu/product.img
: Successfully verified sha1 hashtree of dsu/product.img for image of 905830400 bytes
Создать пакет DSU
Следующий пример создает пакет DSU, содержащий файлы system.img и product.img :
dsu.zip {
- system.img
- product.img
}
После подписания обоих изображений используйте следующую команду для создания ZIP-файла:
$ mkdir -p dsu
$ cp ${OUT}/system.img dsu
$ cp ${OUT}/product.img dsu
$ cd dsu && zip ../dsu.zip *.img && cd -
Настройте DSU одним щелчком мыши
По умолчанию загрузчик DSU указывает на метаданные образов GSI, которые находятся по https://...google.com/.../gsi-src.json .
Производители оборудования могут переопределить этот список, определив свойство persist.sys.fflag.override.settings_dynamic_system.list , указывающее на их собственный JSON-дескриптор. Например, производитель оборудования может предоставить JSON-метаданные, включающие GSI, а также собственные образы оборудования, следующим образом:
{
"include": ["https://dl.google.com/.../gsi-src.JSON"]
"images":[
{
"name":"OEM image",
"os_version":"10",
"cpu_abi": "arm64-v8a",
"details":"...",
"vndk":[
27,
28,
29
],
"spl":"...",
"pubkey":"",
"uri":"https://.../....zip"
},
}
Производитель оборудования может объединять опубликованные метаданные DSU, как показано на рисунке 7.

Рисунок 7. Последовательность опубликованных метаданных DSU.