Cette page décrit les modifications ajoutées à AOSP pour réduire les modifications de fichiers inutiles entre les builds. Les implémentateurs d'appareils qui gèrent leurs propres systèmes de compilation peuvent utiliser ces informations comme guide pour réduire la taille de leurs mises à jour OTA (Over-the-Air).
Les mises à jour OTA Android contiennent parfois des fichiers modifiés qui ne correspondent pas à des modifications de code. Il s'agit en fait d'artefacts du système de compilation. Cela peut se produire lorsque le même code, compilé à différents moments, à partir de différents répertoires ou sur différentes machines, produit un grand nombre de fichiers modifiés. Ces fichiers en trop augmentent la taille d'un correctif OTA et rendent difficile la détermination du code modifié.
Pour rendre le contenu d'une mise à jour OTA plus transparent, AOSP inclut des modifications du système de compilation conçues pour réduire la taille des correctifs OTA. Les modifications de fichiers inutiles entre les builds ont été supprimées, et seuls les fichiers liés aux correctifs sont inclus dans les mises à jour OTA. AOSP inclut également un outil de comparaison de builds, qui filtre les modifications de fichiers courantes liées au build pour fournir une comparaison de fichiers de compilation plus claire, et un outil de mappage de blocs, qui vous aide à maintenir l'allocation de blocs cohérente.
Un système de compilation peut créer des correctifs inutilement volumineux de plusieurs manières. Pour atténuer ce problème, de nouvelles fonctionnalités ont été implémentées dans Android 8.0 et versions ultérieures afin de réduire la taille du correctif pour chaque différence de fichier. Voici les améliorations qui ont permis de réduire la taille des packages de mise à jour OTA:
-
Utilisation de ZSTD, un algorithme de compression sans perte à usage général pour les images complètes sur les mises à jour d'appareils autres que A/B. ZSTD peut être personnalisé pour obtenir des ratios de compression plus élevés en augmentant le niveau de compression. Le niveau de compression est défini au moment de la génération OTA et peut être défini en transmettant l'indicateur
--vabc_compression_param=zstd,$COMPRESSION_LEVEL
. -
Augmentation de la taille de la fenêtre de compression utilisée lors de la mise à jour OTA. Vous pouvez définir la taille maximale de la fenêtre de compression en personnalisant le paramètre de compilation dans le fichier
.mk
d'un appareil. Cette variable est définie surPRODUCT_VIRTUAL_AB_COMPRESSION_FACTOR := 262144
. - Utilisation de la recompression Puffin, un outil de correction déterministe pour les flux de déflation, qui gère les fonctions de compression et de comparaison pour la génération de mises à jour OTA A/B.
-
Modifications apportées à l'utilisation de l'outil de génération de delta, comme la façon dont la bibliothèque
bsdiff
est utilisée pour compresser les correctifs. Sous Android 9 et versions ultérieures, l'outilbsdiff
sélectionne l'algorithme de compression qui offre les meilleurs résultats de compression pour un correctif. -
Les améliorations apportées à
update_engine
ont permis de réduire la consommation de mémoire lorsque des correctifs sont appliqués pour les mises à jour d'appareils A/B.
Les sections suivantes traitent de divers problèmes qui affectent les tailles de mises à jour OTA, de leurs solutions et d'exemples d'implémentation dans AOSP.
Ordre des fichiers
Problème: les systèmes de fichiers ne garantissent pas l'ordre des fichiers lorsqu'ils sont invités à fournir une liste de fichiers dans un répertoire, bien qu'il soit généralement le même pour le même contrôle. Des outils tels que ls
trient les résultats par défaut, mais la fonction de caractères génériques utilisée par des commandes telles que find
et make
ne le fait pas. Avant d'utiliser ces outils, vous devez trier les sorties.
Solution: Lorsque vous utilisez des outils tels que find
et make
avec la fonction de caractère générique, triez la sortie de ces commandes avant de les utiliser. Lorsque vous utilisez $(wildcard)
ou $(shell find)
dans des fichiers Android.mk
, triez-les également. Certains outils, comme Java, trient les entrées. Par conséquent, avant de trier les fichiers, vérifiez que l'outil que vous utilisez ne l'a pas déjà fait.
Exemples:De nombreuses instances ont été corrigées dans le système de compilation principal à l'aide de la macro all-*-files-under
intégrée, qui inclut all-cpp-files-under
(car plusieurs définitions étaient réparties dans d'autres fichiers de compilation).
Pour en savoir plus, consultez les pages suivantes:
- 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
Répertoire de compilation
Problème:modifier le répertoire dans lequel les éléments sont compilés peut entraîner des différences entre les binaires. La plupart des chemins d'accès dans le build Android sont des chemins relatifs. __FILE__
en C/C++ n'est donc pas un problème. Toutefois, les symboles de débogage encodent le chemin d'accès complet par défaut, et .note.gnu.build-id
est généré à partir du hachage du binaire prédébarrassé. Il change donc si les symboles de débogage changent.
Solution:AOSP rend désormais les chemins de débogage relatifs. Pour en savoir plus, consultez CL : https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02.
Codes temporels
Problème:les codes temporels dans la sortie de compilation entraînent des modifications de fichiers inutiles. Cela est susceptible de se produire dans les lieux suivants:
- Macros
__DATE__/__TIME__/__TIMESTAMP__
dans le code C ou C++ - Horodatages intégrés aux archives ZIP
Solutions/Exemples:Pour supprimer les codes temporels de la sortie de compilation, utilisez les instructions ci-dessous dans __DATE_/__TIME_/__TIMESTAMP__ en C/C++ et Codes temporels intégrés dans les archives.
__DATE_/__TIME_/__TIMESTAMP__ en C/C++
Ces macros produisent toujours des résultats différents pour différentes versions. Par conséquent, n'utilisez pas ces macros. Voici quelques options pour éliminer ces macros:
- Supprimez-les. Pour obtenir un exemple, consultez https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f.
- Pour identifier de manière unique le binaire en cours d'exécution, lisez l'ID de compilation à partir de l'en-tête ELF.
-
Pour savoir quand le système d'exploitation a été compilé, lisez
ro.build.date
(cela fonctionne pour tout, sauf pour les builds incrémentiels, qui ne mettent peut-être pas à jour cette date). Pour en savoir plus, consultez https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
Horodatages intégrés dans les archives (ZIP, JAR)
Android 7.0 a résolu le problème des codes temporels intégrés dans les archives ZIP en ajoutant -X
à toutes les utilisations de la commande zip
. Cela a supprimé l'UID/GID du compilateur et le code temporel Unix étendu du fichier ZIP.
Un nouvel outil, ziptime
(situé dans /platform/build/+/android16-release/tools/ziptime/
) réinitialise les codes temporels normaux dans les en-têtes ZIP. Pour en savoir plus, consultez le fichier README.
L'outil signapk
définit des codes temporels pour les fichiers APK qui peuvent varier en fonction du fuseau horaire du serveur. Pour en savoir plus, consultez la CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
L'outil signapk
définit des codes temporels pour les fichiers APK qui peuvent varier en fonction du fuseau horaire du serveur. Pour en savoir plus, consultez la CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Chaînes de version
Problème:la valeur BUILD_NUMBER
était souvent ajoutée aux versions codées en dur des chaînes de version de l'APK. Même si rien d'autre n'a changé dans un APK, l'APK sera toujours différent.
Solution:Supprimez le numéro de build de la chaîne de version de l'APK.
Exemples :
- https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27
- https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c
Activer le calcul de la véracité sur l'appareil
Si dm-verity est activé sur votre appareil, les outils OTA détectent automatiquement votre configuration Verity et activent le calcul Verity sur l'appareil. Cela permet de calculer des blocs de validation sur les appareils Android, au lieu de les stocker en octets bruts dans votre package OTA. Les blocs de vérification peuvent utiliser environ 16 Mo pour une partition de 2 Go.
Toutefois, le calcul de la validité sur l'appareil peut prendre beaucoup de temps. Plus précisément, le code de correction d'erreurs en avant peut prendre beaucoup de temps. Sur les appareils Pixel, cela prend généralement jusqu'à 10 minutes. Sur les appareils bas de gamme, ce délai peut être plus long. Si vous souhaitez désactiver le calcul de la véracité sur l'appareil, mais que vous souhaitez tout de même activer dm-verity, vous pouvez le faire en transmettant --disable_fec_computation
à l'outil ota_from_target_files
lors de la génération d'une mise à jour OTA. Ce flag désactive le calcul de la validité sur l'appareil lors des mises à jour OTA.
Cela réduit le temps d'installation OTA, mais augmente la taille du package OTA. Si dm-verity n'est pas activé sur votre appareil, le transfert de cet indicateur n'a aucun effet.
Outils de compilation cohérents
Problème:les outils qui génèrent des fichiers installés doivent être cohérents (une entrée donnée doit toujours produire la même sortie).
Solutions/Exemples:des modifications ont été apportées aux outils de compilation suivants:
- Créateur du fichier AVIS Le créateur de fichiers NOTICE a été modifié pour créer des collections de NOTICES reproductibles. Consultez la CL : https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack) La chaîne d'outils Jack a nécessité une mise à jour pour gérer les modifications occasionnelles de l'ordre des constructeurs générés. Des accésseurs déterministes pour les constructeurs ont été ajoutés à la chaîne d'outils : https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- Compilateur AOT ART (dex2oat) Le binaire du compilateur ART a reçu une mise à jour qui a ajouté une option permettant de créer une image déterministe : https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9.
-
Le fichier libpac.so (V8) Chaque compilation crée un fichier
/system/lib/libpac.so
différent, car l'instantané V8 change pour chaque compilation. La solution a consisté à supprimer l'instantané : https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - Fichiers de pré-dexopt (.odex) de l'application Les fichiers pré-dexopt (.odex) contenaient une marge non initialisée sur les systèmes 64 bits. Ce problème a été corrigé : https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029.
Utiliser l'outil de comparaison de builds
Lorsque vous ne pouvez pas supprimer les modifications de fichiers liées à la compilation, AOSP inclut un outil de comparaison de compilation, target_files_diff.py
, qui permet de comparer deux packages de fichiers. Cet outil effectue une comparaison récursive entre deux builds, en excluant les modifications de fichiers courantes liées à la compilation, telles que
- Modifications attendues dans la sortie du build (par exemple, en raison d'un changement de numéro de build).
- Modifications dues à des problèmes connus dans le système de compilation actuel.
Pour utiliser l'outil de comparaison de builds, exécutez la commande suivante:
target_files_diff.py dir1 dir2
dir1
et dir2
sont des répertoires de base qui contiennent les fichiers cibles extraits pour chaque build.
Assurer la cohérence de l'allocation des blocs
Pour un fichier donné, bien que son contenu reste le même entre deux builds, les blocs réels contenant les données peuvent avoir changé. Par conséquent, le programme de mise à jour doit effectuer des E/S inutiles pour déplacer les blocs lors d'une mise à jour OTA.
Dans une mise à jour OTA A/B virtuelle, les E/S inutiles peuvent considérablement augmenter l'espace de stockage requis pour stocker l'instantané en mode copie sur écriture. Dans une mise à jour OTA non A/B, le déplacement des blocs pour une mise à jour OTA contribue au temps de mise à jour, car il y a plus d'E/S en raison des déplacements de blocs.
Pour résoudre ce problème, Google a étendu l'outil make_ext4fs
dans Android 7.0 afin de maintenir l'allocation de blocs cohérente entre les builds. L'outil make_ext4fs
accepte un indicateur -d base_fs
facultatif qui tente d'allouer des fichiers aux mêmes blocs lors de la génération d'une image ext4
. Vous pouvez extraire les fichiers de mappage de blocs (tels que les fichiers de mappage base_fs
) à partir du fichier ZIP des fichiers cibles d'une compilation précédente. Pour chaque partition ext4
, un fichier .map
se trouve dans le répertoire IMAGES
(par exemple, IMAGES/system.map
correspond à la partition system
). Ces fichiers base_fs
peuvent ensuite être enregistrés et spécifiés via PRODUCT_<partition>_BASE_FS_PATH
, comme dans cet exemple:
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
Bien que cela ne réduise pas la taille globale du package OTA, cela améliore les performances de la mise à jour OTA en réduisant la quantité d'E/S. Pour les mises à jour A/B virtuelles, il réduit considérablement l'espace de stockage nécessaire pour appliquer la mise à jour OTA.
Éviter de mettre à jour les applications
En plus de réduire les différences de compilation, vous pouvez réduire la taille des mises à jour OTA en excluant les mises à jour des applications qui reçoivent des mises à jour via des plates-formes de téléchargement d'applications. Les APK représentent souvent une part importante de diverses partitions sur un appareil. L'inclusion des dernières versions des applications mises à jour par les plates-formes de téléchargement d'applications dans une mise à jour OTA peut avoir un impact important sur la taille des packages OTA et offrir peu d'avantages aux utilisateurs. Au moment où les utilisateurs reçoivent un package OTA, ils peuvent déjà avoir reçu l'application mise à jour ou une version encore plus récente directement depuis les plates-formes de téléchargement d'applications.