Monitorowanie interfejsu ABI jądra Androida

Możesz użyć narzędzi do monitorowania interfejsu binarnego aplikacji (ABI) dostępnych w Androidzie 11 i nowszych, aby ustabilizować interfejs ABI działający w jądrze Androida. Narzędzie zbiera i porównuje reprezentacje ABI z dotychczasowych binarnych wersji jądra (vmlinux + moduły GKI). Te reprezentacje ABI to pliki .stg i listy symboli. Interfejs, w którym reprezentacja udostępnia widok, nazywa się interfejsem modułu jądra (KMI). Za pomocą tych narzędzi możesz śledzić i ograniczać zmiany w KMI.

Narzędzia do monitorowania ABI są opracowywane w AOSP i korzystają z STG (lub libabigail w Androidzie 13 i starszych), aby generować i porównywać reprezentacje.

Na tej stronie opisujemy narzędzia, proces zbierania i analizowania reprezentacji ABI oraz używanie tych reprezentacji do zapewnienia stabilności interfejsu ABI w jądrze. Na tej stronie znajdziesz też informacje o wprowadzaniu zmian w jądrach Androida.

Proces

Analiza ABI jądra wymaga wykonania kilku kroków, z których większość można zautomatyzować:

  1. Utwórz jądro i jego reprezentacja ABI.
  2. Analizuj różnice w ABI między kompilacją a plikiem referencyjnym.
  3. Zaktualizuj reprezentację ABI (w razie potrzeby).
  4. Praca z listami symboli.

Podane niżej instrukcje dotyczą dowolnego jądra, które można skompilować za pomocą obsługiwanego zestawu narzędzi (np. wstępnie skompilowanego zestawu narzędzi Clang). repo manifestssą dostępne dla wszystkich gałęzi jądra Androida i dla kilku jąder przeznaczonych do konkretnych urządzeń. Zapewniają one prawidłowe użycie zestawu narzędzi podczas kompilowania dystrybucji jądra na potrzeby analizy.

Listy symboli

KMI nie zawiera wszystkich symboli w jądrze,a nawet wszystkich ponad 30 000 wyeksportowanych symboli. Zamiast tego symbole, których mogą używać moduły dostawcy, są wymienione w zestawie plików z listą symboli udostępnianych publicznie w katalogu głównym drzewa jądra. Zbiór wszystkich symboli we wszystkich plikach listy symboli definiuje zbiór symboli KMI, które są utrzymywane jako stabilne. Przykładowy plik z listą symboli to abi_gki_aarch64_db845c, który deklaruje symbole wymagane dla DragonBoard 845c.

Do KMI zalicza się tylko symbole wymienione na liście symboli oraz powiązane z nimi struktury i definicje. Jeśli nie ma na niej potrzebnych symboli, można je opublikować. Nowe interfejsy umieszczone na liście symboli i należące do opisu KMI są zachowywane jako stabilne i nie można ich usuwać z listy symboli ani modyfikować po zawieszeniu gałęzi.

Każda gałąź jądra systemu KMI Androida Common jądra (ACK) ma własny zestaw list symboli. Nie podejmuje się prób zapewnienia stabilności ABI między różnymi gałęziami jądra KMI. Na przykład KMI dla android12-5.10 jest całkowicie niezależny od KMI dla android13-5.10.

Narzędzia ABI wykorzystują listy symboli KMI do ograniczenia, które interfejsy muszą być monitorowane pod kątem stabilności. Lista głównych symboli zawiera symbole wymagane przez moduły jądra GKI. Dostawcy muszą przesyłać i aktualizować dodatkowe listy symboli, aby mieć pewność, że interfejsy, z których korzystają, zachowują zgodność z interfejsem ABI. Aby na przykład wyświetlić listę list symboli dla android13-5.15, użyj kodu https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android.

Lista symboli zawiera symbole, które są potrzebne w przypadku konkretnego dostawcy lub urządzenia. Pełna lista używana przez narzędzia jest zbiorem wszystkich plików listy symboli KMI. Narzędzia ABI określają szczegóły każdego symbolu, w tym sygnaturę funkcji i zagnieżdżone struktury danych.

