La Generic Kernel Image (GKI) riduce la frammentazione del kernel allineando con il kernel Linux upstream. Tuttavia, esistono motivi validi per cui alcune patch non possono essere accettate a monte ed esistono pianificazioni di prodotti che devono essere soddisfatti, quindi alcune patch vengono mantenute nel kernel comune (ACK) di Android. da cui viene creato il GKI.
Gli sviluppatori devono inviare le modifiche al codice upstream utilizzando Linux Kernel Mailing
Elenca (LKML) come prima scelta e invia le modifiche al codice alla richiesta ACK
android-mainline
ramo solo se esiste un valido motivo per cui l'upstream non
sono attuabili. Di seguito sono elencati alcuni esempi di motivi validi e di come gestirli.
La patch è stata inviata a LKML, ma non è stata accettata in tempo per un prodotto . Per gestire questa patch:
- Fornisci prove che la patch è stata inviata a LKML e commenti ricevuto per la patch o il tempo stimato entro il quale inviato a monte.
- Decidere una linea d’azione per ottenere la patch in ACK e farla approvare upstream, per poi rimuoverlo da ACK quando la versione upstream finale è stato unito a ACK.
La patch definisce
EXPORT_SYMBOLS_GPL()
per un modulo del fornitore, ma non può da inviare a monte perché non ci sono moduli in-tree che utilizzano quel . Per gestire questa patch, fornisci dettagli sul motivo per cui il modulo non può essere inviate a monte e le alternative prese in considerazione prima di applicarle richiesta.La patch non è abbastanza generica per l'upstream e non c'è tempo per eseguire il refactoring prima del rilascio di un prodotto. Per gestire questa patch, fornisci un tempo stimato entro il quale una patch sottoposta a refactoring viene inviata a monte (il patch non verrà accettata nella risposta ACK senza un piano di invio di un una patch a monte per la revisione).
La patch non può essere accettata dall'upstream perché... <inserire motivo qui>. Per gestire questa patch, contatta il team del kernel Android e lavorare con noi sulle opzioni per il refactoring della patch in modo che possa essere inviata per la revisione e l'accettazione a monte.
Esistono molte altre giustificazioni potenziali. Quando invii il tuo bug o il tuo patch, includi una giustificazione valida e prevedi un po' di iterazione e discussione. Riconosciamo che l'ACK contiene alcune patch, soprattutto di GKI mentre tutti stanno imparando a lavorare a monte, ma non riescono a rilassarsi le pianificazioni dei prodotti. I requisiti di upstream potrebbero diventare sempre più rigorosamente nel tempo.
Requisiti delle patch
Le patch devono essere conformi agli standard di codifica del kernel Linux descritti nella sezione
Albero del codice sorgente Linux,
sia che vengano inviati a monte
che a ACK. scripts/checkpatch.pl
lo script viene eseguito come parte del test pre-invio Gerrit, quindi eseguilo in anticipo per
assicurarsi che venga superato. Per eseguire lo script checkpatch con la stessa configurazione del
prima dell'invio, usa //build/kernel/static_analysis:checkpatch_presubmit
.
Per maggiori dettagli, vedi
build/kernel/kleaf/docs/checkpatch.md.
Patch ACK
Le patch inviate a ACK devono essere conformi agli standard di codifica del kernel Linux e
le linee guida per i contributi.
Devi includere un elemento Change-Id
nel messaggio di commit; se invii la patch a più rami (ad
ad esempio android-mainline
e android12-5.4
), devi utilizzare lo stesso
Change-Id
per tutte le istanze della patch.
Invia prima le patch a LKML per una revisione upstream. Se la patch è:
- Accettato a monte, viene unito automaticamente a
android-mainline
. - Non accettato a monte, invialo a
android-mainline
con un riferimento all'invio upstream o una spiegazione per il motivo inviate a LKML.
Dopo essere stata accettata a monte o in android-mainline
, la patch può essere
è stato eseguito il backporting all’ACK appropriato basato su LTS (come android12-5.4
e
android11-5.4
per le patch che risolvono il codice specifico per Android). Invio a
android-mainline
consente di testare i nuovi candidati di release upstream e
garantisce che la patch sia nel successivo ACK basato su LTS. Le eccezioni includono i casi
in cui viene eseguito il backport di una patch upstream in android12-5.4
(perché la patch
probabilmente si trova già in android-mainline
).
Patch upstream
Come specificato nel contributo linee guida, Le patch upstream destinate ai kernel ACK rientrano nei seguenti gruppi ( in ordine di probabilità di essere accettati).
UPSTREAM:
- È probabile che le patch scelte da "android-mainline" siano accettati in ACK se esiste un caso d'uso ragionevole.BACKPORT:
- Patch dell'upstream che non si selezionano in modo pulito e di cui hanno bisogno probabilità che la modifica venga accettata se esiste un uso ragionevole per verificare se è così.FROMGIT:
- Patch selezionate da un ramo del manutentore in preparazione per l'invio alla linea principale Linux potrebbero essere accettati se c'è un la scadenza del periodo di conservazione. Questi aspetti devono essere giustificati sia per i contenuti che per la pianificazione.FROMLIST:
- Patch che sono state inviate a LKML ma che non sono state ancora accettate in una filiale del gestore, è improbabile che vengano accettate, a meno che la giustificazione è abbastanza convincente da far sì che la patch venga accettata che arrivi o meno a Linux upstream (supponiamo che non accadrà). Là deve essere un problema associato alle patch diFROMLIST
per facilitare la discussione con il team Android kernel.
Patch specifiche per Android
Se non riesci a ottenere le modifiche richieste a monte, puoi provare a inviare
le patch out-of-tree
per eseguire il ACK direttamente. L'invio di patch out-of-tree richiede
di creare un problema nel reparto IT che cita la patch e la motivazione
non è possibile inviare la patch a monte (vedi l'elenco precedente per alcuni esempi).
Tuttavia, in alcuni casi il codice non può essere inviato a monte. Questi
vengono trattati come segue e devono seguire il contributo
linee guida
per le patch specifiche di Android ed essere contrassegnati con il prefisso ANDROID:
soggetto.
Modifiche a gki_defconfig
Tutte le modifiche di CONFIG
a gki_defconfig
devono essere applicate sia al gruppo 64 sia
versioni x86, a meno che CONFIG
non sia specifico per l'architettura. Per richiedere una modifica
a un'impostazione CONFIG
, crea un problema nell'IT per discutere della modifica. Qualsiasi
Modifica CONFIG
che interessa l'interfaccia modulo del kernel (KMI) dopo che
bloccato viene rifiutato. Nei casi in cui le richieste dei partner
impostazioni per una singola configurazione, risolviamo i conflitti
gli insetti correlati.
Codice che non esiste a monte
Le modifiche al codice già specifico di Android non possono essere inviate upstream. Ad esempio, anche se il driver raccoglitore viene mantenuto a monte, le modifiche alle caratteristiche di ereditarietà della priorità del driver binder non possono essere inviate upstream perché sono specifiche per Android. Spiega in modo esplicito il bug e applica una patch al motivo non può essere inviato a monte. Se possibile, dividi le patch in pezzi l'upstream e gli elementi specifici di Android che non possono essere inviati a monte per ridurre al minimo la quantità di codice out-of-tree mantenuta in ACK.
Altre modifiche in questa categoria sono aggiornamenti ai file di rappresentazione KMI, KMI
elenchi di simboli, gki_defconfig
, script di build o configurazione o altri script
che non esistono a monte.
Moduli esterni
Upstream Linux scoraggia attivamente il supporto per la creazione di moduli out-of-tree. Si tratta di una posizione ragionevole poiché i manutentori Linux non garantiscono sulle sorgenti nel kernel o sulla compatibilità binaria e non vuoi supportare il codice che non si trova nell'albero. Tuttavia, il GKI fa garanzie ABI per moduli del fornitore, assicurando che le interfacce KMI siano stabili per per tutta la durata di un kernel. Ci sono quindi una serie di modifiche per supportare accettati per la conferma ACK ma non per l'upstream.
Ad esempio, prendi in considerazione una patch che aggiunge macro EXPORT_SYMBOL_GPL()
nel punto in cui
e i moduli che utilizzano l'esportazione non sono
nell'albero di origine. Anche se devi tentare
per richiedere EXPORT_SYMBOL_GPL()
upstream e fornire un modulo che utilizza il
simbolo appena esportato, se esiste una giustificazione valida per il motivo per cui il modulo
non viene inviata upstream, puoi invece inviare la patch a ACK. Tu
includere la motivazione per cui il modulo non può essere riportato a monte nel
problema. Non richiedere la variante non GPL, EXPORT_SYMBOL()
.
Configurazioni nascoste
Alcuni moduli in-tree selezionano automaticamente configurazioni nascoste che non possono essere specificate
a gki_defconfig
. Ad esempio, CONFIG_SND_SOC_TOPOLOGY
è selezionato
automaticamente quando viene configurato CONFIG_SND_SOC_SOF=y
. Per soddisfare
la creazione di moduli fuori struttura, GKI include un meccanismo per abilitare le configurazioni nascoste.
Per abilitare una configurazione nascosta, aggiungi un'istruzione select
in init/Kconfig.gki
in modo che
viene selezionato automaticamente
in base alla configurazione del kernel CONFIG_GKI_HACKS_TO_FIX
.
che è abilitato in gki_defconfig
. Usa questo meccanismo solo per le configurazioni nascoste.
Se la configurazione non è nascosta, deve essere specificata in gki_defconfig
esplicitamente o come dipendenza.
Governatori caricabili
Per i framework kernel (ad esempio cpufreq
) che supportano regolatori caricabili,
può sostituire il governatore predefinito (ad esempio il governatore schedutil
di cpufreq
). Per
(come il quadro termico) che non supportano i governatori caricabili
o driver ma richiedono comunque un'implementazione specifica del fornitore, creare un problema
nell'IT e consultati con il team kernel Android.
Collaboreremo con te e con i manutentori upstream per aggiungere il supporto necessario.
Hook per i fornitori
Nelle versioni precedenti potevi aggiungere modifiche specifiche del fornitore direttamente nella del core del kernel. Ciò non è possibile con GKI 2.0 perché il codice specifico del prodotto deve essere implementato in moduli e non sarà accettato nei kernel principali a monte o in ACK. Per abilitare funzionalità a valore aggiunto che i partner fanno affidamento con un impatto minimo sul codice kernel principale, GKI accetta hook del fornitore che consentono di richiamare i moduli dal codice del kernel. Inoltre, le strutture di dati chiave possono essere riempite Campi di dati del fornitore disponibili per archiviare dati specifici del fornitore da implementare queste funzionalità.
Gli hook dei fornitori sono disponibili in due varianti (normale e limitato) che si basano su
tracepoint (non eventi di traccia) a cui possono essere associati i moduli del fornitore. Ad esempio:
anziché aggiungere una nuova funzione sched_exit()
per eseguire una contabilità nell'attività
i fornitori possono aggiungere un hook in do_exit()
a cui un modulo fornitore può essere collegato
per l'elaborazione. Un esempio di implementazione include i seguenti hook del fornitore.
- I normali hook del fornitore usano
DECLARE_HOOK()
per creare una funzione tracepoint con il nometrace_name
dovename
è l'identificatore univoco del traccia. Per convenzione, i normali nomi di hook del fornitore iniziano conandroid_vh
, quindi il nome dell'hooksched_exit()
saràandroid_vh_sched_exit
. - Sono necessari hook dei fornitori limitati per casi come gli hook dello scheduler in cui
la funzione collegata deve essere chiamata anche se la CPU è offline o richiede
un contesto non atomico. Gli hook dei fornitori limitati non possono essere scollegati, quindi i moduli
che si collegano a un hook con restrizioni non possono mai eseguire l'unload. Con restrizioni
I nomi degli hook dei fornitori iniziano con
android_rvh
.
Per aggiungere un hook del fornitore, segnala un problema nel team IT e invia le patch (come in tutte Patch specifiche per Android, deve esistere un problema e devi fornire giustificazione). Il supporto per gli hook dei fornitori è solo in ACK, quindi non inviarli patch per Linux upstream.
Aggiungere campi dei fornitori alle strutture
Puoi associare i dati dei fornitori alle strutture di dati chiave aggiungendo
android_vendor_data
utilizzando le macro ANDROID_VENDOR_DATA()
. Per
Ad esempio, per supportare le caratteristiche a valore aggiunto, aggiungi campi alle strutture come mostrato
nel seguente esempio di codice.
Per evitare potenziali conflitti tra i campi richiesti dai fornitori e dai campi
richiesti dagli OEM, gli OEM non devono mai utilizzare i campi dichiarati
ANDROID_VENDOR_DATA()
macro. Gli OEM devono invece usare ANDROID_OEM_DATA()
per dichiarare i campi android_oem_data
.
#include <linux/android_vendor.h>
...
struct important_kernel_data {
[all the standard fields];
/* Create vendor data for use by hook implementations. The
* size of vendor data is based on vendor input. Vendor data
* can be defined as single u64 fields like the following that
* declares a single u64 field named "android_vendor_data1" :
*/
ANDROID_VENDOR_DATA(1);
/*
* ...or an array can be declared. The following is equivalent to
* u64 android_vendor_data2[20]:
*/
ANDROID_VENDOR_DATA_ARRAY(2, 20);
/*
* SoC vendors must not use fields declared for OEMs and
* OEMs must not use fields declared for SoC vendors.
*/
ANDROID_OEM_DATA(1);
/* no further fields */
}
Definisci gli hook dei fornitori
Aggiungi hook del fornitore al codice kernel come tracepoint dichiarandoli utilizzando
DECLARE_HOOK()
o DECLARE_RESTRICTED_HOOK()
e dopo averle aggiunte al codice come
un tracepoint. Ad esempio, per aggiungere trace_android_vh_sched_exit()
al
funzione kernel do_exit()
esistente:
#include <trace/hooks/exit.h>
void do_exit(long code)
{
struct task_struct *tsk = current;
...
trace_android_vh_sched_exit(tsk);
...
}
Inizialmente, la funzione trace_android_vh_sched_exit()
verifica solo se qualcosa
in allegato. Tuttavia, se un modulo del fornitore registra un gestore utilizzando
register_trace_android_vh_sched_exit()
, viene chiamata la funzione registrata. La
il gestore deve essere a conoscenza del contesto relativo ai blocchi trattenuti, allo stato RCS e
altri fattori. L'hook deve essere definito in un file di intestazione nella sezione
Directory include/trace/hooks
.
Ad esempio, il seguente codice fornisce una possibile dichiarazione per
trace_android_vh_sched_exit()
nel file include/trace/hooks/exit.h
.
/* SPDX-License-Identifier: GPL-2.0 */
#undef TRACE_SYSTEM
#define TRACE_SYSTEM sched
#define TRACE_INCLUDE_PATH trace/hooks
#if !defined(_TRACE_HOOK_SCHED_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_HOOK_SCHED_H
#include <trace/hooks/vendor_hooks.h>
/*
* Following tracepoints are not exported in tracefs and provide a
* mechanism for vendor modules to hook and extend functionality
*/
struct task_struct;
DECLARE_HOOK(android_vh_sched_exit,
TP_PROTO(struct task_struct *p),
TP_ARGS(p));
#endif /* _TRACE_HOOK_SCHED_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
Per creare un'istanza delle interfacce necessarie per l'hook del fornitore, aggiungi il file di intestazione
con la dichiarazione hook in drivers/android/vendor_hooks.c
ed esportare
. Ad esempio, il seguente codice completa la dichiarazione del
android_vh_sched_exit()
gancio.
#ifndef __GENKSYMS__
/* struct task_struct */
#include <linux/sched.h>
#endif
#define CREATE_TRACE_POINTS
#include <trace/hooks/vendor_hooks.h>
#include <trace/hooks/exit.h>
/*
* Export tracepoints that act as a bare tracehook (i.e. have no trace
* event associated with them) to allow external modules to probe
* them.
*/
EXPORT_TRACEPOINT_SYMBOL_GPL(android_vh_sched_exit);
NOTA: le strutture di dati utilizzate all'interno della dichiarazione hook devono essere
completamente definite per garantire
la stabilità di ABI. In caso contrario, non è sicuro
dereferenzia i puntatori opachi o utilizzare lo struct in contesti di dimensioni. Includi
che fornisce la definizione completa di tali strutture di dati, dovrebbe andare all'interno
Sezione #ifndef __GENKSYMS__
di drivers/android/vendor_hooks.c
. L'intestazione
i file in include/trace/hooks
non devono includere il file di intestazione del kernel con
definizioni dei tipi per evitare modifiche CRC che infrangono l'KMI. Invece, inoltra
dichiarano i tipi.
Fissa agli hook del fornitore
Per utilizzare gli hook del fornitore, il modulo del fornitore deve registrare un gestore per l'hook
(in genere durante l'inizializzazione del modulo). Ad esempio, il seguente codice
mostra il gestore del modulo foo.ko
per trace_android_vh_sched_exit()
.
#include <trace/hooks/sched.h>
...
static void foo_sched_exit_handler(void *data, struct task_struct *p)
{
foo_do_exit_accounting(p);
}
...
static int foo_probe(..)
{
...
rc = register_trace_android_vh_sched_exit(foo_sched_exit_handler, NULL);
...
}
Usa hook del fornitore dai file di intestazione
Per utilizzare gli hook del fornitore dai file di intestazione, potresti dover aggiornare l'hook del fornitore
file di intestazione per non definire TRACE_INCLUDE_PATH
per evitare errori di build che indicano
impossibile trovare un file di intestazione dei punti di traccia. Ad esempio,
In file included from .../common/init/main.c:111:
In file included from .../common/include/trace/events/initcall.h:74:
.../common/include/trace/define_trace.h:95:10: fatal error: 'trace/hooks/initcall.h' file not found
95 | #include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:90:32: note: expanded from macro 'TRACE_INCLUDE'
90 | # define TRACE_INCLUDE(system) __TRACE_INCLUDE(system)
| ^~~~~~~~~~~~~~~~~~~~~~~
.../common/include/trace/define_trace.h:87:34: note: expanded from macro '__TRACE_INCLUDE'
87 | # define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:10:27: note: expanded from macro '__stringify'
10 | #define __stringify(x...) __stringify_1(x)
| ^~~~~~~~~~~~~~~~
.../common/include/linux/stringify.h:9:29: note: expanded from macro '__stringify_1'
9 | #define __stringify_1(x...) #x
| ^~
<scratch space>:14:1: note: expanded from here
14 | "trace/hooks/initcall.h"
| ^~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Per correggere questo tipo di errore di generazione, applica la correzione equivalente all'hook del fornitore che stai includendo. Per ulteriori informazioni, consulta https://r.android.com/3066703.
diff --git a/include/trace/hooks/mm.h b/include/trace/hooks/mm.h
index bc6de7e53d66..039926f7701d 100644
--- a/include/trace/hooks/mm.h
+++ b/include/trace/hooks/mm.h
@@ -2,7 +2,10 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM mm
+#ifdef CREATE_TRACE_POINTS
#define TRACE_INCLUDE_PATH trace/hooks
+#define UNDEF_TRACE_INCLUDE_PATH
+#endif
La definizione di UNDEF_TRACE_INCLUDE_PATH
indica a include/trace/define_trace.h
di
non definire TRACE_INCLUDE_PATH
dopo aver creato i punti di traccia.
Funzionalità principali del kernel
Se nessuna delle tecniche precedenti consente di implementare una funzionalità da un modulo, devi aggiungere la funzionalità come modifica specifica di Android all'interfaccia principale in un kernel. Crea un problema in Issue Tracker (IT) per avviare la conversazione.
Interfaccia di programmazione di un'applicazione utente (UAPI)
- File di intestazione UAPI. Modifiche a File di intestazione UAPI devono avvenire a monte, a meno che le modifiche non riguardino interfacce specifiche di Android. Usa file di intestazione specifici del fornitore per definire le interfacce tra i moduli del fornitore e il codice dello spazio utente del fornitore.
- nodi sysfs. Non aggiungere nuovi nodi sysfs al kernel GKI (come le aggiunte sono valide solo nei moduli del fornitore). sysfs utilizzati dal SoC- e librerie indipendenti dal dispositivo e codice Java che comprende il framework Android può essere modificato solo in modi compatibili e deve essere modificato a monte, se non sono nodi sysfs specifici di Android. Puoi creare i nodi sysfs specifici del fornitore che devono essere usati dallo spazio utente del fornitore. Per impostazione predefinita, l'accesso ai nodi sysfs per spazio utente è negato utilizzando SELinux. Tocca al di aggiungere le etichette SELinux appropriate per consentire l'accesso alle il software del fornitore.
- Nodi DebugFS. I moduli del fornitore possono definire nodi in
debugfs
per solo per il debug (poichédebugfs
non viene montato durante il normale funzionamento dell' dispositivo).