Surveillance de l'ABI du noyau Android

Vous pouvez utiliser les outils de surveillance de l'interface binaire d'application (ABI), disponibles dans Android 11 et versions ultérieures, pour stabiliser l'ABI du noyau des noyaux Android. L'outil collecte et compare les représentations ABI des binaires de noyau existants (vmlinux + modules GKI). Ces représentations ABI sont les fichiers .stg et les listes de symboles. L'interface sur laquelle la représentation donne une vue s'appelle l'interface de module de kernel (KMI). Vous pouvez utiliser ces outils pour suivre et atténuer les modifications apportées au KMI.

Les outils de surveillance de l'ABI sont développés dans AOSP et utilisent STG (ou libabigail dans Android 13 et versions antérieures) pour générer et comparer des représentations.

Cette page décrit les outils, le processus de collecte et d'analyse des représentations ABI, ainsi que l'utilisation de ces représentations pour assurer la stabilité de l'ABI dans le noyau. Cette page fournit également des informations sur la contribution de modifications aux noyaux Android.

Procédure

L'analyse de l'ABI du noyau nécessite plusieurs étapes, dont la plupart peuvent être automatisées:

  1. Compilez le kernel et sa représentation ABI.
  2. Analysez les différences ABI entre le build et une référence.
  3. Mettez à jour la représentation ABI (si nécessaire).
  4. Utiliser des listes de symboles

Les instructions suivantes fonctionnent pour tous les noyaux que vous pouvez compiler à l'aide d'une chaîne d'outils compatible (telle que la chaîne d'outils Clang prédéfinie). repo manifests est disponible pour toutes les branches de kernel communes Android et pour plusieurs kernels spécifiques à l'appareil. Il garantit que la chaîne d'outils appropriée est utilisée lorsque vous créez une distribution de kernel à des fins d'analyse.

Listes de symboles

Le KMI n'inclut pas tous les symboles du noyau,ni même tous les plus de 30 000 symboles exportés. À la place, les symboles pouvant être utilisés par les modules de fournisseurs sont explicitement répertoriés dans un ensemble de fichiers de liste de symboles gérés publiquement à la racine de l'arborescence du noyau. L'union de tous les symboles de tous les fichiers de liste de symboles définit l'ensemble des symboles KMI maintenus comme stables. Un exemple de fichier de liste de symboles est abi_gki_aarch64_db845c, qui déclare les symboles requis pour la DragonBoard 845c.

Seuls les symboles répertoriés dans une liste de symboles et leurs structures et définitions associées sont considérés comme faisant partie du KMI. Vous pouvez publier des modifications dans vos listes de symboles si les symboles dont vous avez besoin ne sont pas présents. Une fois que les nouvelles interfaces figurent dans une liste de symboles et figurent dans la description des KMI, elles sont considérées comme stables et ne doivent pas être supprimées de la liste de symboles ni modifiées une fois la branche figée.

Chaque branche du kernel KMI (Android Common Kernel) possède son propre ensemble de listes de symboles. Aucune tentative n'est faite pour assurer la stabilité de l'ABI entre les différentes branches du kernel KMI. Par exemple, le KMI de android12-5.10 est complètement indépendant du KMI de android13-5.10.

Les outils ABI utilisent des listes de symboles KMI pour limiter les interfaces à surveiller pour la stabilité. La liste principale des symboles contient les symboles requis par les modules de noyau GKI. Les fournisseurs doivent envoyer et mettre à jour des listes de symboles supplémentaires pour s'assurer que les interfaces sur lesquelles ils s'appuient maintiennent la compatibilité avec les ABI. Par exemple, pour afficher une liste de listes de symboles pour android13-5.15, consultez https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android.

Une liste de symboles contient les symboles requis pour le fournisseur ou l'appareil concerné. La liste complète utilisée par les outils est l'union de tous les fichiers de liste de symboles KMI. Les outils ABI déterminent les détails de chaque symbole, y compris la signature de fonction et les structures de données imbriquées.

