Android-Kernel-ABI-Überwachung

Sie können das in Android 11 und höher verfügbare Anwendungs-Binary Interface (ABI)-Überwachungstool verwenden, um die In-Kernel-ABI von Android-Kerneln zu stabilisieren. Das Tool sammelt und vergleicht ABI-Darstellungen von vorhandenen Kernel-Binärdateien ( vmlinux + GKI-Module). Diese ABI-Darstellungen sind die .stg Dateien und die Symbollisten. Die Schnittstelle, auf der die Darstellung einen Einblick gibt, wird Kernel Module Interface (KMI) genannt. Mit den Tools können Sie Änderungen am KMI verfolgen und abmildern.

Das ABI-Überwachungstool wird in AOSP entwickelt und verwendet STG (oder libabigail in Android 13 und niedriger), um Darstellungen zu generieren und zu vergleichen.

Auf dieser Seite werden die Tools, der Prozess des Sammelns und Analysierens von ABI-Darstellungen und die Verwendung solcher Darstellungen zur Gewährleistung der Stabilität des ABI im Kernel beschrieben. Diese Seite bietet auch Informationen zum Beitragen von Änderungen an den Android-Kerneln.

Verfahren

Die Analyse des ABI des Kernels erfordert mehrere Schritte, von denen die meisten automatisiert werden können:

  1. Erstellen Sie den Kernel und seine ABI-Darstellung .
  2. Analysieren Sie ABI-Unterschiede zwischen dem Build und einer Referenz .
  3. Aktualisieren Sie die ABI-Darstellung (falls erforderlich) .
  4. Arbeiten Sie mit Symbollisten .

Die folgenden Anweisungen gelten für jeden Kernel, den Sie mit einer unterstützten Toolchain erstellen können (z. B. der vorgefertigten Clang-Toolchain). repo manifests sind für alle gängigen Android-Kernel-Zweige und für mehrere gerätespezifische Kernel verfügbar. Sie stellen sicher, dass die richtige Toolchain verwendet wird, wenn Sie eine Kernel-Distribution für die Analyse erstellen.

Symbollisten

Das KMI umfasst nicht alle Symbole im Kernel oder sogar alle der über 30.000 exportierten Symbole. Stattdessen werden die Symbole, die von Herstellermodulen verwendet werden können, explizit in einer Reihe von Symbollistendateien aufgeführt, die öffentlich im Stammverzeichnis des Kernelbaums verwaltet werden. Die Vereinigung aller Symbole in allen Symbollistendateien definiert den als stabil gehaltenen Satz von KMI-Symbolen. Eine Beispiel-Symbollistendatei ist abi_gki_aarch64_db845c , die die für das DragonBoard 845c erforderlichen Symbole deklariert.

Nur die in einer Symbolliste aufgeführten Symbole und ihre zugehörigen Strukturen und Definitionen gelten als Teil des KMI. Sie können Änderungen an Ihren Symbollisten veröffentlichen, wenn die benötigten Symbole nicht vorhanden sind. Nachdem sich neue Schnittstellen in einer Symbolliste befinden und Teil der KMI-Beschreibung sind, bleiben sie stabil und dürfen nach dem Einfrieren des Zweigs nicht aus der Symbolliste entfernt oder geändert werden.

Jeder KMI-Kernelzweig des Android Common Kernel (ACK) verfügt über einen eigenen Satz von Symbollisten. Es wird kein Versuch unternommen, ABI-Stabilität zwischen verschiedenen KMI-Kernelzweigen bereitzustellen. Beispielsweise ist der KMI für android12-5.10 völlig unabhängig vom KMI für android13-5.10 .

ABI-Tools verwenden KMI-Symbollisten, um einzuschränken, welche Schnittstellen auf Stabilität überwacht werden müssen. Die Hauptsymbolliste enthält die Symbole, die von den GKI-Kernelmodulen benötigt werden. Von den Anbietern wird erwartet, dass sie zusätzliche Symbollisten einreichen und aktualisieren, um sicherzustellen, dass die Schnittstellen, auf die sie sich verlassen, die ABI-Kompatibilität beibehalten. Eine Liste der Symbollisten für android13-5.15 finden Sie beispielsweise unter https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android

