Développer le code du noyau pour GKI

L'image du noyau générique (GKI) réduit la fragmentation du noyau en alignant étroitement avec le noyau Linux en amont. Cependant, il existe des raisons valables certains correctifs ne peuvent pas être acceptés en amont, et des calendriers de produit doit être respectée. Par conséquent, certains correctifs sont conservés dans le noyau commun (ACK) d'Android. sources à partir desquelles le GKI est créé.

Les développeurs doivent soumettre les modifications de code en amont à l'aide du publipostage du noyau Linux. List (LKML) comme premier choix et envoyez les modifications de code à l'ACK Branche android-mainline uniquement lorsqu'il existe une bonne raison pour laquelle les flux en amont ne sont pas viable. Vous trouverez ci-dessous des exemples de motifs valides et la façon de les gérer.

  • Le correctif a été envoyé à LKML, mais n'a pas été accepté à temps pour un produit de sortie. Pour gérer ce correctif:

    • Fournissez la preuve que le correctif a été envoyé au LKML et envoyez vos commentaires le correctif reçu, ou la durée estimée du correctif envoyé en amont.
    • Décidez du plan d'action pour envoyer le correctif dans ACK, faites-le approuver en amont, puis de le retirer de l'ACK lorsque la version finale en amont est fusionné en ACK.
  • Le correctif définit EXPORT_SYMBOLS_GPL() pour un module de fournisseur, mais n'a pas pu être envoyé en amont, car aucun module "in-tree" ne l'utilise . Pour gérer ce correctif, indiquez pourquoi votre module ne peut pas être soumis en amont ainsi que les alternatives envisagées requête.

  • Le correctif n'est pas assez générique pour l'amont et il n'y a pas le temps de le refactoriser avant le lancement d’un produit. Pour gérer ce correctif, fournissez un l'heure estimée à laquelle un correctif refactorisé est envoyé en amont (le patch ne sera pas accepté dans ACK sans plan de soumission d’une refactorisation en amont pour examen).

  • Impossible d'accepter le correctif en amont pour les raisons suivantes : <insérer le motif ici>. Pour gérer ce correctif, contactez l'équipe chargée du noyau Android et travailler avec nous sur les options permettant de refactoriser le correctif afin qu'il puisse être envoyé. pour examen et acceptation en amont.

Il existe bien d'autres justifications potentielles. Lorsque vous signalez un bug ou un correctif, incluez une justification valide et attendez-vous à des itérations et à des discussions. Nous reconnaissons que l’ACK comporte des correctifs, en particulier au début les phases de GKI pendant que tout le monde apprend à travailler en amont, mais ne peut pas se détendre le calendrier du produit. Attendez-vous à ce que les exigences liées à l'augmentation rigoureux au fil du temps.

Exigences concernant les correctifs

Les correctifs doivent respecter les normes de codage du noyau Linux décrites dans les Arborescence source Linux, qu'ils soient envoyés en amont ou envoyés à l'accusé de réception (ACK). scripts/checkpatch.pl est exécuté dans le cadre des tests de pré-envoi Gerrit. Vous devez donc l'exécuter à l'avance pour pour garantir sa réussite. Pour exécuter le script checkpatch avec la même configuration que les tests avant envoi, utilisez //build/kernel/static_analysis:checkpatch_presubmit. Pour en savoir plus, consultez build/kernel/kleaf/docs/checkpatch.md.

Correctifs ACK

Les correctifs envoyés à l'ACK doivent respecter les normes de codage du noyau Linux et les consignes relatives aux contributions. Vous devez inclure un élément Change-Id dans le message de commit. si vous envoyez le correctif à plusieurs branches exemple, android-mainline et android12-5.4), vous devez utiliser la même Change-Id pour toutes les instances du correctif.

Envoyez d'abord les correctifs au LKML pour examen en amont. Si le correctif est:

  • Accepté en amont, il a été fusionné automatiquement dans android-mainline.
  • Refusé en amont, envoyez-le à android-mainline avec un une référence à l'envoi en amont ou une explication pour expliquer pourquoi envoyés au LKML.

Une fois qu'un correctif est accepté en amont ou dans android-mainline, il peut être rétroporté vers l'ACK basé sur LTS approprié (comme android12-5.4 et android11-5.4 pour les correctifs qui corrigent le code spécifique à Android). Envoi à android-mainline permet d'effectuer des tests avec de nouvelles versions candidates en amont et garantit que le correctif se trouve dans le prochain ACK basé sur LTS. à l'exception des cas où un correctif en amont est rétroporté vers android12-5.4 (car le correctif est figure probablement déjà dans android-mainline).

Correctifs en amont

