Modules de noyau chargeables

Dans le cadre des exigences du noyau de module introduites dans Android 8.0, tous les noyaux de système sur puce (SoC) doivent prendre en charge les modules de noyau chargeables.

Options de configuration du noyau

Pour prendre en charge les modules de noyau chargeables, android-base.config dans tous les noyaux courants inclut les options de configuration de noyau suivantes (ou leur équivalent de version de noyau) :

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y

Tous les noyaux de périphériques doivent activer ces options. Les modules du noyau doivent également prendre en charge le déchargement et le rechargement autant que possible.

Signature des modules

La signature de module n'est pas prise en charge pour les modules du fournisseur GKI. Sur les appareils requis pour prendre en charge le démarrage vérifié, Android exige que les modules du noyau se trouvent dans les partitions sur lesquelles dm-verity est activé. Cela supprime le besoin de signer des modules individuels pour leur authenticité. Android 13 a introduit le concept de modules GKI. Les modules GKI utilisent l'infrastructure de signature au moment de la construction du noyau pour différencier GKI des autres modules au moment de l'exécution. Les modules non signés sont autorisés à se charger à condition qu'ils utilisent uniquement les symboles apparaissant sur la liste verte ou fournis par d'autres modules non signés. Pour faciliter la signature des modules GKI pendant la construction de GKI à l'aide de la paire de clés de construction du noyau, la configuration du noyau GKI a activé CONFIG_MODULE_SIG_ALL=y . Pour éviter de signer des modules non GKI lors de la construction du noyau de périphérique, vous devez ajouter # CONFIG_MODULE_SIG_ALL is not set dans le cadre des fragments de configuration de votre noyau.

Emplacements des fichiers

Bien qu'Android 7.x et versions antérieures n'imposent pas les modules du noyau (et incluent la prise en charge de insmod et rmmod ), Android 8.x et versions ultérieures recommandent l'utilisation de modules de noyau dans l'écosystème. Le tableau suivant montre la prise en charge potentielle des périphériques spécifiques à la carte requise dans trois modes de démarrage Android.

Mode d'amorçage Stockage Afficher Clavier Batterie PMIC Écran tactile NFC, Wi-Fi,
Bluetooth
Capteurs Caméra
Récupération
Chargeur
Android

