Conformément aux 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 pouvant être chargés.
Options de configuration du noyau
Pour prendre en charge les modules de kernel pouvant être chargés, android-base.config dans tous les noyaux courants inclut les options de configuration du kernel suivantes (ou leur équivalent de version du kernel):
CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y
Tous les noyaux d'appareil doivent activer ces options. Les modules du noyau doivent également être compatibles avec le déchargement et le rechargement dans la mesure du possible.
Signature de module
La signature de module n'est pas prise en charge pour les modules de fournisseurs GKI. Sur les appareils qui doivent prendre en charge le démarrage validé, Android exige que les modules du noyau se trouvent dans les partitions pour lesquelles dm-verity est activé. Cela évite d'avoir à 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 compilation du noyau pour différencier les GKI des autres modules au moment de l'exécution.
Les modules non signés sont autorisés à se charger tant qu'ils n'utilisent que des symboles figurant sur la liste d'autorisation ou fournis par d'autres modules non signés.
Pour faciliter la signature des modules GKI lors de la compilation GKI à l'aide de la paire de clés de compilation du kernel, la configuration du kernel GKI a activé CONFIG_MODULE_SIG_ALL=y
.
Pour éviter de signer des modules autres que GKI lors de la compilation du kernel de l'appareil, vous devez ajouter # CONFIG_MODULE_SIG_ALL is not set
dans vos fragments de configuration du kernel.
Emplacements de fichiers
Bien qu'Android 7.x et versions antérieures n'interdisent pas les modules de kernel (et incluent la prise en charge de insmod
et rmmod
), Android 8.x et versions ultérieures recommandent l'utilisation de modules de kernel dans l'écosystème. Le tableau suivant présente la prise en charge potentielle des périphériques spécifiques à la carte requise pour trois modes de démarrage Android.
Mode de démarrage | Stockage | Écran | Clavier | Batterie | PMIC | Écran tactile | NFC, Wi-Fi, Bluetooth |
Capteurs | Appareil photo |
---|---|---|---|---|---|---|---|---|---|
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 en fonction de leur propriétaire (le fournisseur de SoC ou l'OEM). Si des modules de kernel sont utilisés, les exigences concernant leur emplacement dans le système de fichiers sont les suivantes:
- Tous les noyaux doivent être compatibles avec 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 appareils nécessitant un démarrage validé, les modules du noyau doivent être chargés à partir de partitions validées.
- Les modules du noyau ne doivent pas se trouver dans
/system
. - Les modules GKI requis pour l'appareil doivent être chargés à partir de
/system/lib/modules
, qui est un lien symbolique vers/system_dlkm/lib/modules
. - Les modules du noyau du fournisseur de SoC requis pour les modes Android complet ou Chargeur doivent se trouver dans
/vendor/lib/modules
. - Si une partition ODM existe, les modules du noyau de l'ODM requis pour les modes Android complet ou Chargeur doivent se trouver dans
/odm/lib/modules
. Sinon, ces modules doivent se trouver dans/vendor/lib/modules
. - Les modules du noyau du fournisseur de SoC et de l'ODM requis pour le mode de récupération doivent se trouver dans le
ramfs
de récupération à/lib/modules
. - Les modules du noyau requis pour le mode de récupération et les modes Android complet ou Chargeur doivent exister à la fois dans le
rootfs
de récupération et dans les partitions/vendor
ou/odm
(comme décrit ci-dessus). - Les modules de kernel utilisés en mode Récupération ne doivent pas dépendre de modules situés uniquement dans
/vendor
ou/odm
, car ces partitions ne sont pas montées en mode Récupération. - Les modules de kernel du fournisseur de SoC ne doivent pas dépendre des modules de kernel de l'ODM.
Dans Android 7.x et versions antérieures, les partitions /vendor
et /odm
ne sont pas montées à l'avance. Sous Android 8.x et versions ultérieures, pour permettre le chargement de modules à partir de ces partitions, des dispositions ont été prises pour monter les partitions à l'avance à la fois pour les appareils non A/B et A/B. Cela garantit également que les partitions sont montées en mode Android et en mode Chargeur.
Compatibilité avec le système de compilation Android
Dans BoardConfig.mk
, le build Android définit une variable BOARD_VENDOR_KERNEL_MODULES
qui fournit la liste complète des modules du kernel destinés à l'image du fournisseur. Les modules listés dans cette variable sont copiés dans l'image du fournisseur à /lib/modules/
et, après avoir été installés dans 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 dépôt précompilé de module de kernel du fournisseur est mappé dans le build Android à l'emplacement indiqué ci-dessus.
L'image de récupération peut contenir un sous-ensemble des modules du fournisseur. La compilation 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 compilation Android s'occupe d'exécuter depmod
pour générer les fichiers modules.dep
requis dans /vendor/lib/modules
et /lib/modules
(recovery ramfs
).
Chargement et gestion des versions des modules
Chargez tous les modules du noyau en une seule fois à partir de init.rc*
en appelant modprobe -a
. Cela évite d'avoir à initialiser à plusieurs reprises l'environnement d'exécution C pour le binaire modprobe
. L'événement early-init
peut être modifié pour appeler modprobe
:
on early-init exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d \ /vendor/lib/modules module_a module_b module_c ...
En règle générale, un kernel module doit être compilé avec le kernel avec lequel il doit être utilisé (sinon, le kernel refuse de charger le module).
CONFIG_MODVERSIONS
fournit une solution de contournement en détectant les pannes 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 noyau. Pour les symboles utilisés par un module de noyau, les valeurs sont également stockées dans le module de 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'apporter de petites mises à jour du kernel (telles que des corrections de bugs à partir de LTS) tout en conservant la compatibilité avec les modules de kernel existants dans l'image du fournisseur. Toutefois, CONFIG_MODVERSIONS
ne corrige pas une erreur ABI par lui-même. Si le prototype d'un symbole exporté dans le noyau change, soit en raison d'une modification de la source, soit en raison d'une modification de la configuration du noyau, la compatibilité avec les modules du noyau qui utilisent ce symbole est rompue. Dans ce cas, le kernel module doit être recompilé.
Par exemple, la structure task_struct
du noyau (définie dans include/linux/sched.h
) contient de nombreux champs inclus de manière conditionnelle en fonction de la configuration du noyau. Le champ sched_info
n'est présent que 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 mise en page 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, ce qui nécessite de recompiler ces modules avec la nouvelle configuration du noyau.
Pour en savoir plus sur CONFIG_MODVERSIONS
, consultez la documentation dans l'arborescence du kernel à l'adresse Documentation/kbuild/modules.rst
.