Virtuelle A/B-Übersicht

Android verfügt über zwei Update-Mechanismen: A/B-Updates (seamless) und Nicht-A/B-Updates. Um die Codekomplexität zu reduzieren und den Aktualisierungsprozess zu verbessern, werden in Android 11 die beiden Mechanismen durch virtuelles A/B vereinheitlicht, um nahtlose Aktualisierungen für alle Geräte mit minimierten Speicherkosten bereitzustellen. Android 12 bietet die Option der virtuellen A/B-Komprimierung, um Snapshot-Partitionen zu komprimieren. Sowohl in Android 11 als auch in Android 12 gilt Folgendes:

  • Virtuelle A/B-Updates sind nahtlos wie A/B-Updates. Virtuelle A/B-Updates minimieren die Zeit, in der ein Gerät offline und unbrauchbar ist.
  • Virtuelle A/B-Updates können rückgängig gemacht werden . Wenn das neue Betriebssystem nicht gestartet werden kann, werden die Geräte automatisch auf die vorherige Version zurückgesetzt.
  • Virtuelle A/B-Updates verwenden ein Minimum an zusätzlichem Speicherplatz, indem nur die Partitionen dupliziert werden, die vom Bootloader verwendet werden. Von anderen aktualisierbaren Partitionen wird ein Snapshot erstellt .

Hintergrund und Terminologie

Dieser Abschnitt definiert die Terminologie und beschreibt die Technologie, die virtuelles A/B unterstützt.

