Aktualizacja OTA na urządzeniach innych niż A/B z partycjami dynamicznymi

Android 10 obsługuje partycje dynamiczne, czyli system partycjonowania przestrzeni użytkownika, który może tworzyć, zmieniać rozmiar i usuwać partycje podczas aktualizacji bezprzewodowych (OTA).

Na tej stronie opisujemy, jak klienci OTA zmieniają rozmiar partycji dynamicznych podczas aktualizacji na urządzeniach innych niż A/B.

W przypadku urządzeń innych niż A/B aktualizacja OTA partycji dynamicznych jest stosowana za pomocą pliku updater w pakiecie aktualizacji.

Aktualizowanie urządzeń wprowadzanych na rynek

Ta sekcja dotyczy urządzeń innych niż A/B, które są wprowadzane na rynek z obsługą partycji dynamicznych. Te urządzenia są aktualizowane z Androida 10 do nowszych wersji.

Generowanie pakietów aktualizacji

Pakiety aktualizacji OTA są generowane przez skrypt ota_from_target_files znajdujący się w folderze build/make/tools/releasetools. Domyślnie skrypt generuje pakiet, który aktualizuje partycje systemvendor. Jeśli istnieją dodatkowe partycje dynamiczne, takie jak product, product_services lub odm, ich aktualizacje muszą być generowane w kodzie specyficznym dla urządzenia.

Aby generować aktualizacje, w rozszerzonym module Pythona zaimplementuj FullOTA_GetBlockDifferences()IncrementalOTA_GetBlockDifferences(). Te 2 funkcje zwracają listę obiektów BlockDifference, z których każdy opisuje poprawkę aktualizacji, która zostanie zastosowana do partycji. Partycji zwracanych przez te 2 funkcje nie należy modyfikować ręcznie ani weryfikować w innych miejscach, np. w *_InstallBegin() lub *_InstallEnd().

Przykład generowania aktualizacji:

# 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()]

Aktualizowanie przepływu

W skrypcie edify dodawane są te funkcje:

  • unmap_partition(name)
    • Usuń mapowanie partycji, jeśli jest zmapowana, w przeciwnym razie nie rób nic.
    • W przypadku powodzenia zwraca ciąg znaków t, a w przypadku niepowodzenia – pusty ciąg znaków.
  • map_partition(name)
    • Zmapuj partycję, jeśli nie jest jeszcze zmapowana.
    • Zwraca bezwzględną ścieżkę zamapowanego urządzenia blokowego w przypadku powodzenia lub pusty ciąg znaków w przypadku niepowodzenia.
  • update_dynamic_partitions(op_list)
    • Zastosuj podaną listę operacji do metadanych partycji dynamicznej, w razie potrzeby usuwając mapowanie partycji.
    • W przypadku powodzenia zwraca t, a w przypadku niepowodzenia – pusty ciąg znaków.

Argument op_list do update_dynamic_partitions wskazuje plik w pakiecie aktualizacji. Każdy wiersz w pliku określa operację. Jeśli jakakolwiek operacja zakończy się niepowodzeniem, funkcja update_dynamic_partitions natychmiast zwraca pusty ciąg. Dostępne są te operacje:

  • resize partition-name size
    • Odłącz partycję, a następnie zmień jej rozmiar na size.
  • remove partition_name
    • Odłącz partycję, a następnie ją usuń.
  • add partition-name group-name
    • Dodaj nowy podział do określonej grupy.
    • Przerwij, jeśli grupa nie istnieje lub partycja już istnieje.
  • move partition-name group-name
    • Przenieś partycję do określonej grupy.
    • Przerwij, jeśli grupa lub partycja nie istnieje.
  • add_group group-name maximum-size
    • Dodaj grupę o podanej nazwie i maksymalnym rozmiarze.
    • Przerwij, jeśli grupa już istnieje.
    • Wartość maximum_size równa 0 oznacza, że w grupie nie ma ograniczeń rozmiaru partycji. Konieczne są dodatkowe testy, aby upewnić się, że partycje w grupie nie przekraczają dostępnego miejsca na urządzeniu.
  • resize_group group-name maximum-size
    • Zmień rozmiar grupy do podanego maksymalnego rozmiaru.
    • Przerwij, jeśli grupa nie istnieje.
    • Wartość maximum_size równa 0 oznacza, że w grupie nie ma ograniczeń rozmiaru partycji. Konieczne są dodatkowe testy, aby upewnić się, że partycje w grupie nie przekraczają dostępnego miejsca na urządzeniu.
  • remove_group group-name
    • Usuń grupę.
    • Przerwij, jeśli w grupie są partycje.
  • remove_all_groups
    • Odłącz wszystkie partycje od mapowania urządzeń.
    • Usuń wszystkie partycje i grupy.

Przyrostowa OTA

Przyrostowe aktualizacje OTA działają według tej logiki:

  1. Zmniejszanie partycji, usuwanie partycji lub przenoszenie partycji poza grupę (aby było wystarczająco dużo miejsca na zmniejszenie grup)
  2. Zmniejszanie grup (aby było wystarczająco dużo miejsca na ich powiększenie)
  3. powiększać grupy (aby mieć wystarczająco dużo miejsca na powiększanie i dodawanie partycji);
  4. Zwiększanie rozmiaru partycji, dodawanie partycji i przenoszenie partycji do nowej grupy

W szczegółach wartość update-script jest generowana zgodnie z tą logiką:

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), …)

Plik op_list dla update_dynamic_partitions jest generowany zgodnie z tą logiką:

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

Pełna aktualizacja OTA

Pełne aktualizacje OTA korzystają z tej logiki:

  1. Usuń wszystkie istniejące grupy i partycje.
  2. Dodaj grupy
  3. Dodawanie partycji

W szczegółach wartość update-script jest generowana zgodnie z tą logiką:

update_dynamic_partitions(op_list)

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

Plik op_list dla update_dynamic_partitions jest generowany zgodnie z tą logiką:

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