En plus de la disponibilité dans les modes de démarrage Android, les modules du noyau peuvent également être classés selon leur propriétaire (le fournisseur SoC ou l'ODM). Si des modules du noyau sont utilisés, les exigences relatives à leur placement dans le système de fichiers sont les suivantes :

  • Tous les noyaux doivent avoir une prise en charge intégrée pour le démarrage et le montage des partitions.
  • Les modules du noyau doivent être chargés à partir d'une partition en lecture seule.
  • Pour les périphériques devant avoir un démarrage vérifié, les modules du noyau doivent être chargés à partir des partitions vérifiées.
  • Les modules du noyau ne doivent pas être situés dans /system .
  • Les modules GKI requis pour le périphérique doivent être chargés à partir de /system/lib/modules qui est un lien symbolique vers /system_dlkm/lib/modules .
  • Les modules de noyau du fournisseur SoC requis pour les modes Android ou Charger complets doivent être situés dans /vendor/lib/modules .
  • Si une partition ODM existe, les modules du noyau de l'ODM requis pour les modes Android ou Charger complets doivent être situés dans /odm/lib/modules . Sinon, ces modules doivent être situés dans /vendor/lib/modules .
  • Les modules de noyau du fournisseur SoC et d'ODM requis pour le mode de récupération doivent être situés dans les ramfs de récupération à l' /lib/modules .
  • Les modules de noyau requis pour le mode de récupération et les modes Android ou Charger complets doivent exister à la fois dans les rootfs de récupération et dans les partitions /vendor ou /odm (comme décrit ci-dessus).
  • Les modules du noyau utilisés en mode de récupération ne doivent pas dépendre des modules situés uniquement dans /vendor ou /odm , car ces partitions ne sont pas montées en mode de récupération.
  • Les modules du noyau du fournisseur SoC ne devraient pas dépendre des modules du noyau ODM.

Sous Android 7.x et versions antérieures, les partitions /vendor et /odm ne sont pas montées prématurément. Dans Android 8.x et versions ultérieures, pour rendre possible le chargement de modules à partir de ces partitions, des dispositions ont été prises pour monter les partitions plus tôt pour les appareils non-A/B et A/B . Cela garantit également que les partitions sont montées en modes Android et Charger.

Prise en charge du système de construction Android

Dans BoardConfig.mk , la version Android définit une variable BOARD_VENDOR_KERNEL_MODULES qui fournit une liste complète des modules du noyau destinés à l'image du fournisseur. Les modules répertoriés dans cette variable sont copiés dans l'image du fournisseur dans /lib/modules/ et, après avoir été montés sous Android, apparaissent dans /vendor/lib/modules (conformément aux exigences ci-dessus). Exemple de configuration des modules du noyau du fournisseur :

vendor_lkm_dir := device/$(vendor)/lkm-4.x
BOARD_VENDOR_KERNEL_MODULES := \
  $(vendor_lkm_dir)/vendor_module_a.ko \
  $(vendor_lkm_dir)/vendor_module_b.ko \
  $(vendor_lkm_dir)/vendor_module_c.ko

Dans cet exemple, un référentiel prédéfini de module de noyau de fournisseur est mappé dans la version Android à l'emplacement indiqué ci-dessus.

L'image de récupération peut contenir un sous-ensemble des modules du fournisseur. La version Android définit la variable BOARD_RECOVERY_KERNEL_MODULES pour ces modules. Exemple:

vendor_lkm_dir := device/$(vendor)/lkm-4.x
BOARD_RECOVERY_KERNEL_MODULES := \
  $(vendor_lkm_dir)/vendor_module_a.ko \
  $(vendor_lkm_dir)/vendor_module_b.ko

La version Android se charge d'exécuter depmod pour générer les fichiers modules.dep requis dans /vendor/lib/modules et /lib/modules ( recovery ramfs ).

Chargement et versionnage des modules

Chargez tous les modules du noyau en un seul passage depuis init.rc* en appelant modprobe -a . Cela évite la surcharge liée à l'initialisation répétée de l'environnement d'exécution C pour le binaire modprobe . L'événement early-init peut être modifié pour invoquer modprobe :

on early-init
    exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d \
        /vendor/lib/modules module_a module_b module_c ...

Généralement, un module du noyau doit être compilé avec le noyau avec lequel le module doit être utilisé (sinon le noyau refuse de charger le module). CONFIG_MODVERSIONS fournit une solution de contournement en détectant les ruptures dans l'interface binaire de l'application (ABI). Cette fonctionnalité calcule une valeur de contrôle de redondance cyclique (CRC) pour le prototype de chaque symbole exporté dans le noyau et stocke les valeurs dans le cadre du noyau ; pour les symboles utilisés par un module noyau, les valeurs sont également stockées dans le module noyau. Lorsque le module est chargé, les valeurs des symboles utilisés par le module sont comparées à celles du noyau. Si les valeurs correspondent, le module est chargé ; sinon, la charge échoue.

Pour activer la mise à jour de l'image du noyau séparément de l'image du fournisseur, activez CONFIG_MODVERSIONS . Cela permet d'effectuer de petites mises à jour du noyau (telles que des corrections de bogues de LTS) tout en maintenant la compatibilité avec les modules de noyau existants dans l'image du fournisseur. Cependant, CONFIG_MODVERSIONS ne résout pas à lui seul une panne ABI. Si le prototype d'un symbole exporté dans le noyau change, soit en raison d'une modification de la source, soit parce que la configuration du noyau a changé, cela rompt la compatibilité avec les modules du noyau qui utilisent ce symbole. Dans de tels cas, le module noyau doit être recompilé.

Par exemple, la structure task_struct dans le noyau (définie dans include/linux/sched.h ) contient de nombreux champs inclus conditionnellement en fonction de la configuration du noyau. Le champ sched_info est présent uniquement si CONFIG_SCHED_INFO est activé (ce qui se produit lorsque CONFIG_SCHEDSTATS ou CONFIG_TASK_DELAY_ACCT sont activés). Si ces options de configuration changent d'état, la disposition de la structure task_struct change et toutes les interfaces exportées du noyau qui utilisent task_struct sont modifiées (par exemple, set_cpus_allowed_ptr dans kernel/sched/core.c ). La compatibilité avec les modules de noyau précédemment compilés qui utilisent ces interfaces est interrompue, nécessitant la reconstruction de ces modules avec la nouvelle configuration du noyau.

Pour plus de détails sur CONFIG_MODVERSIONS , reportez-vous à la documentation dans l'arborescence du noyau à Documentation/kbuild/modules.rst .