Gerätemapper

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

  • Am Ende des Stapels befindet sich die physische Superpartition (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 Partition bilden. Dies erscheint als /dev/block/mapper/system_[a|b] auf einem A/B-Gerät oder /dev/block/mapper/system auf einem Nicht-A/B-Gerät.
  • Ganz oben befindet sich ein dm-verity Gerät, das für verifizierte Partitionen erstellt wurde. Dieses Gerät überprüft, ob Blöcke auf dem dm-linear Gerät korrekt signiert sind. Es erscheint als /dev/block/mapper/system-verity und ist die Quelle des Einhängepunkts /system .

Abbildung 1 zeigt, wie der Stack unter dem Einhängepunkt /system aussieht.

Partition stacking underneath system

Abbildung 1. Stack unter dem Einhängepunkt /system

dm-Schnappschuss

Virtuelles A/B basiert auf dm-snapshot , einem Device-Mapper-Modul zum Erstellen von Snapshots des Zustands eines Speichergeräts. Bei der Verwendung von dm-snapshot sind vier Geräte im Spiel:

  • Das Basisgerät ist das Gerät, das einen Snapshot erstellt. Auf dieser Seite ist das Basisgerät immer eine dynamische Partition, z. B. System oder Hersteller.
  • Das COW-Gerät ( Copy-on-Write ) zum Protokollieren von Änderungen am Basisgerät. Es kann beliebig groß sein, muss aber groß genug sein, um alle Änderungen am Basisgerät aufzunehmen.
  • Das Snapshot -Gerät wird mithilfe des snapshot -Ziels erstellt. Schreibvorgänge auf das Snapshot-Gerät werden auf das COW-Gerät geschrieben. Lesevorgänge vom Snapshot-Gerät lesen entweder vom Basisgerät oder vom COW-Gerät, je nachdem, ob die Daten, auf die zugegriffen wird, durch den Snapshot geändert wurden.
  • Das Ursprungsgerät wird mithilfe des snapshot-origin Ziels erstellt. Liest auf dem Ursprungsgerät, das direkt vom Basisgerät gelesen wird. Schreibvorgänge auf das Ursprungsgerät schreiben direkt auf das Basisgerät, aber die ursprünglichen Daten werden gesichert, indem auf das COW-Gerät geschrieben wird.

Device mapping for dm-snapshot

Abbildung 2. Gerätezuordnung für dm-snapshot

Komprimierte Schnappschüsse

Da der Speicherplatzbedarf auf der /data Partition in Android 12 hoch sein kann, können Sie komprimierte Snapshots in Ihrem Build aktivieren, um die höheren Speicherplatzanforderungen der /data Partition zu erfüllen.

Virtuelle A/B-komprimierte Snapshots bauen auf zwei neuen Komponenten auf, die in Android 12 verfügbar sind:

  • dm-user , ein Kernel-Modul ähnlich FUSE, das es dem Userspace ermöglicht, Blockgeräte zu implementieren.
  • snapuserd , ein Userspace-Daemon zur Implementierung eines neuen Snapshot-Formats.

Diese Komponenten ermöglichen die Komprimierung. Die anderen notwendigen Änderungen, die zur Implementierung der Funktionen für komprimierte Snapshots vorgenommen wurden, werden in den nächsten Abschnitten beschrieben: COW-Format für komprimierte Snapshots , dm-user und Snapuserd .

COW-Format für komprimierte Schnappschüsse

In Android 12 verwenden komprimierte Snapshots ein neues COW-Format. Ähnlich wie das eingebaute Format des Kernels, das für unkomprimierte Snapshots verwendet wird, hat das COW-Format für die komprimierten Snapshots abwechselnde Abschnitte von Metadaten und Daten. Die Metadaten des ursprünglichen Formats erlaubten nur „Ersetzungs“-Operationen: Ersetzen Sie Block X im Basisbild durch den Inhalt von Block Y im Schnappschuss. Das komprimierte Snapshot-COW-Format ist ausdrucksstärker und unterstützt drei Operationen:

  • 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 gz-komprimiert.
  • Null – Block X im Basisgerät sollte durch alle Nullen ersetzt werden.

Vollständige OTA-Updates bestehen nur aus Ersetzungs- und Nulloperationen . Inkrementelle OTA-Updates können zusätzlich Kopiervorgänge haben.

dm-Benutzer in Android 12

Das dm-user-Kernelmodul ermöglicht es userspace , Device-Mapper-Blockgeräte zu implementieren. Ein dm-user-Tabelleneintrag erstellt ein sonstiges Gerät unter /dev/dm-user/<control-name> . Ein userspace -Prozess kann das Gerät abfragen, um Lese- und Schreibanforderungen vom Kernel zu erhalten. Jede Anfrage hat einen zugehörigen Puffer, den der Userspace entweder füllen (für einen Lesevorgang) oder propagieren (für einen Schreibvorgang) kann.

Das dm-user Kernelmodul bietet eine neue, für den Benutzer 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 in Android zu ändern.

Snapuserd

Die Userspace-Komponente snapuserd für dm-user implementiert die virtuelle A/B-Komprimierung.

In der unkomprimierten Version von Virtual A/B (entweder in Android 11 und niedriger oder in Android 12 ohne die komprimierte Snapshot-Option) ist das COW-Gerät eine Rohdatei. Wenn die Komprimierung aktiviert ist, fungiert der COW stattdessen als dm-user Gerät, das mit einer Instanz des snapuserd Daemons verbunden ist.

Der Kernel verwendet das neue COW-Format nicht. Die snapuserd Komponente übersetzt also Anfragen zwischen dem Android COW-Format und dem eingebauten Format des Kernels:

Snapuserd component translating requests between Android COW format and kernel built-in format

Abbildung 3. Flussdiagramm von snapuserd als Übersetzer zwischen Android- und Kernel-COW-Formaten

Diese Übersetzung und Dekomprimierung erfolgt niemals auf der Festplatte. Die snapuserd Komponente fängt die COW-Lese- und -Schreibvorgänge ab, die im Kernel auftreten, und implementiert sie mithilfe des Android-COW-Formats.

Virtuelle A/B-Komprimierungsverfahren

Diese Abschnitte enthalten Details zu den Prozessen, die bei der virtuellen A/B-Komprimierung verwendet werden: Lesen von Metadaten, Zusammenführen und Ausführen von Init-Übergängen.

Lesen von Metadaten

Metadaten werden von einem snapuserd Daemon erstellt. Die Metadaten sind in erster Linie eine Abbildung von 2 IDs mit jeweils 8 Bytes, die die zusammenzuführenden Sektoren darstellen. In dm-snapshot heißt es disk_exception .

struct disk_exception {
    uint64_t old_chunk;
    uint64_t new_chunk;
};

Eine Plattenausnahme wird verwendet, wenn ein alter Datenblock durch einen neuen ersetzt wird.

Ein Snapuserd Daemon liest die interne COW-Datei über die COW-Bibliothek und erstellt die Metadaten für jede der in der COW-Datei vorhandenen COW-Operationen.

Metadaten-Lesevorgänge werden vom dm-snapshot im Kernel initiiert, wenn das dm- dm- snapshot -Gerät erstellt wird.

Die folgende Abbildung zeigt ein Sequenzdiagramm für den IO-Pfad für die Metadatenkonstruktion.

Sequence diagram, IO path for metadata construction

Abbildung 4. Sequenzfluss für den IO-Pfad in der Metadatenkonstruktion

Zusammenführen

Sobald der Startvorgang abgeschlossen ist, markiert die Update-Engine den Steckplatz als Start erfolgreich und leitet die Zusammenführung ein, indem sie das dm-snapshot Ziel auf das dm-snapshot-merge Ziel umschaltet.

dm-snapshot durchläuft die Metadaten und initiiert einen Zusammenführungs-E/A für jede Datenträgerausnahme. Eine allgemeine Übersicht über den Zusammenführungs-E/A-Pfad ist unten dargestellt.

Merge IO path

Abbildung 5. Übersicht über Merge-IO-Pfade

Wenn das Gerät während des Zusammenführungsvorgangs neu gestartet wird, wird die Zusammenführung beim nächsten Neustart fortgesetzt und die Zusammenführung abgeschlossen.

Übergänge einleiten

Beim Booten mit komprimierten Snapshots muss die Init der ersten Stufe snapuserd starten, um Partitionen zu mounten. Dies stellt ein Problem dar: Wenn sepolicy geladen und erzwungen wird, wird snapuserd in den falschen Kontext versetzt, und seine Leseanforderungen schlagen mit selinux-Denials fehl.

Um dies zu beheben, werden snapuserd -Übergänge im Gleichschritt mit init wie folgt ausgeführt:

  1. init der ersten Stufe startet snapuserd von der Ramdisk und speichert einen offenen Dateideskriptor in einer Umgebungsvariablen.
  2. init der ersten Stufe schaltet das Root-Dateisystem auf die Systempartition um und führt dann die Systemkopie von init aus.
  3. Die Systemkopie von init liest die kombinierte sepolicy in einen String.
  4. Init ruft mlock() auf allen ext4-unterstützten Seiten auf. Es deaktiviert dann alle Device-Mapper-Tabellen für Snapshot-Geräte und stoppt snapuserd . Danach ist es verboten, von Partitionen zu lesen, da dies zu einem Deadlock führt.
  5. Unter Verwendung des offenen Deskriptors für die Ramdisk-Kopie von snapuserd init den Daemon mit dem korrekten Selinux-Kontext neu. Device-Mapper-Tabellen für Snapshot-Devices werden reaktiviert.
  6. Init ruft munlockall() auf - es ist sicher, IO erneut auszuführen.

Platznutzung

Die folgende Tabelle bietet einen Vergleich der Speicherplatznutzung für verschiedene OTA-Mechanismen unter Verwendung der OS- und OTA-Größen von Pixel.

Einfluss auf die Größe Nicht-A/B A/B Virtuelles A/B Virtuelles A/B (komprimiert)
Originalbild der Fabrik 4,5 GB Super (3,8 GB Bild + 700 MB reserviert) 1 9 GB Super (3,8 G + 700 MB reserviert, für zwei Slots) 4,5 GB Super (3,8 GB Bild + 700 MB reserviert) 4,5 GB Super (3,8 GB Bild + 700 MB reserviert)
Andere statische Partitionen /Zwischenspeicher Keiner Keiner Keiner
Zusätzlicher Speicher während OTA (Speicherplatz wird nach Anwendung von OTA zurückgegeben) 1,4 GB auf /data 0 3,8 GB 2 auf /data 2,1 GB 2 auf /data
Für die Anwendung von OTA erforderlicher Gesamtspeicher 5,9 GB 3 (Super und Daten) 9 GB (super) 8,3 GB 3 (Super und Daten) 6,6 GB 3 (Super und Daten)

1 Zeigt das angenommene Layout basierend auf der Pixelzuordnung an.

2 Geht davon aus, dass das neue Systemabbild die gleiche Größe wie das Original hat.

3 Speicherplatzbedarf ist vorübergehend bis zum Neustart.

Informationen zum Implementieren von Virtual A/B oder zum Verwenden komprimierter Snapshot-Funktionen finden Sie unter Implementieren von Virtual A/B