Gdy interfejs KMI jest zamrożony, nie można wprowadzać zmian w dotychczasowych interfejsach KMI, ponieważ są one stabilne. Dostawcy mogą jednak dodawać symbole do KMI w dowolnym momencie, o ile nie wpłynie to na stabilność istniejącego ABI. Nowo dodane symbole są utrzymywane w stanie stabilnym od momentu, gdy są one wymienione na liście symboli KMI. Symboli nie należy usuwać z listy jądra, chyba że można potwierdzić, że żadne urządzenie nigdy nie było dostarczane z zależnością od tego symbolu.

Listę symboli KMI dla urządzenia możesz wygenerować, postępując zgodnie z instrukcjami podanymi w artykule Praca z listami symboli. Wielu partnerów przesyła po 1 liście symboli na każde potwierdzenie, ale nie jest to absolutnie wymagane. Jeśli ułatwi to konserwację, możesz przesłać kilka list symboli.

Rozszerzenie KMI

Chociaż symbole KMI i powiązane z nimi struktury są utrzymywane jako stabilne (co oznacza, że zmiany, które powodują niestabilność interfejsów w jądrze z zamrożonym KMI, nie mogą być akceptowane), jądro GKI pozostaje otwarte na rozszerzenia, aby urządzenia wysyłane w późniejszej części roku nie musiały definiować wszystkich swoich zależności przed zamrożeniem KMI. Aby rozszerzyć KMI, możesz dodać do niego nowe symbole dla nowych lub istniejących wyeksportowanych funkcji jądra, nawet jeśli KMI jest zamrożony. Nowe poprawki jądra mogą być również akceptowane, jeśli nie naruszają KMI.

Awarie KMI

Jądro ma źródła i na ich podstawie są tworzone pliki binarne. Gałęzie jądra monitorowane pod kątem ABI zawierają reprezentację ABI bieżącego ABI GKI (w postaci pliku .stg). Po skompilowaniu plików binarnych (vmlinux, Image i dowolnych modułów GKI) można z nich wyodrębnić reprezentację interfejsu ABI. Każda zmiana wprowadzona w pliku źródłowym jądra może wpłynąć na pliki binarne, a w efekcie także na wyodrębnione .stg. Analizator AbiAnalyzer porównuje zaakceptowany plik .stg z plikiem wyodrębnionym z elementów kompilacji i w przypadku wykrycia różnicy semantycznej ustawia etykietę Lint-1 dla zmiany w Gerrecie.

Rozwiązywanie problemów z interfejsem ABI

Na przykład ten pakiet poprawek wprowadza bardzo oczywiste naruszenie 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.

Gdy uruchomisz kompilację ABI z zaimplementowaną łatką, narzędzie zakończy działanie z niezerowym kodem błędu i zgłosi różnicę w ABI podobną do tej:

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

różnice w ABI wykryte w momencie kompilacji,

Najczęstszą przyczyną błędów jest użycie przez sterownik nowego symbolu z jądra, którego nie ma na żadnej z list symboli.

Jeśli symbol nie znajduje się na liście symboli (android/abi_gki_aarch64), musisz najpierw sprawdzić, czy został wyeksportowany za pomocą funkcji EXPORT_SYMBOL_GPL(symbol_name), a następnie zaktualizować reprezentację XML i listę symboli ABI. Na przykład poniższe zmiany wprowadzają do gałęzi android-12-5.10 nową funkcję przyrostowego FS, która obejmuje zaktualizowanie listy symboli i reprezentacji XML ABI.

Jeśli symbol jest wyeksportowany (przez Ciebie lub wcześniej), ale nie jest używany przez żaden inny sterownik, może pojawić się błąd kompilacji podobny do tego.

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

Aby rozwiązać ten problem, zaktualizuj listę symboli KMI zarówno w jądrze, jak i w potwierdzeniu potwierdzenia (zobacz Aktualizowanie reprezentacji interfejsu ABI). Przykład aktualizacji pliku XML i listy symboli ABI w ACK znajdziesz w aosp/1367601.

Napraw błędy ABI jądra

Aby rozwiązać problemy z awariami interfejsu ABI jądra, możesz zrefaktoryzować kod, aby nie zmieniać interfejsu ABI, lub zaktualizować reprezentację interfejsu ABI. Na podstawie poniższej tabeli określ, która metoda jest najlepsza w Twojej sytuacji.

Schemat procesu w przypadku naruszenia interfejsu ABI

