Беспроводное обновление для устройств без разделов A/B с динамическими разделами

В Android 10 поддерживаются динамические разделы – система разделов пользовательского пространства, которая позволяет создавать, изменять и удалять разделы во время беспроводных обновлений.

На этой странице описывается, как клиенты OTA изменяют размер динамических разделов во время обновления для устройств, отличных от A/B.

На устройствах, не поддерживающих A/B-обновления, беспроводное обновление динамических разделов выполняется с помощью файла updater из пакета обновления.

Обновить устройства для запуска

Этот раздел относится к устройствам без A/B-обновлений, которые поставляются с поддержкой динамических разделов и обновляются с Android 10 до более поздних версий.

Как создавать пакеты обновлений

Пакеты беспроводного обновления создаются с помощью скрипта ota_from_target_files, расположенного в каталоге build/make/tools/releasetools. По умолчанию скрипт создает пакет, который обновляет разделы system и vendor. Если есть дополнительные динамические разделы, например product, product_services или odm, их обновления должны быть сгенерированы в коде, предназначенном для определенного устройства.

Чтобы сгенерировать обновления, в расширенном модуле Python реализуйте функции FullOTA_GetBlockDifferences() и IncrementalOTA_GetBlockDifferences(). Эти две функции возвращают список объектов BlockDifference, каждый из которых описывает патч обновления, который будет применен к разделу. Разделы, возвращаемые этими двумя функциями, не должны изменяться вручную или проверяться в других местах, например в *_InstallBegin() или *_InstallEnd().

Пример создания обновления:

# device/yoyodyne/tardis/releasetools.py

import os
from common import BlockDifference, EmptyImage, GetUserImage

# The joined list of user image partitions of source and target builds.
# - Items should be added to the list if new dynamic partitions are added.
# - Items should not be removed from the list even if dynamic partitions are
#   deleted. When generating an incremental OTA package, this script needs to
#   know that an image is present in source build but not in target build.
USERIMAGE_PARTITIONS = [
    "product",
    "odm",
]

def GetUserImages(input_tmp, input_zip):
  return {partition: GetUserImage(partition, input_tmp, input_zip)
          for partition in USERIMAGE_PARTITIONS
          if os.path.exists(os.path.join(input_tmp,
                                         "IMAGES", partition + ".img"))}

def FullOTA_GetBlockDifferences(info):
  images = GetUserImages(info.input_tmp, info.input_zip)
  return [BlockDifference(partition, image)
          for partition, image in images.items()]

def IncrementalOTA_GetBlockDifferences(info):
  source_images = GetUserImages(info.source_tmp, info.source_zip)
  target_images = GetUserImages(info.target_tmp, info.target_zip)

  # Use EmptyImage() as a placeholder for partitions that will be deleted.
  for partition in source_images:
    target_images.setdefault(partition, EmptyImage())

  # Use source_images.get() because new partitions are not in source_images.
  return [BlockDifference(partition, target_image, source_images.get(partition))
          for partition, target_image in target_images.items()]

Обновить поток

В скрипт edify добавляются следующие функции:

  • unmap_partition(name)
    • Отменить сопоставление раздела, если оно выполнено, в противном случае ничего не делать.
    • Возвращает строку t в случае успеха или пустую строку в случае ошибки.
  • map_partition(name)
    • Если раздел ещё не сопоставлен, сопоставьте его.
    • Возвращает абсолютный путь к сопоставленному блочному устройству в случае успеха или пустую строку в случае ошибки.
  • update_dynamic_partitions(op_list)
    • Применить к метаданным динамического раздела список операций, при необходимости отменив сопоставление разделов.
    • Возвращает t при успешном выполнении или пустую строку при неудачном.

Аргумент op_list для update_dynamic_partitions указывает на файл в пакете обновлений. Каждая строка в файле соответствует одной операции. Если какая-либо операция завершится неудачно, функция update_dynamic_partitions немедленно вернет пустую строку. Доступны следующие операции:

  • resize partition-name size
    • Отмените сопоставление раздела, а затем измените его размер до size.
  • remove partition_name
    • Отмените сопоставление раздела, а затем удалите его.
  • add partition-name group-name
    • Добавьте в указанную группу новую группу товаров.
    • Прервать, если группа не существует или сегмент уже существует.
  • move partition-name group-name
    • Переместить раздел в указанную группу.
    • Прервать выполнение, если группа или раздел не существуют.
  • add_group group-name maximum-size
    • Добавить группу с указанным названием и максимальным размером.
    • Прервать, если группа уже существует.
    • Значение maximum_size, равное 0, означает, что размер разделов в группе не ограничен. Чтобы убедиться, что разделы в группе не превышают доступное пространство на устройстве, требуется дополнительное тестирование.
  • resize_group group-name maximum-size
    • Изменить размер группы до указанного максимального значения.
    • Прервать, если группа не существует.
    • Если значение maximum_size равно 0, то ограничений на размер разделов в группе нет. Чтобы убедиться, что разделы в группе не превышают доступное пространство на устройстве, требуется дополнительное тестирование.
  • remove_group group-name
    • Удалить группу.
    • Прервать работу, если в группе есть разделы.
  • remove_all_groups
    • Отмените сопоставление всех разделов с менеджером устройств.
    • Удалите все разделы и группы.

Дополнительное беспроводное обновление

При добавочном беспроводном обновлении используется следующая логика:

  1. Уменьшить или удалить разделы или переместить их из группы (чтобы было достаточно места для уменьшения групп).
  2. Уменьшать группы (чтобы было достаточно места для роста групп).
  3. Увеличить группы (чтобы было достаточно места для увеличения/добавления разделов).
  4. Увеличить разделы/добавить разделы/переместить разделы в новую группу

Значение update-script генерируется по следующей логике:

for each shrinking partition:
    block_image_update(map_partition(name), …)

update_dynamic_partitions(op_list)

for each growing / adding partition:
    block_image_update(map_partition(name), …)

Файл op_list для update_dynamic_partitions генерируется по следующей логике:

for each deleting partition:
    remove
for each partition that changes groups:
    move to "default"
for each shrinking partition:
    resize
for each shrinking / removing group:
    resize_group / remove_group
for each growing / adding group:
    resize_group / add_group
for each adding partition:
    add
for each growing / adding partition:
    resize
for each partition that changes groups:
    move to target group

Полный образ OTA

Полные беспроводные обновления выполняются по следующей логике:

  1. Удалите все существующие группы и разделы.
  2. Добавить группы
  3. Добавить разделы

update-script генерируется по следующей логике:

update_dynamic_partitions(op_list)

for each adding partition:
    block_image_update(map_partition(name), …)

Файл op_list для update_dynamic_partitions создается по следующей логике:

remove_all_groups
for each adding group:
    add_group
for each adding partition:
    add
for each adding partition:
    resize