Implementieren von A/B-Updates

OEMs und SoC - Anbieter , die A / B - System - Updates müssen ihre Bootloader implementiert die boot_control HAL sicherzustellen , und übergibt die implementieren möchten korrekten Parameter an den Kernel.

Implementieren der Bootkontrolle HAL

A / B-fähig Bootloader muss die Umsetzung boot_control HAL bei hardware/libhardware/include/hardware/boot_control.h . Sie können Implementierungen testen Sie die Verwendung von system/extras/bootctl Dienstprogramm und system/extras/tests/bootloader/ .

Sie müssen auch die unten gezeigte Zustandsmaschine implementieren:

Abbildung 1. Bootloader - Zustandsmaschine

Kernel einrichten

So implementieren Sie A/B-Systemupdates:

  1. Wählen Sie die folgenden Kernel-Patch-Serien aus (falls erforderlich):
  2. Stellen Sie sicher , Kernel Befehlszeilenargumente enthalten die folgenden zusätzlichen Argumente:
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... wo die <public-key-id> Wert die ID des öffentlichen Schlüssels verwendet die Verity Tabelle Signatur zu verifizieren (Details siehe dm-Verity ) .
  3. Fügen Sie das .X509-Zertifikat mit dem öffentlichen Schlüssel zum Systemschlüsselbund hinzu:
    1. Kopieren Sie die .X509 Zertifikat formatiert im .der Format an die Wurzel des kernel - Verzeichnis. Wenn das .X509 Zertifikat als formatiert ist .pem - Datei, verwenden Sie den folgenden openssl Befehl zu konvertieren von .pem zu .der Format:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. Erstellen Sie das zImage das Zertifikat als Teil des Systems Schlüsselbund aufzunehmen. Um zu überprüfen, überprüfen Sie den procfs Eintrag (erfordert KEYS_CONFIG_DEBUG_PROC_KEYS aktiviert sein):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      Erfolgreiche Einbeziehung des .X509 Zertifikats , das Vorhandensein des öffentlichen Schlüssels im System Schlüsselbund zeigt (Highlight bezeichnet die öffentlichen Schlüssel - ID).
    3. Ersetzen Sie den Raum mit # und gibt es als <public-key-id> in der Kernel - Kommandozeile. Zum Beispiel passiert Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f anstelle von <public-key-id> .

Build-Variablen setzen

A/B-fähige Bootloader müssen die folgenden Build-Variablen-Kriterien erfüllen:

Muss für A/B-Ziel definiert werden
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
    boot \
    system \
    vendor
    und andere Partitionen durch aktualisierte update_engine (Radio, Bootloader, usw.)
  • PRODUCT_PACKAGES += \
    update_engine \
    update_verifier
Ein Beispiel finden Sie in /device/google/marlin/+/android-7.1.0_r1/device-common.mk . Optional können Sie führen die nach der Installation (aber pre-Neustart) dex2oat Schritt in beschrieben compilieren .
Dringend empfohlen für A/B-Ziele
  • Definieren TARGET_NO_RECOVERY := true
  • Definieren BOARD_USES_RECOVERY_AS_BOOT := true
  • Sie nicht definieren BOARD_RECOVERYIMAGE_PARTITION_SIZE
Kann nicht für A/B-Ziel definiert werden
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
Optional für Debug-Builds PRODUCT_PACKAGES_DEBUG += update_engine_client

Partitionen (Slots) einstellen

A/B-Geräte benötigen keine Wiederherstellungspartition oder Cache-Partition, da Android diese Partitionen nicht mehr verwendet. Die Datenpartition wird jetzt für das heruntergeladene OTA-Paket verwendet und der Wiederherstellungs-Image-Code befindet sich auf der Boot-Partition. Alle Partitionen , die A / B-ed sind wie folgt benannt werden (Slots sind immer genannt a , b , usw.): boot_a , boot_b , system_a , system_b , vendor_a , vendor_b .

Zwischenspeicher