Rysunek 1. Rozwiązanie problemu z naruszeniem ABI

Refaktoryzuj kod, aby uniknąć zmian ABI

Dokładaj wszelkich starań, aby nie modyfikować istniejącego ABI. W wielu przypadkach można refaktoryzować kod, aby usunąć zmiany, które wpływają na interfejs ABI.

  • Refaktoryzacja zmian pól struktury. Jeśli zmiana modyfikuje interfejs ABI funkcji debugowania, dodaj #ifdef do pól (w elementach struct i odwołaniach do źródła) i upewnij się, że CONFIG używana w przypadku interfejsu #ifdef jest wyłączona dla defconfig i gki_defconfig w środowisku produkcyjnym. Przykład dodawania konfiguracji debugowania do struktury bez naruszania ABI znajdziesz w tym zestawie poprawek.

  • Funkcje refaktoryzacyjne pozwalające nie zmieniać podstawowego jądra. Jeśli do obsługi modułów partnera trzeba dodać do ACK nowych funkcji, spróbuj przerobić ABI w ramach zmiany, aby uniknąć modyfikowania ABI jądra. Przykład użycia istniejącego interfejsu ABI jądra w celu dodania dodatkowych funkcji bez zmiany interfejsu ABI jądra: aosp/1312213.

Naprawianie uszkodzonego interfejsu ABI na Androidzie Gerrit

Jeśli nie doszło do celowego naruszenia ABI jądra, musisz zbadać problem, korzystając z wskazówek podanych przez narzędzie do monitorowania ABI. Najczęstsze przyczyny przerw w działaniu to zmiany struktur danych i powiązane zmiany CRC symboli lub zmiany opcji konfiguracji, które prowadzą do któregokolwiek z wymienionych wyżej. Zacznij od rozwiązania problemów znalezionych przez narzędzie.

Wyniki dotyczące interfejsu ABI możesz odtworzyć lokalnie. Więcej informacji znajdziesz w artykule o tworzeniu jądra i jego reprezentacji ABI.

Informacje o etykietach Lint-1

Jeśli przesyłasz zmiany do gałęzi zawierającej zamrożoną lub sfinalizowaną KMI, zmiany muszą przejść weryfikację AbiAnalyzer, aby upewnić się, że nie wpływają one na stabilną ABI w niezgodny sposób. Podczas tego procesu AbiAnalyzer szuka raportu ABI utworzonego podczas kompilacji (rozszerzona kompilacja, która wykonuje normalną kompilację, a potem niektóre kroki wyodrębniania i porównywania ABI).

Jeśli AbiAnalyzer znajdzie niepusty raport, ustawi etykietę Lint-1, a zmiana będzie blokowana przed przesłaniem do momentu rozwiązania problemu, dopóki zbiór poprawek nie otrzyma etykiety Lint+1.

Aktualizacja ABI jądra

Jeśli modyfikacja ABI jest nieunikniona, musisz zastosować zmiany kodu, reprezentację ABI i listę symboli w ACK. Aby Lint usuwał -1, a nie łamał zgodności z GKI, wykonaj te czynności:

  1. Przesłać zmiany kodu do ACK

  2. Poczekaj na otrzymanie weryfikacji kodu +2 dla zestawu poprawek.

  3. Zaktualizuj referencyjną reprezentację ABI.

  4. Połącz zmiany kodu z aktualizacją ABI.

Prześlij zmiany kodu ABI do ACK

Aktualizacja ABI ACK zależy od typu wprowadzanej zmiany.

  • Jeśli zmiana interfejsu ABI jest powiązana z funkcją, która wpływa na testy CTS lub VTS, zwykle można ją wybrać do potwierdzenia w niezmienionej postaci. Na przykład:

    • Aby dźwięk działał, musisz mieć zainstalowaną wersję aosp/1289677.
    • aosp/1295945 jest wymagany do działania USB.
  • Jeśli zmiana ABI dotyczy funkcji, którą można udostępnić w wersji ACK, można ją przenieść do tej wersji w postaci dosłownej. Na przykład te zmiany nie są potrzebne do testu CTS ani VTS, ale można je udostępnić w wersji ACK:

  • Jeśli zmiana ABI wprowadza nową funkcję, która nie musi być uwzględniona w ACK, możesz wprowadzić symbole do ACK za pomocą zastępnika zgodnie z opisem w następującej sekcji.

