Monitoraggio ABI del kernel Android

Puoi utilizzare gli strumenti di monitoraggio dell'interfaccia binaria (ABI) dell'applicazione, disponibili in Android 11 e versioni successive, per stabilizzare l'ABI in-kernel dei kernel Android. Gli strumenti raccolgono e confrontano le rappresentazioni ABI dai file binari del kernel esistenti (moduli vmlinux + GKI). Queste rappresentazioni ABI sono i file .stg e gli elenchi di simboli. L'interfaccia su cui la rappresentazione fornisce una vista è chiamata Kernel Module Interface (KMI). È possibile utilizzare gli strumenti per tenere traccia e mitigare le modifiche al KMI.

Lo strumento di monitoraggio ABI è sviluppato in AOSP e utilizza STG (o libabigail in Android 13 e versioni precedenti) per generare e confrontare rappresentazioni.

Questa pagina descrive gli strumenti, il processo di raccolta e analisi delle rappresentazioni ABI e l'utilizzo di tali rappresentazioni per fornire stabilità all'ABI nel kernel. Questa pagina fornisce anche informazioni per apportare modifiche ai kernel Android.

Processi

L'analisi dell'ABI del kernel richiede più passaggi, la maggior parte dei quali può essere automatizzata:

  1. Costruisci il kernel e la sua rappresentazione ABI .
  2. Analizzare le differenze ABI tra la build e un riferimento .
  3. Aggiornare la rappresentazione ABI (se richiesto) .
  4. Lavora con elenchi di simboli .

Le seguenti istruzioni funzionano per qualsiasi kernel che puoi creare utilizzando una toolchain supportata (come la toolchain Clang precompilata). repo manifests sono disponibili per tutti i rami comuni del kernel Android e per diversi kernel specifici del dispositivo, garantiscono che venga utilizzata la toolchain corretta quando si crea una distribuzione del kernel per l'analisi.

Elenchi di simboli

Il KMI non include tutti i simboli nel kernel e nemmeno tutti gli oltre 30.000 simboli esportati. Invece, i simboli che possono essere utilizzati dai moduli del fornitore sono elencati esplicitamente in un insieme di file di elenchi di simboli mantenuti pubblicamente nella radice dell'albero del kernel. L'unione di tutti i simboli in tutti i file dell'elenco dei simboli definisce l'insieme dei simboli KMI mantenuti stabili. Un esempio di file di elenco dei simboli è abi_gki_aarch64_db845c , che dichiara i simboli richiesti per DragonBoard 845c .

Solo i simboli elencati in un elenco di simboli e le relative strutture e definizioni sono considerati parte del KMI. Puoi pubblicare modifiche ai tuoi elenchi di simboli se i simboli che ti servono non sono presenti. Dopo che le nuove interfacce sono in un elenco di simboli e fanno parte della descrizione KMI, vengono mantenute stabili e non devono essere rimosse dall'elenco di simboli o modificate dopo che il ramo è stato congelato.

Ogni ramo del kernel KMI Android Common Kernel (ACK) ha il proprio set di elenchi di simboli. Non viene fatto alcun tentativo di fornire stabilità ABI tra diversi rami del kernel KMI. Ad esempio, il KMI per android12-5.10 è completamente indipendente dal KMI per android13-5.10 .

Gli strumenti ABI utilizzano elenchi di simboli KMI per limitare quali interfacce devono essere monitorate per la stabilità. L' elenco dei simboli principale contiene i simboli richiesti dai moduli del kernel GKI. Si prevede che i fornitori inviino e aggiornino ulteriori elenchi di simboli per garantire che le interfacce su cui fanno affidamento mantengano la compatibilità ABI. Ad esempio, per visualizzare un elenco di elenchi di simboli per android13-5.15 , fare riferimento a https://android.googlesource.com/kernel/common/+/refs/heads/android13-5.15/android

Un elenco di simboli contiene i simboli ritenuti necessari per un particolare fornitore o dispositivo. L'elenco completo utilizzato dagli strumenti è l'unione di tutti i file dell'elenco dei simboli KMI. Gli strumenti ABI determinano i dettagli di ciascun simbolo, inclusa la firma della funzione e le strutture di dati nidificate.