Bei Nicht-A/B-Updates wurde die Cache-Partition verwendet, um heruntergeladene OTA-Pakete zu speichern und Blöcke während der Anwendung von Updates vorübergehend zu verstauen. Es gab nie eine gute Möglichkeit, die Cache-Partition zu dimensionieren: Wie groß sie sein musste, hing davon ab, welche Updates Sie anwenden wollten. Der schlimmste Fall wäre eine Cache-Partition, die so groß ist wie das Systemabbild. Bei A/B-Updates ist es nicht erforderlich, Blöcke zu verstauen (weil Sie immer auf eine Partition schreiben, die derzeit nicht verwendet wird) und beim Streaming von A/B müssen Sie nicht das gesamte OTA-Paket herunterladen, bevor Sie es anwenden.

Erholung

Die Erholung RAM - Disk ist nun in der enthaltenen boot.img Datei. Wenn in dem Recovery geht, kann der Bootloader setzt die nicht skip_initramfs Option auf der Kernel - Kommandozeile.

Bei Nicht-A/B-Updates enthält die Wiederherstellungspartition den Code, der zum Anwenden von Updates verwendet wird. A / B - Updates angewandt wird durch update_engine in dem regulären gestiefelten Systemabbild ausgeführt wird . Es gibt immer noch einen Wiederherstellungsmodus, der verwendet wird, um das Zurücksetzen auf die Werkseinstellungen und das seitliche Laden von Aktualisierungspaketen zu implementieren (woher der Name "Wiederherstellung" stammt). Der Code und die Daten für den Wiederherstellungsmodus werden in der regulären Bootpartition auf einer Ramdisk gespeichert; Um in das System-Image zu booten, weist der Bootloader den Kernel an, die Ramdisk zu überspringen (sonst bootet das Gerät in den Wiederherstellungsmodus. Der Wiederherstellungsmodus ist klein (und vieles davon befand sich bereits auf der Boot-Partition), sodass die Boot-Partition nicht größer wird in Größe.

Fstab

Das slotselect Argument muß für die A / B-ed Partitionen auf die Linie sein. Zum Beispiel:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

Keine Partition sollte genannt werden vendor . Stattdessen Partition vendor_a oder vendor_b wird ausgewählt und an dem /vendor

Kernel-Slot-Argumente

Die aktuellen Schlitz Suffix sollte entweder durch einen spezifischen Gerätebaum (DT) Knoten (weitergegeben /firmware/android/slot_suffix ) oder durch die androidboot.slot_suffix kernel Befehlszeilen oder bootconfig Argument.

Standardmäßig flasht Fastboot den aktuellen Steckplatz auf einem A/B-Gerät. Wenn das Update-Paket auch Images für den anderen, nicht aktuellen Slot enthält, flasht Fastboot auch diese Images. Zu den verfügbaren Optionen gehören:

  • --slot SLOT . Überschreiben Sie das Standardverhalten und fordern Sie Fastboot auf, den als Argument übergebenen Steckplatz zu flashen.
  • --set-active [ SLOT ] . Setzen Sie den Steckplatz als aktiv. Wenn kein optionales Argument angegeben wird, wird der aktuelle Slot als aktiv gesetzt.
  • fastboot --help . Holen Sie sich Details zu Befehlen.

Wenn der Bootloader implementiert Fast Boot, sollte es den Befehl unterstützen set_active <slot> dass setzt den aktuellen aktiven Schlitz zum gegebenen Schlitz (dies auch die unbootable Flagge für diesen Schlitz löschen müssen und die Wiederholungsanzahl auf die Standardwerte zurückgesetzt). Der Bootloader sollte auch die folgenden Variablen unterstützen:

  • has-slot:<partition-base-name-without-suffix> . Gibt "yes" zurück, wenn die angegebene Partition Slots unterstützt, andernfalls "no".
  • current-slot . Gibt das Slot-Suffix zurück, von dem als nächstes gebootet wird.
  • slot-count . Gibt eine ganze Zahl zurück, die die Anzahl der verfügbaren Slots darstellt. Derzeit sind zwei Steckplätze unterstützt , so ist dieser Wert 2 .
  • slot-successful:<slot-suffix> . Gibt "yes" zurück, wenn der angegebene Slot als erfolgreich gebootet wurde, andernfalls "no".
  • slot-unbootable:<slot-suffix> . Gibt "yes" zurück, wenn der angegebene Slot als nicht bootfähig markiert ist, andernfalls "no".
  • slot-retry-count . Anzahl der verbleibenden Versuche, den angegebenen Steckplatz zu booten.

Um alle Variablen anzuzeigen, führen fastboot getvar all .

OTA-Pakete generieren

Die OTA - Paket Werkzeuge folgen die gleichen Befehle , wie die Befehle für die Nicht-A / B - Geräte. Die target_files.zip Datei muss durch die Definition der Build - Variablen für die A / B - Target erzeugt werden. Die OTA-Pakettools identifizieren und generieren Pakete automatisch im Format für den A/B-Updater.

Beispiele:

  • So generieren Sie einen vollständigen OTA:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • So generieren Sie eine inkrementellen OTA:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

Partitionen konfigurieren

Die update_engine kann jedes Paar von A / B Partitionen Aktualisierung in der gleichen Festplatte definiert ist . Ein Paar von Partitionen hat einen gemeinsamen Präfix (wie system oder boot ) und pro-Schlitz - Suffix (wie _a ). Die Liste der Partitionen , für die der Payload Generator definiert eine Aktualisierung durch die konfiguriert ist AB_OTA_PARTITIONS machen variabel.

Zum Beispiel, wenn ein Paar von Trennwänden bootloader_a und booloader_b enthalten sind ( _a und _b sind die Slot - Suffixe), können Sie diese Partitionen aktualisieren , indem Sie die folgenden auf dem Produkt oder Board - Konfiguration festgelegt wird :

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

Alle Partitionen aktualisiert update_engine darf nicht vom Rest des Systems verändert werden. Während der inkrementalen oder Delta - Updates werden die binären Daten aus dem aktuellen Schlitz verwendet , um die Daten in dem neuen Schlitz zu erzeugen. Jede Änderung kann dazu führen, dass die Überprüfung der neuen Steckplatzdaten während des Aktualisierungsprozesses fehlschlägt und daher die Aktualisierung fehlschlägt.

Nachinstallation konfigurieren

Sie können den Schritt nach der Installation für jede aktualisierte Partition unterschiedlich konfigurieren, indem Sie einen Satz von Schlüssel-Wert-Paaren verwenden. Bei sich , um ein Programm auszuführen /system/usr/bin/postinst in einem neuen Bild, den Pfad relativ zu der Wurzel des Dateisystems in der Systempartition.

Zum Beispiel usr/bin/postinst ist system/usr/bin/postinst (wenn nicht eine RAM - Disk verwenden). Darüber hinaus gibt den Dateisystem - Typen an den passiert mount(2) Systemaufruf. Fügen Sie die folgende auf die Produkt oder Gerät .mk Dateien (falls zutreffend):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

Kompilieren

Aus Sicherheitsgründen system_server kann nicht verwendet werden just-in-time (JIT) Kompilierung. Das heißt , Sie müssen vor der Zeit odex Dateien für kompilieren system_server und ihre Abhängigkeiten auf ein Minimum; alles andere ist optional.

Um Apps im Hintergrund zu kompilieren, müssen Sie der Gerätekonfiguration des Produkts (in der device.mk des Produkts) Folgendes hinzufügen:

  1. Schließen Sie die nativen Komponenten in den Build ein, um sicherzustellen, dass das Kompilierungsskript und die Binärdateien kompiliert und in das Systemabbild aufgenommen werden.
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. Schließen Sie das Kompilation Skript update_engine so dass Läufe als ein Schritt nach der Installation.
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

Für Hilfe bei den preopted Dateien in der ungenutzten zweiten Systempartition installieren, finden Sie in Erste - Boot - Installation von DEX_PREOPT Dateien .