Eine Symbolliste enthält die Symbole, die für den jeweiligen Anbieter oder das jeweilige Gerät benötigt werden. Die von den Tools verwendete vollständige Liste ist die Vereinigung aller KMI-Symbollistendateien. ABI-Tools bestimmen die Details jedes Symbols, einschließlich Funktionssignatur und verschachtelter Datenstrukturen.

Wenn das KMI eingefroren ist, sind keine Änderungen an den vorhandenen KMI-Schnittstellen zulässig; sie sind stabil. Es steht den Anbietern jedoch jederzeit frei, Symbole zum KMI hinzuzufügen, solange die Ergänzungen die Stabilität des bestehenden ABI nicht beeinträchtigen. Neu hinzugefügte Symbole bleiben stabil, sobald sie von einer KMI-Symbolliste zitiert werden. Symbole sollten nicht aus einer Liste für einen Kernel entfernt werden, es sei denn, es kann bestätigt werden, dass noch nie ein Gerät mit einer Abhängigkeit von diesem Symbol ausgeliefert wurde.

Sie können eine KMI-Symbolliste für ein Gerät erstellen, indem Sie die Anweisungen unter So arbeiten Sie mit Symbollisten befolgen . Viele Partner reichen eine Symbolliste pro ACK ein, dies ist jedoch keine zwingende Anforderung. Wenn es bei der Wartung hilfreich ist, können Sie mehrere Symbollisten einreichen.

Erweitern Sie das KMI

Während KMI-Symbole und zugehörige Strukturen stabil bleiben (d. h. Änderungen, die stabile Schnittstellen in einem Kernel mit eingefrorenem KMI zerstören, können nicht akzeptiert werden), bleibt der GKI-Kernel offen für Erweiterungen, sodass Geräte, die später im Jahr ausgeliefert werden, nicht alle definieren müssen ihre Abhängigkeiten, bevor das KMI eingefroren wird. Um das KMI zu erweitern, können Sie dem KMI neue Symbole für neue oder vorhandene exportierte Kernelfunktionen hinzufügen, auch wenn das KMI eingefroren ist. Möglicherweise werden auch neue Kernel-Patches akzeptiert, wenn sie den KMI nicht beschädigen.

Über KMI-Brüche

Ein Kernel hat Quellen und Binärdateien werden aus diesen Quellen erstellt. ABI-überwachte Kernelzweige enthalten eine ABI-Darstellung des aktuellen GKI-ABI (in Form einer .stg Datei). Nachdem die Binärdateien ( vmlinux , Image und alle GKI-Module) erstellt wurden, kann eine ABI-Darstellung aus den Binärdateien extrahiert werden. Jede an einer Kernel-Quelldatei vorgenommene Änderung kann sich auf die Binärdateien und damit auch auf die extrahierte .stg auswirken. Der AbiAnalyzer Analysator vergleicht die festgeschriebene .stg Datei mit der aus Build-Artefakten extrahierten Datei und setzt ein Lint-1-Label für die Änderung in Gerrit, wenn er einen semantischen Unterschied findet.

Behandeln Sie ABI-Brüche

Der folgende Patch führt beispielsweise einen sehr offensichtlichen ABI-Fehler ein:

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.

Wenn Sie Build ABI mit diesem Patch ausführen, wird das Tool mit einem Fehlercode ungleich Null beendet und meldet einen ABI-Unterschied ähnlich diesem:

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

Zur Erstellungszeit erkannte ABI-Unterschiede

Der häufigste Grund für Fehler ist, dass ein Treiber ein neues Symbol aus dem Kernel verwendet, das in keiner der Symbollisten enthalten ist.

Wenn das Symbol nicht in der Symbolliste ( android/abi_gki_aarch64 ) enthalten ist, müssen Sie zunächst überprüfen, ob es mit EXPORT_SYMBOL_GPL( symbol_name ) exportiert wurde, und dann die ABI-XML-Darstellung und Symbolliste aktualisieren. Die folgenden Änderungen fügen beispielsweise die neue Funktion „Inkrementelles FS“ zum Zweig android-12-5.10 hinzu, einschließlich der Aktualisierung der Symbolliste und der ABI-XML-Darstellung.

  • Ein Beispiel für eine Funktionsänderung finden Sie in aosp/1345659 .
  • Ein Beispiel für eine Symbolliste finden Sie in aosp/1346742 .
  • Ein Beispiel für eine ABI-XML-Änderung finden Sie in aosp/1349377 .