Quando il KMI è congelato, non sono consentite modifiche alle interfacce KMI esistenti; sono stabili. Tuttavia, i fornitori sono liberi di aggiungere simboli al KMI in qualsiasi momento purché le aggiunte non influenzino la stabilità dell'ABI esistente. I simboli appena aggiunti vengono mantenuti stabili non appena vengono citati da un elenco di simboli KMI. I simboli non dovrebbero essere rimossi da un elenco per un kernel a meno che non si possa confermare che nessun dispositivo sia mai stato distribuito con una dipendenza da quel simbolo.

È possibile generare un elenco di simboli KMI per un dispositivo utilizzando le istruzioni di Come lavorare con gli elenchi di simboli . Molti partner inviano un elenco di simboli per ACK, ma questo non è un requisito difficile. Se aiuta con la manutenzione, puoi inviare più elenchi di simboli.

Estendere il KMI

Mentre i simboli KMI e le strutture correlate vengono mantenuti stabili (il che significa che non possono essere accettate modifiche che interrompono le interfacce stabili in un kernel con un KMI congelato) il kernel GKI rimane aperto alle estensioni in modo che i dispositivi che verranno spediti più avanti nel corso dell'anno non debbano definire tutti le loro dipendenze prima che il KMI venga congelato. Per estendere il KMI, è possibile aggiungere nuovi simboli al KMI per funzioni del kernel esportate nuove o esistenti, anche se il KMI è congelato. Possono essere accettate anche nuove patch del kernel se non interrompono il KMI.

Informazioni sulle rotture KMI

Un kernel ha sorgenti e i binari vengono creati da tali sorgenti. I rami del kernel monitorati da ABI includono una rappresentazione ABI dell'attuale ABI GKI (sotto forma di file .stg ). Dopo aver creato i file binari ( vmlinux , Image ed eventuali moduli GKI), è possibile estrarre una rappresentazione ABI dai file binari. Qualsiasi modifica apportata a un file sorgente del kernel può influenzare i file binari e, a sua volta, influenzare anche il .stg estratto. L'analizzatore AbiAnalyzer confronta il file .stg impegnato con quello estratto dagli artefatti di build e imposta un'etichetta Lint-1 sulla modifica in Gerrit se trova una differenza semantica.

Gestire le rotture ABI

Ad esempio, la seguente patch introduce una rottura ABI molto evidente:

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.

Quando esegui build ABI con questa patch applicata, lo strumento esce con un codice di errore diverso da zero e segnala una differenza ABI simile a questa:

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

Differenze ABI rilevate in fase di creazione

La ragione più comune degli errori è quando un driver utilizza un nuovo simbolo dal kernel che non è presente in nessuno degli elenchi di simboli.

Se il simbolo non è incluso nell'elenco dei simboli ( android/abi_gki_aarch64 ), devi prima verificare che sia esportato con EXPORT_SYMBOL_GPL( symbol_name ) e quindi aggiornare la rappresentazione XML ABI e l'elenco dei simboli. Ad esempio, le seguenti modifiche aggiungono la nuova funzionalità FS incrementale al ramo android-12-5.10 , che include l'aggiornamento dell'elenco dei simboli e della rappresentazione XML ABI.

Se il simbolo viene esportato (da te o è stato esportato in precedenza) ma nessun altro driver lo utilizza, potresti ricevere un errore di compilazione simile al seguente.

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

Per risolvere, aggiorna l'elenco dei simboli KMI sia nel kernel che nell'ACK (vedi Aggiornamento della rappresentazione ABI ). Per un esempio di aggiornamento dell'XML ABI e dell'elenco dei simboli nell'ACK, fare riferimento a aosp/1367601 .

Risolvere le rotture dell'ABI del kernel

È possibile gestire le interruzioni dell'ABI del kernel eseguendo il refactoring del codice per non modificare l'ABI o aggiornando la rappresentazione ABI . Utilizza la tabella seguente per determinare l'approccio migliore per la tua situazione.

Diagramma di flusso di rottura ABI

