Übersicht über virtuelles A/B

Virtual A/B ist der wichtigste Updatemechanismus von Android. Virtuelle A/B-Updates basieren auf den alten A/B-Updates (siehe A/B-Systemupdates) und Nicht-A/B-Updates, die in Android 15 eingestellt werden, um den Speicherbedarf von Updates zu reduzieren.

Bei Virtual A/B gibt es keinen zusätzlichen Slot für dynamische Partitionen. Weitere Informationen finden Sie unter Dynamische Partitionen. Stattdessen wird das Delta in einen Snapshot geschrieben und dann in die Basispartition eingefügt, nachdem ein erfolgreicher Start bestätigt wurde. Für Virtual A/B wird ein Android-spezifisches Snapshot-Format verwendet. Weitere Informationen finden Sie unter COW-Format für komprimierte Snapshots. Damit können Snapshots komprimiert werden, um den Speicherplatzbedarf zu minimieren. Bei einem vollständigen OTA wird die Snapshot-Größe durch die Komprimierung um etwa 45% reduziert, bei einem inkrementellen OTA um etwa 55%.

Android 12 bietet die Option der virtuellen A/B-Komprimierung zum Komprimieren von Partitionen, für die ein Snapshot erstellt wurde. Virtual A/B bietet Folgendes:

  • Virtuelle A/B-Updates sind wie A/B-Updates nahtlos. Das Update erfolgt vollständig im Hintergrund, während das Gerät in Betrieb ist. Virtuelle A/B-Updates minimieren die Zeit, in der ein Gerät offline und nicht nutzbar ist.
  • Virtuelle A/B-Updates können rückgängig gemacht werden. Wenn das neue Betriebssystem nicht gestartet werden kann, wird automatisch ein Rollback auf die vorherige Version durchgeführt.
  • Bei virtuellen A/B-Updates wird nur wenig zusätzlicher Speicherplatz benötigt, da nur die Partitionen dupliziert werden, die vom Bootloader verwendet werden. Andere aktualisierbare Partitionen werden per Snapshot gesichert.

Hintergrund und Terminologie

In diesem Abschnitt werden die Terminologie definiert und die Technologie beschrieben, die virtuelles A/B unterstützt. Während der OTA-Installation werden neue Betriebssystemdaten entweder in den neuen Slot für physische Partitionen oder auf ein Android-spezifisches COW-Gerät geschrieben. Nach dem Neustart des Geräts werden die Daten der dynamischen Partition mithilfe von dm-user und snapuserd-Daemon wieder in das Basisgerät eingefügt. Dieser Vorgang findet vollständig im Nutzerbereich statt.

Device Mapper

Device Mapper ist eine virtuelle Linux-Blockebene, die häufig in Android verwendet wird. Bei dynamischen Partitionen sind Partitionen wie /system ein Stapel aus geschichteten Geräten:

  • Unten im Stapel befindet sich die physische Super-Partition (z. B. /dev/block/by-name/super).
  • In der Mitte befindet sich ein dm-linear-Gerät, das angibt, welche Blöcke in der Superpartition die angegebene dynamische Partition bilden. Auf einem A/B-Gerät wird dies als /dev/block/mapper/system_[a|b] und auf einem Nicht-A/B-Gerät als /dev/block/mapper/system angezeigt.
  • Oben befindet sich ein dm-verity-Gerät, das für überprüfte Partitionen erstellt wurde. Dieses Gerät überprüft, ob Blöcke auf dem dm-linear-Gerät korrekt signiert sind. Sie wird als /dev/block/mapper/system-verity angezeigt und ist die Quelle des Bereitstellungspunkts /system.

Abbildung 1 zeigt, wie der Stack unter dem Bereitstellungspunkt /system aussieht.

Partitionsstapelung unter dem System

Abbildung 1: Stapel unter dem Bereitstellungspunkt „/system“

Komprimierte Snapshots

In Android 12 und höher können Sie komprimierte Snapshots in Ihrem Build aktivieren, um den hohen Speicheranforderungen der /data-Partition gerecht zu werden, da die Speicheranforderungen in der /data-Partition hoch sein können.

Virtuelle A/B-komprimierte Snapshots basieren auf den folgenden Komponenten, die in Android 12 und höher verfügbar sind:

  • dm-user ist ein Kernelmodul, das FUSE ähnelt und mit dem der Userspace Blockgeräte implementieren kann.
  • snapuserd, ein Userspace-Daemon zur Implementierung eines neuen Snapshot-Formats.

Diese Komponenten ermöglichen die Komprimierung. Die anderen erforderlichen Änderungen zur Implementierung der Funktionen für komprimierte Snapshots sind in den folgenden Abschnitten beschrieben: COW-Format für komprimierte Snapshots, dm-user und snapuserd.