Lorsque le KMI est figé, aucune modification n'est autorisée sur les interfaces KMI existantes. Elles sont stables. Toutefois, les fournisseurs sont libres d'ajouter des symboles à la KMI à tout moment, à condition que ces ajouts n'affectent pas la stabilité de l'ABI existante. Les symboles nouvellement ajoutés sont considérés comme stables dès qu'ils sont cités dans une liste de symboles KMI. Les symboles ne doivent pas être supprimés d'une liste pour un noyau, sauf si vous pouvez confirmer qu'aucun appareil n'a jamais été expédié avec une dépendance à ce symbole.

Vous pouvez générer une liste de symboles KMI pour un appareil en suivant les instructions de la section Utiliser les listes de symboles. De nombreux partenaires envoient une liste de symboles par ACK, mais ce n'est pas une exigence stricte. Si cela facilite la maintenance, vous pouvez envoyer plusieurs listes de symboles.

Étendez le KMI

Bien que les symboles KMI et les structures associées soient maintenus comme stables (ce qui signifie que les modifications qui endommagent les interfaces stables d'un noyau avec un KMI figé ne peuvent pas être acceptées), le noyau GKI reste ouvert aux extensions afin que les appareils expédiés plus tard dans l'année n'aient pas besoin de définir toutes leurs dépendances avant que le KMI ne soit figé. Pour étendre le KMI, vous pouvez ajouter de nouveaux symboles au KMI pour les nouvelles ou les fonctions de kernel exportées existantes, même si le KMI est gelé. Les nouveaux correctifs du noyau peuvent également être acceptés s'ils ne cassent pas le KMI.

À propos des problèmes de KMI

Un noyau possède des sources et les binaires sont créés à partir de ces sources. Les branches du kernel surveillées par l'ABI incluent une représentation ABI de l'ABI GKI actuelle (sous la forme d'un fichier .stg). Une fois les binaires (vmlinux, Image et tous les modules GKI) compilés, une représentation ABI peut être extraite des binaires. Toute modification apportée au fichier source du noyau peut affecter les binaires et, à son tour, affecter le .stg extrait. L'analyseur AbiAnalyzer compare le fichier .stg validé avec celui extrait des artefacts de compilation et attribue un libellé lint-1 à la modification dans Gerrit s'il détecte une différence sémantique.

Gérer les erreurs ABI

Par exemple, le correctif suivant introduit une faille évidente dans l'ABI:

diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 42786e6364ef..e15f1d0f137b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -657,6 +657,7 @@ struct mm_struct {
                ANDROID_KABI_RESERVE(1);
        } __randomize_layout;

+       int tickle_count;
        /*
         * The mm_cpumask needs to be at the end of mm_struct, because it
         * is dynamically sized based on nr_cpu_ids.

Lorsque vous exécutez l'ABI de compilation avec ce correctif appliqué, l'outil s'arrête avec un code d'erreur différent de zéro et signale une différence d'ABI semblable à celle-ci:

function symbol 'struct block_device* I_BDEV(struct inode*)' changed
  CRC changed from 0x8d400dbd to 0xabfc92ad

function symbol 'void* PDE_DATA(const struct inode*)' changed
  CRC changed from 0xc3c38b5c to 0x7ad96c0d

function symbol 'void __ClearPageMovable(struct page*)' changed
  CRC changed from 0xf489e5e8 to 0x92bd005e

... 4492 omitted; 4495 symbols have only CRC changes

type 'struct mm_struct' changed
  byte size changed from 992 to 1000
  member 'int tickle_count' was added
  member 'unsigned long cpu_bitmap[0]' changed
    offset changed by 64

Différences d'ABI détectées au moment de la compilation

La cause la plus courante des erreurs est qu'un pilote utilise un nouveau symbole du noyau qui ne figure dans aucune des listes de symboles.

Si le symbole n'est pas inclus dans la liste des symboles (android/abi_gki_aarch64), vous devez d'abord vérifier qu'il est exporté avec EXPORT_SYMBOL_GPL(symbol_name), puis mettre à jour la représentation XML de l'ABI et la liste des symboles. Par exemple, les modifications suivantes ajoutent la nouvelle fonctionnalité FS incrémentielle à la branche android-12-5.10, ce qui inclut la mise à jour de la liste des symboles et de la représentation XML de l'ABI.

  • L'exemple de modification de fonctionnalité se trouve dans aosp/1345659.
  • L'exemple de liste de symboles se trouve dans aosp/1346742.
  • L'exemple de modification du fichier XML ABI se trouve dans aosp/1349377.

Si le symbole est exporté (par vous ou par un autre utilisateur) mais qu'aucun autre pilote ne l'utilise, une erreur de compilation semblable à celle-ci peut s'afficher.

Comparing the KMI and the symbol lists:
+ build/abi/compare_to_symbol_list out/$BRANCH/common/Module.symvers out/$BRANCH/common/abi_symbollist.raw
ERROR: Differences between ksymtab and symbol list detected!
Symbols missing from ksymtab:
Symbols missing from symbol list:
 - simple_strtoull

Pour résoudre ce problème, mettez à jour la liste des symboles KMI dans le noyau et l'ACK (voir la section Mettre à jour la représentation de l'ABI). Pour obtenir un exemple de mise à jour de la liste de symboles et du fichier XML ABI dans l'ACK, consultez aosp/1367601.

Résoudre les erreurs ABI du noyau

Vous pouvez gérer les erreurs de l'ABI du kernel en refactorant le code pour ne pas modifier l'ABI ou en mettant à jour la représentation de l'ABI. Utilisez le tableau suivant pour déterminer la meilleure approche dans votre cas.

Organigramme de la rupture de l'ABI

Figure 1 : Résolution des erreurs ABI

Refactoriser le code pour éviter les modifications de l'ABI

Faites tout votre possible pour éviter de modifier l'ABI existant. Dans de nombreux cas, vous pouvez refactoriser votre code pour supprimer les modifications qui affectent l'ABI.

  • Réfactorisation des modifications apportées aux champs de structure. Si une modification modifie l'ABI pour une fonctionnalité de débogage, ajoutez un #ifdef autour des champs (dans les structures et les références de source) et assurez-vous que le CONFIG utilisé pour le #ifdef est désactivé pour la defconfig de production et le gki_defconfig. Pour savoir comment ajouter une configuration de débogage à une struct sans endommager l'ABI, consultez ce correctif.

  • Fonctionnalités de refactorisation pour ne pas modifier le noyau principal. Si de nouvelles fonctionnalités doivent être ajoutées à l'ACK pour prendre en charge les modules partenaires, essayez de refactoriser la partie ABI de la modification pour éviter de modifier l'ABI du noyau. Pour voir un exemple d'utilisation de l'ABI du kernel existant pour ajouter des fonctionnalités supplémentaires sans modifier l'ABI du kernel, consultez aosp/1312213.

Corriger une ABI défectueuse sur Android Gerrit

Si vous n'avez pas intentionnellement endommagé l'ABI du kernel, vous devez mener une enquête en vous appuyant sur les conseils fournis par les outils de surveillance de l'ABI. Les causes de défaillance les plus courantes sont les modifications des structures de données et les modifications du CRC des symboles associés, ou des modifications des options de configuration à l'origine de l'un des problèmes susmentionnés. Commencez par résoudre les problèmes détectés par l'outil.

Vous pouvez reproduire les résultats de l'ABI localement. Pour ce faire, consultez la section Compiler le noyau et sa représentation ABI.

À propos des étiquettes lint-1

Si vous importez des modifications dans une branche contenant un KMI figé ou finalisé, les modifications doivent passer l'AbiAnalyzer pour s'assurer qu'elles n'affectent pas l'ABI stable de manière incompatible. Au cours de ce processus, AbiAnalyzer recherche le rapport ABI créé lors de la compilation (une compilation étendue qui effectue la compilation normale, puis certaines étapes d'extraction et de comparaison ABI.

Si AbiAnalyzer trouve un rapport non vide, il définit le libellé Lint-1 et l'envoi du changement est bloqué jusqu'à ce qu'il soit résolu, jusqu'à ce que le correctif reçoive un libellé Lint+1.

Mettre à jour l'ABI du noyau

Si la modification de l'ABI est inévitable, vous devez appliquer vos modifications de code, la représentation de l'ABI et la liste de symboles à l'ACK. Pour que Lint supprime le -1 et ne brise pas la compatibilité avec GKI, procédez comme suit:

  1. Importez les modifications de code dans l'ACK.

  2. Attendez de recevoir un code-review +2 pour le lot de correctifs.

  3. Mettez à jour la représentation de l'ABI de référence.

  4. Fusionnez vos modifications de code et la modification de mise à jour de l'ABI.

Importer les modifications de code ABI dans l'ACK

La mise à jour de l'ABI ACK dépend du type de modification apportée.

  • Si une modification d'ABI est liée à une fonctionnalité qui affecte les tests CTS ou VTS, la modification peut généralement être sélectionnée pour être confirmée telle quelle. Par exemple:

  • Si une modification de l'ABI concerne une fonctionnalité pouvant être partagée avec l'ACK, cette modification peut être sélectionnée pour l'ACK telle quelle. Par exemple, les modifications suivantes ne sont pas nécessaires pour les tests CTS ou VTS, mais peuvent être partagées avec l'ACK:

  • Si un changement d'ABI introduit une nouvelle fonctionnalité qui n'a pas besoin d'être incluse dans l'ACK, vous pouvez introduire les symboles dans l'ACK à l'aide d'un bouchon, comme décrit dans la section suivante.

Utiliser des bouchons pour l'acquittement

Les stubs ne doivent être nécessaires que pour les modifications de noyau du noyau qui ne profitent pas à l'ACK, telles que les changements de performances et d'alimentation. La liste suivante détaille des exemples de bouchons et de choix partiels dans ACK pour GKI.

  • Bouchon de fonctionnalité de l'isolation du noyau (aosp/1284493). Les capacités dans ACK ne sont pas nécessaires, mais les symboles doivent y être présents pour que vos modules puissent utiliser ces symboles.

  • Symbole d'espace réservé pour le module du fournisseur (aosp/1288860).

  • Sélection de la fonctionnalité de suivi des événements mm par processus (aosp/1288454) uniquement pour les ABI. Le correctif d'origine a été sélectionné pour l'acceptation, puis affiné pour n'inclure que les modifications nécessaires pour résoudre la différence ABI pour task_struct et mm_event_count. Ce correctif met également à jour l'énumération mm_event_type pour qu'elle contienne les membres finaux.

  • Sélection partielle des modifications de l'ABI de la structure thermique qui nécessitaient plus que l'ajout des nouveaux champs ABI.

    • Le correctif aosp/1255544 a résolu les différences ABI entre le kernel partenaire et ACK.

    • Le correctif aosp/1291018 a corrigé les problèmes fonctionnels détectés lors des tests GKI du correctif précédent. La correction consistait à initialiser la struct de paramètres du capteur pour enregistrer plusieurs zones thermiques sur un seul capteur.

  • Modifications de l'ABI CONFIG_NL80211_TESTMODE (aosp/1344321). Ce correctif a ajouté les modifications de structure nécessaires pour l'ABI et s'est assuré que les champs supplémentaires n'entraînaient pas de différences fonctionnelles, permettant aux partenaires d'inclure CONFIG_NL80211_TESTMODE dans leurs noyaux de production tout en maintenant la conformité avec GKI.

Appliquer le KMI au moment de l'exécution

Les noyaux GKI utilisent les options de configuration TRIM_UNUSED_KSYMS=y et UNUSED_KSYMS_WHITELIST=<union of all symbol lists>, qui limitent les symboles exportés (tels que les symboles exportés à l'aide de EXPORT_SYMBOL_GPL()) à ceux figurant sur une liste de symboles. Tous les autres symboles ne sont pas exportés, et le chargement d'un module nécessitant un symbole non exporté est refusé. Cette restriction est appliquée au moment de la compilation et les entrées manquantes sont signalées.

À des fins de développement, vous pouvez utiliser un build du kernel GKI qui n'inclut pas le recadrage des symboles (ce qui signifie que tous les symboles exportés habituellement peuvent être utilisés). Pour localiser ces builds, recherchez les builds kernel_debug_aarch64 sur ci.android.com.

Appliquer le KMI à l'aide de la gestion des versions de module

Les noyaux de l'image du noyau générique (GKI) utilisent le gestion des versions des modules (CONFIG_MODVERSIONS) comme mesure supplémentaire pour appliquer la conformité de la KMI au moment de l'exécution. La gestion des versions de module peut entraîner des échecs de non-concordance du contrôle de redondance cyclique (CRC) au moment du chargement du module si son KMI attendu ne correspond pas au KMI vmlinux. Par exemple, voici une erreur typique qui se produit au moment du chargement du module en raison d'une non-concordance de CRC pour le symbole module_layout():

init: Loading module /lib/modules/kernel/.../XXX.ko with args ""
XXX: disagrees about version of symbol module_layout
init: Failed to insmod '/lib/modules/kernel/.../XXX.ko' with args ''

Utilisations de la gestion des versions des modules

Le contrôle des versions des modules est utile pour les raisons suivantes:

  • La gestion des versions de module détecte les modifications apportées à la visibilité de la structure des données. Si les modules modifient des structures de données opaques, c'est-à-dire des structures de données qui ne font pas partie du KMI, ils ne fonctionnent plus après de futures modifications de la structure.

    Prenons l'exemple du champ fwnode dans struct device. Ce champ DOIT être opaque pour les modules afin qu'ils ne puissent pas modifier les champs de device->fw_node ni faire d'hypothèses sur sa taille.

    Toutefois, si un module inclut <linux/fwnode.h> (directement ou indirectement), le champ fwnode de struct device n'est plus opaque pour lui. Le module peut ensuite apporter des modifications à device->fwnode->dev ou device->fwnode->ops. Ce scénario pose problème pour plusieurs raisons, comme suit:

    • Il peut briser les hypothèses que le code du noyau principal fait sur ses structures de données internes.

    • Si une future mise à jour du kernel modifie le struct fwnode_handle (le type de données de fwnode), le module ne fonctionne plus avec le nouveau kernel. De plus, stgdiff ne montrera aucune différence, car le module enfreint le KMI en manipulant directement les structures de données internes d'une manière qui ne peut pas être capturée en inspectant uniquement la représentation binaire.

  • Un module actuel est considéré comme incompatible avec KMI lorsqu'il est chargé à une date ultérieure par un nouveau noyau incompatible. La gestion des versions des modules ajoute une vérification au moment de l'exécution pour éviter de charger accidentellement un module qui n'est pas compatible avec le noyau KMI. Cette vérification évite les problèmes d'exécution difficiles à déboguer et les plantages du noyau pouvant résulter d'une incompatibilité non détectée dans le KMI.

L'activation de la gestion des versions des modules évite tous ces problèmes.

Vérifier les incohérences de CRC sans démarrer l'appareil

stgdiff compare et signale les incohérences de CRC entre les noyaux, ainsi que d'autres différences d'ABI.

De plus, une compilation complète du noyau avec CONFIG_MODVERSIONS activé génère un fichier Module.symvers dans le cadre du processus de compilation normal. Ce fichier comporte une ligne pour chaque symbole exporté par le noyau (vmlinux) et les modules. Chaque ligne comprend la valeur CRC, le nom du symbole, l'espace de noms du symbole, le nom vmlinux ou le nom du module qui exporte le symbole, ainsi que le type d'exportation (par exemple, EXPORT_SYMBOL par rapport à EXPORT_SYMBOL_GPL).

Vous pouvez comparer les fichiers Module.symvers entre la compilation GKI et votre compilation pour vérifier s'il existe des différences de CRC dans les symboles exportés par vmlinux. S'il existe une différence de valeur CRC dans un symbole exporté par vmlinux et que ce symbole est utilisé par l'un des modules que vous chargez sur votre appareil, le module ne se charge pas.

Si vous ne disposez pas de tous les artefacts de compilation, mais que vous disposez des fichiers vmlinux du noyau GKI et de votre noyau, vous pouvez comparer les valeurs CRC d'un symbole spécifique en exécutant la commande suivante sur les deux noyaux et en comparant le résultat:

nm <path to vmlinux>/vmlinux | grep __crc_<symbol name>

Par exemple, la commande suivante vérifie la valeur CRC du symbole module_layout:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

Résoudre les problèmes de correspondance du CRC

Pour résoudre un problème de non-concordance de CRC lors du chargement d'un module, procédez comme suit:

  1. Créez le noyau GKI et le noyau de votre appareil à l'aide de l'option --kbuild_symtypes, comme indiqué dans la commande suivante:

    tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
    

    Cette commande génère un fichier .symtypes pour chaque fichier .o. Pour en savoir plus, consultez KBUILD_SYMTYPES dans Kleaf.

    Pour Android 13 et versions antérieures, créez le kernel GKI et le kernel de votre appareil en ajoutant KBUILD_SYMTYPES=1 au début de la commande que vous utilisez pour créer le kernel, comme indiqué dans la commande suivante:

    KBUILD_SYMTYPES=1 BUILD_CONFIG=common/build.config.gki.aarch64 build/build.sh
    

    Lorsque vous utilisez build_abi.sh,, l'indicateur KBUILD_SYMTYPES=1 est déjà défini implicitement.

  2. Recherchez le fichier .c dans lequel le symbole avec une non-concordance de CRC est exporté à l'aide de la commande suivante:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. Le fichier .c possède un fichier .symtypes correspondant dans le GKI et les artefacts de compilation du kernel de votre appareil. Recherchez le fichier .c à l'aide des commandes suivantes:

    cd out/$BRANCH/common && ls -1 kernel/module.*
    kernel/module.o
    kernel/module.o.symversions
    kernel/module.symtypes
    

    Voici les caractéristiques du fichier .c:

    • Le format du fichier .c correspond à une ligne (potentiellement très longue) par symbole.

    • [s|u|e|etc]# au début de la ligne signifie que le symbole est de type de données [struct|union|enum|etc]. Exemple :

      t#bool typedef _Bool bool
      
    • L'absence de préfixe # au début de la ligne indique que le symbole est une fonction. Exemple :

      find_module s#module * find_module ( const char * )
      
  4. Comparez les deux fichiers et corrigez toutes les différences.

Cas 1: Différences dues à la visibilité des types de données

Si un kernel conserve un symbole ou un type de données opaque pour les modules et que l'autre ne le fait pas, cette différence apparaît entre les fichiers .symtypes des deux kernels. Le fichier .symtypes de l'un des noyaux contient UNKNOWN pour un symbole, et le fichier .symtypes de l'autre noyau affiche une vue étendue du symbole ou du type de données.

Par exemple, l'ajout de la ligne suivante au fichier include/linux/device.h de votre noyau entraîne des incohérences au niveau du CRC, dont l'une concerne module_layout():

 #include <linux/fwnode.h>

En comparant les module.symtypes de ce symbole, les différences suivantes apparaissent:

 $ diff -u <GKI>/kernel/module.symtypes <your kernel>/kernel/module.symtypes
  --- <GKI>/kernel/module.symtypes
  +++ <your kernel>/kernel/module.symtypes
  @@ -334,12 +334,15 @@
  ...
  -s#fwnode_handle struct fwnode_handle { UNKNOWN }
  +s#fwnode_reference_args struct fwnode_reference_args { s#fwnode_handle * fwnode ; unsigned int nargs ; t#u64 args [ 8 ] ; }
  ...

Si votre kernel a la valeur UNKNOWN et que le kernel GKI affiche la vue agrandie du symbole (très peu probable), fusionnez le dernier kernel Android Common dans votre kernel afin d'utiliser la dernière base de kernel GKI.

Dans la plupart des cas, le noyau GKI a la valeur UNKNOWN, mais votre noyau dispose des détails internes du symbole en raison des modifications apportées à votre noyau. En effet, l'un des fichiers de votre kernel a ajouté un #include qui n'est pas présent dans le kernel GKI.

Souvent, la solution consiste simplement à masquer le nouveau #include de genksyms.

#ifndef __GENKSYMS__
#include <linux/fwnode.h>
#endif

Sinon, pour identifier le #include à l'origine de la différence, procédez comme suit:

  1. Ouvrez le fichier d'en-tête qui définit le symbole ou le type de données présentant cette différence. Par exemple, modifiez include/linux/fwnode.h pour struct fwnode_handle.

  2. Ajoutez le code suivant en haut du fichier d'en-tête:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. Dans le fichier .c du module présentant un décalage de CRC, ajoutez la ligne suivante en tant que première ligne avant toutes les lignes #include.

    #define CRC_CATCH 1
    
  4. Compilez votre module. L'erreur de temps de compilation qui en résulte affiche la chaîne du fichier d'en-tête #include qui a entraîné cette non-concordance de CRC. Exemple :

    In file included from .../drivers/clk/XXX.c:16:`
    In file included from .../include/linux/of_device.h:5:
    In file included from .../include/linux/cpu.h:17:
    In file included from .../include/linux/node.h:18:
    .../include/linux/device.h:16:2: error: "Included from here"
    #error "Included from here"
    

    L'un des maillons de cette chaîne de #include est dû à une modification apportée à votre noyau, qui est manquante dans le noyau GKI.

  5. Identifiez la modification, annulez-la dans votre kernel ou importez-la dans ACK et fusionnez-la.

Cas 2: Différences dues à des modifications de type de données

Si le non-respect du CRC pour un symbole ou un type de données n'est pas dû à une différence de visibilité, il est dû à des modifications réelles (ajouts, suppressions ou modifications) du type de données lui-même.

Par exemple, la modification suivante dans votre kernel entraîne plusieurs incohérences de CRC, car de nombreux symboles sont indirectement affectés par ce type de modification:

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
  --- a/include/linux/iommu.h
  +++ b/include/linux/iommu.h
  @@ -259,7 +259,7 @@ struct iommu_ops {
     void (*iotlb_sync)(struct iommu_domain *domain);
     phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
     phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
  -        dma_addr_t iova);
  +        dma_addr_t iova, unsigned long trans_flag);
     int (*add_device)(struct device *dev);
     void (*remove_device)(struct device *dev);
     struct iommu_group *(*device_group)(struct device *dev);

Un problème de non-correspondance du CRC concerne devm_of_platform_populate().

Si vous comparez les fichiers .symtypes de ce symbole, ils peuvent se présenter comme suit:

 $ diff -u <GKI>/drivers/of/platform.symtypes <your kernel>/drivers/of/platform.symtypes
  --- <GKI>/drivers/of/platform.symtypes
  +++ <your kernel>/drivers/of/platform.symtypes
  @@ -399,7 +399,7 @@
  ...
  -s#iommu_ops struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t ) ; int
    ( * add_device ) ( s#device * ) ; ...
  +s#iommu_ops struct iommu_ops { ... ; t#phy
  s_addr_t ( * iova_to_phys_hard ) ( s#iommu_domain * , t#dma_addr_t , unsigned long ) ; int ( * add_device ) ( s#device * ) ; ...

Pour identifier le type modifié, procédez comme suit:

  1. Recherchez la définition du symbole dans le code source (généralement dans les fichiers .h).

    • Pour identifier les différences de symboles entre votre kernel et le kernel GKI, recherchez le commit en exécutant la commande suivante:
    git blame
    
    • Pour les symboles supprimés (lorsque vous supprimez un symbole dans un arbre et que vous souhaitez également le supprimer dans l'autre arbre), vous devez trouver la modification qui a supprimé la ligne. Utilisez la commande suivante sur l'arborescence où la ligne a été supprimée:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. Examinez la liste des commits renvoyés pour localiser la modification ou la suppression. Le premier commit est probablement celui que vous recherchez. Si ce n'est pas le cas, parcourez la liste jusqu'à trouver le commit.

  3. Après avoir identifié la modification, annulez-la dans votre kernel ou importez-la dans ACK et faites-la fusionner.