Wenn das Symbol exportiert wird (entweder von Ihnen oder es wurde zuvor exportiert), aber kein anderer Treiber es verwendet, erhalten Sie möglicherweise einen Build-Fehler ähnlich dem folgenden.

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

Um das Problem zu beheben, aktualisieren Sie die KMI-Symbolliste sowohl in Ihrem Kernel als auch im ACK (siehe Aktualisieren der ABI-Darstellung ). Ein Beispiel für die Aktualisierung des ABI-XML und der Symbolliste im ACK finden Sie unter aosp/1367601 .

Beheben Sie Kernel-ABI-Fehler

Sie können Kernel-ABI-Fehler beheben, indem Sie den Code so umgestalten, dass der ABI nicht geändert wird , oder indem Sie die ABI-Darstellung aktualisieren . Verwenden Sie die folgende Tabelle, um den besten Ansatz für Ihre Situation zu ermitteln.

ABI-Bruch-Flussdiagramm

Abbildung 1. ABI-Bruchauflösung

Code umgestalten, um ABI-Änderungen zu vermeiden

Bemühen Sie sich nach Kräften, eine Änderung des bestehenden ABI zu vermeiden. In vielen Fällen können Sie Ihren Code umgestalten, um Änderungen zu entfernen, die sich auf die ABI auswirken.

  • Refactoring von Strukturfeldänderungen. Wenn eine Änderung die ABI für eine Debug-Funktion ändert, fügen Sie ein #ifdef um die Felder (in den Strukturen und Quellreferenzen) hinzu und stellen Sie sicher, dass die für das #ifdef verwendete CONFIG für die Produktions-defconfig und gki_defconfig deaktiviert ist. Ein Beispiel dafür, wie einer Struktur eine Debug-Konfiguration hinzugefügt werden kann, ohne die ABI zu beschädigen, finden Sie in diesem Patchset .

  • Refactoring-Funktionen, um den Kernel nicht zu verändern. Wenn zur Unterstützung der Partnermodule neue Funktionen zu ACK hinzugefügt werden müssen, versuchen Sie, den ABI-Teil der Änderung umzugestalten, um eine Änderung der Kernel-ABI zu vermeiden. Ein Beispiel für die Verwendung der vorhandenen Kernel-ABI zum Hinzufügen zusätzlicher Funktionen ohne Änderung der Kernel-ABI finden Sie unter aosp/1312213 .

Beheben Sie einen defekten ABI auf Android Gerrit

Wenn Sie die Kernel-ABI nicht absichtlich beschädigt haben, müssen Sie dies anhand der Anleitung des ABI-Überwachungstools untersuchen. Die häufigsten Fehlerursachen sind geänderte Datenstrukturen und die damit verbundenen Symbol-CRC-Änderungen oder Änderungen der Konfigurationsoptionen, die zu einem der oben genannten Probleme führen. Beheben Sie zunächst die vom Tool gefundenen Probleme.

Sie können die ABI-Ergebnisse lokal reproduzieren, siehe Erstellen des Kernels und seiner ABI-Darstellung .

Über Fussel-1-Etiketten

Wenn Sie Änderungen in einen Zweig hochladen, der ein eingefrorenes oder finalisiertes KMI enthält, müssen die Änderungen den AbiAnalyzer passieren, um sicherzustellen, dass sich die Änderungen nicht auf inkompatible Weise auf das stabile ABI auswirken. Während dieses Prozesses sucht der AbiAnalyzer nach dem ABI-Bericht, der während des Builds erstellt wurde (ein erweiterter Build, der den normalen Build und dann einige ABI-Extraktions- und Vergleichsschritte durchführt).

Wenn der AbiAnalyzer einen nicht leeren Bericht findet, legt er das Lint-1-Label fest und die Änderung wird für die Übermittlung blockiert, bis sie gelöst ist. bis das Patchset ein Lint+1-Label erhält.