COW-Format für komprimierte Snapshots

In Android 12 und höher verwenden komprimierte Snapshots ein Android-spezifisches COW-Format. Das COW-Format enthält Metadaten zum OTA und separate Puffer mit COW-Vorgängen und neuen Betriebssystemdaten. Im Vergleich zum Kernel-Snapshot-Format, das nur replace-Vorgänge zulässt (Block X im Basis-Image durch den Inhalt von Block Y im Snapshot ersetzen), ist das COW-Format für komprimierte Android-Snapshots ausdrucksstärker und unterstützt die folgenden Vorgänge:

  • Kopieren: Block X im Basisgerät sollte durch Block Y im Basisgerät ersetzt werden.
  • Ersetzen: Block X auf dem Basisgerät sollte durch den Inhalt von Block Y im Snapshot ersetzt werden. Jeder dieser Blöcke ist mit GZ-Kompression komprimiert.
  • Null: Block X im Basisgerät sollte durch Nullen ersetzt werden.
  • XOR: Das COW-Gerät speichert XOR-komprimierte Bytes zwischen Block X und Block Y. Verfügbar ab Android 13.

Vollständige OTA-Updates bestehen nur aus replace- und zero-Vorgängen. Inkrementelle OTA-Updates können zusätzlich copy-Vorgänge enthalten.

Das vollständige Snapshot-Layout auf der Festplatte sieht so aus:

Kuhformat

Abbildung 2: Android-COW-Format auf der Festplatte

dm-user

Mit dem dm-user-Kernelmodul kann userspace Device Mapper-Blockgeräte implementieren. Durch einen dm-user-Tabelleneintrag wird unter /dev/dm-user/<control-name> ein sonstiges Gerät erstellt. Ein userspace-Prozess kann das Gerät abfragen, um Lese- und Schreibanfragen vom Kernel zu empfangen. Jeder Anfrage ist ein Puffer für den Nutzerbereich zugeordnet, der entweder gefüllt (für einen Lesevorgang) oder weitergegeben (für einen Schreibvorgang) wird.

Das dm-user-Kernelmodul bietet eine neue, für Nutzer sichtbare Schnittstelle zum Kernel, die nicht Teil der Upstream-Codebasis von kernel.org ist. Bis dahin behält sich Google das Recht vor, die dm-user-Schnittstelle in Android zu ändern.

snapuserd

Die snapuserd-Nutzerbereichskomponente für dm-user implementiert die Virtual A/B-Kompression. Snapuserd ist ein Userspace-Daemon, der für das Schreiben und Lesen der Android-COW-Geräte zuständig ist. Alle Ein-/Ausgaben für den Snapshot müssen über diesen Dienst erfolgen. Während der OTA-Installation werden neue Betriebssystemdaten von snapuserd (mit Komprimierung) in den Snapshot geschrieben. Hier werden auch die Metadaten geparst und die neuen Blockdaten entpackt.

XOR-Komprimierung

Bei Geräten, die mit Android 13 und höher auf den Markt kommen, können mit der standardmäßig aktivierten XOR-Komprimierungsfunktion XOR-komprimierte Bytes zwischen alten und neuen Blöcken in Userspace-Snapshots gespeichert werden. Wenn bei einem virtuellen A/B-Update nur wenige Byte in einem Block geändert werden, benötigt das XOR-Komprimierungsspeicherschema weniger Speicherplatz als das Standardspeicherschema, da in Snapshots keine vollständigen 4 KB gespeichert werden. Diese Reduzierung der Snapshot-Größe ist möglich, da XOR-Daten viele Nullen enthalten und leichter zu komprimieren sind als Rohblockdaten. Auf Pixel-Geräten wird die Snapshot-Größe durch die XOR-Komprimierung um 25% bis 40 % reduziert.

Für Geräte, die auf Android 13 und höher aktualisiert werden, muss die XOR-Komprimierung aktiviert sein. Weitere Informationen finden Sie unter XOR-Komprimierung.

Snapshot-Zusammenführung

Bei Geräten, die bei Markteinführung Android 13 oder höher nutzen, werden die Snapshot- und Snapshot-Zusammenführungsprozesse in der virtuellen A/B-Komprimierung von der snapuserd-Userspace-Komponente ausgeführt. Auf Geräten, die auf Android 13 und höher aktualisiert werden, muss diese Funktion aktiviert sein. Weitere Informationen finden Sie unter Userspace-Merge.