Comme indiqué dans la contribution consignes, les correctifs en amont destinés aux noyaux ACK appartiennent aux groupes suivants (répertoriés par ordre de probabilité d'être acceptés).

  • UPSTREAM: : les correctifs sélectionnés dans "android-mainline" sont susceptibles d'être accepté en ACK dans le cas d’un cas d’utilisation raisonnable.
  • BACKPORT: : correctifs en amont qui ne sont pas soigneusement sélectionnés modification sont également susceptibles d'être acceptées s'il existe une utilisation raisonnable .
  • FROMGIT: : correctifs sélectionnés par une branche chargée de la maintenance en préparation pour l'envoi au réseau principal Linux peuvent être acceptés s'il y a les délais. Ces raisons doivent être justifiées aussi bien pour le contenu que pour le calendrier.
  • FROMLIST: : correctifs qui ont été envoyés à LKML, mais qui n'ont pas été acceptées dans une branche de gestion mais sont peu susceptibles d'être acceptées, à moins la justification est suffisamment convaincante pour que le correctif soit accepté s'il atterrit ou non sous Linux en amont (nous supposons que ce n'est pas le cas). Il y doit être un problème associé aux correctifs FROMLIST pour faciliter la discussion avec l'équipe du noyau Android.

Correctifs spécifiques à Android

Si vous n'arrivez pas à apporter les modifications requises en amont, vous pouvez essayer d'envoyer des correctifs hors de l’arborescence à ACK directement. L'envoi de correctifs hors arbre nécessite que vous créez un problème dans le service informatique qui cite le correctif et explique pourquoi le correctif ne peut pas être envoyé en amont (voir la liste précédente pour des exemples). Toutefois, dans certains cas, le code ne peut pas être envoyé en amont. Ces les cas d'utilisation sont traités comme suit et doivent respecter la contribution consignes pour les correctifs spécifiques à Android et être taguée avec le préfixe ANDROID: dans l'objet.

Modifications apportées à gki_defconfig

Toutes les modifications de CONFIG apportées à gki_defconfig doivent être appliquées à la fois au groupe arm64 et Versions x86, sauf si CONFIG est spécifique à l'architecture. Pour demander une modification sur un paramètre CONFIG, demandez à l'équipe informatique de discuter du changement. N'importe quelle valeur Modification de CONFIG qui affecte l'interface de module du noyau (KMI) après son figée est refusée. Dans les cas où les partenaires demandent d'une seule configuration, nous résolvons les conflits en discutant les bugs associés.

Code qui n'existe pas en amont

Les modifications du code déjà spécifique à Android ne peuvent pas être envoyées en amont. Par exemple, même si le pilote de liaison est géré en amont, les modifications aux caractéristiques d'héritage prioritaires du pilote de liaison ne peuvent pas être envoyées en amont car ils sont spécifiques à Android. Soyez explicite dans le bug et corrigez la cause du problème. ne peut pas être envoyé en amont. Si possible, divisez les correctifs en morceaux qui peuvent être envoyés en amont et des éléments spécifiques à Android qui ne peuvent pas être envoyés ; en amont afin de minimiser la quantité de code hors-arbre conservé dans ACK.

D'autres modifications de cette catégorie sont les mises à jour des fichiers de représentation KMI, KMI listes de symboles, gki_defconfig, scripts de compilation, configuration ou autres scripts qui n'existent pas en amont.

Modules hors arborescence

Linux en amont déconseille activement la création de modules hors arborescence. C'est une position raisonnable étant donné que les responsables de Linux n'offrent aucune garantie à propos de la compatibilité binaire ou source dans le noyau et ne voulez pas prendre en charge le code qui ne figure pas dans l'arborescence. Cependant, le GKI émet des garanties d'ABI pour modules fournisseurs, ce qui garantit la stabilité des interfaces KMI pour les durée de vie d’un noyau. Il existe donc une série de modifications pour le fournisseur d'assistance modules qui sont acceptables pour l'ACK, mais pas pour l'amont.

Prenons l'exemple d'un correctif qui ajoute des macros EXPORT_SYMBOL_GPL() aux endroits modules qui utilisent l'exportation ne figurent pas dans l'arborescence source. Bien que vous deviez essayer pour demander EXPORT_SYMBOL_GPL() en amont et fournir un module qui utilise le récemment exporté, si la raison pour laquelle le module n'est pas envoyé en amont, vous pouvez envoyer le correctif à ACK à la place. Toi vous devez justifier la raison pour laquelle le module ne peut pas être mis en place problème. (Ne demandez pas la variante non-GPL, EXPORT_SYMBOL().)

Configurations masquées