Aktualisieren Sie die Kernel-ABI

Wenn eine Änderung des ABI unvermeidlich ist, müssen Sie Ihre Codeänderungen, die ABI-Darstellung und die Symbolliste auf das ACK anwenden. Führen Sie die folgenden Schritte aus, damit Lint die -1 entfernt und die GKI-Kompatibilität nicht beeinträchtigt:

  1. Laden Sie Codeänderungen in das ACK hoch .

  2. Warten Sie, bis Sie ein Code-Review +2 für das Patchset erhalten.

  3. Aktualisieren Sie die Referenz-ABI-Darstellung .

  4. Führen Sie Ihre Codeänderungen und die ABI-Update-Änderung zusammen.

Laden Sie ABI-Codeänderungen in das ACK hoch

Die Aktualisierung der ACK-ABI hängt von der Art der vorgenommenen Änderung ab.

  • Wenn eine ABI-Änderung mit einer Funktion zusammenhängt, die sich auf CTS- oder VTS-Tests auswirkt, kann die Änderung normalerweise so wie sie ist in ACK übernommen werden. Zum Beispiel:

  • Wenn eine ABI-Änderung eine Funktion betrifft, die mit dem ACK geteilt werden kann, kann diese Änderung unverändert an das ACK weitergegeben werden. Beispielsweise sind die folgenden Änderungen für den CTS- oder VTS-Test nicht erforderlich, können aber mit ACK geteilt werden:

  • Wenn eine ABI-Änderung eine neue Funktion einführt, die nicht in die ACK aufgenommen werden muss, können Sie die Symbole mithilfe eines Stubs in die ACK einführen, wie im folgenden Abschnitt beschrieben.

Verwenden Sie Stubs für ACK

Stubs dürfen nur für Kernel-Änderungen erforderlich sein, die dem ACK nicht zugute kommen, wie etwa Leistungs- und Energieänderungen. Die folgende Liste enthält Beispiele für Stubs und partielle Rosinenauswahl in ACK für GKI.

  • Core-Isolate-Feature-Stub ( aosp/1284493 ). Die Funktionalität in ACK ist nicht erforderlich, aber die Symbole müssen in ACK vorhanden sein, damit Ihre Module diese Symbole verwenden können.

  • Platzhaltersymbol für Anbietermodul ( aosp/1288860 ).

  • Nur ABI-Auswahl der mm -Ereignisverfolgungsfunktion pro Prozess ( aosp/1288454 ). Der ursprüngliche Patch wurde auf ACK ausgewählt und dann so gekürzt, dass er nur die notwendigen Änderungen enthielt, um den ABI-Diff für task_struct und mm_event_count aufzulösen. Dieser Patch aktualisiert auch die Enumeration mm_event_type , um die endgültigen Mitglieder zu enthalten.

  • Teilweise Auswahl der ABI-Änderungen der thermischen Struktur, die mehr als nur das Hinzufügen der neuen ABI-Felder erforderten.

    • Patch aosp/1255544 behebt ABI-Unterschiede zwischen dem Partnerkernel und ACK.

    • Patch aosp/1291018 behebt die Funktionsprobleme, die beim GKI-Test des vorherigen Patches festgestellt wurden. Der Fix umfasste die Initialisierung der Sensorparameterstruktur, um mehrere thermische Zonen für einen einzelnen Sensor zu registrieren.

  • CONFIG_NL80211_TESTMODE ABI-Änderungen ( aosp/1344321 ). Dieser Patch fügte die notwendigen Strukturänderungen für ABI hinzu und stellte sicher, dass die zusätzlichen Felder keine funktionalen Unterschiede verursachten, sodass Partner CONFIG_NL80211_TESTMODE in ihre Produktionskerne integrieren und dennoch die GKI-Konformität gewährleisten konnten.

Erzwingen Sie das KMI zur Laufzeit

