Auf dieser Seite werden Änderungen beschrieben, die in AOSP hinzugefügt wurden, um unnötige Dateiänderungen zwischen Builds zu reduzieren. Geräteimplementierer, die ihre eigenen Build-Systeme verwalten, können diese Informationen als Leitfaden verwenden, um die Größe ihrer Over-the-Air-Updates (OTA) zu reduzieren.
Android-OTA-Updates enthalten gelegentlich geänderte Dateien, die nicht mit Codeänderungen übereinstimmen. Tatsächlich handelt es sich um Artefakte des Build-Systems. Dies kann passieren, wenn derselbe Code, der zu unterschiedlichen Zeiten, aus unterschiedlichen Verzeichnissen oder auf unterschiedlichen Computern erstellt wurde, eine große Anzahl geänderter Dateien erzeugt. Solche zusätzlichen Dateien erhöhen die Größe eines OTA-Patches und erschweren die Bestimmung des geänderten Codes.
Um den Inhalt eines OTA transparenter zu machen, enthält AOSP Änderungen am Build-System, die darauf ausgelegt sind, die Größe von OTA-Patches zu reduzieren. Unnötige Dateiänderungen zwischen Builds wurden eliminiert und OTA-Updates enthalten nur Patch-bezogene Dateien. AOSP enthält außerdem ein Tool zum Vergleichen von Builds, das häufige buildbezogene Dateiänderungen herausfiltert, um einen übersichtlicheren Vergleich von Build-Dateien zu ermöglichen, sowie ein Tool zum Zuordnen von Blöcken, mit dem Sie die Blockzuweisung konsistent halten können.
Ein Build-System kann auf verschiedene Weise unnötig große Patches erstellen. Um dies zu vermeiden, wurden in Android 8.0 und höher neue Funktionen implementiert, um die Patchgröße für jeden Dateidiff zu reduzieren. Die folgenden Verbesserungen haben dazu beigetragen, die Größe von OTA-Updatepaketen zu reduzieren:
-
Verwendung von ZSTD, einem universellen, verlustfreien Komprimierungsalgorithmus für vollständige Images bei Updates auf Nicht-A/B-Geräten. ZSTD kann für höhere Komprimierungsverhältnisse angepasst werden, indem die Komprimierungsstufe erhöht wird. Die Komprimierungsstufe wird während der OTA-Generierung festgelegt. Sie kann durch Übergabe des Flags
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
festgelegt werden. -
Die Größe des Komprimierungsfensters, das während der OTA-Aktualisierung verwendet wird, wird erhöht. Die maximale Größe des Komprimierungsfensters kann durch Anpassen des Build-Parameters in der
.mk
-Datei eines Geräts festgelegt werden. Diese Variable wird alsPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
festgelegt. - Verwendung der Puffin-Rekompression, einem deterministischen Patching-Tool für Deflate-Streams, das die Komprimierungs- und Differenzfunktionen für die A/B-OTA-Update-Generierung übernimmt.
-
Änderungen bei der Verwendung des Tools zur Deltagenerierung, z. B. wie die Bibliothek
bsdiff
zum Komprimieren von Patches verwendet wird. Unter Android 9 und höher wählt das Toolbsdiff
den Komprimierungsalgorithmus aus, der die besten Komprimierungsergebnisse für einen Patch liefert. -
Durch Verbesserungen an
update_engine
wird weniger Arbeitsspeicher belegt, wenn Patches für A/B-Geräteupdates angewendet werden.
In den folgenden Abschnitten werden verschiedene Probleme behandelt, die sich auf die Größe von OTA-Updates auswirken, sowie Lösungen und Beispiele für die Implementierung in AOSP.
Reihenfolge der Dateien
Problem: Dateisysteme garantieren keine bestimmte Reihenfolge, wenn eine Liste von Dateien in einem Verzeichnis angefordert wird. Bei demselben Checkout ist die Reihenfolge jedoch in der Regel gleich. Tools wie ls
sortieren die Ergebnisse standardmäßig, aber die Platzhalterfunktion, die von Befehlen wie find
und make
verwendet wird, sortiert nicht. Bevor Sie diese Tools verwenden, müssen Sie die Ausgaben sortieren.
Lösung: Wenn Sie Tools wie find
und make
mit der Platzhalterfunktion verwenden, sortieren Sie die Ausgabe dieser Befehle, bevor Sie sie verwenden. Wenn Sie $(wildcard)
oder $(shell find)
in Android.mk
-Dateien verwenden, sortieren Sie sie ebenfalls. Einige Tools, z. B. Java, sortieren Eingaben. Prüfen Sie daher, ob das von Ihnen verwendete Tool die Dateien bereits sortiert hat, bevor Sie sie sortieren.
Beispiele:Viele Instanzen wurden im Core-Build-System mit dem integrierten Makro all-*-files-under
korrigiert, das all-cpp-files-under
enthält (da mehrere Definitionen auf andere Makefiles verteilt waren).
Weitere Informationen finden Sie unter:
- https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f
- https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410
- https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653
- https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c
Build-Verzeichnis
Problem:Wenn Sie das Verzeichnis ändern, in dem Elemente erstellt werden, können sich die Binärdateien unterscheiden. Die meisten Pfade im Android-Build sind relative Pfade, sodass __FILE__
in C/C++ kein Problem darstellt. In den Debug-Symbolen wird jedoch standardmäßig der vollständige Pfadname codiert. Die .note.gnu.build-id
wird durch Hashing des vorab bereinigten Binärcodes generiert. Sie ändert sich also, wenn sich die Debug-Symbole ändern.
Lösung:In AOSP sind Debug-Pfade jetzt relativ. Weitere Informationen finden Sie unter CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.
Zeitstempel
Problem:Zeitstempel in der Build-Ausgabe führen zu unnötigen Dateiänderungen. Dies wird wahrscheinlich an den folgenden Orten passieren:
__DATE__/__TIME__/__TIMESTAMP__
-Makros in C- oder C++-Code.- Zeitstempel, die in ZIP-basierten Archiven eingebettet sind.
Lösungen/Beispiele:Wenn Sie Zeitstempel aus der Build-Ausgabe entfernen möchten, folgen Sie der Anleitung unten unter __DATE__/__TIME__/__TIMESTAMP__ in C/C++ und Eingebettete Zeitstempel in Archiven.
__DATE__/__TIME__/__TIMESTAMP__ in C/C++
Diese Makros erzeugen immer unterschiedliche Ausgaben für verschiedene Builds. Verwenden Sie sie daher nicht. Hier sind einige Optionen zum Entfernen dieser Makros:
- Entfernen Sie sie. Ein Beispiel finden Sie unter https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- Um die ausgeführte Binärdatei eindeutig zu identifizieren, lesen Sie die Build-ID aus dem ELF-Header.
-
Das Erstellungsdatum des Betriebssystems finden Sie in
ro.build.date
. Das funktioniert für alle Builds außer inkrementellen Builds, bei denen das Datum möglicherweise nicht aktualisiert wird. Ein Beispiel finden Sie unter https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
Eingebettete Zeitstempel in Archiven (ZIP, JAR)
Unter Android 7.0 wurde das Problem mit eingebetteten Zeitstempeln in ZIP-Archiven behoben, indem -X
bei allen Verwendungen des Befehls zip
hinzugefügt wurde. Dadurch wurden die UID/GID des Builders und der erweiterte Unix-Zeitstempel aus der ZIP-Datei entfernt.
Ein neues Tool, ziptime
(im Verzeichnis /platform/build/+/android16-release/tools/ziptime/
), setzt die normalen Zeitstempel in den ZIP-Headern zurück. Weitere Informationen finden Sie in der README-Datei.
Mit dem Tool signapk
werden Zeitstempel für die APK-Dateien festgelegt, die je nach Serverzeitzone variieren können. Weitere Informationen finden Sie im CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Mit dem Tool signapk
werden Zeitstempel für die APK-Dateien festgelegt, die je nach Serverzeitzone variieren können. Weitere Informationen finden Sie im CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Versionsstrings
Problem:An die hartcodierten Versionen von APK-Versionsstrings wurde oft BUILD_NUMBER
angehängt. Auch wenn sich in einem APK nichts anderes geändert hat, wäre es trotzdem anders.
Lösung:Entfernen Sie die Build-Nummer aus dem APK-Versionsstring.
Beispiele:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Verity-Berechnung auf dem Gerät aktivieren
Wenn dm-verity auf Ihrem Gerät aktiviert ist, übernehmen OTA-Tools automatisch Ihre Verity-Konfiguration und aktivieren die Verity-Berechnung auf dem Gerät. So können Verity-Blöcke auf Android-Geräten berechnet werden, anstatt als Rohbytes in Ihrem OTA-Paket gespeichert zu werden. Verity-Blöcke können für eine 2-GB-Partition etwa 16 MB verwenden.
Die Berechnung der Wahrhaftigkeit auf dem Gerät kann jedoch lange dauern. Insbesondere kann der Forward Error-Correction-Code lange dauern. Auf Pixel-Geräten dauert es in der Regel bis zu 10 Minuten. Auf Low-End-Geräten kann es länger dauern. Wenn Sie die Berechnung von „on-device verity“ deaktivieren, aber „dm-verity“ weiterhin aktivieren möchten, können Sie dazu --disable_fec_computation
an das Tool ota_from_target_files
übergeben, wenn Sie ein OTA-Update generieren. Mit diesem Flag wird die Berechnung von „Verity“ auf dem Gerät während OTA-Updates deaktiviert.
Dadurch wird die OTA-Installationszeit verkürzt, aber die OTA-Paketgröße erhöht. Wenn auf Ihrem Gerät „dm-verity“ nicht aktiviert ist, hat das Übergeben dieses Flags keine Auswirkungen.
Konsistente Build-Tools
Problem:Tools, mit denen installierte Dateien generiert werden, müssen konsistent sein. Eine bestimmte Eingabe sollte immer dieselbe Ausgabe erzeugen.
Lösungen/Beispiele:In den folgenden Build-Tools waren Änderungen erforderlich:
- NOTICE-Datei-Generator Der Ersteller der NOTICE-Datei wurde geändert, um reproduzierbare NOTICE-Sammlungen zu erstellen. Siehe CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack) Die Jack-Toolchain musste aktualisiert werden, um gelegentliche Änderungen bei der Reihenfolge der generierten Konstruktoren zu verarbeiten. Der Toolchain wurden deterministische Accessoren für Konstruktoren hinzugefügt: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- ART AOT-Compiler (dex2oat) Die Binärdatei des ART-Compilers wurde aktualisiert und bietet jetzt eine Option zum Erstellen eines deterministischen Images: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
Die Datei „libpac.so“ (V8) Bei jedem Build wird eine andere
/system/lib/libpac.so
-Datei erstellt, da sich der V8-Snapshot für jeden Build ändert. Die Lösung bestand darin, den Snapshot zu entfernen: https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - Vordexoptimierte Anwendungsdateien (.odex). Die Dateien für die Vorab-Dex-Optimierung (.odex) enthielten auf 64-Bit-Systemen nicht initialisiertes Padding. Das wurde korrigiert: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Build-Vergleichstool verwenden
Für Fälle, in denen es nicht möglich ist, buildbezogene Dateiänderungen zu vermeiden, enthält AOSP ein Tool zum Vergleichen von Builds, target_files_diff.py
, mit dem zwei Dateipakete verglichen werden können. Dieses Tool führt einen rekursiven Vergleich zwischen zwei Builds durch und schließt dabei allgemeine buildbezogene Dateiänderungen aus, z. B.
- Erwartete Änderungen in der Build-Ausgabe (z. B. aufgrund einer Änderung der Build-Nummer).
- Änderungen aufgrund bekannter Probleme im aktuellen Build-System.
Führen Sie den folgenden Befehl aus, um das Tool zum Vergleichen von Builds zu verwenden:
target_files_diff.py dir1 dir2
dir1
und dir2
sind Basisverzeichnisse, die die extrahierten Zieldateien für jeden Build enthalten.
Blockzuweisung konsistent halten
Obwohl der Inhalt einer bestimmten Datei zwischen zwei Builds gleich bleibt, können sich die tatsächlichen Blöcke, in denen die Daten gespeichert sind, geändert haben. Daher muss das Updater-Tool unnötige Ein-/Ausgabeoperationen ausführen, um die Blöcke für ein OTA-Update zu verschieben.
Bei einem virtuellen A/B-OTA-Update kann unnötige E/A den Speicherplatz, der zum Speichern des Copy-on-Write-Snapshots erforderlich ist, erheblich erhöhen. Bei einem OTA-Update ohne A/B-Partitionen trägt das Verschieben der Blöcke für ein OTA-Update zur Aktualisierungszeit bei, da aufgrund der Blockverschiebungen mehr E/A-Vorgänge erforderlich sind.
Um dieses Problem zu beheben, hat Google in Android 7.0 das Tool make_ext4fs
erweitert, um die Blockzuweisung über verschiedene Builds hinweg konsistent zu halten. Das make_ext4fs
-Tool akzeptiert das optionale Flag -d base_fs
, mit dem versucht wird, Dateien beim Generieren eines ext4
-Images denselben Blöcken zuzuweisen. Sie können die Blockzuordnungsdateien (z. B. die base_fs
-Kartendateien) aus der ZIP-Datei der Zieldateien eines vorherigen Builds extrahieren. Für jede ext4
-Partition gibt es eine .map
-Datei im Verzeichnis IMAGES
(z. B. entspricht IMAGES/system.map
der system
-Partition). Diese base_fs
-Dateien können dann eingecheckt und über PRODUCT_<partition>_BASE_FS_PATH
angegeben werden, wie in diesem Beispiel:
PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map PRODUCT_SYSTEM_EXT_BASE_FS_PATH := path/to/base_fs_files/base_system_ext.map PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map PRODUCT_PRODUCT_BASE_FS_PATH := path/to/base_fs_files/base_product.map PRODUCT_ODM_BASE_FS_PATH := path/to/base_fs_files/base_odm.map
Dadurch wird zwar nicht die Gesamtgröße des OTA-Pakets reduziert, aber die Leistung von OTA-Updates wird durch die Reduzierung der E/A-Menge verbessert. Bei virtuellen A/B-Updates wird der für die Anwendung des OTA-Updates benötigte Speicherplatz drastisch reduziert.
App-Updates vermeiden
Neben der Minimierung von Build-Unterschieden können Sie die Größe von OTA-Updates reduzieren, indem Sie Updates für Apps ausschließen, die über App-Shops aktualisiert werden. APKs machen oft einen erheblichen Teil verschiedener Partitionen auf einem Gerät aus. Die Einbeziehung der neuesten Versionen von Apps, die von App-Shops aktualisiert werden, in ein OTA-Update kann sich stark auf die Größe von OTA-Paketen auswirken und bietet nur wenig Vorteile für Nutzer. Wenn Nutzer ein OTA-Paket erhalten, haben sie möglicherweise bereits die aktualisierte App oder eine noch neuere Version, die sie direkt aus App-Shops erhalten haben.