Certains modules "in-tree" sélectionnent automatiquement les configurations masquées qui ne peuvent pas être spécifiées dans gki_defconfig. Par exemple, CONFIG_SND_SOC_TOPOLOGY est sélectionné automatiquement lorsque CONFIG_SND_SOC_SOF=y est configuré. Pour accueillir création de modules hors arborescence, GKI inclut un mécanisme permettant d'activer les configurations masquées.

Pour activer une configuration masquée, ajoutez une instruction select dans init/Kconfig.gki afin qu'elle est automatiquement sélectionné en fonction de la configuration du noyau CONFIG_GKI_HACKS_TO_FIX, qui est activé dans gki_defconfig. N'utilisez ce mécanisme que pour les configurations masquées. Si la configuration n'est pas masquée, elle doit être spécifiée dans gki_defconfig explicitement ou en tant que dépendance.

Gouverneurs chargeables

Pour les frameworks de noyau (tels que cpufreq) compatibles avec les gouverneurs chargeables, vous peut remplacer le gouverneur par défaut (tel que le gouverneur schedutil de cpufreq). Pour (par exemple, l'infrastructure thermique) qui ne sont pas compatibles avec les gouverneurs chargeables ou pilotes, mais nécessitant une mise en œuvre spécifique au fournisseur, créez un problème au service informatique et consultez l'équipe du noyau Android.

Nous collaborerons avec vous et les responsables de la maintenance en amont pour ajouter la prise en charge nécessaire.

Hooks des fournisseurs

Dans les versions précédentes, vous pouviez ajouter des modifications spécifiques au fournisseur directement dans la noyau. Cela n'est pas possible avec GKI 2.0, car le code spécifique au produit doit être implémentée dans des modules et ne sera pas acceptée dans les noyaux en amont ou dans ACK. Pour proposer des fonctionnalités à valeur ajoutée dont dépendent les partenaires, avec un impact minimal sur le code central du noyau, GKI accepte les hooks de fournisseur qui permettent d'appeler des modules du code du noyau. De plus, les structures de données clés peuvent être remplies champs de données de fournisseur disponibles pour stocker des données spécifiques aux fournisseurs à implémenter ces fonctionnalités.

Il existe deux variantes des accroches de fournisseurs (normales et limitées), basées sur Points de trace (et non les événements de trace) auxquels les modules du fournisseur peuvent s'associer. Par exemple : au lieu d'ajouter une nouvelle fonction sched_exit() pour effectuer une traçabilité au niveau de la tâche les fournisseurs peuvent ajouter un hook dans do_exit() qu'un module de fournisseur peut associer pour traitement. Un exemple d'implémentation inclut les hooks de fournisseur suivants.

  • Les hooks de fournisseur normaux utilisent DECLARE_HOOK() pour créer une fonction tracepoint nommée trace_name, où name est l'identifiant unique de traceur. Par convention, les noms de hook de fournisseur normaux commencent par android_vh. le nom du hook sched_exit() serait android_vh_sched_exit.
  • Des hooks de fournisseur restreints sont nécessaires dans les cas, par exemple, pour les hooks de planificateur. la fonction associée doit être appelée même si le processeur est hors connexion ou nécessite dans un contexte non atomique. Les hooks de fournisseur restreints ne peuvent pas être dissociés, donc les modules qui s'attachent à un crochet limité ne peuvent jamais être déchargés. Limité Les noms des hook de fournisseur commencent par android_rvh.

Pour ajouter une accroche de fournisseur, signalez un problème au service informatique et envoyez des correctifs (comme Correctifs spécifiques à Android, un problème doit exister et vous devez fournir justification). La prise en charge des hooks de fournisseur ne se fait qu'en ACK. N'envoyez donc pas ces des correctifs à Linux en amont.

Ajouter des champs de fournisseur aux structures

Vous pouvez associer des données de fournisseurs à des structures de données clés en ajoutant Champs android_vendor_data à l'aide des macros ANDROID_VENDOR_DATA(). Pour Par exemple, pour accepter des caractéristiques à valeur ajoutée, ajoutez des champs aux structures comme indiqué. dans l'exemple de code suivant.

Pour éviter les conflits potentiels entre les champs nécessaires aux fournisseurs et les champs requis par les OEM, ils ne doivent jamais utiliser de champs déclarés via ANDROID_VENDOR_DATA(). Les OEM doivent utiliser ANDROID_OEM_DATA() à la place. pour déclarer les champs 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 */
}

Définir les hooks de fournisseur

Ajoutez des hooks de fournisseur au code du noyau en tant que tracepoints en les déclarant à l'aide de DECLARE_HOOK() ou DECLARE_RESTRICTED_HOOK(), puis en les ajoutant au code en tant que un point de trace. Par exemple, pour ajouter trace_android_vh_sched_exit() au fonction de noyau do_exit() existante:

#include <trace/hooks/exit.h>
void do_exit(long code)
{
    struct task_struct *tsk = current;
    ...
    trace_android_vh_sched_exit(tsk);
    ...
}

Au départ, la fonction trace_android_vh_sched_exit() ne vérifie que si quelque chose est jointe. Toutefois, si un module "provider" enregistre un gestionnaire à l'aide de register_trace_android_vh_sched_exit(), la fonction enregistrée est appelée. La le gestionnaire doit connaître le contexte concernant les verrouillages de ce type, l'état RCS et d'autres facteurs. Le hook doit être défini dans un fichier d'en-tête dans la Répertoire include/trace/hooks.

Par exemple, le code suivant donne une déclaration possible pour trace_android_vh_sched_exit() dans le fichier 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>

Pour instancier les interfaces requises pour le hook de fournisseur, ajoutez le fichier d'en-tête avec la déclaration de hook vers drivers/android/vendor_hooks.c et exporter symboles. Par exemple, le code suivant complète la déclaration du android_vh_sched_exit() crochet.

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

REMARQUE: Les structures de données utilisées dans la déclaration de hook doivent être entièrement définie pour garantir la stabilité de l'ABI. Sinon, il est dangereux de déréférencer les pointeurs opaques ou utiliser le struct dans des contextes dimensionnés. L'inclusion qui fournit la définition complète de ces structures de données, doit se trouver Section #ifndef __GENKSYMS__ sur drivers/android/vendor_hooks.c. L'en-tête les fichiers dans include/trace/hooks ne doivent pas inclure le fichier d'en-tête du noyau avec le les définitions de type pour éviter les modifications du CRC qui rompent le KMI. Transférer plutôt déclarer les types.

Associer aux hooks de fournisseur

Pour utiliser des hooks de fournisseur, le module du fournisseur doit enregistrer un gestionnaire pour le hook. (généralement effectuée lors de l'initialisation du module). Par exemple, le code suivant affiche le gestionnaire du module foo.ko pour 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);
    ...
}

Utiliser des hooks de fournisseur à partir des fichiers d'en-tête

Pour utiliser des hooks de fournisseur à partir des fichiers d'en-tête, vous devrez peut-être le mettre à jour d'en-tête pour annuler la définition de TRACE_INCLUDE_PATH afin d'éviter les erreurs de compilation indiquant un fichier d'en-tête de point de trace est introuvable. Par exemple :

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.

Pour corriger ce type d'erreur de compilation, appliquez le correctif équivalent au hook de fournisseur. que vous incluez. Pour en savoir plus, consultez 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

Définir UNDEF_TRACE_INCLUDE_PATH indique à include/trace/define_trace.h de annulez la définition de TRACE_INCLUDE_PATH après avoir créé les points de trace.

Principales fonctionnalités du noyau

Si aucune des techniques précédentes ne vous permet d'implémenter une fonctionnalité à partir d'un module, vous devez ajouter la fonctionnalité en tant que modification spécifique à Android dans noyau. Créez un problème dans l'outil de suivi des problèmes (en informatique) pour engager la conversation.

Interface de programmation d'application utilisateur (UAPI)

  • Fichiers d'en-tête UAPI. Modifications apportées à Fichiers d'en-tête UAPI doivent avoir lieu en amont, sauf si les modifications concernent des interfaces spécifiques à Android. Utiliser des fichiers d'en-tête spécifiques au fournisseur pour définir les interfaces entre les modules du fournisseur et le code de l'espace utilisateur du fournisseur.
  • nœuds sysfs. N'ajoutez pas de nouveaux nœuds sysfs au noyau GKI (de tels ajouts ne sont valides que dans les modules de fournisseurs). nœuds sysfs utilisés par le SoC et des bibliothèques indépendantes de l'appareil et du code Java qui comprend le framework Android. ne peuvent être modifiés que d'une manière compatible et doivent être modifiés en amont si ce ne sont pas des nœuds sysfs spécifiques à Android. Vous pouvez créer des nœuds sysfs spécifiques au fournisseur à utiliser par l’espace utilisateur du fournisseur. Par défaut, l'accès aux nœuds sysfs par l'espace utilisateur est refusé en utilisant SELinux. C'est à vous pour ajouter les étiquettes SELinux appropriées afin d'autoriser l'accès le logiciel du fournisseur.
  • Nœuds DebugFS Les modules des fournisseurs peuvent définir des nœuds dans debugfs pour débogage uniquement (car debugfs n'est pas installé en fonctionnement normal de la appareil).