Die GKI-Kernel verwenden die Konfigurationsoptionen TRIM_UNUSED_KSYMS=y und UNUSED_KSYMS_WHITELIST=<union of all symbol lists> , die die exportierten Symbole (z. B. mit EXPORT_SYMBOL_GPL() exportierte Symbole) auf die in einer Symbolliste aufgeführten Symbole beschränken. Alle anderen Symbole werden nicht exportiert und das Laden eines Moduls, das ein nicht exportiertes Symbol erfordert, wird verweigert. Diese Einschränkung wird zum Zeitpunkt der Erstellung erzwungen und fehlende Einträge werden gekennzeichnet.

Für Entwicklungszwecke können Sie einen GKI-Kernel-Build verwenden, der kein Symbolkürzen beinhaltet (d. h. alle normalerweise exportierten Symbole können verwendet werden). Um diese Builds zu finden, suchen Sie auf ci.android.com nach den kernel_debug_aarch64 Builds.

Erzwingen Sie die KMI mithilfe der Modulversionierung

Die Generic Kernel Image (GKI)-Kernel verwenden die Modulversionierung ( CONFIG_MODVERSIONS ) als zusätzliche Maßnahme, um die KMI-Konformität zur Laufzeit durchzusetzen. Die Modulversionierung kann beim Laden des Moduls zu Fehlern bei der zyklischen Redundanzprüfung (CRC) führen, wenn der erwartete KMI eines Moduls nicht mit dem KMI von vmlinux übereinstimmt. Das Folgende ist beispielsweise ein typischer Fehler, der beim Laden des Moduls aufgrund einer CRC-Nichtübereinstimmung für das Symbol module_layout() auftritt:

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 ''

Verwendungsmöglichkeiten der Modulversionierung

Die Modulversionierung ist aus folgenden Gründen sinnvoll:

  • Die Modulversionierung erfasst Änderungen in der Sichtbarkeit der Datenstruktur. Wenn Module undurchsichtige Datenstrukturen ändern, also Datenstrukturen, die nicht Teil des KMI sind, brechen sie nach zukünftigen Änderungen an der Struktur.

    Betrachten Sie als Beispiel das Feld fwnode in struct device . Dieses Feld MUSS für Module undurchsichtig sein, damit sie keine Änderungen an den Feldern von device->fw_node vornehmen oder Annahmen über dessen Größe treffen können.

    Wenn ein Modul jedoch <linux/fwnode.h> (direkt oder indirekt) enthält, ist das Feld fwnode im struct device für es nicht mehr undurchsichtig. Das Modul kann dann Änderungen an device->fwnode->dev oder device->fwnode->ops vornehmen. Dieses Szenario ist aus mehreren Gründen problematisch:

    • Es kann Annahmen widerlegen, die der Kernel-Code über seine internen Datenstrukturen macht.

    • Wenn ein zukünftiges Kernel-Update die struct fwnode_handle (den Datentyp von fwnode ) ändert, funktioniert das Modul nicht mehr mit dem neuen Kernel. Darüber hinaus zeigt stgdiff keine Unterschiede an, da das Modul den KMI durch direkte Manipulation interner Datenstrukturen auf eine Weise zerstört, die nicht erfasst werden kann, wenn nur die Binärdarstellung untersucht wird.

  • Ein aktuelles Modul gilt als KMI-inkompatibel, wenn es zu einem späteren Zeitpunkt von einem neuen Kernel geladen wird, der inkompatibel ist. Die Modulversionierung fügt eine Laufzeitprüfung hinzu, um zu verhindern, dass versehentlich ein Modul geladen wird, das nicht mit dem Kernel KMI-kompatibel ist. Diese Prüfung verhindert schwer zu debuggende Laufzeitprobleme und Kernel-Abstürze, die auf eine unerkannte Inkompatibilität im KMI zurückzuführen sein könnten.

Durch die Aktivierung der Modulversionierung werden all diese Probleme vermieden.

Suchen Sie nach CRC-Nichtübereinstimmungen, ohne das Gerät zu starten

stgdiff vergleicht und meldet CRC-Nichtübereinstimmungen zwischen Kerneln sowie andere ABI-Unterschiede.

