Ladebare Kernelmodule

Im Rahmen der in Android 8.0 eingeführten Anforderungen an den Modul-Kernel müssen alle SoC-Kernel (System-on-Chip) ladbare Kernelmodule unterstützen.

Kernel-Konfigurationsoptionen

Zur Unterstützung ladbarer Kernelmodule enthält android-base.config in allen gängigen Kerneln die folgenden Kernel-Konfigurationsoptionen (oder deren Kernel-Versionsäquivalente):

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y

Diese Optionen müssen für alle Gerätekerne aktiviert sein. Kernelmodule sollten nach Möglichkeit auch das Entladen und Neuladen unterstützen.

Modulsignatur

Die Modulsignatur wird für GKI-Anbietermodule nicht unterstützt. Auf Geräten, die den sicheren Start unterstützen müssen, müssen sich die Kernelmodule in den Partitionen befinden, für die dm-verity aktiviert ist. Dadurch müssen einzelne Module nicht mehr auf Authentizität signiert werden. Mit Android 13 wurde das Konzept der GKI-Module eingeführt. GKI-Module verwenden die Signaturinfrastruktur der Buildzeit des Kernels, um bei der Laufzeit zwischen GKI- und anderen Modulen zu unterscheiden. Unsignierte Module dürfen geladen werden, solange sie nur Symbole verwenden, die auf der Zulassungsliste stehen oder von anderen unsignierten Modulen bereitgestellt werden. Um die Signatur von GKI-Modulen während des GKI-Builds mit dem Buildzeit-Schlüsselpaar des Kernels zu ermöglichen, wurde in der GKI-Kernelkonfiguration CONFIG_MODULE_SIG_ALL=y aktiviert. Damit bei der Erstellung des Gerätekernels keine nicht GKI-Module signiert werden, müssen Sie # CONFIG_MODULE_SIG_ALL is not set als Teil Ihrer Kernel-Konfigurationsfragmente hinzufügen.

Dateispeicherorte

Unter Android 7.x und niedriger sind Kernelmodule zwar nicht vorgeschrieben (und es wird Unterstützung für insmod und rmmod angeboten), unter Android 8.x und höher wird jedoch die Verwendung von Kernelmodulen im Android-System empfohlen. In der folgenden Tabelle sind die möglichen gerätespezifischen Peripheriegeräte aufgeführt, die für die drei Android-Bootmodi erforderlich sind.

Bootmodus Speicher Anzeige Wähltastatur Akku PMIC Touchscreen NFC, WLAN,
Bluetooth
Sensoren Kamera
Recovery
Ladegerät
Android

Neben der Verfügbarkeit in den Android-Bootmodi können Kernelmodule auch nach dem Eigentümer (SoC-Anbieter oder ODM) kategorisiert werden. Wenn Kernelmodule verwendet werden, gelten für deren Platzierung im Dateisystem folgende Anforderungen:

  • Alle Kernel sollten eine integrierte Unterstützung für das Booten und das Bereitstellen von Partitionen haben.
  • Kernelmodule müssen von einer schreibgeschützten Partition geladen werden.
  • Bei Geräten, für die ein bestätigter Boot erforderlich ist, sollten Kernelmodule aus bestätigten Partitionen geladen werden.
  • Kernelmodule sollten sich nicht in /system befinden.
  • Die für das Gerät erforderlichen GKI-Module sollten von /system/lib/modules geladen werden, einem symbolischen Link zu /system_dlkm/lib/modules.
  • Kernelmodule des SoC-Anbieters, die für den vollständigen Android-Betrieb oder Lademodi erforderlich sind, sollten sich in /vendor/lib/modules befinden.
  • Wenn eine ODM-Partition vorhanden ist, sollten sich die Kernelmodule des ODM, die für den vollständigen Android- oder Lademodus erforderlich sind, in /odm/lib/modules befinden. Andernfalls sollten sich diese Module in /vendor/lib/modules befinden.
  • Kernelmodule vom SoC-Anbieter und ODM, die für den Wiederherstellungsmodus erforderlich sind, sollten sich in der Wiederherstellungspartition ramfs unter /lib/modules befinden.
  • Kernelmodule, die sowohl für den Wiederherstellungsmodus als auch für den vollständigen Android- oder Lademodus erforderlich sind, müssen sowohl in der Wiederherstellungspartition rootfs als auch in der Partition /vendor oder /odm vorhanden sein (wie oben beschrieben).
  • Kernelmodule, die im Wiederherstellungsmodus verwendet werden, dürfen nicht von Modulen abhängen, die sich nur in /vendor oder /odm befinden, da diese Partitionen im Wiederherstellungsmodus nicht bereitgestellt werden.
  • Kernelmodule von SoC-Anbietern sollten nicht von ODM-Kernelmodulen abhängen.