Im Folgenden wird die virtuelle A/B-Kompression beschrieben:

  1. Das Framework mountet die Partition /system von einem dm-verity-Gerät, das auf einem dm-user-Gerät gestapelt ist. Das bedeutet, dass jede E/A-Operation des Root-Dateisystems an dm-user weitergeleitet wird.
  2. dm-user leitet die E/A an den Userspace-Daemon snapuserd weiter, der die E/A-Anfrage verarbeitet.
  3. Wenn der Zusammenführungsvorgang abgeschlossen ist, wird dm-verity im Framework über dm-linear (system_base) platziert und dm-user wird entfernt.

Virtual A/B-Komprimierungsprozess

Abbildung 3: Virtual A/B-Komprimierungsprozess

Der Snapshot-Zusammenführungsprozess kann unterbrochen werden. Wenn das Gerät während des Zusammenführungsvorgangs neu gestartet wird, wird der Vorgang nach dem Neustart fortgesetzt.

Übergänge initialisieren

Beim Booten mit komprimierten Snapshots muss die Initialisierung der ersten Phase snapuserd starten, um Partitionen bereitzustellen. Das ist ein Problem: Wenn sepolicy geladen und erzwungen wird, wird snapuserd in den falschen Kontext gesetzt und seine Leseanfragen schlagen mit SELinux-Verweigerungen fehl.

Um dieses Problem zu beheben, wird snapuserd synchron mit init umgestellt:

  1. Die erste Phase init startet snapuserd über die RAM-Disk und speichert einen offenen Dateideskriptor dafür in einer Umgebungsvariablen.
  2. In der ersten Phase wird mit init das Root-Dateisystem auf die Systempartition umgestellt und dann die Systemkopie von init ausgeführt.
  3. Beim Systemkopieren von init wird die kombinierte sepolicy in einen String gelesen.
  4. Init ruft mlock() auf allen ext4-basierten Seiten auf. Anschließend werden alle Device-Mapper-Tabellen für Snapshot-Geräte deaktiviert und snapuserd wird beendet. Danach ist es verboten, aus Partitionen zu lesen, da dies zu einem Deadlock führt.
  5. Mit dem offenen Deskriptor für die RAM-Disk-Kopie von snapuserd wird init mit dem richtigen SELinux-Kontext neu gestartet. Device-Mapper-Tabellen für Snapshot-Geräte werden reaktiviert.
  6. „Init“ ruft munlockall() auf. Es ist sicher, E/A-Vorgänge wieder auszuführen.

Speicherplatznutzung

In der folgenden Tabelle wird die Speicherplatznutzung für verschiedene OTA-Mechanismen anhand der Betriebssystem- und OTA-Größen von Pixel verglichen.

Auswirkungen der Größe Nicht-A/B A/B Virtual A/B Virtual A/B (komprimiert)
Original-Werksabbild 4,5 GB Super (3,8 GB Bild + 700 MB reserviert)1 9 GB Super (3,8 GB + 700 MB reserviert, für zwei Slots) 4,5 GB (3,8 GB Bild + 700 MB reserviert) 4,5 GB (3,8 GB Bild + 700 MB reserviert)
Andere statische Partitionen /cache Keine Keine Keine
Zusätzlicher Speicher während OTA (Speicherplatz wird nach der Anwendung von OTA zurückgegeben) 1,4 GB auf /data 0 3,8 GB2 auf /data 2,1 GB2 auf /data
Gesamtspeicherplatz, der für die Anwendung von OTA erforderlich ist 5,9 GB3 (Super und Daten) 9 GB (Super) 8,3 GB3 (Super und Daten) 6,6 GB3 (Super und Daten)

1 Gibt das angenommene Layout basierend auf der Pixelzuordnung an.

2: Das neue Systemimage hat dieselbe Größe wie das Original.

3 Der Speicherplatzbedarf ist vorübergehend, bis das Gerät neu gestartet wird.

Virtual A/B in Android 11

Unter Android 11 wurde Virtual A/B mit dem Kernel-COW-Format in die dynamische Partition geschrieben. Es wurde schließlich eingestellt, da das Kernel-COW-Format keine Komprimierung unterstützt.

Virtual A/B unter Android 12

Unter Android 12 wird die Komprimierung in Form eines Android-spezifischen COW-Formats unterstützt. Für diese Version von Virtual A/B war eine Übersetzung des android-spezifischen COW in das Kernel-COW-Format erforderlich. Schließlich wurde dies in Android 13 ersetzt, wodurch die Abhängigkeit vom Kernel-COW-Format und von dm-snapshot entfiel.

Informationen zur Implementierung von Virtual A/B oder zur Verwendung von komprimierten Snapshots finden Sie unter Virtual A/B implementieren.