Implementieren Sie virtuelles A/B

Um virtuelles A/B auf einem neuen Gerät zu implementieren oder ein eingeführtes Gerät nachzurüsten, müssen Sie Änderungen am gerätespezifischen Code vornehmen.

Flaggen bauen

Geräte, die virtuelles A/B verwenden, müssen als A/B-Gerät konfiguriert sein und mit dynamischen Partitionen starten .

Legen Sie für Geräte, die mit virtuellem A/B gestartet werden, fest, dass sie die Basiskonfiguration des virtuellen A/B-Geräts erben:

$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota.mk)

Geräte, die mit virtuellem A/B starten, benötigen für BOARD_SUPER_PARTITION_SIZE nur halb so viel Platinengröße, da sich B-Steckplätze nicht mehr in Super befinden. Das heißt, BOARD_SUPER_PARTITION_SIZE muss größer oder gleich sum(size of update groups) + overhead sein, was wiederum größer oder gleich sum(size of partitions) + overhead sein muss.

Für Android 13 und höher erben Sie die folgende Basiskonfiguration, um komprimierte Snapshots mit Virtual A/B zu ermöglichen:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/android_t_baseline.mk)

Dies ermöglicht Userspace-Snapshots mit Virtual A/B unter Verwendung einer No-Op-Komprimierungsmethode. Anschließend können Sie die Komprimierungsmethode auf eine der unterstützten Methoden gz , zstd und lz4 konfigurieren.

PRODUCT_VIRTUAL_AB_COMPRESSION_METHOD := lz4

Für Android 12 erben Sie die folgende Basiskonfiguration, um komprimierte Snapshots mit Virtual A/B zu aktivieren:

$(call inherit-product, $(SRC_TARGET_DIR)/product/generic_ramdisk.mk)
$(call inherit-product, \
    $(SRC_TARGET_DIR)/product/virtual_ab_ota/compression.mk)

XOR-Komprimierung

Bei Geräten, die auf Android 13 und höher aktualisiert werden, ist die XOR-Komprimierungsfunktion standardmäßig nicht aktiviert. Um die XOR-Komprimierung zu aktivieren, fügen Sie Folgendes zur .mk Datei des Geräts hinzu.

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.compression.xor.enabled=true

Die XOR-Komprimierung ist standardmäßig für Geräte aktiviert, die von android_t_baseline.mk erben.

Userspace-Zusammenführung

Für Geräte, die auf Android 13 und höher aktualisiert werden, ist der unter Device-Mapper-Layering beschriebene Userspace-Zusammenführungsprozess nicht standardmäßig aktiviert. Um die Zusammenführung von Userspaces zu aktivieren, fügen Sie der .mk Datei des Geräts die folgende Zeile hinzu:

PRODUCT_VENDOR_PROPERTIES += ro.virtual_ab.userspace.snapshots.enabled=true

Die Zusammenführung von Userspaces ist auf Geräten mit Version 13 und höher standardmäßig aktiviert.

Boot-Steuerung HAL

Der Boot-Control-HAL bietet eine Schnittstelle für OTA-Clients zur Steuerung von Boot-Slots. Virtual A/B erfordert ein kleineres Versions-Upgrade der Boot-Control-HAL, da zusätzliche APIs erforderlich sind, um sicherzustellen, dass der Bootloader während des Flashens/Zurücksetzens auf die Werkseinstellungen geschützt ist. Die neueste Version der HAL-Definition finden Sie unter IBootControl.hal undtypes.hal .

// hardware/interfaces/boot/1.1/types.hal
enum MergeStatus : uint8_t {
    NONE, UNKNOWN, SNAPSHOTTED, MERGING, CANCELLED };

// hardware/interfaces/boot/1.1/IBootControl.hal
package android.hardware.boot@1.1;
interface IBootControl extends @1.0::IBootControl {
    setSnapshotMergeStatus(MergeStatus status)
        generates (bool success);
    getSnapshotMergeStatus()
        generates (MergeStatus status);
}
// Recommended implementation