Figura 1. Risoluzione delle rotture ABI

Codice di refactoring per evitare modifiche ABI

Fare ogni sforzo per evitare di modificare l’ABI esistente. In molti casi, puoi eseguire il refactoring del codice per rimuovere le modifiche che influiscono sull'ABI.

  • Refactoring delle modifiche al campo della struttura. Se una modifica modifica l'ABI per una funzionalità di debug, aggiungi un #ifdef attorno ai campi (nelle strutture e nei riferimenti ai sorgenti) e assicurati che CONFIG utilizzato per #ifdef sia disabilitato per la produzione defconfig e gki_defconfig . Per un esempio di come una configurazione di debug può essere aggiunta a una struttura senza interrompere l'ABI, fare riferimento a questo patchset .

  • Funzionalità di refactoring per non modificare il kernel principale. Se è necessario aggiungere nuove funzionalità a ACK per supportare i moduli partner, provare a rifattorizzare la parte ABI della modifica per evitare di modificare l'ABI del kernel. Per un esempio di utilizzo dell'ABI del kernel esistente per aggiungere funzionalità aggiuntive senza modificare l'ABI del kernel, fare riferimento a aosp/1312213 .

Correggi un ABI rotto su Android Gerrit

Se non hai danneggiato intenzionalmente l'ABI del kernel, devi indagare utilizzando le indicazioni fornite dagli strumenti di monitoraggio ABI. Le cause più comuni di rotture sono la modifica delle strutture dati e le modifiche del simbolo CRC associato o le modifiche alle opzioni di configurazione che portano a uno dei casi sopra menzionati. Inizia affrontando i problemi rilevati dallo strumento.

È possibile riprodurre i risultati dell'ABI localmente, vedere Compilazione del kernel e della relativa rappresentazione ABI .

Informazioni sulle etichette Lint-1

Se carichi modifiche su un ramo contenente un KMI congelato o finalizzato, le modifiche devono passare AbiAnalyzer per garantire che le modifiche non influenzino l'ABI stabile in modo incompatibile. Durante questo processo, AbiAnalyzer cerca il report ABI creato durante la compilazione (una build estesa che esegue la compilazione normale e quindi alcuni passaggi di estrazione e confronto ABI.

Se AbiAnalyzer trova un report non vuoto imposta l'etichetta Lint-1 e la modifica viene bloccata dall'invio fino alla risoluzione; finché il patchset non riceve un'etichetta Lint+1.

Aggiorna l'ABI del kernel

Se la modifica dell'ABI è inevitabile, è necessario applicare le modifiche al codice, la rappresentazione ABI e l'elenco dei simboli all'ACK. Per fare in modo che Lint rimuova -1 e non interrompa la compatibilità GKI, attenersi alla seguente procedura:

  1. Carica le modifiche del codice nell'ACK .

  2. Attendi di ricevere una Code-Review +2 per il patchset.

  3. Aggiorna la rappresentazione ABI di riferimento .

  4. Unisci le modifiche al codice e la modifica dell'aggiornamento ABI.

Carica le modifiche del codice ABI nell'ACK

L'aggiornamento dell'ACK ABI dipende dal tipo di modifica che si sta apportando.

  • Se una modifica ABI è correlata a una funzionalità che influisce sui test CTS o VTS, la modifica può in genere essere selezionata con cura per ACK così com'è. Per esempio:

  • Se una modifica ABI riguarda una funzionalità che può essere condivisa con l'ACK, tale modifica può essere selezionata con cura per ACK così com'è. Ad esempio, le seguenti modifiche non sono necessarie per il test CTS o VTS ma possono essere condivise con ACK:

  • Se una modifica ABI introduce una nuova funzionalità che non necessita di essere inclusa nell'ACK, puoi introdurre i simboli nell'ACK utilizzando uno stub come descritto nella sezione seguente.

Usa stub per ACK

