Cette page décrit les modifications ajoutées à AOSP pour réduire les modifications de fichiers inutiles entre les builds. Les implémenteurs 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, génère un grand nombre de fichiers modifiés files. Ces fichiers supplémentaires augmentent la taille d'un correctif OTA et rendent difficile la détermination du code modifié.
Pour rendre le contenu d'une 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é éliminées, et seules les mises à jour OTA contiennent des fichiers liés aux correctifs. AOSP inclut également un outil de comparaison de builds, qui filtre les modifications de fichiers courantes liées aux builds pour fournir une comparaison de fichiers de build plus propre, et un outil de mappage de blocs, qui vous aide à maintenir une 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, dans Android 8.0 et versions ultérieures, de nouvelles fonctionnalités ont été implémentées pour réduire la taille des correctifs pour chaque comparaison de fichiers. Voici quelques 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érique pour les images complètes sur les mises à jour d'appareils non A/B. ZSTD peut être personnalisé pour des taux de compression plus élevés
en augmentant le niveau de compression. Le niveau de compression est défini lors de la génération de l'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 l'OTA. La taille maximale de la fenêtre de compression
peut être définie en personnalisant le paramètre de compilation dans le fichier
.mkd'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 deflate 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 delta, par exemple la manière dont la
bsdiffbibliothèque est utilisée pour compresser les correctifs. Dans Android 9 et versions ultérieures, l' outilbsdiffsélectionne l'algorithme de compression qui offre les meilleurs résultats de compression pour un correctif. -
Les améliorations apportées à
update_engineont permis de réduire la mémoire consommée lors de l'application de correctifs pour les mises à jour d'appareils A/B.
Les sections suivantes abordent différents problèmes qui affectent la taille des mises à jour OTA, leurs solutions, et des exemples d'implémentation dans AOSP.
Ordre des fichiers
Problème : Les systèmes de fichiers ne garantissent pas un ordre de fichiers lorsqu'une liste de
fichiers dans un répertoire est demandée, bien qu'il soit généralement le même pour le même checkout. Les outils tels que
ls trient les résultats par défaut, mais la fonction de caractère générique utilisée par les commandes telles
que find et make ne trie 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 le résultat de ces commandes avant de les utiliser. Lorsque vous utilisez $(wildcard) ou $(shell find) dans
Android.mk fichiers, 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
intégrée all-*-files-under, qui inclut
all-cpp-files-under (car plusieurs définitions étaient réparties dans d’autres makefiles).
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 : La modification du répertoire dans lequel les éléments sont compilés peut entraîner une différence entre les
binaires. La plupart des chemins d'accès dans la compilation Android sont des chemins d'accès relatifs. Par conséquent,
__FILE__ en C/C++ ne pose pas de problème. Toutefois, les symboles de débogage encodent le nom de chemin complet
par défaut, et le .note.gnu.build-id est généré à partir du hachage du
binaire pré-supprimé. 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 aux emplacements suivants :
- Macros
__DATE__/__TIME__/__TIMESTAMP__dans le code C ou C++. - Codes temporels intégrés dans des archives basées sur des fichiers ZIP.
Solutions/Exemples : Pour supprimer les codes temporels de la sortie de compilation, suivez les instructions ci-dessous dans __DATE__/__TIME__/__TIMESTAMP__ en C/C++. et Codes temporels intégrés dans des archives.
__DATE__/__TIME__/__TIMESTAMP__ en C/C++
Ces macros produisent toujours des sorties différentes pour différentes compilations. Ne les utilisez donc pas. 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 l'OS a été compilé, lisez le
ro.build.date(cela fonctionne pour tout, à l'exception des compilations incrémentielles, qui peuvent ne pas mettre à jour cette date). Pour obtenir un exemple, consultez https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84.
Codes temporels intégrés dans des 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 zip commande. 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/+/android17-release/tools/ziptime/), réinitialise les codes temporels normaux dans les en-têtes ZIP. Pour plus d'informations, 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 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 CL
https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.
Chaînes de version
Problème : Les chaînes de version APK avaient souvent le BUILD_NUMBER ajouté
à leurs versions codées en dur. Même si rien d'autre n'a changé dans un APK, il serait toujours différent.
Solution : Supprimez le numéro de build de la chaîne de version 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 récupèrent automatiquement votre configuration de véracité et activent le calcul de la véracité sur l'appareil. Cela permet de calculer les blocs de véracité sur les appareils Android, au lieu de les stocker sous forme d'octets bruts dans votre package OTA. Les blocs de véracité peuvent utiliser environ 16 Mo pour une partition de 2 Go.
Toutefois, le calcul de la véracité sur l'appareil peut prendre beaucoup de temps. Plus précisément, le code de correction d'erreur directe
peut prendre beaucoup de temps. Sur les appareils Pixel, cela prend généralement jusqu'à 10
minutes. Sur les appareils bas de gamme, cela peut prendre plus de temps. Si vous souhaitez désactiver le calcul de la véracité sur l'appareil, mais toujours 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. Cet indicateur désactive le calcul de la véracité sur l'appareil lors des mises à jour OTA.
Il réduit le temps d'installation de l'OTA, mais augmente la taille du package OTA. Si dm-verity n'est pas activé sur votre appareil, la transmission 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é nécessaires dans les outils de compilation suivants :
- Créateur de fichiers NOTICE. Le créateur de fichiers NOTICE a été modifié pour créer des collections NOTICE reproductibles. Consultez CL: https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64.
- Java Android Compiler Kit (Jack). La chaîne d'outils Jack nécessitait une mise à jour pour gérer les modifications occasionnelles de l'ordre des constructeurs générés. Des accesseurs déterministes pour les constructeurs ont été ajoutés à la chaîne d'outils: https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b.
- Compilateur ART AOT (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.
-
Fichier libpac.so (V8). Chaque build crée un fichier
/system/lib/libpac.sodifférent, car l'instantané V8 change pour chaque build. La solution consistait à supprimer l'instantané : https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29. - Fichiers de pré-dexopt d'application (.odex). Les fichiers de pré-dexopt (.odex) contenaient un remplissage non initialisé 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
Dans les cas où il n'est pas possible d'éliminer les modifications de fichiers liées aux builds, AOSP inclut un
outil de comparaison de builds,
target_files_diff.py
à utiliser pour comparer deux packages de fichiers. Cet outil effectue une comparaison récursive entre deux
builds, à l'exclusion des modifications de fichiers courantes liées aux builds, telles que
- Modifications attendues dans la sortie de compilation (par exemple, en raison d'une modification du 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.
Maintenir une allocation de blocs cohérente
Pour un fichier donné, bien que son contenu reste le même entre deux builds, les blocs réels qui contiennent 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 pour une mise à jour OTA.
Dans une mise à jour OTA Virtual A/B, les E/S inutiles peuvent augmenter considérablement l'espace de stockage requis pour stocker l'instantané de 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, dans Android 7.0, Google a étendu l'outil make_ext4fs afin de
maintenir une allocation de blocs cohérente entre les builds. L'outil make_ext4fs accepte
un indicateur facultatif -d base_fs 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 base_fs fichiers de mappage) à partir du fichier ZIP des fichiers cibles d'un build précédent. Pour chaque
ext4 partition, il existe un .map fichier dans le
IMAGES répertoire (par exemple, IMAGES/system.map correspond à la
system partition). Ces fichiers base_fs peuvent ensuite être archivé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 permette pas de réduire la taille globale du package OTA, cela améliore les performances de mise à jour OTA en réduisant la quantité d'E/S. Pour les mises à jour Virtual A/B, cela réduit considérablement l' espace de stockage nécessaire pour appliquer l'OTA.
Éviter de mettre à jour les applications
En plus de minimiser les différences de build, vous pouvez réduire la taille des mises à jour OTA en excluant les mises à jour des applications qui sont mises à jour via les boutiques d'applications. Les APK représentent souvent une partie importante des différentes partitions d'un appareil. L'inclusion des dernières versions des applications mises à jour par les boutiques 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à disposer de l'application mise à jour, ou d'une version plus récente, reçue directement des boutiques d'applications.