Return<bool> BootControl::setSnapshotMergeStatus(MergeStatus v) {
    // Write value to persistent storage
    // e.g. misc partition (using libbootloader_message)
    // bootloader rejects wipe when status is SNAPSHOTTED
    // or MERGING
}

Fstab-Änderungen

Die Integrität der Metadatenpartition ist für den Startvorgang von entscheidender Bedeutung, insbesondere direkt nach der Anwendung eines OTA-Updates. Daher muss die Metadatenpartition überprüft werden, bevor first_stage_init sie bereitstellt. Um sicherzustellen, dass dies geschieht, fügen Sie das Flag check fs_mgr zum Eintrag für /metadata hinzu. Im Folgenden finden Sie ein Beispiel:

/dev/block/by-name/metadata /metadata ext4 noatime,nosuid,nodev,discard,sync wait,formattable,first_stage_mount,check

Kernel-Anforderungen

Um Snapshotting zu aktivieren, setzen Sie CONFIG_DM_SNAPSHOT auf true .

Fügen Sie für Geräte, die F2FS verwenden, das Flag f2fs: export FS_NOCOW_FL in den Benutzer- Kernel-Patch ein, um das Anheften von Dateien zu beheben. Fügen Sie auch den f2fs: support-Kernel-Patch für ausgerichtete angeheftete Dateien hinzu.

Virtual A/B basiert auf Funktionen, die in Kernel-Version 4.3 hinzugefügt wurden: das Überlaufstatusbit in den snapshot und snapshot-merge Zielen. Alle Geräte, die mit Android 9 und höher starten, sollten bereits über die Kernel-Version 4.4 oder höher verfügen.

Um komprimierte Snapshots zu ermöglichen, ist die minimal unterstützte Kernelversion 4.19. Legen Sie CONFIG_DM_USER=m oder CONFIG_DM_USER=y fest. Wenn ersteres (ein Modul) verwendet wird, muss das Modul in die Ramdisk der ersten Stufe geladen werden. Dies kann durch Hinzufügen der folgenden Zeile zum Geräte-Makefile erreicht werden:

BOARD_GENERIC_RAMDISK_KERNEL_MODULES_LOAD := dm-user.ko

Nachrüstung bei Geräten, die auf Android 11 aktualisiert werden

Beim Upgrade auf Android 11 können Geräte, die mit dynamischen Partitionen gestartet sind, optional virtuelles A/B nachrüsten. Der Update-Prozess ist größtenteils derselbe wie bei Geräten, die mit Virtual A/B gestartet werden, mit einigen geringfügigen Unterschieden:

  • Speicherort der COW-Dateien – Für Startgeräte nutzt der OTA-Client den gesamten verfügbaren leeren Speicherplatz in der Superpartition, bevor er Speicherplatz in /data verwendet. Bei Nachrüstgeräten ist in der Superpartition immer genügend Platz vorhanden, sodass die COW-Datei nie auf /data erstellt wird.

  • Build-Time-Feature-Flags – Für Geräte, die virtuelles A/B nachrüsten, werden sowohl PRODUCT_VIRTUAL_AB_OTA als auch PRODUCT_VIRTUAL_AB_OTA_RETROFIT auf true gesetzt, wie unten gezeigt:

    (call inherit-product, \
        (SRC_TARGET_DIR)/product/virtual_ab_ota_retrofit.mk)
    
  • Super-Partitionsgröße – Geräte, die mit virtuellem A/B gestartet werden, können BOARD_SUPER_PARTITION_SIZE halbieren, da sich B-Steckplätze nicht in der Super-Partition befinden. Geräte, die Virtual A/B nachrüsten, behalten die alte Superpartitionsgröße bei, sodass BOARD_SUPER_PARTITION_SIZE größer oder gleich 2 * Summe (Größe der Aktualisierungsgruppen) + Overhead ist, was wiederum größer oder gleich 2 * Summe (Größe der Partitionen) ist. + Overhead .