Gli stub devono essere necessari solo per modifiche core del kernel che non apportano benefici all'ACK, come modifiche alle prestazioni e alla potenza. L'elenco seguente descrive in dettaglio esempi di stub e scelte parziali in ACK per GKI.

  • Stub della funzionalità di isolamento del core ( aosp/1284493 ). La funzionalità in ACK non è necessaria, ma i simboli devono essere presenti in ACK affinché i tuoi moduli utilizzino questi simboli.

  • Simbolo segnaposto per il modulo fornitore ( aosp/1288860 ).

  • Selezione solo ABI della funzionalità di tracciamento degli eventi mm per processo ( aosp/1288454 ). La patch originale è stata scelta attentamente per ACK e quindi ritagliata per includere solo le modifiche necessarie per risolvere la differenza ABI per task_struct e mm_event_count . Questa patch aggiorna anche l'enumerazione mm_event_type per contenere i membri finali.

  • Selezione parziale delle modifiche ABI della struttura termica che hanno richiesto molto più della semplice aggiunta dei nuovi campi ABI.

    • La patch aosp/1255544 ha risolto le differenze ABI tra il kernel partner e ACK.

    • La patch aosp/1291018 ha risolto i problemi funzionali rilevati durante il test GKI della patch precedente. La correzione includeva l'inizializzazione della struttura dei parametri del sensore per registrare più zone termiche su un singolo sensore.

  • CONFIG_NL80211_TESTMODE Modifiche ABI ( aosp/1344321 ). Questa patch ha aggiunto le modifiche strutturali necessarie per ABI e ha assicurato che i campi aggiuntivi non causassero differenze funzionali, consentendo ai partner di includere CONFIG_NL80211_TESTMODE nei loro kernel di produzione e mantenere comunque la conformità GKI.

Applicare il KMI in fase di esecuzione

I kernel GKI utilizzano le opzioni di configurazione TRIM_UNUSED_KSYMS=y e UNUSED_KSYMS_WHITELIST=<union of all symbol lists> , che limitano i simboli esportati (come i simboli esportati utilizzando EXPORT_SYMBOL_GPL() ) a quelli elencati in un elenco di simboli. Tutti gli altri simboli non vengono esportati e il caricamento di un modulo che richiede un simbolo non esportato viene negato. Questa restrizione viene applicata in fase di compilazione e le voci mancanti vengono contrassegnate.

Per scopi di sviluppo, è possibile utilizzare una build del kernel GKI che non includa il trimming dei simboli (il che significa che è possibile utilizzare tutti i simboli solitamente esportati). Per individuare queste build, cerca le build kernel_debug_aarch64 su ci.android.com .

Applica il KMI utilizzando il controllo delle versioni del modulo

I kernel Generic Kernel Image (GKI) utilizzano il controllo delle versioni dei moduli ( CONFIG_MODVERSIONS ) come misura aggiuntiva per imporre la conformità KMI in fase di runtime. Il controllo delle versioni del modulo può causare errori di mancata corrispondenza del controllo di ridondanza ciclico (CRC) al momento del caricamento del modulo se il KMI previsto di un modulo non corrisponde al KMI vmlinux . Ad esempio, quello che segue è un tipico errore che si verifica durante il caricamento del modulo a causa di una mancata corrispondenza CRC per il simbolo 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 ''

Usi del controllo delle versioni dei moduli

Il controllo delle versioni del modulo è utile per i seguenti motivi:

  • Il controllo delle versioni del modulo rileva i cambiamenti nella visibilità della struttura dei dati. Se i moduli modificano strutture dati opache, ovvero strutture dati che non fanno parte del KMI, si interrompono dopo future modifiche alla struttura.

    Ad esempio, considera il campo fwnode nella struct device . Questo campo DEVE essere opaco per i moduli in modo che non possano apportare modifiche ai campi di device->fw_node o fare ipotesi sulla sua dimensione.

    Tuttavia, se un modulo include <linux/fwnode.h> (direttamente o indirettamente), allora il campo fwnode nella struct device non è più opaco per esso. Il modulo può quindi apportare modifiche a device->fwnode->dev o device->fwnode->ops . Questo scenario è problematico per diversi motivi, indicati come segue:

    • Può infrangere le ipotesi che il codice principale del kernel sta facendo sulle sue strutture dati interne.

    • Se un futuro aggiornamento del kernel modifica la struct fwnode_handle (il tipo di dati di fwnode ), il modulo non funzionerà più con il nuovo kernel. Inoltre, stgdiff non mostrerà alcuna differenza perché il modulo sta rompendo il KMI manipolando direttamente le strutture di dati interne in modi che non possono essere catturati esaminando solo la rappresentazione binaria.

  • Un modulo corrente è considerato incompatibile con KMI quando viene caricato in un secondo momento da un nuovo kernel incompatibile. Il controllo delle versioni del modulo aggiunge un controllo in fase di esecuzione per evitare di caricare accidentalmente un modulo che non è compatibile con KMI con il kernel. Questo controllo previene problemi di runtime difficili da eseguire il debug e arresti anomali del kernel che potrebbero derivare da un'incompatibilità non rilevata nel KMI.