Unter Android 7.x und niedriger werden die Partitionen /vendor und /odm nicht frühzeitig bereitgestellt. Unter Android 8.x und höher werden Partitionen sowohl für Nicht-A/B- als auch für A/B-Geräte frühzeitig bereitgestellt, damit das Laden von Modulen aus diesen Partitionen möglich ist. So wird auch sichergestellt, dass die Partitionen sowohl im Android- als auch im Lademodus bereitgestellt werden.

Unterstützung für Android-Build-System

In BoardConfig.mk definiert der Android-Build eine BOARD_VENDOR_KERNEL_MODULES-Variable, die eine vollständige Liste der Kernelmodule enthält, die für das Anbieterimage vorgesehen sind. Die in dieser Variablen aufgeführten Module werden in das Anbieterimage unter /lib/modules/ kopiert und nach dem Bereitstellen in Android unter /vendor/lib/modules angezeigt (gemäß den oben genannten Anforderungen). Beispielkonfiguration der Kernelmodule des Anbieters:

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

In diesem Beispiel wird ein vorkonfiguriertes Repository für ein Kernelmodul eines Anbieters dem Android-Build an dem oben aufgeführten Speicherort zugeordnet.

Das Wiederherstellungsimage kann eine Teilmenge der Anbietermodule enthalten. Der Android-Build definiert die Variable BOARD_RECOVERY_KERNEL_MODULES für diese Module. Beispiel:

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

Beim Android-Build wird depmod ausgeführt, um die erforderlichen modules.dep-Dateien in /vendor/lib/modules und /lib/modules (recovery ramfs) zu generieren.

Modulladen und -versionierung

Laden Sie alle Kernelmodule in einem Durchlauf von init.rc*, indem Sie modprobe -a aufrufen. So wird der Overhead vermieden, der durch wiederholtes Initialisieren der C-Laufzeitumgebung für das modprobe-Binärprogramm entsteht. Das Ereignis early-init kann so geändert werden, dass modprobe aufgerufen wird:

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

Normalerweise muss ein Kernelmodul mit dem Kernel kompiliert werden, mit dem es verwendet werden soll. Andernfalls lädt der Kernel das Modul nicht. CONFIG_MODVERSIONS bietet eine Lösung, indem Unterbrechungen in der Application Binary Interface (ABI) erkannt werden. Diese Funktion berechnet einen CRC-Wert (Cyclic Redundancy Check) für den Prototyp jedes exportierten Symbols im Kernel und speichert die Werte als Teil des Kernels. Bei Symbolen, die von einem Kernelmodul verwendet werden, werden die Werte auch im Kernelmodul gespeichert. Beim Laden des Moduls werden die Werte für die vom Modul verwendeten Symbole mit denen im Kernel verglichen. Wenn die Werte übereinstimmen, wird das Modul geladen. Andernfalls schlägt das Laden fehl.

Wenn Sie das Kernel-Image unabhängig vom Anbieter-Image aktualisieren möchten, aktivieren Sie CONFIG_MODVERSIONS. So können kleine Updates am Kernel (z. B. Fehlerkorrekturen aus LTS) vorgenommen werden, während die Kompatibilität mit vorhandenen Kernelmodulen im Anbieter-Image erhalten bleibt. CONFIG_MODVERSIONS behebt jedoch nicht automatisch eine ABI-Unterbrechung. Wenn sich der Prototyp eines exportierten Symbols im Kernel ändert, entweder aufgrund einer Änderung der Quelle oder aufgrund einer Änderung der Kernelkonfiguration, wird die Kompatibilität mit Kernelmodulen, die dieses Symbol verwenden, aufgehoben. In solchen Fällen muss das Kernelmodul neu kompiliert werden.

Die task_struct-Struktur im Kernel (definiert in include/linux/sched.h) enthält beispielsweise viele Felder, die je nach Kernelkonfiguration bedingt eingeschlossen sind. Das Feld sched_info ist nur vorhanden, wenn CONFIG_SCHED_INFO aktiviert ist. Das ist der Fall, wenn CONFIG_SCHEDSTATS oder CONFIG_TASK_DELAY_ACCT aktiviert sind. Wenn sich der Status dieser Konfigurationsoptionen ändert, ändert sich auch das Layout der task_struct-Struktur und alle vom Kernel exportierten Schnittstellen, die task_struct verwenden, werden geändert (z. B. set_cpus_allowed_ptr in kernel/sched/core.c). Die Kompatibilität mit zuvor kompilierten Kernelmodulen, die diese Schnittstellen verwenden, wird unterbrochen. Diese Module müssen mit der neuen Kernelkonfiguration neu erstellt werden.

Weitere Informationen zu CONFIG_MODVERSIONS finden Sie in der Dokumentation im Kernel-Baum unter Documentation/kbuild/modules.rst.