Auf dieser Seite werden Änderungen beschrieben, die dem AOSP hinzugefügt wurden, um unnötige Dateiänderungen zwischen Builds zu reduzieren. Geräteimplementierer, die eigene Build-Systeme verwalten, können diese Informationen als Leitfaden verwenden, um die Größe ihrer Over-the-air-Updates (OTA-Updates) zu reduzieren.
Android-Over-the-air-Updates enthalten gelegentlich geänderte Dateien, die nicht mit Codeänderungen übereinstimmen. Sie sind Build-System-Artefakte. Dies kann passieren, wenn derselbe Code, der zu unterschiedlichen Zeiten, aus verschiedenen Verzeichnissen oder auf verschiedenen Maschinen erstellt wurde, eine große Anzahl von geänderten 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 Over-the-air-Updates transparenter zu machen, enthält AOSP Änderungen am Build-System, die die Größe von Over-the-air-Patches reduzieren sollen. Unnötige Dateiänderungen zwischen Builds wurden entfernt und nur patchbezogene Dateien sind in OTA-Updates enthalten. AOSP enthält außerdem ein Build-Diff-Tool, mit dem häufige buildbezogene Dateiänderungen herausgefiltert werden, um eine sauberere Builddatei-Diff zu erhalten, und ein Blockzuordnungstool, 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 jede Dateidifferenz zu reduzieren. Zu den Verbesserungen, die die Größe von OTA-Update-Paketen reduziert haben, gehören:
-
Verwendung von ZSTD, einem verlustfreien Komprimierungsalgorithmus für allgemeine Zwecke für vollständige Images bei nicht A/B-Geräteupdates. ZSTD kann für höhere Komprimierungsverhältnisse angepasst werden, indem die Komprimierungsstufe erhöht wird. Der Komprimierungspegel wird während der OTA-Generierung festgelegt und kann durch Übergabe des Flags
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
festgelegt werden. -
Die Größe des Komprimierungsfensters, das bei der Over-the-air-Aktualisierung verwendet wird, wurde erhöht. Die maximale Komprimierungsfenstergröße 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-Rekomprimierung, einem deterministischen Patching-Tool für Deflate-Streams, das die Komprimierungs- und Differenzfunktionen für die Generierung von A/B-OTA-Updates verarbeitet.
-
Änderungen an der Verwendung des Delta-Generierungstools, z. B. wie die
bsdiff
-Bibliothek zum Komprimieren von Patches verwendet wird. In Android 9 und höher wird mit dem Toolbsdiff
der Komprimierungsalgorithmus ausgewählt, der die besten Komprimierungsergebnisse für einen Patch liefert. -
Durch Verbesserungen an der
update_engine
wird beim Anwenden von Patches für A/B-Geräteupdates weniger Arbeitsspeicher verbraucht.
In den folgenden Abschnitten werden verschiedene Probleme besprochen, die sich auf die Größe von OTA-Updates auswirken, sowie deren Lösungen und Beispiele für die Implementierung in AOSP.
Dateireihenfolge
Problem: Dateisysteme garantieren keine Dateireihenfolge, wenn nach einer Liste der Dateien in einem Verzeichnis gefragt wird. Sie ist jedoch in der Regel für dieselbe Kasse gleich. Tools wie ls
sortieren die Ergebnisse standardmäßig, die Wildcard-Funktion, die von Befehlen wie find
und make
verwendet wird, führt jedoch keine Sortierung durch. Bevor Sie diese Tools verwenden können, müssen Sie die Ausgabe sortieren.
Lösung: Wenn Sie Tools wie find
und make
mit der Platzhalterfunktion verwenden, sollten Sie die Ausgabe dieser Befehle vor der Verwendung sortieren. Wenn Sie $(wildcard)
oder $(shell find)
in Android.mk
-Dateien verwenden, sollten Sie sie auch sortieren. Einige Tools wie Java sortieren Eingaben. Prüfen Sie daher, bevor Sie die Dateien sortieren, ob das von Ihnen verwendete Tool dies bereits getan hat.
Beispiele:Viele Instanzen wurden im Kern-Build-System mit dem integrierten Makro all-*-files-under
korrigiert, das all-cpp-files-under
enthält (da mehrere Definitionen in anderen 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 die Dateien erstellt werden, können die Binärdateien unterschiedlich sein. Die meisten Pfade im Android-Build sind relative Pfade, sodass __FILE__
in C/C++ kein Problem darstellt. Die Debugsymbole codieren jedoch standardmäßig den vollständigen Pfadnamen und .note.gnu.build-id
wird durch Hashing des vorab entfernten Binärcodes generiert. Daher ändert sich .note.gnu.build-id
, wenn sich die Debugsymbole ändern.
Lösung:In AOSP sind Debugpfade jetzt relativ. Weitere Informationen finden Sie in CL: https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.
Zeitstempel
Problem: Zeitstempel in der Build-Ausgabe führen zu unnötigen Dateiänderungen. Das ist wahrscheinlich an den folgenden Orten der Fall:
__DATE__/__TIME__/__TIMESTAMP__
-Makros in C- oder C++-Code.- Zeitstempel, die in ZIP-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 liefern immer unterschiedliche Ergebnisse für verschiedene Builds. Verwenden Sie sie daher nicht. Hier sind einige Möglichkeiten, diese Makros zu entfernen:
- Entfernen Sie sie. Ein Beispiel finden Sie unter https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- Lesen Sie die Build-ID aus dem ELF-Header, um das ausführbare Binary eindeutig zu identifizieren.
-
Das Datum, an dem das Betriebssystem erstellt wurde, finden Sie in
ro.build.date
. Das funktioniert für alle Builds mit Ausnahme von inkrementellen Builds, bei denen dieses 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 allen Verwendungen des Befehls zip
-X
hinzugefügt wurde. Dadurch wurden die UID/GID des Builders und der erweiterte Unix-Zeitstempel aus der ZIP-Datei entfernt.
Mit dem neuen Tool ziptime
(unter /platform/build/+/android16-release/tools/ziptime/
) werden die normalen Zeitstempel in den ZIP-Headern zurückgesetzt. Weitere Informationen finden Sie in der README-Datei.
Das Tool signapk
legt Zeitstempel für die APK-Dateien fest, die je nach Serverzeitzone variieren können. Weitere Informationen finden Sie in der CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Das Tool signapk
legt Zeitstempel für die APK-Dateien fest, die je nach Serverzeitzone variieren können. Weitere Informationen finden Sie in der CL unter https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Versionsstrings
Problem:An die hartcodierten Versionen von APK-Versionsstrings wurde häufig BUILD_NUMBER
angehängt. Selbst wenn sich in einem APK sonst nichts geändert hat, ist es dadurch 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
On-Device-Bestätigungsberechnung aktivieren
Wenn dm-verity auf Ihrem Gerät aktiviert ist, übernehmen OTA-Tools automatisch Ihre Verity-Konfiguration und aktivieren die On-Device-Verity-Berechnung. 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 belegen.
Die Berechnung der Verschlüsselung auf dem Gerät kann jedoch sehr lange dauern. Insbesondere kann der Vorwärtsfehlerkorrekturcode sehr 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 On-Device-Verity-Berechnung deaktivieren, aber dm-verity weiterhin aktivieren möchten, können Sie beim Generieren eines OTA-Updates --disable_fec_computation
an das ota_from_target_files
-Tool übergeben. Dieses Flag deaktiviert die On-Device-Bestätigungsberechnung während OTA-Updates.
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.
Einheitliche Buildtools
Problem: Tools, die installierte Dateien generieren, müssen konsistent sein. Eine bestimmte Eingabe sollte immer dieselbe Ausgabe liefern.
Lösungen/Beispiele:Änderungen waren in den folgenden Build-Tools erforderlich:
- Ersteller der NOTICE-Datei Der Ersteller von NOTICE-Dateien wurde geändert, um reproduzierbare NOTICE-Sammlungen zu erstellen. Weitere Informationen finden Sie in CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack) Die Jack-Toolchain musste aktualisiert werden, um gelegentliche Änderungen an der Reihenfolge der generierten Konstruktoren zu verarbeiten. Der Toolbox wurden deterministische Zugriffsmethoden für Konstruktoren hinzugefügt: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- ART-AOT-Compiler (dex2oat) Das ART-Compiler-Binary wurde aktualisiert und es wurde eine Option zum Erstellen eines deterministischen Images hinzugefügt: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
Die Datei „libpac.so“ (V8) Für jeden 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. - Pre-Dexopt-Dateien (.odex) der Anwendung Die Pre-Dexopt-Dateien (.odex) enthielten auf 64-Bit-Systemen nicht initialisierte Paddings. Dies wurde korrigiert: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Build-Diff-Tool verwenden
Falls es nicht möglich ist, buildbezogene Dateiänderungen zu beseitigen, enthält AOSP ein Build-Diff-Tool,target_files_diff.py
das zum Vergleichen von zwei Dateipaketen verwendet werden kann. Dieses Tool führt einen rekursiven Vergleich zwischen zwei Builds durch und schließt gängige buildbezogene Dateiänderungen aus, z. B.
- Erwartete Änderungen an der Build-Ausgabe (z. B. aufgrund einer Änderung der Build-Nummer)
- Änderungen aufgrund bekannter Probleme im aktuellen Buildsystem.
Führen Sie den folgenden Befehl aus, um das Build-Diff-Tool zu verwenden:
target_files_diff.py dir1 dir2
dir1
und dir2
sind Basisverzeichnisse, die die extrahierten Zieldateien für jeden Build enthalten.
Blockzuweisung einheitlich halten
Auch wenn der Inhalt einer bestimmten Datei zwischen zwei Builds gleich bleibt, können sich die tatsächlichen Blöcke, die die Daten enthalten, geändert haben. Daher muss der Aktualisierer unnötige I/O-Vorgänge ausführen, um die Blöcke für ein Over-the-air-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 nicht A/B-OTA-Update trägt das Verschieben der Blöcke für ein OTA-Update zur Aktualisierungszeit bei, da aufgrund von Blockverschiebungen mehr I/O erforderlich ist.
Um dieses Problem zu beheben, hat Google in Android 7.0 das make_ext4fs
-Tool erweitert, um die Blockzuweisung über Builds hinweg konsistent zu halten. Das make_ext4fs
-Tool akzeptiert ein optionales -d base_fs
-Flag, mit dem beim Generieren eines ext4
-Images versucht wird, Dateien denselben Blöcken zuzuweisen. Sie können die Blockzuordnungsdateien (z. B. die base_fs
-Map-Dateien) aus der ZIP-Datei der Zieldateien eines vorherigen Builds extrahieren. Für jede ext4
-Partition gibt es eine .map
-Datei im Verzeichnis IMAGES
. IMAGES/system.map
entspricht beispielsweise 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 des OTA-Updates verbessert, da die Anzahl der E/A-Vorgänge verringert wird. Bei virtuellen A/B-Updates wird der für die Anwendung des Over-the-air-Updates erforderliche Speicherplatz drastisch reduziert.
Apps nicht aktualisieren
Sie können nicht nur Build-Diffs minimieren, sondern auch die Größe von Over-the-air-Updates reduzieren, indem Sie Updates für Apps ausschließen, die über App-Shops aktualisiert werden. APKs machen häufig einen erheblichen Teil verschiedener Partitionen auf einem Gerät aus. Wenn Sie die neuesten Versionen von Apps, die von App-Shops aktualisiert werden, in ein Over-the-air-Update aufnehmen, kann sich das erheblich auf die Größe von Over-the-air-Paketen auswirken und für Nutzer nur wenig Nutzen bieten. Wenn Nutzer ein Over-the-air-Paket erhalten, haben sie möglicherweise bereits die aktualisierte App oder eine noch neuere Version, die sie direkt über App-Shops erhalten haben.