L'abilitazione del controllo delle versioni del modulo previene tutti questi problemi.

Controlla le mancate corrispondenze CRC senza avviare il dispositivo

stgdiff confronta e segnala le mancate corrispondenze CRC tra i kernel insieme ad altre differenze ABI.

Inoltre, una compilazione completa del kernel con CONFIG_MODVERSIONS abilitato genera un file Module.symvers come parte del normale processo di compilazione. Questo file ha una riga per ogni simbolo esportato dal kernel ( vmlinux ) e dai moduli. Ogni riga è composta dal valore CRC, dal nome del simbolo, dallo spazio dei nomi del simbolo, dal nome del modulo o vmlinux che esporta il simbolo e dal tipo di esportazione (ad esempio, EXPORT_SYMBOL rispetto a EXPORT_SYMBOL_GPL ).

Puoi confrontare i file Module.symvers tra la build GKI e la tua build per verificare eventuali differenze CRC nei simboli esportati da vmlinux . Se c'è una differenza di valore CRC in qualsiasi simbolo esportato da vmlinux e quel simbolo viene utilizzato da uno dei moduli caricati nel dispositivo, il modulo non viene caricato.

Se non disponi di tutti gli artefatti di compilazione, ma disponi dei file vmlinux del kernel GKI e del tuo kernel, puoi confrontare i valori CRC per un simbolo specifico eseguendo il seguente comando su entrambi i kernel e confrontando l'output:

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

Ad esempio, il comando seguente controlla il valore CRC per il simbolo module_layout :

nm vmlinux | grep __crc_module_layout
0000000008663742 A __crc_module_layout

Risolvere le mancate corrispondenze CRC

Utilizzare i passaggi seguenti per risolvere una mancata corrispondenza CRC durante il caricamento di un modulo:

  1. Crea il kernel GKI e il kernel del tuo dispositivo utilizzando l'opzione --kbuild_symtypes come mostrato nel comando seguente:

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

    Questo comando genera un file .symtypes per ogni file .o . Vedi KBUILD_SYMTYPES in Kleaf per i dettagli.

    Per Android 13 e versioni precedenti, crea il kernel GKI e il kernel del tuo dispositivo anteponendo KBUILD_SYMTYPES=1 al comando che utilizzi per creare il kernel, come mostrato nel comando seguente:

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

    Quando si utilizza build_abi.sh, il flag KBUILD_SYMTYPES=1 è già implicitamente impostato.

  2. Trova il file .c in cui viene esportato il simbolo con mancata corrispondenza CRC, utilizzando il seguente comando:

    cd common && git grep EXPORT_SYMBOL.*module_layout
    kernel/module.c:EXPORT_SYMBOL(module_layout);
    
  3. Il file .c ha un file .symtypes corrispondente nella GKI e gli artefatti di build del kernel del dispositivo. Individuare il file .c utilizzando i seguenti comandi:

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

    Di seguito le caratteristiche del file .c :

    • Il formato del file .c è una riga (potenzialmente molto lunga) per simbolo.

    • [s|u|e|etc]# all'inizio della riga significa che il simbolo è del tipo di dati [struct|union|enum|etc] . Per esempio:

      t#bool typedef _Bool bool
      
    • Un prefisso # mancante all'inizio della riga indica che il simbolo è una funzione. Per esempio:

      find_module s#module * find_module ( const char * )
      
  4. Confronta i due file e correggi tutte le differenze.