Użyj wycinków z kodem ACK

Stuby muszą być potrzebne tylko w przypadku zmian w rdzeniu jądra, które nie przynoszą korzyści ACK, takich jak zmiany wydajności i poboru mocy. Poniżej znajdziesz przykłady stubów i częściowych elementów w ACK dla GKI.

  • Krótka część funkcji (aosp/1284493). Funkcje w ACK nie są wymagane, ale symbole muszą być obecne w ACK, aby moduły mogły ich używać.

  • Symbol zastępczy dla modułu dostawcy (aosp/1288860).

  • Funkcja śledzenia zdarzeń mm (aosp/1288454) korzystająca z funkcji selektywnego mm (tylko ABI). Pierwotny pakiet poprawek został wybrany do zaakceptowania, a potem przycięty tak, aby zawierał tylko zmiany niezbędne do rozwiązania różnic w ABI w przypadku task_structmm_event_count. Ta poprawka aktualizuje też enumerację mm_event_type, aby zawierała ostatecznych członków.

  • Częściowy wybór zmian interfejsu ABI struktury termicznej, który wymagał więcej niż tylko dodania nowych pól ABI.

    • Poprawka aosp/1255544 rozwiązała różnice w ABI między jądrem partnera a ACK.

    • Aktualizacja aosp/1291018 naprawia problemy z funkcjonalnością, które zostały wykryte podczas testowania poprzedniej aktualizacji przez GKI. Poprawka obejmowała zainicjowanie struktury parametrów czujnika w celu zarejestrowania wielu stref termicznych dla jednego czujnika.

  • Zmiany interfejsu ABI usługi CONFIG_NL80211_TESTMODE (aosp/1344321). Ta poprawka wprowadziła niezbędne zmiany struktury dla ABI i zadbała o to, aby dodatkowe pola nie powodowały różnic w funkcjonalności, co umożliwiło partnerom uwzględnienie CONFIG_NL80211_TESTMODE w ich produkcyjnych jądrach i zachowanie zgodności z GKI.

Egzekwuj KMI w czasie działania

Kernele GKI używają opcji konfiguracji TRIM_UNUSED_KSYMS=y i UNUSED_KSYMS_WHITELIST=<union of all symbol lists>, które ograniczają eksportowane symbole (takie jak symbole eksportowane za pomocą EXPORT_SYMBOL_GPL()) do tych wymienionych na liście symboli. Wszystkie inne symbole nie są eksportowane, a wczytywanie modułu wymagającego niewyeksportowanego symbolu jest odrzucane. To ograniczenie jest egzekwowane w czasie kompilacji, a brakujące wpisy są oznaczane.

Na potrzeby programowania możesz użyć wersji jądra GKI, która nie obejmuje przycinania symboli (co oznacza, że można używać wszystkich symboli wyeksportowanych w standardowy sposób). Aby znaleźć te kompilacje, poszukaj kompilacji kernel_debug_aarch64 na stronie ci.android.com.

Egzekwowanie KMI za pomocą wersji modułu

Kernele z obrazu Generic Kernel Image (GKI) korzystają z wersji modułów (CONFIG_MODVERSIONS) jako dodatkowego sposobu zapewnienia zgodności z KMI w czasie wykonywania. Wersja modułu może powodować błędy niezgodności CRC podczas wczytywania modułu, jeśli oczekiwany KMI modułu nie jest zgodny z vmlinux KMI. Na przykład poniższy błąd występuje podczas ładowania modułu z powodu niezgodności CRC z symbolem 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 ''

Zastosowanie obsługi wersji modułów