Bootloader-Änderungen

Während des Zusammenführungsschritts eines Updates enthält /data die einzige vollständige Instanz des Android-Betriebssystems. Sobald die Migration beginnt, sind die nativen system , vendor und product unvollständig, bis die Kopie abgeschlossen ist. Wenn das Gerät während dieses Vorgangs entweder durch Wiederherstellung oder über das Dialogfeld „Systemeinstellungen“ auf die Werkseinstellungen zurückgesetzt wird, kann das Gerät nicht mehr gestartet werden.

Bevor Sie /data löschen, schließen Sie je nach Gerätestatus die Zusammenführung bei der Wiederherstellung oder beim Rollback ab:

  • Wenn der neue Build zuvor erfolgreich gestartet wurde, schließen Sie die Migration ab.
  • Ansonsten Rollback zum alten Slot:
    • Führen Sie bei dynamischen Partitionen ein Rollback auf den vorherigen Zustand durch.
    • Stellen Sie bei statischen Partitionen den aktiven Steckplatz auf den alten Steckplatz ein.

Sowohl der Bootloader als auch fastbootd können die /data Partition löschen, wenn das Gerät entsperrt ist. Während fastbootd den Abschluss der Migration erzwingen kann, ist dies beim Bootloader nicht möglich. Der Bootloader weiß nicht, ob gerade eine Zusammenführung stattfindet oder welche Blöcke in /data die Betriebssystempartitionen bilden. Geräte müssen verhindern, dass der Benutzer das Gerät unwissentlich funktionsunfähig macht (Bricking), indem er Folgendes tut:

  1. Implementieren Sie die Boot-Steuerungs-HAL, damit der Bootloader den von der setSnapshotMergeStatus() Methode festgelegten Wert lesen kann.
  2. Wenn der Zusammenführungsstatus MERGING lautet oder wenn der Zusammenführungsstatus SNAPSHOTTED lautet und der Steckplatz in den neu aktualisierten Steckplatz geändert wurde, müssen Anforderungen zum Löschen userdata , metadata oder der Partition, die den Zusammenführungsstatus speichert, im Bootloader abgelehnt werden.
  3. Implementieren Sie den Befehl fastboot snapshot-update cancel , damit Benutzer dem Bootloader signalisieren können, dass sie diesen Schutzmechanismus umgehen möchten.
  4. Ändern Sie benutzerdefinierte Flash-Tools oder Skripte, um beim Flashen des gesamten Geräts fastboot snapshot-update cancel auszulösen. Dies ist sicher, da durch das Flashen des gesamten Geräts der OTA entfernt wird. Tooling kann diesen Befehl zur Laufzeit erkennen, indem es fastboot getvar snapshot-update-status implementiert. Dieser Befehl hilft bei der Unterscheidung zwischen Fehlerbedingungen.

Beispiel

struct VirtualAbState {
    uint8_t StructVersion;
    uint8_t MergeStatus;
    uint8_t SourceSlot;
};

bool ShouldPreventUserdataWipe() {
    VirtualAbState state;
    if (!ReadVirtualAbState(&state)) ...
    return state.MergeStatus == MergeStatus::MERGING ||
           (state.MergeStatus == MergeStatus::SNAPSHOTTED &&
            state.SourceSlot != CurrentSlot()));
}

Änderungen an den Fastboot-Tools

