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-Kernels zu stabilisieren. Das Tool sammelt und vergleicht ABI-Darstellungen aus bestehenden Kernel-Binärdateien ( vmlinux
+ Module). Diese ABI-Darstellungen sind die .xml
Dateien und die Symbollisten. Die Schnittstelle, auf die die Darstellung eine Ansicht gibt, wird Kernel Module Interfaces (KMIs) genannt. Sie können die Tools verwenden, um Änderungen am KMI nachzuverfolgen und abzumildern.
Das ABI-Überwachungstool wurde in AOSP entwickelt und verwendet libabigail
zum Generieren und Vergleichen von Darstellungen.
Diese Seite beschreibt die Tools, den Prozess des Sammelns und Analysierens von ABI-Repräsentationen und die Verwendung solcher Repräsentationen, um der Kernel-ABI Stabilität zu verleihen. Diese Seite enthält auch Informationen zum Beitragen von Änderungen an den Android-Kernels.
Dieses Verzeichnis enthält die spezifischen Tools für die ABI-Analyse. Verwenden Sie es mit den von build_abi.sh
bereitgestellten Build-Skripten.)
Verfahren
Die Analyse des ABI des Kernels erfordert mehrere Schritte, von denen die meisten automatisiert werden können:
- Erwerben Sie die Toolchain, erstellen Sie Skripte und Kernelquellen über
repo
. - Stellen Sie alle Voraussetzungen bereit (z. B. die
libabigail
Bibliothek und die Sammlung von Tools). - Erstellen Sie den Kernel und seine ABI-Darstellung .
- Analysieren Sie ABI-Unterschiede zwischen dem Build und einer Referenz .
- Aktualisieren Sie die ABI-Darstellung (falls erforderlich) .
- Mit Symbollisten arbeiten .
Die folgenden Anweisungen funktionieren für jeden Kernel, den Sie mit einer unterstützten Toolchain (z. B. der vorgefertigten Clang-Toolchain) erstellen können . repo manifests
sind für alle gängigen Android-Kernel-Zweige und für mehrere gerätespezifische Kernel verfügbar und stellen sicher, dass die richtige Toolchain verwendet wird, wenn Sie eine Kernel-Distribution für die Analyse erstellen.
Verwenden Sie die ABI-Überwachungstools
1. Erwerben Sie die Toolchain, erstellen Sie Skripte und Kernelquellen über das Repo
Sie können die Toolchain erwerben, Skripte (diese Skripte), vorgefertigte Binärdateien und Kernelquellen mit repo
. Eine ausführliche Dokumentation finden Sie in den entsprechenden Informationen zum Erstellen von Android-Kernels .
Um den Prozess zu veranschaulichen, verwenden die folgenden Schritte common-android12-5.10
, einen Android-Kernel-Zweig, der zum Zeitpunkt der Erstellung dieses Artikels der neueste veröffentlichte GKI-Kernel ist. Führen Sie Folgendes aus, um diesen Zweig über repo
zu erhalten:
repo init -u https://android.googlesource.com/kernel/manifest -b common-android12-5.10
repo sync
2. Erstellen Sie den Kernel und seine ABI-Darstellung
An diesem Punkt sind Sie bereit, einen Kernel mit der richtigen Toolchain zu bauen und eine ABI-Darstellung aus seinen Binärdateien ( vmlinux
+ module) zu extrahieren.
Ähnlich wie beim üblichen Android-Kernel-Erstellungsprozess (mit build.sh
) erfordert dieser Schritt die Ausführung von build_abi.sh
.
BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh
Dadurch wird der Kernel erstellt und die ABI-Darstellung in das Unterverzeichnis out_abi
. In diesem Fall ist out/android12-5.10/dist/abi.xml
ein symbolischer Link zu out_abi/android12-5.10/dist/abi-<id>.xml
. < id>
wird berechnet, indem git describe
für den Kernel-Quellbaum ausgeführt wird.
Für Android 13-Zweige und höher ist Bazel im Kernel-Build aktiviert. Das Bazel-Äquivalent des obigen Befehls lautet:
tools/bazel run //common:kernel_aarch64_abi_dist
Weitere Informationen finden Sie unter Unterstützung der ABI-Überwachung mit Bazel (GKI) und Unterstützung der ABI-Überwachung mit Bazel (Gerätekernel) .
3. Analysieren Sie die ABI-Unterschiede zwischen dem Build und einer Referenzdarstellung
build_abi.sh
analysiert und meldet alle ABI-Unterschiede, wenn eine Referenz über die Umgebungsvariable ABI_DEFINITION
wird. ABI_DEFINITION
muss auf eine Referenzdatei relativ zum Kernel-Quellbaum zeigen und kann auf der Befehlszeile oder häufiger als Wert in build.config angegeben werden . Im Folgenden finden Sie ein Beispiel:
BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh
Im obigen Befehl definiert build.config.gki.aarch64
die Referenzdatei (als ABI_DEFINITION=android/abi_gki_aarch64.xml
) und diff_abi
ruft abidiff
auf, um die frisch generierte ABI-Darstellung mit der Referenzdatei zu vergleichen. build_abi.sh
den Speicherort des Berichts aus und gibt einen kurzen Bericht für jeden ABI-Bruch aus. Wenn Brüche erkannt werden, wird build_abi.sh
beendet und gibt einen Exit-Code ungleich Null zurück.
Für Android 13-Zweige und höher ist Bazel im Kernel-Build aktiviert. Das Bazel-Äquivalent des obigen Befehls lautet:
tools/bazel run //common:kernel_aarch64_abi_dist
Weitere Informationen finden Sie unter Unterstützung der ABI-Überwachung mit Bazel (GKI) und Unterstützung der ABI-Überwachung mit Bazel (Gerätekernel) .
4. Aktualisieren Sie die ABI-Darstellung (falls erforderlich)
Um die ABI-Darstellung zu aktualisieren, rufen build_abi.sh
mit dem Flag --update
auf. Es aktualisiert die entsprechende abi.xml
-Datei, die durch build.config
definiert ist. Um die ABI-Unterschiede aufgrund des Updates auszudrucken, rufen Sie das Skript mit --print-report
auf. Stellen Sie sicher, dass Sie den Bericht in die Commit-Nachricht aufnehmen, wenn Sie die Datei abi.xml
aktualisieren.
Für Android 13-Zweige und höher ist Bazel im Kernel-Build aktiviert. Der Bazel-Befehl zum Aktualisieren der ABI-Darstellung für GKI lautet:
tools/bazel run //common:kernel_aarch64_abi_update_symbol_list &&
tools/bazel run //common:kernel_aarch64_abi_update
Weitere Informationen finden Sie unter Unterstützung der ABI-Überwachung mit Bazel (GKI) und Unterstützung der ABI-Überwachung mit Bazel (Gerätekernel) .
5. Arbeiten Sie mit Symbollisten
Parametrieren build_abi.sh
mit KMI-Symbollisten, um Symbole während der ABI-Extraktion zu filtern. Dies sind einfache Textdateien, die relevante ABI-Kernel-Symbole auflisten. Beispielsweise beschränkt eine Symbollistendatei mit folgendem Inhalt die ABI-Analyse auf die ELF-Symbole mit den Namen symbol1
und symbol2
:
[abi_symbol_list]
symbol1
symbol2
Änderungen an anderen ELF-Symbolen werden nicht berücksichtigt. Eine Symbollistendatei kann in der entsprechenden Konfigurationsdatei build.config
mit KMI_SYMBOL_LIST=
als Datei relativ zum Kernel-Quellverzeichnis ( $KERNEL_DIR
) angegeben werden. Um eine Organisationsebene bereitzustellen, können Sie zusätzliche Symbollistendateien angeben, indem Sie ADDITIONAL_KMI_SYMBOL_LISTS=
in der Datei build.config
verwenden. Dies spezifiziert weitere Symbollistendateien, relativ zu $KERNEL_DIR
; Trennen Sie mehrere Dateinamen durch Leerzeichen.
Um eine anfängliche Symbolliste zu erstellen oder eine vorhandene zu aktualisieren , müssen Sie das Skript build_abi.sh
mit dem Parameter --update-symbol-list
verwenden.
Wenn das Skript mit einer geeigneten Konfiguration ausgeführt wird, erstellt es den Kernel und extrahiert die Symbole, die aus vmlinux
und GKI-Modulen exportiert werden und die von jedem anderen Modul im Baum benötigt werden.
Ziehen Sie in Betracht, vmlinux
die folgenden Symbole zu exportieren (normalerweise über die Makros EXPORT_SYMBOL*
):
func1
func2
func3
Stellen Sie sich außerdem vor, es gäbe zwei Anbietermodule, modA.ko
und modB.ko
, die die folgenden Symbole erfordern (mit anderen Worten, sie listen undefined
Symboleinträge in ihrer Symboltabelle auf):
modA.ko: func1 func2
modB.ko: func2
Aus Sicht der ABI-Stabilität müssen func1
und func2
stabil gehalten werden, da sie von einem externen Modul verwendet werden. Im Gegenteil, während func3
exportiert wird, wird es von keinem Modul aktiv verwendet (mit anderen Worten, es wird nicht benötigt). Daher enthält die Symbolliste nur func1
und func2
.
Um eine bestehende Symbolliste zu erstellen oder zu aktualisieren, muss build_abi.sh
wie folgt ausgeführt werden:
BUILD_CONFIG=path/to/build.config.device build/build_abi.sh --update-symbol-list
In diesem Beispiel muss build.config.device
mehrere Konfigurationsoptionen enthalten:
-
vmlinux
muss sich in derFILES
-Liste befinden. -
KMI_SYMBOL_LIST
muss gesetzt sein und auf die zu aktualisierende KMI-Symbolliste zeigen. -
GKI_MODULES_LIST
muss gesetzt sein und auf die Liste der GKI-Module zeigen. Dieser Pfad ist normalerweiseandroid/gki_aarch64_modules
.
Arbeiten Sie mit den untergeordneten ABI-Werkzeugen
Die meisten Benutzer müssen nur build_abi.sh
verwenden. In einigen Fällen kann es erforderlich sein, direkt mit den untergeordneten ABI-Tools zu arbeiten. Die beiden von build_abi.sh
verwendeten Befehle dump_abi
und diff_abi
stehen zum Extrahieren und Vergleichen von ABI-Dateien zur Verfügung. Siehe die folgenden Abschnitte für ihre Verwendung.
Erstellen Sie ABI-Darstellungen aus Kernel-Bäumen
Ausgehend von einem Linux-Kernel-Baum mit eingebauten vmlinux
und Kernel-Modulen erstellt das Tool dump_abi
eine ABI-Darstellung unter Verwendung des ausgewählten ABI-Tools. Ein Beispielaufruf sieht so aus:
dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml
Die Datei abi.xml
enthält eine Text-ABI-Darstellung der kombinierten, beobachtbaren ABI von vmlinux
und den Kernel-Modulen im angegebenen Verzeichnis. Diese Datei kann zur manuellen Überprüfung, weiteren Analyse oder als Referenzdatei zur Durchsetzung der ABI-Stabilität verwendet werden.
Vergleichen Sie ABI-Darstellungen
Von dump_abi
erstellte ABI-Darstellungen können mit diff_abi
verglichen werden. Verwenden Sie dasselbe abi-tool für dump_abi
und diff_abi
. Ein Beispielaufruf sieht so aus:
diff_abi --baseline abi1.xml --new abi2.xml --report report.out
Der generierte Bericht listet erkannte ABI-Änderungen auf, die sich auf das KMI auswirken. Die als baseline
und new
angegebenen Dateien sind ABI-Repräsentationen, die mit dump_abi
gesammelt wurden. diff_abi
den Exit-Code des zugrunde liegenden Tools weiter und gibt daher einen Wert ungleich Null zurück, wenn die verglichenen ABIs inkompatibel sind.
Filtern Sie KMI-Darstellungen und -Symbole
Um mit dump_abi
erstellte Repräsentationen zu filtern oder Symbole im Vergleich zu diff_abi
zu filtern, verwenden Sie den Parameter --kmi-symbol-list
, der einen Pfad zu einer KMI-Symbollistendatei annimmt:
dump_abi --linux-tree path/to/out --out-file /path/to/abi.xml --kmi-symbol-list /path/to/symbol_list_file
Arbeiten mit Symbollisten
Das KMI enthält nicht alle Symbole im Kernel oder sogar alle der über 30.000 exportierten Symbole. Stattdessen werden die Symbole, die von Modulen verwendet werden können, explizit in einem Satz 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 beispielhafte 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 nicht aus der Symbolliste entfernt oder geändert werden, nachdem der Zweig eingefroren wurde.
Jeder KMI-Kernel-Zweig des Android Common Kernel (ACK) hat seinen eigenen Satz von Symbollisten. Es wird kein Versuch unternommen, ABI-Stabilität zwischen verschiedenen KMI-Kernelzweigen bereitzustellen. Beispielsweise ist die KMI für android12-5.10
völlig unabhängig von der 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, ABI-kompatibel bleiben. Eine Liste mit 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, von denen berichtet wird, dass sie für den jeweiligen Anbieter oder das Gerät benötigt werden. Die vollständige Liste, die von den Tools verwendet wird, 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. Anbietern steht es jedoch frei, dem KMI jederzeit Symbole hinzuzufügen, solange Ergänzungen die Stabilität des bestehenden ABI nicht beeinträchtigen. Neu hinzugefügte Symbole werden stabil gehalten, 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 kein Gerät jemals mit einer Abhängigkeit von diesem Symbol ausgeliefert wurde.
Sie können eine KMI-Symbolliste für ein Gerät mit dem Dienstprogramm build/abi/extract_symbols
, das die Symbolabhängigkeiten aus den *.ko
extrahiert. Dieses Dienstprogramm fügt der Ausgabe Anmerkungen in Form von Kommentaren hinzu, die beim Identifizieren von Benutzern eines Symbols hilfreich sind. Wenn Sie die Symbolliste an ACK senden, wird dringend empfohlen, diese Kommentare beizubehalten, um den Überprüfungsprozess zu vereinfachen. Um Kommentare wegzulassen, übergeben Sie die Option --skip-module-grouping
grouping beim Ausführen des Skripts extract_symbols
. Viele Partner reichen eine Symbolliste pro ACK ein, aber das ist keine zwingende Voraussetzung. Wenn es bei der Wartung hilft, können Sie mehrere Symbollisten einreichen.
Hilfe zum Anpassen von Symbollisten und Verwenden von High- und Low-Level-ABI-Tools zum Debuggen und für detaillierte Analysen finden Sie unter ABI-Überwachung für Android-Kernel .
Erweitern Sie das KMI
Während KMI-Symbole und verwandte Strukturen stabil bleiben (d. h. Änderungen, die stabile Schnittstellen in einem Kernel mit eingefrorenem KMI unterbrechen, können nicht akzeptiert werden), bleibt der GKI-Kernel offen für Erweiterungen, sodass Geräte, die später im Jahr ausgeliefert werden, dies nicht tun müssen Definieren Sie alle 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, selbst wenn das KMI eingefroren ist. Neue Kernel-Patches werden auch akzeptiert, wenn sie das KMI nicht beschädigen.
Über KMI-Brüche
Ein Kernel hat Quellen und eine Binärdatei wird basierend auf diesen Quellen erstellt. ABI-überwachte Kernel-Zweige enthalten abi.xml
, das eine Darstellung der aktuellen GKI-ABI ist. Nachdem die Binärdatei erstellt wurde (die Kernel-Binärdatei, vmlinux
, Image
plus Kernelmodule), kann eine abi.xml
-Datei aus den Binärdateien extrahiert werden. Jede an einer Kernelquelle vorgenommene Änderung kann die Binärdatei und möglicherweise auch die extrahierte abi.xml
(die Datei, die nach dem Anwenden der Änderung und dem Erstellen des Kernels extrahiert wird). Der AbiAnalyzer
Analyzer vergleicht die beiden abi.xml
-Dateien semantisch und setzt ein Lint-1-Label auf die Änderung, wenn er ein Problem findet.
Behandeln Sie ABI-Brüche
Als Beispiel führt der folgende Patch einen sehr offensichtlichen ABI-Fehler ein:
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 5ed8f6292a53..f2ecb34c7645 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -339,6 +339,7 @@ struct core_state {
struct kioctx_table;
struct mm_struct {
struct {
+ int dummy;
struct vm_area_struct *mmap; /* list of VMAs */
struct rb_root mm_rb;
u64 vmacache_seqnum; /* per-thread vmacache */
Wenn Sie build_abi.sh
mit diesem angewendeten Patch erneut ausführen, wird das Tool mit einem Fehlercode ungleich Null beendet und meldet einen ABI-Unterschied ähnlich dem folgenden:
Leaf changes summary: 1 artifact changed
Changed leaf types summary: 1 leaf type changed
Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
'struct mm_struct at mm_types.h:372:1' changed:
type size changed from 6848 to 6912 (in bits)
there are data member changes:
[...]
ABI-Unterschiede zur Build-Zeit erkannt
Die häufigste Ursache für Fehler ist, wenn 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 zuerst überprüfen, ob es mit EXPORT_SYMBOL_GPL( symbol_name )
exportiert wurde, und dann die ABI-XML-Darstellung und Symbolliste aktualisieren. Beispielsweise fügen die folgenden Änderungen die neue Funktion Incremental FS zum android-12-5.10
Zweig hinzu, die das Aktualisieren der Symbolliste und der ABI-XML-Darstellung umfasst.
- Ein Beispiel für Funktionsänderungen finden Sie in aosp/1345659 .
- Ein Beispiel für eine Symbolliste befindet sich in aosp/1346742 .
- Das Beispiel für die ABI-XML-Änderung befindet sich in aosp/1349377 .
Wenn das Symbol exportiert wird (entweder von Ihnen oder es wurde zuvor exportiert), es aber derzeit von keinem anderen Treiber verwendet wird, 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 lösen, aktualisieren Sie die KMI-Symbolliste sowohl in Ihrem Kernel als auch in der 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-Brüche
Sie können Kernel - ABI - Brüche handhaben , indem Sie den Code so umgestalten , dass er die ABI nicht ändert , oder indem Sie die ABI - Darstellung aktualisieren . Verwenden Sie das folgende Diagramm, um den besten Ansatz für Ihre Situation zu ermitteln.
Abbildung 1. Auflösung des ABI-Bruchs
Code umgestalten, um ABI-Änderungen zu vermeiden
Bemühen Sie sich, die bestehende ABI nicht zu modifizieren. 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 modifiziert, fügen Sie ein
#ifdef
um die Felder (in den Strukturen und Quellverweisen) hinzu und stellen Sie sicher, dass die fürCONFIG
verwendete#ifdef
für die Produktions-defconfig undgki_defconfig
ist. Ein Beispiel dafür, wie eine Debug-Konfiguration zu einer Struktur hinzugefügt werden kann, ohne die ABI zu beschädigen, finden Sie in diesem Patchset .Refactoring-Funktionen, um den Kernel nicht zu ändern. Wenn neue Funktionen zu ACK hinzugefügt werden müssen, um die Partnermodule zu unterstützen, 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 Ursachen für Brüche sind hinzugefügte oder gelöschte Funktionen, geänderte Datenstrukturen oder Änderungen an der ABI, die durch Hinzufügen von Konfigurationsoptionen verursacht werden, die zu einem der oben genannten führen. Beginnen Sie damit, die vom Tool gefundenen Probleme zu beheben.
Sie können den ABI-Test lokal reproduzieren, indem Sie den folgenden Befehl mit denselben Argumenten ausführen, die Sie zum Ausführen von build/build.sh
verwendet hätten:
Dies ist ein Beispielbefehl für die GKI-Kernel:
BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh
Über Lint-1-Etiketten
Wenn Sie Änderungen in einen Zweig hochladen, der ein eingefrorenes oder abgeschlossenes KMI enthält, müssen die Änderungen den ABIAnalyzer
passieren, um sicherzustellen, dass Änderungen die stabile ABI nicht inkompatibel beeinflussen. Während dieses Vorgangs 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, setzt er das Lint-1-Label und die Änderung wird für die Übermittlung blockiert, bis sie behoben ist, bis das Patchset ein Lint+1-Label erhält.
Aktualisieren Sie die Kernel-ABI
Wenn Sie die Kernel-ABI-Darstellung aktualisieren müssen, müssen Sie die entsprechende abi.xml
-Datei im Kernel-Quellbaum aktualisieren. Der bequemste Weg, dies zu tun, ist die Verwendung von build/build_abi.sh
wie folgt:
build/build_abi.sh --update --print-report
Verwenden Sie dieselben Argumente, die Sie zum Ausführen von build/build.sh
verwendet hätten. Dadurch wird die korrekte abi.xml
im Quellbaum aktualisiert und die erkannten Unterschiede gedruckt. Als Übungssache fügen Sie den gedruckten (kurzen) Bericht (zumindest teilweise) in die Commit-Nachricht ein.
Aktualisieren Sie die ABI-Darstellung
Wenn eine Änderung der ABI unvermeidlich ist, ändert sich Ihr Code und die ABI-XML und die Symbolliste müssen auf die ACK angewendet werden. Führen Sie die folgenden Schritte aus, um Lint dazu zu bringen, die -1 zu entfernen und die GKI-Kompatibilität nicht zu beeinträchtigen:
Führen Sie Ihre Codeänderungen und die Änderung des ABI-Updates zusammen.
Laden Sie ABI-Codeänderungen in die ACK hoch
Das Aktualisieren 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 unverändert in ACK aufgenommen werden. Zum Beispiel:
- aosp/1289677 wird benötigt, damit Audio funktioniert.
- aosp/1295945 wird benötigt, damit USB funktioniert.
Wenn eine ABI-Änderung für eine Funktion gilt, die mit dem ACK geteilt werden kann, kann diese Änderung unverändert in ACK aufgenommen werden. Beispielsweise sind die folgenden Änderungen für den CTS- oder VTS-Test nicht erforderlich, können aber mit ACK geteilt werden:
- aosp/1250412 ist eine thermische Funktionsänderung.
- aosp/1288857 ist eine
EXPORT_SYMBOL_GPL
-Änderung.
Wenn eine ABI-Änderung eine neue Funktion einführt, die nicht in die ACK aufgenommen werden muss, können Sie die Symbole in die ACK einführen, indem Sie einen Stub verwenden, wie im folgenden Abschnitt beschrieben.
Verwenden Sie Stubs für ACK
Stubs müssen nur für Core-Kernel-Änderungen erforderlich sein, die dem ACK nicht zugute kommen, wie z. B. Leistungs- und Energieänderungen. Die folgende Liste enthält Beispiele für Stubs und partielle Rosinenpicks 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 Herstellermodul ( aosp/1288860 ).
ABI-only Cherry-Pick der Pro-Prozess-
mm
-Ereignisverfolgungsfunktion ( aosp/1288454 ). Der ursprüngliche Patch wurde zu ACK herausgepickt und dann so getrimmt, dass er nur die notwendigen Änderungen enthält, um den ABI-Diff fürtask_struct
undmm_event_count
. Dieser Patch aktualisiert auch die Aufzählungmm_event_type
, sodass sie die endgültigen Mitglieder enthält.Teilweise Rosinenpickerei von thermischen Struktur-ABI-Änderungen, die mehr als nur das Hinzufügen der neuen ABI-Felder erforderten.
Patch aosp/1255544 hat ABI-Unterschiede zwischen dem Partner-Kernel und ACK behoben.
Patch aosp/1291018 behebt die funktionalen Probleme, die beim GKI-Testen 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 PartnerCONFIG_NL80211_TESTMODE
in ihre Produktionskernel aufnehmen und dennoch die GKI-Konformität aufrechterhalten konnten.
Aktualisieren Sie die ACK-ABI-Dateien
So aktualisieren Sie die ACK ABI-Dateien:
Laden Sie die ABI-Änderungen hoch und warten Sie, bis Sie einen Code-Review +2 für das Patchset erhalten.
Aktualisieren Sie die ACK ABI-Dateien.
cp partner kernel/android/abi_gki_aarch64_partner ACK kernel/abi_gki_aarch64_partner
BUILD_CONFIG=common/build.config.gki.aarch64 build/build_abi.sh --update
# Or, with Bazel,
tools/bazel run //common:kernel_aarch64_abi_update_symbol_list && tools/bazel run //common:kernel_aarch64_abi_update
Übertragen Sie das ABI-Update:
cd common
git add android/abi*
git commit -s -F $DIST_DIR/abi.report.short
<push to gerrit>
$DIST_DIR/abi.report.short
enthält einen kurzen Bericht über die Änderungen. Die Verwendung des Flags-F
mitgit commit
verwendet automatisch den Bericht für den Commit-Text, den Sie dann bearbeiten können, um eine Betreffzeile hinzuzufügen (oder zu kürzen, wenn die Nachricht zu lang ist).
Android Kernel Branches mit vordefiniertem ABI
Einige Kernel-Zweige enthalten vordefinierte ABI-Darstellungen für Android als Teil ihrer Quelldistribution. Diese ABI-Darstellungen sollen genau sein und das Ergebnis von build_abi.sh
als ob Sie es selbst ausführen würden. Da die ABI stark von verschiedenen Kernel-Konfigurationsoptionen beeinflusst wird, gehören diese .xml
-Dateien normalerweise zu einer bestimmten Konfiguration. Beispielsweise enthält der Zweig common-android12-5.10
eine abi_gki_aarch64.xml
, die dem Build-Ergebnis entspricht, wenn build.config.gki.aarch64
. Insbesondere build.config.gki.aarch64
verweist auch auf diese Datei durch ABI_DEFINITION
.
Solche vordefinierten ABI-Darstellungen werden beim Vergleich mit diff_abi
als Basisdefinition verwendet. Um beispielsweise einen Kernel-Patch in Bezug auf Änderungen an der ABI zu validieren, erstellen Sie die ABI-Darstellung mit dem angewendeten Patch und verwenden diff_abi
, um sie mit der erwarteten ABI für diesen bestimmten Quellbaum oder diese bestimmte Konfiguration zu vergleichen. Wenn ABI_DEFINITION
gesetzt ist, reicht es aus, build_abi.sh
entsprechend auszuführen.
KMI zur Laufzeit erzwingen
Die GKI-Kernel verwenden die 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 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 zur Erstellungszeit erzwungen und fehlende Einträge werden gekennzeichnet.
Für Entwicklungszwecke können Sie einen GKI-Kernel-Build verwenden, der kein Symbolkürzen enthält (dh alle normalerweise exportierten Symbole können verwendet werden). Um diese Builds zu finden, suchen Sie auf kernel_debug_aarch64
nach den Builds kernel_debug_aarch64 .
Erzwingen Sie die KMI mithilfe der Modulversionsverwaltung
Die GKI-Kernel (Generic Kernel Image) 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 CRC-Fehlern (Cyclic Redundancy Check) führen, wenn die erwartete KMI eines Moduls nicht mit der vmlinux
KMI übereinstimmt. Das Folgende ist beispielsweise ein typischer Fehler, der beim Laden des Moduls aufgrund einer CRC-Nichtübereinstimmung für das Symbol 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 ''
Verwendung der Modulversionierung
Die Modulversionierung ist aus folgenden Gründen nützlich:
Die Modulversionierung erfasst Änderungen in der Sichtbarkeit der Datenstruktur. Wenn Module undurchsichtige Datenstrukturen ändern, d. h. Datenstrukturen, die nicht Teil des KMI sind, brechen sie nach zukünftigen Änderungen an der Struktur.
Betrachten Sie als Beispiel das Feld
fwnode
instruct device
. Dieses Feld MUSS für Module undurchsichtig sein, damit sie keine Änderungen an den Feldern vondevice->fw_node
oder Annahmen über seine Größe treffen können.Wenn ein Modul jedoch
<linux/fwnode.h>
(direkt oder indirekt) enthält, dann ist dasfwnode
-Feld in derstruct device
für es nicht mehr undurchsichtig. Das Modul kann dann Änderungen andevice->fwnode->dev
oderdevice->fwnode->ops
. Dieses Szenario ist aus mehreren Gründen problematisch, die wie folgt angegeben werden:Es kann Annahmen brechen, die der Core-Kernel-Code über seine internen Datenstrukturen macht.
Wenn ein zukünftiges Kernel-Update die
struct fwnode_handle
(den Datentyp vonfwnode
) ändert, funktioniert das Modul nicht mehr mit dem neuen Kernel. Darüber hinaus zeigtabidiff
keine Unterschiede, da das Modul das KMI bricht, indem es interne Datenstrukturen direkt auf eine Weise manipuliert, die nicht erfasst werden kann, indem nur die binäre Darstellung untersucht wird.
Ein aktuelles Modul gilt als KMI-inkompatibel, wenn es zu einem späteren Zeitpunkt von einem neuen Kernel geladen wird, der nicht kompatibel ist. Die Modulversionierung fügt eine Laufzeitprüfung hinzu, um zu vermeiden, dass versehentlich ein Modul geladen wird, das nicht KMI-kompatibel mit dem Kernel ist. Diese Prüfung verhindert schwer zu debuggende Laufzeitprobleme und Kernel-Abstürze, die aus einer unentdeckten Inkompatibilität im KMI resultieren könnten.
abidiff
hat Einschränkungen beim Identifizieren von ABI-Unterschieden in bestimmten komplizierten Fällen, dieCONFIG_MODVERSIONS
abfangen können.
Die Aktivierung der Modulversionierung verhindert all diese Probleme.
Suchen Sie nach CRC-Nichtübereinstimmungen, ohne das Gerät zu booten
abidiff
vergleicht und meldet CRC-Nichtübereinstimmungen zwischen Kerneln. Mit diesem Tool können Sie nicht übereinstimmende CRCs gleichzeitig mit anderen ABI-Unterschieden erkennen.
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 hat 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
versus EXPORT_SYMBOL_GPL
).
Sie können die Module.symvers
Dateien zwischen dem GKI-Build und Ihrem Build vergleichen, um nach CRC-Unterschieden in den von vmlinux
exportierten Symbolen zu suchen. 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 alle Build-Artefakte, aber die vmlinux
Dateien des GKI-Kernels und Ihres Kernels haben, 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 prüft beispielsweise den CRC-Wert für das Symbol module_layout
:
nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout
Beheben Sie CRC-Nichtübereinstimmungen
Verwenden Sie die folgenden Schritte, um eine CRC-Nichtübereinstimmung beim Laden eines Moduls zu beheben:
Erstellen Sie den GKI-Kernel und Ihren Gerätekern, 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
Dieser Befehl generiert eine
.symtypes
-Datei für jede.o
-Datei. Bei Verwendung vonbuild_abi.sh,
dasKBUILD_SYMTYPES=1
implizit bereits gesetzt.Für Android 13-Zweige und höher ist Bazel im Kernel-Build aktiviert. Das Bazel-Äquivalent des obigen Befehls lautet:
tools/bazel run --kbuild_symtypes //common:kernel_aarch64_dist
Siehe
KBUILD_SYMTYPES
in Kleaf für Details.Suchen Sie mit dem folgenden Befehl die
.c
-Datei, in die das Symbol mit CRC-Nichtübereinstimmung exportiert wurde:cd common && git grep EXPORT_SYMBOL.*module_layout kernel/module.c:EXPORT_SYMBOL(module_layout);
Die
.c
-Datei hat eine entsprechende.symtypes
-Datei in der GKI und Ihre Geräte-Kernel-Build-Artefakte. 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 Anfang der Zeile zeigt an, dass das Symbol eine Funktion ist. Zum Beispiel:find_module s#module * find_module ( const char * )
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 nicht, erscheint dieser Unterschied zwischen den .symtypes
Dateien der beiden Kernel. Die .symtypes
-Datei von einem der Kernel hat UNKNOWN
für ein Symbol und die .symtypes
-Datei von dem anderen Kernel hat eine erweiterte Ansicht des Symbols oder Datentyps.
Beispielsweise führt das Hinzufügen der folgenden Zeile zur Datei include/linux/device.h
in Ihrem Kernel zu CRC-Nichtübereinstimmungen, von denen eine für module_layout()
gilt:
#include <linux/fwnode.h>
Beim Vergleich der module.symtypes
für dieses Symbol werden die folgenden Unterschiede sichtbar:
$ 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 die erweiterte Ansicht des Symbols hat (sehr unwahrscheinlich), 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 hat die internen Details des Symbols aufgrund von Änderungen, die an Ihrem Kernel vorgenommen wurden. Dies liegt daran, dass eine der Dateien in Ihrem Kernel ein #include
hinzugefügt hat, das im GKI-Kernel nicht vorhanden ist.
Führen Sie die folgenden Schritte aus, um das #include
zu identifizieren, das den Unterschied verursacht:
Öffnen Sie die Header-Datei, die das Symbol oder den Datentyp mit diesem Unterschied definiert. Bearbeiten Sie beispielsweise
include/linux/fwnode.h
für diestruct fwnode_handle
.Fügen Sie den folgenden Code oben in der Header-Datei hinzu:
#ifdef CRC_CATCH #error "Included from here" #endif
Fügen Sie in der
.c
-Datei des Moduls, die eine CRC-Nichtübereinstimmung aufweist, Folgendes als erste Zeile vor einer der#include
-Zeilen hinzu.#define CRC_CATCH 1
Kompilieren Sie Ihr Modul. Der resultierende Build-Time-Fehler 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 Änderung in Ihrem Kernel zurückzuführen, die im GKI-Kernel fehlt.Identifizieren Sie die Änderung, setzen Sie sie in Ihrem Kernel zurück oder laden Sie sie in ACK hoch und lassen Sie sie zusammenführen .
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, dann auf tatsächliche Änderungen (Hinzufügungen, Entfernungen oder Änderungen) im Datentyp selbst. Normalerweise fängt abidiff
dies ab, aber wenn es aufgrund bekannter Erkennungslücken irgendwelche übersieht, kann der MODVERSIONS
Mechanismus sie abfangen.
Wenn Sie beispielsweise die folgende Änderung in Ihrem Kernel vornehmen, führt dies 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 gilt für 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 * ) ; ...
Gehen Sie folgendermaßen vor, um den geänderten Typ zu identifizieren:
Suchen Sie die Definition des Symbols im Quellcode (normalerweise in
.h
Dateien).- Bei einfachen Symbolunterschieden zwischen Ihrem Kernel und dem GKI-Kernel finden Sie den Commit, indem Sie den folgenden Befehl ausführen:
git blame
- For deleted symbols (where a symbol is deleted in a tree and you also want to delete it in the other tree), you need to find the change that deleted the line. Use the following command on the tree where the line was deleted:
git log -S "copy paste of deleted line/word" -- <file where it was deleted>
Review the returned list of commits to locate the change or deletion. The first commit is probably the one you are searching for. If it isn't, go through the list until you find the commit.
After you identify the change, either revert it in your kernel or upload it to ACK and get it merged .