Динамические обновления системы

Динамические обновления системы (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
    • 104s, пользователь 8G, система 867M, тип файловой системы: F2FS: шифрование = лед
  • Использование ext4:
    • 135s, пользователь 8G, система 867M, тип файловой системы: ext4: шифрование=aes-256-xts:aes-256-cts

Если на вашей платформе это занимает намного больше времени, вы можете проверить, содержит ли флаг монтирования какой-либо флаг, который заставляет «синхронную» запись, или вы можете явно указать «асинхронный» флаг, чтобы повысить производительность.

Раздел metadata (16 МБ или больше) требуется для хранения данных, связанных с установленными образами. Он должен быть установлен во время монтажа первого этапа.

Раздел userdata должен использовать файловую систему F2FS или ext4. При использовании F2FS включите все исправления, связанные с F2FS, доступные в общем ядре Android .

DSU был разработан и протестирован с ядром/common 4.9. Для этой функции рекомендуется использовать ядро ​​4.9 и выше.

Поведение поставщика HAL

Уивер ХЭЛ

Weaver HAL предоставляет фиксированное количество слотов для хранения пользовательских ключей. DSU занимает два дополнительных слота для ключей. Если у OEM-производителя есть HAL Weaver, у него должно быть достаточно слотов для универсального образа системы (GSI) и образа хоста.

Привратник HAL

HAL гейткипера должен поддерживать большие значения USER_ID , поскольку GSI смещает UID относительно HAL на +1000000.

Проверить загрузку

Если вы хотите поддерживать загрузку образов Developer GSI в состоянии LOCKED без отключения проверенной загрузки, включите ключи Developer GSI, добавив следующую строку в файл device/<device_name>/device.mk :

$(call inherit-product, $(SRC_TARGET_DIR)/product/developer_gsi_keys.mk)

Защита от отката

При использовании DSU загруженный образ системы Android должен быть новее текущего образа системы на устройстве. Это делается путем сравнения уровней исправлений безопасности в дескрипторе свойства AVB Android Verified Boot (AVB) обоих образов системы: 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 , OEM-приложения или загрузчика 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 является android.os.image.DynamicSystemClient.java API:

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, вы не можете создать приложение с помощью обычного SDK API и не можете опубликовать его в Google Play. Цель этого приложения:

  1. Получите список изображений и соответствующий URL-адрес с помощью схемы, определенной поставщиком.
  2. Сопоставьте изображения в списке с устройством и покажите совместимые изображения для выбора пользователем.
  3. 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 одним щелчком мыши, который является внешним интерфейсом в настройках разработчика.

Запуск загрузчика DSU

Рисунок 1. Запуск загрузчика DSU

Когда разработчик нажимает кнопку DSU Loader , он извлекает предварительно настроенный дескриптор DSU 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 для добавления/удаления/изменения выпущенного образа системы.

Изображения должны быть в открытом доступе, как показано здесь:

Общий доступ в GCE

Рисунок 4. Общий доступ в GCE

Процедура публикации элемента доступна в документации Google Cloud .

DSU с несколькими разделами в ZIP-файле

Начиная с Android 11, DSU может иметь более одного раздела. Например, он может содержать product.img в дополнение к system.img . Когда устройство загружается, первый этап init обнаруживает установленные разделы DSU и временно заменяет раздел на устройстве, когда установленный DSU включен. Пакет DSU может содержать раздел, которому нет соответствующего раздела на устройстве.

Процесс DSU с несколькими разделами

Рисунок 5. Процесс DSU с несколькими разделами

OEM-подписанный DSU

Чтобы убедиться, что все образы, работающие на устройстве, авторизованы производителем устройства, все образы в пакете DSU должны быть подписаны. Например, предположим, что есть пакет DSU, содержащий два образа разделов, как показано ниже:

dsu.zip {
    - system.img
    - product.img
}

И system.img , и product.img должны быть подписаны OEM-ключом, прежде чем они будут помещены в ZIP-файл. Общепринятой практикой является использование асимметричного алгоритма, например, RSA, где секретный ключ используется для подписи пакета, а открытый ключ — для его проверки. Виртуальный диск первого этапа должен содержать открытый ключ паринга, например, /avb/*.avbpubkey . Если устройство уже приняло AVB, существующей процедуры подписи будет достаточно. В следующих разделах показан процесс подписания и показано размещение открытого ключа AVB, используемого для проверки образов в пакете DSU.

Дескриптор DSU JSON

Дескриптор DSU JSON описывает пакеты 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 с указанным атрибутом условий обслуживания, открывается диалоговое окно, показанное на рис. 6, в котором разработчику предлагается принять условия обслуживания перед установкой пакета DSU.

    Диалоговое окно "Условия использования"

    Рис. 6. Диалоговое окно «Условия обслуживания»

Для справки, вот дескриптор DSU JSON для 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 10 os_version равен 10 , а для Android 11 os_version равен 11 . Когда этот атрибут указан, он должен быть больше или равен системному свойству ro.system.build.version.release . Эта проверка используется для предотвращения загрузки образа Android 10 GSI на устройстве поставщика Android 11, которое в настоящее время не поддерживается. Загрузка образа Android 11 GSI на устройстве Android 10 разрешена.

  • vndk — необязательный массив, в котором указаны все VNDK, включенные в пакет DSU. Когда он указан, загрузчик DSU проверяет, включено ли число, извлеченное из системного свойства ro.vndk.version .

Отзыв ключей DSU в целях безопасности

В крайне редком случае, когда пара ключей RSA, используемая для подписи образов DSU, скомпрометирована, виртуальный диск следует как можно скорее обновить, чтобы удалить скомпрометированный ключ. В дополнение к обновлению загрузочного раздела вы можете заблокировать скомпрометированные ключи, используя список отзыва ключей DSU (черный список ключей) из URL-адреса HTTPS.

Список отозванных ключей DSU содержит список отозванных открытых ключей AVB. Во время установки DSU открытые ключи внутри образов DSU проверяются с помощью списка отзыва. Если обнаруживается, что образы содержат отозванный открытый ключ, процесс установки DSU останавливается.

URL-адрес списка отзыва ключей должен быть 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. Эту строку ресурса можно накладывать и настраивать, чтобы OEM-производители, использующие функцию DSU, могли предоставлять и поддерживать свой собственный черный список ключей. Это дает OEM-производителю возможность блокировать определенные открытые ключи без обновления образа виртуального диска устройства.

Формат списка отзыва:

{
   "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 см. в разделе Добавление открытого ключа сопряжения на электронный диск .

Чтобы преобразовать сертификат x509 в формат PEM:

$ openssl x509 -pubkey -noout -in oem_cert_pub.x509.pem > oem_cert_pub.pem

Пропустите этот шаг, если сертификат уже является файлом PEM.

Добавление ключа сопряжения на виртуальный диск

oem_cert.avbpubkey необходимо поместить в /avb/*.avbpubkey для проверки подписанного пакета DSU. Сначала преобразуйте открытый ключ в формате PEM в формат открытого ключа AVB:

$ avbtool extract_public_key --key oem_cert_pub.pem --output oem_cert.avbpubkey

Затем включите открытый ключ в виртуальный диск первого этапа, выполнив следующие действия.

  1. Добавьте готовый модуль, чтобы скопировать 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)
    
  2. Сделайте цель 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 .

OEM-производители могут перезаписать список, определив свойство persist.sys.fflag.override.settings_dynamic_system.list , которое указывает на их собственный дескриптор JSON. Например, OEM-производитель может предоставить метаданные JSON, включающие GSI, а также проприетарные образы OEM, например:

{
    "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"
      },

}

OEM-производитель может объединить опубликованные метаданные DSU, как показано на рис. 7.

Объединение опубликованных метаданных DSU

Рисунок 7. Объединение опубликованных метаданных DSU в цепочку