OTA für Nicht-A/B-Geräte mit dynamischen Partitionen

Android 10 unterstützt dynamische Partitionen, ein Partitionssystem im Userspace, mit dem Partitionen bei Over-the-air-Updates (OTA) erstellt, neu formatiert und gelöscht werden können.

Auf dieser Seite wird beschrieben, wie OTA-Clients die Größe dynamischer Partitionen während eines Updates für Nicht-A/B-Geräte anpassen.

Bei Geräten ohne A/B-Partition wird das OTA-Update für dynamische Partitionen mithilfe der updater im Update-Paket angewendet.

Startgeräte aktualisieren

Dieser Abschnitt gilt für Geräte, die nicht A/B sind und mit dynamischer Partitionsunterstützung ausgeliefert werden. Auf diesen Geräten wird von Android 10 auf eine höhere Version umgestellt.

Update-Pakete generieren

OTA-Update-Pakete werden vom ota_from_target_files-Script unter build/make/tools/releasetools generiert. Standardmäßig generiert das Script ein Paket, mit dem die Partitionen system und vendor aktualisiert werden. Wenn es zusätzliche dynamische Partitionen wie product, product_services oder odm gibt, müssen ihre Updates in gerätespezifischem Code generiert werden.

Um Aktualisierungen zu generieren, implementieren Sie im erweiterten Python-Modul FullOTA_GetBlockDifferences() und IncrementalOTA_GetBlockDifferences(). Diese beiden Funktionen geben eine Liste von BlockDifference-Objekten zurück, die jeweils den Update-Patch beschreiben, der auf eine Partition angewendet werden würde. Partitionen, die von diesen beiden Funktionen zurückgegeben werden, sollten nicht manuell geändert oder an anderer Stelle bestätigt werden, z. B. in *_InstallBegin() oder *_InstallEnd().

Beispiel für die Generierung eines Updates:

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

Ablauf aktualisieren

Im Hintergrund werden dem edify-Script die folgenden Funktionen hinzugefügt:

  • unmap_partition(name)
    • Entfernen Sie die Zuordnung der Partition, falls zugewiesen, andernfalls tun Sie nichts.
    • Gib bei Erfolg den String t zurück oder bei einem Fehler einen leeren String.
  • map_partition(name)
    • Weisen Sie die Partition zu, falls noch nicht geschehen.
    • Gibt im Erfolgsfall den absoluten Pfad des zugeordneten Blockgeräts oder im Falle eines Fehlers einen leeren String zurück.
  • update_dynamic_partitions(op_list)
    • Wenden Sie die angegebene Liste von Vorgängen auf die Metadaten der dynamischen Partitionen an und heben Sie die Zuordnung von Partitionen bei Bedarf auf.
    • Gib bei Erfolg t oder bei einem Fehler einen leeren String zurück.

Das Argument op_list für update_dynamic_partitions verweist auf eine Datei im Update-Paket. Jede Zeile in der Datei gibt einen Vorgang an. Wenn ein Vorgang fehlschlägt, gibt update_dynamic_partitions sofort einen leeren String zurück. Die Vorgänge sind:

  • resize partition-name size
    • Heben Sie die Zuordnung der Partition auf und ändern Sie die Größe auf size.
  • remove partition_name
    • Heben Sie die Zuordnung der Partition auf und entfernen Sie sie.
  • add partition-name group-name
    • Fügen Sie der angegebenen Gruppe eine neue Partition hinzu.
    • Der Vorgang wird abgebrochen, wenn die Gruppe nicht oder die Partition bereits vorhanden ist.
  • move partition-name group-name
    • Verschieben Sie die Partition in die angegebene Gruppe.
    • Abbruch, wenn die Gruppe oder Partition nicht vorhanden ist.
  • add_group group-name maximum-size
    • Fügen Sie eine Gruppe mit dem angegebenen Namen und der maximalen Größe hinzu.
    • Wenn die Gruppe bereits vorhanden ist, wird der Vorgang abgebrochen.
    • Ein Wert von 0 für maximum_size bedeutet, dass es keine Größenbeschränkungen für Partitionen in der Gruppe gibt. Es sind zusätzliche Tests erforderlich, um sicherzustellen, dass die Partitionen in der Gruppe den verfügbaren Speicherplatz auf dem Gerät nicht überschreiten.
  • resize_group group-name maximum-size
    • Ändern Sie die Größe der Gruppe auf die angegebene maximale Größe.
    • Abbruch, wenn die Gruppe nicht vorhanden ist.
    • Ein Wert von 0 für maximum_size bedeutet, dass es keine Größenbeschränkungen für Partitionen in der Gruppe gibt. Es sind zusätzliche Tests erforderlich, um sicherzustellen, dass die Partitionen in der Gruppe den verfügbaren Speicherplatz auf dem Gerät nicht überschreiten.
  • remove_group group-name
    • Eine Gruppe entfernen.
    • Der Vorgang wird abgebrochen, wenn die Gruppe Partitionen enthält.
  • remove_all_groups
    • Entfernen Sie alle Partitionen aus dem Geräte-Mapper.
    • Entfernen Sie alle Partitionen und Gruppen.

Inkrementelles OTA

Für inkrementelle OTA-Updates wird die folgende Logik verwendet:

  1. Partitionen verkleinern, löschen oder aus der Gruppe verschieben, damit genügend Speicherplatz vorhanden ist, um Gruppen zu verkleinern
  2. Gruppen verkleinern, damit genügend Platz für eine Erweiterung vorhanden ist
  3. Gruppen vergrößern (damit genügend Platz für die Erweiterung/das Hinzufügen von Partitionen vorhanden ist)
  4. Partitionen vergrößern/Partitionen hinzufügen/Partitionen in eine neue Gruppe verschieben

Im Detail wird update-script mit dieser Logik generiert:

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

Die op_list-Datei für update_dynamic_partitions wird mit dieser Logik generiert:

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

Vollständiges OTA

Für vollständige OTA-Updates wird die folgende Logik verwendet:

  1. Alle vorhandenen Gruppen und Partitionen löschen
  2. Gruppen hinzufügen
  3. Partitionen hinzufügen

Im Einzelnen wird update-script mit dieser Logik generiert:

update_dynamic_partitions(op_list)

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

Die op_list-Datei für update_dynamic_partitions wird mit dieser Logik generiert:

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