Auf dieser Seite werden Änderungen beschrieben, die zu 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 für die Reduzierung der Größe ihrer OTA-Updates (Over-the-Air) verwenden.
Android-OTA-Updates enthalten gelegentlich geänderte Dateien, die nicht mit Codeänderungen übereinstimmen. Es handelt sich tatsächlich um Build-System-Artefakte. Dies kann auftreten, 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 überschüssigen Dateien erhöhen die Größe eines OTA-Patches und erschweren die Feststellung, welcher Code geändert wurde.
Um den Inhalt eines OTA transparenter zu machen, enthält AOSP Build-Systemänderungen, die darauf abzielen, die Größe von OTA-Patches zu reduzieren. Unnötige Dateiänderungen zwischen Builds wurden eliminiert und in OTA-Updates sind nur Patch-bezogene Dateien enthalten. AOSP enthält außerdem ein Build-Diff-Tool , das häufige Build-bezogene Dateiänderungen herausfiltert, um einen saubereren Build-Datei-Diff bereitzustellen, und ein Block-Mapping-Tool , das Ihnen dabei hilft, die Blockzuordnung konsistent zu halten.
Ein Build-System kann auf verschiedene Weise unnötig große Patches erstellen. Um dies zu mildern, wurden in Android 8.0 und höher neue Funktionen implementiert, um die Patchgröße für jeden Dateiunterschied zu reduzieren. Zu den Verbesserungen, die die Größe der OTA-Update-Pakete reduzierten, gehören die folgenden:
- Verwendung von Brotli , einem generischen, verlustfreien Komprimierungsalgorithmus für vollständige Bilder bei Nicht-A/B-Geräteaktualisierungen. Brotli kann angepasst werden, um die Komprimierung zu optimieren. Bei größeren Updates, die aus zwei oder mehr Blöcken im Dateisystem bestehen (z. B.
system.img
), können Gerätehersteller oder Partner ihre eigenen Komprimierungsalgorithmen hinzufügen und unterschiedliche Komprimierungsalgorithmen für verschiedene Blöcke desselben Updates verwenden. - Verwendung der Puffin- Rekomprimierung, eines deterministischen Patching-Tools für Deflate-Streams, das die Komprimierungs- und Diff-Funktionen für die A/B-OTA-Update-Generierung übernimmt.
- Ä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 wählt dasbsdiff
Tool den Komprimierungsalgorithmus aus, der die besten Komprimierungsergebnisse für einen Patch liefert. - Verbesserungen an der
update_engine
führten dazu, dass bei der Anwendung von Patches für A/B-Geräteaktualisierungen weniger Speicher verbraucht wurde. - Verbesserungen beim Aufteilen großer ZIP-Dateien für blockbasierte OTA-Updates. Ein Modus in
imgdiff
teilt übergroße APK-Dateien basierend auf Eintragsnamen auf. Dadurch entsteht ein kleinerer Patch im Vergleich zur linearen Aufteilung der Dateien und deren Komprimierung mit dembsdiff
Tool.
In den folgenden Abschnitten werden verschiedene Probleme besprochen, die sich auf die Größe von OTA-Updates auswirken, ihre Lösungen und Beispiele für die Implementierung in AOSP.
Dateireihenfolge
Problem : Dateisysteme garantieren keine Dateireihenfolge, wenn sie nach einer Liste von Dateien in einem Verzeichnis gefragt werden, obwohl diese normalerweise für denselben Checkout dieselbe ist. Werkzeuge wie ls
sortieren die Ergebnisse standardmäßig, aber die Platzhalterfunktion, die von Befehlen wie find
und make
verwendet wird, führt keine Sortierung durch. 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 diese ebenfalls. Einige Tools wie Java sortieren Eingaben. Stellen Sie daher vor dem Sortieren der Dateien sicher, dass das von Ihnen verwendete Tool dies nicht bereits getan hat.
Beispiele: Viele Instanzen wurden im Kern-Build-System mithilfe des integrierten Makros all-*-files-under
behoben, das all-cpp-files-under
einschließt (da mehrere Definitionen in anderen Makefiles verteilt waren). Einzelheiten finden Sie hier:
- 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: Das Ändern des Verzeichnisses, in dem Dinge erstellt werden, kann dazu führen, dass die Binärdateien unterschiedlich sind. Die meisten Pfade im Android-Build sind relative Pfade, sodass __FILE__
in C/C++ kein Problem darstellt. Allerdings kodieren die Debug-Symbole standardmäßig den vollständigen Pfadnamen und die .note.gnu.build-id
wird durch Hashing der vorab entfernten Binärdatei generiert, sodass sie sich ändert, wenn sich die Debug-Symbole ändern.
Lösung: AOSP macht Debug-Pfade jetzt relativ. Einzelheiten 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. Dies kann an folgenden Orten der Fall sein:
-
__DATE__/__TIME__/__TIMESTAMP__
Makros in C- oder C++-Code. - In zip-basierten Archiven eingebettete Zeitstempel.
Lösungen/Beispiele: Um Zeitstempel aus der Build-Ausgabe zu entfernen, verwenden Sie die unten aufgeführten Anweisungen in __DATE__/__TIME__/__TIMESTAMP__ in C/C++. und Eingebettete Zeitstempel in Archiven .
__DATE__/__TIME__/__TIMESTAMP__ in C/C++
Diese Makros erzeugen für unterschiedliche Builds immer unterschiedliche Ausgaben, also verwenden Sie sie nicht. Hier sind einige Möglichkeiten, diese Makros zu entfernen:
- Entferne sie. Ein Beispiel finden Sie unter https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f .
- Um die laufende Binärdatei eindeutig zu identifizieren, lesen Sie die Build-ID aus dem ELF-Header.
- Um zu erfahren, wann das Betriebssystem erstellt wurde, lesen Sie das
ro.build.date
(dies funktioniert für alles außer 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)
Android 7.0 hat das Problem der eingebetteten Zeitstempel in Zip-Archiven behoben, indem -X
zu allen Verwendungen des zip
Befehls hinzugefügt wurde. Dadurch wurden die UID/GID des Builders und der erweiterte Unix-Zeitstempel aus der ZIP-Datei entfernt.
Ein neues Tool, ziptime
(zu finden in /platform/build/+/main/tools/ziptime/
), setzt die normalen Zeitstempel in den Zip-Headern zurück. Einzelheiten finden Sie in der README-Datei .
Das Tool signapk
legt Zeitstempel für die APK-Dateien fest, die je nach Serverzeitzone variieren können. Einzelheiten finden Sie im CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028 .
Versionszeichenfolgen
Problem: Bei APK-Versionszeichenfolgen wurde häufig die BUILD_NUMBER
an die fest codierten Versionen angehängt. Selbst wenn sich sonst nichts an einem APK ändern würde, wäre das APK dadurch immer noch anders.
Lösung: Entfernen Sie die Build-Nummer aus der APK-Versionszeichenfolge.
Beispiele:
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Aktivieren Sie die Wahrheitsberechnung auf dem Gerät
Wenn dm-verity auf Ihrem Gerät aktiviert ist, übernehmen die OTA-Tools automatisch Ihre Verity-Konfiguration und aktivieren die Verity-Berechnung auf dem Gerät. Dadurch 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 etwa 16 MB für eine 2-GB-Partition belegen.
Allerdings kann die Berechnung der Wahrheit auf dem Gerät lange dauern. Insbesondere der Forward Error-Correction-Code kann lange dauern. Auf Pixelgeräten dauert es in der Regel bis zu 10 Minuten. Bei Low-End-Geräten kann es länger dauern. Wenn Sie die Verity-Berechnung auf dem Gerät deaktivieren, aber dennoch dm-verity aktivieren möchten, können Sie dies tun, indem Sie beim Generieren eines OTA-Updates --disable_fec_computation
an das Tool ota_from_target_files
übergeben. Dieses Flag deaktiviert die Wahrheitsberechnung auf dem Gerät während OTA-Updates. Es verkürzt die OTA-Installationszeit, erhöht aber die OTA-Paketgröße. Wenn auf Ihrem Gerät dm-verity nicht aktiviert ist, hat die Übergabe dieses Flags keine Auswirkung.
Konsistente Build-Tools
Problem: Tools, die installierte Dateien generieren, müssen konsistent sein (eine bestimmte Eingabe sollte immer die gleiche Ausgabe erzeugen).
Lösungen/Beispiele: In den folgenden Build-Tools waren Änderungen erforderlich:
- HINWEIS Dateiersteller . 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 erforderte ein Update, um gelegentliche Änderungen in der generierten Konstruktorreihenfolge zu bewältigen. Der Toolchain wurden deterministische Zugriffsfunktionen für Konstruktoren hinzugefügt: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b .
- ART AOT-Compiler (dex2oat) . Die ART-Compiler-Binärdatei hat ein Update erhalten, das eine Option zum Erstellen eines deterministischen Bildes hinzufügt: https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9 .
- Die libpac.so-Datei (V8) . Jeder Build erstellt eine andere Datei
/system/lib/libpac.so
, 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 . - Anwendungs-Pre-Dexopt-Dateien (.odex) . Die Pre-Dexopt-Dateien (.odex) enthielten auf 64-Bit-Systemen nicht initialisierte Auffüllungen. Dies wurde korrigiert: https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029 .
Verwenden Sie das Build-Diff-Tool
Für Fälle, in denen es nicht möglich ist, buildbezogene Dateiänderungen zu eliminieren, enthält AOSP ein Build-Diff-Tool, target_files_diff.py
, zum Vergleich zweier Dateipakete. Dieses Tool führt einen rekursiven Vergleich zwischen zwei Builds durch und schließt dabei häufige Build-bezogene Dateiänderungen aus, z
- Erwartete Änderungen in der Build-Ausgabe (z. B. aufgrund einer Änderung der Build-Nummer).
- Änderungen aufgrund bekannter Probleme im aktuellen Build-System.
Um das Build-Diff-Tool zu verwenden, führen Sie den folgenden Befehl aus:
target_files_diff.py dir1 dir2
dir1
und dir2
sind Basisverzeichnisse, die die extrahierten Zieldateien für jeden Build enthalten.
Halten Sie die Blockzuteilung konsistent
Obwohl 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. Infolgedessen muss der Updater unnötige E/A-Vorgänge ausführen, um die Blöcke für ein OTA-Update zu verschieben.
Bei einem Virtual A/B OTA-Update kann unnötige E/A den zum Speichern des Copy-on-Write-Snapshots erforderlichen Speicherplatz 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 anfällt.
Um dieses Problem zu beheben, hat Google in Android 7.0 das Tool make_ext4fs
erweitert, um die Blockzuteilung über Builds hinweg konsistent zu halten. Das Tool make_ext4fs
akzeptiert ein optionales Flag -d base_fs
, das versucht, beim Generieren eines ext4
Images Dateien denselben Blöcken zuzuordnen. Sie können die Blockzuordnungsdateien (z. B. die base_fs
Zuordnungsdateien) aus der ZIP-Datei der Zieldateien eines früheren Builds extrahieren. Für jede ext4
Partition gibt es eine .map
Datei im IMAGES
Verzeichnis (beispielsweise entspricht IMAGES/system.map
der system
). 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
Dies trägt zwar nicht dazu bei, die Gesamtgröße des OTA-Pakets zu reduzieren, verbessert jedoch die Leistung der OTA-Aktualisierung, indem die Menge an E/A reduziert wird. Bei virtuellen A/B-Updates wird der für die Anwendung des OTA benötigte Speicherplatz drastisch reduziert.
Vermeiden Sie die Aktualisierung von Apps
Zusätzlich zur Minimierung von Build-Unterschieden können Sie die Größe von OTA-Updates reduzieren, indem Sie Updates für Apps ausschließen, die Updates über App Stores erhalten. APKs machen oft einen erheblichen Teil verschiedener Partitionen auf einem Gerät aus. Das Einbeziehen der neuesten Versionen von Apps, die von App Stores aktualisiert werden, in ein OTA-Update kann große Auswirkungen auf OTA-Pakete haben und nur geringe Vorteile für den Benutzer bieten. Wenn Benutzer ein OTA-Paket erhalten, verfügen sie möglicherweise bereits über die aktualisierte App oder eine noch neuere Version, die sie direkt aus den App-Stores erhalten haben.