Wersje modułów są przydatne z tych powodów:

  • Wersje modułów rejestrują zmiany w widoczności struktury danych. Jeśli moduły zmieniają nieprzezroczystą strukturę danych, czyli struktury danych, które nie są częścią KMI, po wprowadzeniu przyszłych zmian w strukturze mogą ulec uszkodzeniu.

    Weźmy np. pole fwnode w elemencie struct device. To pole MUSI być nieprzezroczyste dla modułów, aby nie mogły one wprowadzać zmian w polach device->fw_node ani zakładać jego rozmiaru.

    Jeśli jednak moduł zawiera element <linux/fwnode.h> (bezpośrednio lub pośrednio), pole fwnode w elementzie struct device nie jest już dla niego nieprzezroczyste. Następnie moduł może wprowadzić zmiany w  lub device->fwnode->ops.device->fwnode->dev Ten scenariusz jest problematyczny z kilku powodów:

    • Może to zakłócić założenia, które kod jądra przyjmuje na temat swoich wewnętrznych struktur danych.

    • Jeśli przyszła aktualizacja jądra zmieni struct fwnode_handle (typ danych fwnode), moduł przestanie działać z nowym jądrem. Poza tym funkcja stgdiff nie wykaże żadnych różnic, ponieważ moduł zakłóca wskaźnik KMI przez bezpośrednie manipulowanie wewnętrznymi strukturami danych w sposób, którego nie da się zarejestrować jedynie przez sprawdzenie reprezentacji binarnej.

  • Bieżący moduł jest uznawany za niezgodny z KMI, gdy zostanie wczytany później przez nowe jądro, które będzie niezgodne z zasadami. Obsługa wersji modułów dodaje kontrolę w czasie działania, aby zapobiec przypadkowemu wczytaniu modułu, który nie jest zgodny z jądrem KMI. Ten test zapobiega trudnym do debugowania problemom w czasie działania i awarjom jądra, które mogą być spowodowane niezauważoną niezgodnością w KMI.

Włączenie obsługi wersji modułów zapobiega tym problemom.

Sprawdzanie niezgodności CRC bez uruchamiania urządzenia

Pole stgdiff porównuje i zgłasza rozbieżności CRC między rdzeniami oraz inne różnice w ABI.

Oprócz tego pełna kompilacja jądra z włączoną obsługą CONFIG_MODVERSIONS generuje plik Module.symvers w ramach normalnego procesu kompilacji. Ten plik zawiera po jednym wierszu na każdy symbol wyeksportowany przez jądro (vmlinux) i moduły. Każdy wiersz składa się z wartości CRC, nazwy symbolu, przestrzeni nazw symbolu, nazwy vmlinux lub modułu, który eksportuje symbol, oraz typu eksportu (np. EXPORT_SYMBOL lub EXPORT_SYMBOL_GPL).

Możesz porównać pliki Module.symvers z wersji GKI i swojej wersji, aby sprawdzić, czy w symbolach wyeksportowanych przez vmlinux występują różnice CRC. Jeśli wartość CRC dowolnego symbolu wyeksportowanego przez vmlinux i jest inna, a symbol jest używany przez jeden z modułów wczytywanych na urządzeniu, moduł nie wczytuje się.

Jeśli nie masz wszystkich artefaktów kompilacji, ale masz pliki vmlinux z jądra GKI i swojego jądra, możesz porównać wartości CRC dla konkretnego symbolu, wykonując to polecenie w obu jądrach i porównując dane wyjściowe:

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

Na przykład następujące polecenie sprawdza wartość CRC dla symbolu module_layout:

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

Rozwiąż problemy z niezgodnością CRC

Aby rozwiązać problem z niezgodnością CRC podczas wczytywania modułu, wykonaj te czynności:

  1. Utwórz jądro GKI i jądro urządzenia, używając opcji --kbuild_symtypes, jak pokazano w tym poleceniu:

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

    To polecenie generuje plik .symtypes dla każdego pliku .o. Więcej informacji znajdziesz w KBUILD_SYMTYPES w Kleaf.

    W przypadku Androida 13 i starszych kompiluj jądro GKI oraz jądro urządzenia, dodając do polecenia kompilacji KBUILD_SYMTYPES=1, jak w tym przykładzie:

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

    Gdy używasz parametru build_abi.sh,, flaga KBUILD_SYMTYPES=1 jest już domyślnie ustawiona.

  2. Znajdź plik .c, w którym symbol z niezgodnością CRC został wyeksportowany, za pomocą tego polecenia:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
  3. Plik .c ma odpowiadający mu plik .symtypes w GKI oraz artefakty kompilacji jądra urządzenia. Znajdź plik .c, używając tych poleceń:

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

    Poniżej znajdziesz informacje o pliku .c:

    • Format pliku .c to 1 wiersz (potencjalnie bardzo długi) na symbol.

    • [s|u|e|etc]# na początku wiersza oznacza, że symbol ma typ danych [struct|union|enum|etc]. Na przykład:

      t#bool typedef _Bool bool
      
    • Brakujący na początku wiersza prefiks # wskazuje, że symbol jest funkcją. Na przykład:

      find_module s#module * find_module ( const char * )
      
  4. Porównaj oba pliki i usuń wszystkie różnice.