Darüber hinaus generiert ein vollständiger Kernel-Build mit aktiviertem CONFIG_MODVERSIONS eine Module.symvers Datei als Teil des normalen Build-Prozesses. Diese Datei enthält eine Zeile für jedes Symbol, das vom Kernel ( vmlinux ) und den Modulen exportiert wird. Jede Zeile besteht aus dem CRC-Wert, dem Symbolnamen, dem Symbol-Namespace, dem vmlinux oder Modulnamen, der das Symbol exportiert, und dem Exporttyp (z. B. EXPORT_SYMBOL im Vergleich zu EXPORT_SYMBOL_GPL ).

Sie können die Module.symvers Dateien zwischen dem GKI-Build und Ihrem Build vergleichen, um zu prüfen, ob es CRC-Unterschiede in den von vmlinux exportierten Symbolen gibt. Wenn in einem von vmlinux exportierten Symbol ein CRC-Wertunterschied besteht und dieses Symbol von einem der Module verwendet wird, die Sie in Ihr Gerät laden, wird das Modul nicht geladen.

Wenn Sie nicht über alle Build-Artefakte, aber über die vmlinux Dateien des GKI-Kernels und Ihres Kernels verfügen, können Sie die CRC-Werte für ein bestimmtes Symbol vergleichen, indem Sie den folgenden Befehl auf beiden Kerneln ausführen und die Ausgabe vergleichen:

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

Der folgende Befehl überprüft beispielsweise den CRC-Wert für das module_layout -Symbol:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

Beheben Sie CRC-Nichtübereinstimmungen

Führen Sie die folgenden Schritte aus, um eine CRC-Nichtübereinstimmung beim Laden eines Moduls zu beheben:

  1. Erstellen Sie den GKI-Kernel und Ihren Gerätekernel mit der Option --kbuild_symtypes , wie im folgenden Befehl gezeigt:

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

    Dieser Befehl generiert eine .symtypes Datei für jede .o Datei. Weitere Informationen finden Sie unter KBUILD_SYMTYPES in Kleaf .

    Erstellen Sie für Android 13 und niedriger den GKI-Kernel und den Kernel Ihres Geräts, indem Sie KBUILD_SYMTYPES=1 dem Befehl voranstellen, den Sie zum Erstellen des Kernels verwenden, wie im folgenden Befehl gezeigt:

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

    Bei Verwendung von build_abi.sh, ist das Flag KBUILD_SYMTYPES=1 implizit bereits gesetzt.

  2. Suchen Sie mit dem folgenden Befehl nach der .c Datei, in die das Symbol mit der CRC-Nichtübereinstimmung exportiert wurde:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. Die .c Datei verfügt über eine entsprechende .symtypes Datei im GKI und über Build-Artefakte Ihres Gerätekernels. Suchen Sie die .c Datei mit den folgenden Befehlen:

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

    Im Folgenden sind die Merkmale der .c Datei aufgeführt:

    • Das Format der .c Datei ist eine (möglicherweise sehr lange) Zeile pro Symbol.

    • [s|u|e|etc]# am Anfang der Zeile bedeutet, dass das Symbol vom Datentyp [struct|union|enum|etc] ist. Zum Beispiel:

      t#bool typedef _Bool bool
      
    • Ein fehlendes # -Präfix am Zeilenanfang weist darauf hin, dass es sich bei dem Symbol um eine Funktion handelt. Zum Beispiel:

      find_module s#module * find_module ( const char * )
      
  4. Vergleichen Sie die beiden Dateien und beheben Sie alle Unterschiede.

Fall 1: Unterschiede aufgrund der Sichtbarkeit des Datentyps

Wenn ein Kernel ein Symbol oder einen Datentyp für die Module undurchsichtig hält und der andere Kernel dies nicht tut, tritt dieser Unterschied zwischen den .symtypes Dateien der beiden Kernel auf. Die .symtypes Datei von einem der Kernel hat UNKNOWN für ein Symbol und die .symtypes Datei vom anderen Kernel hat eine erweiterte Ansicht des Symbols oder Datentyps.

Wenn Sie beispielsweise die folgende Zeile zur Datei include/linux/device.h in Ihrem Kernel hinzufügen, kommt es zu CRC-Nichtübereinstimmungen, eine davon betrifft module_layout() :

 #include <linux/fwnode.h>

Beim Vergleich der module.symtypes für dieses Symbol werden die folgenden Unterschiede deutlich:

 $ 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 ] ; }
  ...

