Réduire la taille des mises à jour OTA

Cette page décrit les modifications ajoutées à AOSP pour réduire les modifications de fichiers inutiles entre les builds. Les responsables de l'implémentation 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é à des moments différents, à partir de répertoires différents ou sur des machines différentes, produit un grand nombre de fichiers modifiés. Ces fichiers en excès 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, l'AOSP inclut des modifications du système de compilation conçues pour réduire la taille des correctifs OTA. Les modifications inutiles apportées aux fichiers entre les versions ont été éliminées, et seules les mises à jour OTA contiennent les fichiers liés aux correctifs. AOSP inclut également un outil de comparaison des builds, qui filtre les modifications courantes des fichiers liées au build pour fournir une comparaison plus claire des fichiers de build, et un outil de mappage des blocs, qui vous aide à maintenir la cohérence de l'allocation des blocs.

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 quelques-unes des 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 lors des mises à jour d'appareils non A/B. ZSTD peut être personnalisé pour obtenir 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 OTA et peut être défini en transmettant l'indicateur --vabc_compression_param=zstd,$COMPRESSION_LEVEL.
  • Augmenter la taille de la fenêtre de compression utilisée lors de la mise à jour OTA. La taille maximale de la fenêtre de compression peut être définie en personnalisant le paramètre de compilation dans le fichier .mk d'un appareil. Cette variable est définie sur PRODUCT_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 différenciation 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, par exemple la façon dont la bibliothèque bsdiff est utilisée pour compresser les correctifs. Dans Android 9 et versions ultérieures, l'outil bsdiff sélectionne l'algorithme de compression qui donnerait les meilleurs résultats de compression pour un correctif.
  • Les améliorations apportées à update_engine ont permis de réduire la mémoire consommée lors de l'application de correctifs pour les mises à jour A/B des appareils.

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 l'ordre des fichiers lorsqu'une liste de fichiers dans un répertoire est demandée, bien que l'ordre soit généralement le même pour la même extraction. Des 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 les trie pas. Avant d'utiliser ces outils, vous devez trier les résultats.

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 les fichiers Android.mk, triez-les également. Certains outils, comme Java, trient les entrées. Avant de trier les fichiers, vérifiez donc 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 makefile). Pour en savoir plus, consultez les ressources suivantes :

Répertoire de compilation

Problème : Changer le répertoire dans lequel les éléments sont créés peut entraîner une différence entre les binaires. La plupart des chemins d'accès dans le build Android sont des chemins relatifs. Par conséquent, __FILE__ en C/C++ ne pose pas de problème. Toutefois, les symboles de débogage encodent le chemin d'accès complet par défaut, et le .note.gnu.build-id est généré à partir du hachage du binaire pré-dépouillé. Il changera 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 le résultat de la compilation entraînent des modifications inutiles des fichiers. Cela se produira probablement dans les lieux suivants :

  • Macros __DATE__/__TIME__/__TIMESTAMP__ dans le code C ou C++.
  • Codes temporels intégrés dans les archives au format 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 les archives.

__DATE__/__TIME__/__TIMESTAMP__ en C/C++

Ces macros produisent toujours des sorties différentes pour différentes versions. Ne les utilisez donc pas. Voici quelques options pour éliminer ces macros :

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 le 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 le CL https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028.

Chaînes de version

Problème : Les chaînes de version APK étaient souvent suivies de BUILD_NUMBER dans leurs versions codées en dur. Même si rien d'autre n'a changé dans un APK, celui-ci sera quand même différent.

Solution : Supprimez le numéro de build de la chaîne de version de l'APK.

Exemples :

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érification et activent le calcul de la vérification sur l'appareil. Cela permet de calculer les blocs de vérification sur les appareils Android, au lieu de les stocker sous forme d'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 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. Ce signalement désactive le calcul de la véracité 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, 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 :

Utiliser l'outil de comparaison des builds

Dans les cas où il n'est pas possible d'éliminer les modifications de fichiers liées à la compilation, l'AOSP inclut un outil de comparaison de compilation, target_files_diff.py, à utiliser pour comparer deux packages de fichiers. Cet outil effectue une comparaison récursive entre deux builds, en excluant les modifications courantes des fichiers liés à la compilation, telles que

  • Modifications attendues dans le résultat de la compilation (par exemple, en raison d'un changement de numéro de compilation).
  • Modifications dues à des problèmes connus dans le système de compilation actuel.

Pour utiliser l'outil de comparaison des compilations, 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é de copie lors de l'é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 une allocation de blocs cohérente entre les versions. 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) du fichier ZIP des fichiers cibles d'une compilation précédente. Pour chaque partition ext4, il existe un fichier .map dans le répertoire IMAGES (par exemple, IMAGES/system.map correspond à la partition system). 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 A/B virtuelles, la quantité d'espace de stockage nécessaire pour appliquer la mise à jour OTA est considérablement réduite.

Éviter de mettre à jour les applications

En plus de minimiser les différences de compilation, vous pouvez réduire la taille des mises à jour OTA en excluant les mises à jour des applications qui sont mises à jour via les plates-formes de téléchargement d'applications. Les APK représentent souvent une part importante des différentes partitions d'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 n'apporter que peu d'avantages aux utilisateurs. Au moment où les utilisateurs reçoivent un package OTA, il est possible qu'ils aient déjà l'application mise à jour, voire une version encore plus récente, reçue directement depuis les plates-formes de téléchargement d'applications.