Przypadek 1. Różnice wynikające z widoczności typu danych

Jeśli jedno jądro ukrywa symbol lub typ danych przed modułami, a drugie nie, ta różnica pojawi się w plikach .symtypes tych dwóch jąder. Plik .symtypes z jednego z jąder zawiera symbol UNKNOWN, a plik .symtypes z drugiego jądra ma rozwinięty widok symbolu lub typu danych.

Na przykład dodanie do pliku include/linux/device.h w jądrze tego wiersza powoduje niezgodności CRC, z których jedna dotyczy module_layout():

 #include <linux/fwnode.h>

Porównanie module.symtypes dla tego symbolu pokazuje te różnice:

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

Jeśli wartość Twojego jądra to UNKNOWN, a jądro GKI zawiera rozszerzony widok symbolu (bardzo mało prawdopodobne), scal najnowsze jądro Android Common Kernel ze swoim jądrem, aby używać najnowszej wersji jądra GKI.

W większości przypadków wartość rdzenia GKI to UNKNOWN, ale Twój rdzeń zawiera wewnętrzne szczegóły symbolu z powodu zmian wprowadzonych w Twoim rdzeniu. Wynika to z faktu, że do jednego z plików w jądrze dodano obiekt #include, którego nie ma w jądrze GKI.

Często wystarczy ukryć nowy element #include z elementu genksyms.

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

Aby zidentyfikować #include, który powoduje różnicę, wykonaj te czynności:

  1. Otwórz plik nagłówka, który definiuje symbol lub typ danych z tą różnicą. Zmodyfikuj na przykład kolumnę include/linux/fwnode.h w wierszu struct fwnode_handle.

  2. U góry pliku nagłówka dodaj ten kod:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. W pliku .c modułu, który ma niezgodność CRC, dodaj następujący wiersz jako pierwszy przed dowolnym wierszem #include.

    #define CRC_CATCH 1
    
  4. Zkompiluj moduł. Wygenerowany błąd w czasie kompilacji zawiera łańcuch plików nagłówka #include, który doprowadził do niezgodności CRC. Na przykład:

    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"
    

    Jeden z linków w tym łańcuchu #include jest spowodowany zmianą w jądrze, która nie występuje w jądrze GKI.

  5. Zidentyfikuj zmianę, cofnij ją w jądrze lub prześlij do ACK i połącz ją z innymi zmianami.

Przypadek 2. Różnice spowodowane zmianami typu danych

Jeśli rozbieżność CRC symbolu lub typu danych nie jest spowodowana różnicą w widoczności, to wynika to z rzeczywistych zmian (dodanych, usuniętych lub zmienionych) w samym typie danych.

Na przykład wprowadzenie następującej zmiany w jądrze powoduje kilka niedopasowań CRC, ponieważ ta zmiana wpływa pośrednio na wiele symboli:

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

Jeden niespójny CRC dotyczy pliku devm_of_platform_populate().

Jeśli porównasz pliki .symtypes dla tego symbolu, mogą one wyglądać tak:

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

Aby określić zmieniony typ, wykonaj te czynności:

  1. Znajdź definicję symbolu w kodzie źródłowym (zwykle w plikach .h).

    • Aby znaleźć różnice w symbolach między Twoim jądrem a jądrem GKI, znajdź zatwierdzanie, uruchamiając to polecenie:
    git blame
    • W przypadku usuniętych symboli (gdy symbol został usunięty z drzewa i chcesz go usunąć z drugiego drzewa) musisz znaleźć zmianę, która spowodowała usunięcie linii. Użyj tego polecenia w drzewie, w którym usunięto linię:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
  2. Przejrzyj zwróconą listę zatwierdzeń, aby znaleźć zmianę lub usunięcie. Pierwsze zatwierdzenie jest prawdopodobnie tym, którego szukasz. Jeśli nie, przejrzyj listę, aż znajdziesz odpowiednią wersję.

  3. Po zidentyfikowaniu zmiany cofnij ją w jądrze lub prześlij do ACK i połącz ją z jądrem.