Übersicht über virtuelles A/B

Virtual A/B ist der Hauptmechanismus für Updates in 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.

Für dynamische Partitionen ist bei Virtual A/B kein zusätzlicher Slot erforderlich. 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 und die Nutzung von Speicherplatz wird minimiert. 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, von denen Snapshots erstellt wurden. Virtual A/B bietet Folgendes:

  • Virtuelle A/B-Updates sind wie A/B-Updates nahtlos, da das Update vollständig im Hintergrund erfolgt, 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 auf den Geräten 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-Blockschicht, 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 prü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.

Partitionen unter dem System stapeln

Abbildung 1. Stapel unter dem Bereitstellungspunkt „/system“

Komprimierte Snapshots

Unter Android 12 und höher können die Speicheranforderungen für die /data-Partition hoch sein. Daher können Sie in Ihrem Build komprimierte Snapshots aktivieren, um den höheren Speicheranforderungen der /data-Partition gerecht zu werden.

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

  • dm-user: Ein Kernelmodul, das FUSE ähnelt und mit dem Blockgeräte im Userspace implementiert werden können.
  • snapuserd: Ein Userspace-Daemon zur Implementierung eines neuen Snapshot-Formats.

Diese Komponenten ermöglichen die Komprimierung. Die anderen notwendigen Ä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 (Ersetze Block X im Basis-Image durch den Inhalt von Block Y im Snapshot), 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 im Basisgerät sollte durch den Inhalt von Block Y im Snapshot ersetzt werden. Jeder dieser Blöcke ist mit Gzip 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 unter Android 13 und höher)

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 ein sonstiges Gerät unter /dev/dm-user/<control-name> 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-Komprimierung. 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 Größe von Snapshots 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 hängt die Partition /system von einem dm-verity-Gerät ein, das auf einem dm-user-Gerät gestapelt ist. Das bedeutet, dass jede E/A aus dem Root-Dateisystem an dm-user weitergeleitet wird.
  2. dm-user leitet die E/A an den snapuserd-Daemon im Userspace weiter, der die E/A-Anfrage verarbeitet.
  3. Wenn der Zusammenführungs-Vorgang 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 Prozess zum Zusammenführen von Snapshots 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. Die Systemkopie von init liest die kombinierte sepolicy in einen String ein.
  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 Ramdisk-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 der OTA-Aktualisierung (Speicherplatz wird nach der OTA-Aktualisierung 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. Dies wurde schließlich 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.