Android 11 nimmt die folgenden Änderungen am Fastboot-Protokoll vor:

  • getvar snapshot-update-status – Gibt den Wert zurück, den die Boot-Steuerungs-HAL dem Bootloader mitgeteilt hat:
    • Wenn der Status MERGING lautet, muss der Bootloader merging zurückgeben.
    • Wenn der Status SNAPSHOTTED ist, muss der Bootloader snapshotted zurückgeben.
    • Andernfalls muss der Bootloader none zurückgeben.
  • snapshot-update merge – Führt einen Zusammenführungsvorgang durch und startet bei Bedarf mit Recovery/Fastbootd. Dieser Befehl ist nur gültig, wenn snapshot-update-status merging ist, und wird nur in fastbootd unterstützt.
  • snapshot-update cancel – Setzt den Zusammenführungsstatus der Boot-Steuerungs-HAL auf CANCELLED . Dieser Befehl ist ungültig, wenn das Gerät gesperrt ist.
  • erase oder wipe – Ein erase oder wipe von metadata , userdata oder einer Partition, die den Zusammenführungsstatus für die Startsteuerung enthält. HAL sollte den Snapshot-Zusammenführungsstatus überprüfen. Wenn der Status MERGING oder SNAPSHOTTED lautet, sollte das Gerät den Vorgang abbrechen.
  • set_active – Ein set_active Befehl, der den aktiven Slot ändert, sollte den Snapshot-Zusammenführungsstatus überprüfen. Wenn der Status MERGING lautet, sollte das Gerät den Vorgang abbrechen. Der Steckplatz kann im SNAPSHOTTED Zustand sicher geändert werden.

Diese Änderungen sollen verhindern, dass ein Gerät versehentlich nicht mehr gestartet werden kann, sie können jedoch zu Störungen bei automatisierten Tools führen. Wenn die Befehle als Komponente zum Flashen aller Partitionen verwendet werden, z. B. beim Ausführen von fastboot flashall , wird die Verwendung des folgenden Ablaufs empfohlen:

  1. Fragen Sie getvar snapshot-update-status .
  2. Wenn merging oder snapshotted erstellen, geben Sie snapshot-update cancel aus.
  3. Fahren Sie mit den blinkenden Schritten fort.

Reduzieren Sie den Speicherbedarf

Für Geräte, denen in Super nicht der volle A/B-Speicher zugewiesen ist und die voraussichtlich /data nach Bedarf verwenden, wird dringend empfohlen, das Block-Mapping-Tool zu verwenden. Das Blockzuordnungstool sorgt dafür, dass die Blockzuordnung zwischen den Builds konsistent bleibt und unnötige Schreibvorgänge in den Snapshot reduziert werden. Dies ist unter „Reduzierung der OTA-Größe“ dokumentiert.

OTA-Komprimierungsmethoden

OTA-Pakete können für verschiedene Leistungsmetriken optimiert werden. Android bietet mehrere unterstützte Komprimierungsmethoden ( gz , lz4 , zstd und none ), die Kompromisse zwischen Installationszeit, COW-Speicherplatznutzung, Startzeit und Snapshot-Zusammenführungszeit mit sich bringen. Die für Virtual AB mit Komprimierung aktivierte Standardoption ist die gz compression method . (Hinweis: Die relative Leistung zwischen den Komprimierungsmethoden variiert je nach CPU-Geschwindigkeit und Speicherdurchsatz, die sich je nach Gerät ändern können. Bei allen unten generierten OTA-Paketen ist PostInstall deaktiviert, was die Startzeit etwas verlangsamt. Die gesamte dynamische Partitionsgröße eines vollständigen OTA ohne Komprimierung beträgt 4,81 GB ).

Inkrementelles OTA auf Pixel 6 Pro

Installationszeit ohne Nachinstallationsphase COW-Raumnutzung Post-OTA-Startzeit Snapshot-Zusammenführungszeit
gz 24 Min 1,18 GB 40,2 Sek 45,5 Sek
lz4 13 Min 1,49 GB 37,4 Sek 37,1 Sek
keiner 13 Min 2,90 GB 37,6 Sek 40,7 Sek

Vollständiges OTA auf Pixel 6 Pro

Installationszeit ohne Nachinstallationsphase COW-Raumnutzung Post-OTA-Startzeit Snapshot-Zusammenführungszeit
gz 23 Min 2,79 GB 24,9 Sek 41,7 Sek
lz4 12 Min 3,46 GB 20,0 Sek 25,3 Sek
keiner 10 Minuten 4,85 GB 20,6 Sek 29,8 Sek