Wenn Ihr Kernel den Wert UNKNOWN hat und der GKI-Kernel über die erweiterte Ansicht des Symbols verfügt (sehr unwahrscheinlich), dann führen Sie den neuesten Android Common Kernel in Ihren Kernel ein, sodass Sie die neueste GKI-Kernelbasis verwenden.

In den meisten Fällen hat der GKI-Kernel den Wert UNKNOWN , aber Ihr Kernel verfügt aufgrund von an Ihrem Kernel vorgenommenen Änderungen über die internen Details des Symbols. Dies liegt daran, dass eine der Dateien in Ihrem Kernel ein #include hinzugefügt hat, das im GKI-Kernel nicht vorhanden ist.

Oft ist die Lösung so einfach wie das Ausblenden des neuen #include vor genksyms .

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

Andernfalls führen Sie die folgenden Schritte aus, um das #include zu identifizieren, das den Unterschied verursacht:

  1. Öffnen Sie die Header-Datei, die das Symbol oder den Datentyp definiert, der diesen Unterschied aufweist. Bearbeiten Sie beispielsweise include/linux/fwnode.h für die struct fwnode_handle .

  2. Fügen Sie den folgenden Code oben in der Header-Datei hinzu:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. Fügen Sie in der .c Datei des Moduls, das eine CRC-Nichtübereinstimmung aufweist, Folgendes als erste Zeile vor einer der #include Zeilen hinzu.

    #define CRC_CATCH 1
    
  4. Kompilieren Sie Ihr Modul. Der resultierende Build-Zeitfehler zeigt die Kette der Header-Datei #include , die zu dieser CRC-Nichtübereinstimmung geführt hat. Zum Beispiel:

    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"
    

    Eines der Glieder in dieser #include Kette ist auf eine in Ihrem Kernel vorgenommene Änderung zurückzuführen, die im GKI-Kernel fehlt.

  5. Identifizieren Sie die Änderung, setzen Sie sie in Ihrem Kernel zurück oder laden Sie sie in ACK hoch und führen Sie sie zusammen .

Fall 2: Unterschiede aufgrund von Datentypänderungen

Wenn die CRC-Nichtübereinstimmung für ein Symbol oder einen Datentyp nicht auf einen Unterschied in der Sichtbarkeit zurückzuführen ist, liegt sie an tatsächlichen Änderungen (Hinzufügungen, Entfernungen oder Änderungen) am Datentyp selbst.

Wenn Sie beispielsweise die folgende Änderung in Ihrem Kernel vornehmen, kommt es zu mehreren CRC-Nichtübereinstimmungen, da viele Symbole indirekt von dieser Art von Änderung betroffen sind:

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);

Eine CRC-Nichtübereinstimmung betrifft devm_of_platform_populate() .

Wenn Sie die .symtypes Dateien für dieses Symbol vergleichen, könnte es so aussehen:

 $ 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 * ) ; ...

Um den geänderten Typ zu identifizieren, führen Sie die folgenden Schritte aus:

  1. Suchen Sie die Definition des Symbols im Quellcode (normalerweise in .h Dateien).

    • Für einfache Symbolunterschiede zwischen Ihrem Kernel und dem GKI-Kernel suchen Sie den Commit, indem Sie den folgenden Befehl ausführen:
    git blame
    
    • Bei gelöschten Symbolen (bei denen ein Symbol in einem Baum gelöscht wird und Sie es auch im anderen Baum löschen möchten) müssen Sie die Änderung finden, die die Linie gelöscht hat. Verwenden Sie den folgenden Befehl für den Baum, in dem die Zeile gelöscht wurde:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. Überprüfen Sie die zurückgegebene Liste der Commits, um die Änderung oder Löschung zu finden. Das erste Commit ist wahrscheinlich das, nach dem Sie suchen. Ist dies nicht der Fall, gehen Sie die Liste durch, bis Sie den Commit gefunden haben.

  3. Nachdem Sie die Änderung identifiziert haben, setzen Sie sie entweder in Ihrem Kernel zurück oder laden Sie sie in ACK hoch und führen Sie sie zusammen .