Caso 1: differenze dovute alla visibilità del tipo di dati

Se un kernel mantiene un simbolo o un tipo di dati opaco ai moduli e l'altro kernel no, tale differenza appare tra i file .symtypes dei due kernel. Il file .symtypes di uno dei kernel ha UNKNOWN per un simbolo e il file .symtypes dell'altro kernel ha una vista espansa del simbolo o del tipo di dati.

Ad esempio, l'aggiunta della seguente riga al file include/linux/device.h nel kernel provoca mancate corrispondenze CRC, una delle quali è per module_layout() :

 #include <linux/fwnode.h>

Confrontando i module.symtypes per quel simbolo, si espongono le seguenti differenze:

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

Se il tuo kernel ha un valore UNKNOWN e il kernel GKI ha la visualizzazione estesa del simbolo (molto improbabile), unisci l'ultimo kernel comune Android nel tuo kernel in modo da utilizzare la base del kernel GKI più recente.

Nella maggior parte dei casi, il kernel GKI ha il valore UNKNOWN , ma il tuo kernel ha i dettagli interni del simbolo a causa delle modifiche apportate al tuo kernel. Questo perché uno dei file nel kernel ha aggiunto un #include che non è presente nel kernel GKI.

Spesso la soluzione è semplice come nascondere il nuovo #include da genksyms .

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

Altrimenti, per identificare l' #include che causa la differenza, attenersi alla seguente procedura:

  1. Apri il file di intestazione che definisce il simbolo o il tipo di dati con questa differenza. Ad esempio, modificare include/linux/fwnode.h per la struct fwnode_handle .

  2. Aggiungi il seguente codice nella parte superiore del file di intestazione:

    #ifdef CRC_CATCH
    #error "Included from here"
    #endif
    
  3. Nel file .c del modulo che presenta una mancata corrispondenza CRC, aggiungi quanto segue come prima riga prima di qualsiasi riga #include .

    #define CRC_CATCH 1
    
  4. Compila il tuo modulo. L'errore in fase di compilazione risultante mostra la catena del file di intestazione #include che ha portato a questa mancata corrispondenza CRC. Per esempio:

    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"
    

    Uno degli anelli di questa catena di #include è dovuto a una modifica apportata al kernel, che manca nel kernel GKI.

  5. Identifica la modifica, ripristinala nel kernel o caricala su ACK e uniscila .

Caso 2: differenze dovute a modifiche del tipo di dati

Se la mancata corrispondenza CRC per un simbolo o un tipo di dati non è dovuta a una differenza di visibilità, è dovuta a modifiche effettive (aggiunte, rimozioni o modifiche) nel tipo di dati stesso.

Ad esempio, apportare la seguente modifica al kernel provoca diverse mancate corrispondenze CRC poiché molti simboli sono indirettamente influenzati da questo tipo di modifica:

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

Una mancata corrispondenza CRC è per devm_of_platform_populate() .

Se confronti i file .symtypes per quel simbolo, potrebbe assomigliare a questo:

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

Per identificare il tipo modificato, attenersi alla seguente procedura:

  1. Trova la definizione del simbolo nel codice sorgente (solitamente nei file .h ).

    • Per semplici differenze di simboli tra il tuo kernel e il kernel GKI, trova il commit eseguendo il seguente comando:
    git blame
    
    • Per i simboli eliminati (dove un simbolo viene eliminato in un albero e si desidera eliminarlo anche nell'altro albero), è necessario trovare la modifica che ha eliminato la linea. Utilizzare il seguente comando sull'albero in cui è stata eliminata la riga:
    git log -S "copy paste of deleted line/word" -- <file where it was deleted>
    
  2. Esaminare l'elenco dei commit restituito per individuare la modifica o l'eliminazione. Il primo commit è probabilmente quello che stai cercando. In caso contrario, scorri l'elenco finché non trovi il commit.

  3. Dopo aver identificato la modifica, ripristinala nel kernel o caricala su ACK e uniscila .