В рамках требований к ядру модуля, представленных в Android 8.0, все ядра системы на кристалле (SoC) должны поддерживать загружаемые модули ядра.
Параметры конфигурации ядра
Для поддержки загружаемых модулей ядра файл android-base.cfg во всех распространенных ядрах включает следующие параметры конфигурации ядра (или их эквивалент версии ядра):
CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y
Все ядра устройств должны включать эти параметры. Модули ядра также должны поддерживать выгрузку и перезагрузку, когда это возможно.
Подписание модуля
Подписание модулей не поддерживается для модулей поставщика GKI. На устройствах, которые должны поддерживать проверенную загрузку, Android требует, чтобы модули ядра находились в разделах с включенной dm-verity. Это устраняет необходимость подписывать отдельные модули для их подлинности.
Расположение файлов
В то время как Android 7.x и более ранние версии не требуют модулей ядра (и включают поддержку insmod
и rmmod
), Android 8.x и более поздние версии рекомендуют использовать модули ядра в экосистеме. В следующей таблице показана потенциальная поддержка периферийных устройств для конкретных плат, необходимая для трех режимов загрузки Android.
Режим загрузки | Место хранения | Отображать | Клавиатура | Батарея | PMIC | Сенсорный экран | NFC, Wi-Fi, блютус | Датчики | Камера |
---|---|---|---|---|---|---|---|---|---|
Восстановление | |||||||||
Зарядное устройство | |||||||||
Андроид |
Помимо доступности в режимах загрузки Android, модули ядра также могут быть классифицированы по тому, кто ими владеет (поставщик SoC или ODM). Если используются модули ядра, требования к их размещению в файловой системе следующие:
- Все ядра должны иметь встроенную поддержку загрузки и монтирования разделов.
- Модули ядра должны загружаться из раздела, доступного только для чтения.
- Для устройств, требующих проверенной загрузки, модули ядра должны быть загружены из проверенных разделов.
- Модули ядра не должны располагаться в
/system
. - Модули ядра от поставщика SoC, необходимые для полнофункциональных режимов Android или Charger, должны находиться в
/vendor/lib/modules
. - Если раздел ODM существует, модули ядра из ODM, необходимые для полнофункциональных режимов Android или Charger, должны находиться в
/odm/lib/modules
. В противном случае эти модули должны находиться в/vendor/lib/modules
. - Модули ядра от поставщика SoC и ODM, необходимые для режима восстановления, должны находиться в
ramfs
восстановления в/lib/modules
. - Модули ядра, необходимые как для режима восстановления, так и для полных режимов Android или Charger, должны существовать как в
rootfs
восстановления, так и в разделах/vendor
или/odm
(как описано выше). - Модули ядра, используемые в режиме восстановления, не должны зависеть от модулей, расположенных только в
/vendor
или/odm
, поскольку эти разделы не монтируются в режиме восстановления. - Модули ядра поставщика SoC не должны зависеть от модулей ядра ODM.
В Android 7.x и ниже разделы /vendor
и /odm
не монтируются заранее. В Android 8.x и более поздних версиях, чтобы сделать возможной загрузку модулей из этих разделов, были созданы условия для раннего монтирования разделов как для устройств, отличных от A/B, так и для устройств A/B . Это также гарантирует, что разделы будут смонтированы как в режиме Android, так и в режиме зарядного устройства.
Поддержка системы сборки Android
В BoardConfig.mk
Android определяет переменную BOARD_VENDOR_KERNEL_MODULES
, которая предоставляет полный список модулей ядра, предназначенных для образа поставщика. Модули, перечисленные в этой переменной, копируются в образ вендора по адресу /lib/modules/
и после монтирования в Android появляются в /vendor/lib/modules
(в соответствии с вышеуказанными требованиями). Пример конфигурации модулей ядра производителя:
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
В этом примере предварительно созданный репозиторий модуля ядра поставщика сопоставляется со сборкой Android в расположении, указанном выше.
Образ восстановления может содержать подмножество модулей поставщика. Сборка Android определяет переменную BOARD_RECOVERY_KERNEL_MODULES
для этих модулей. Пример:
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
Сборка Android заботится о запуске depmod
для создания необходимых файлов modules.dep
в каталогах /vendor/lib/modules
и /lib/modules
( recovery ramfs
).
Загрузка модуля и управление версиями
Загрузите все модули ядра за один проход из init.rc*
, вызвав modprobe -a
. Это позволяет избежать накладных расходов на повторную инициализацию среды выполнения C для двоичного modprobe
. Событие early-init
можно изменить для вызова modprobe
:
on early-init exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d \ /vendor/lib/modules module_a module_b module_c ...
Как правило, модуль ядра должен быть скомпилирован с ядром, с которым он будет использоваться (иначе ядро отказывается загружать модуль). CONFIG_MODVERSIONS
обеспечивает обходной путь, обнаруживая сбои в двоичном интерфейсе приложения (ABI). Эта функция вычисляет значение проверки циклическим избыточным кодом (CRC) для прототипа каждого экспортируемого символа в ядре и сохраняет значения как часть ядра; для символов, используемых модулем ядра, значения также хранятся в модуле ядра. Когда модуль загружается, значения символов, используемых модулем, сравниваются со значениями в ядре. Если значения совпадают, модуль загружается; в противном случае загрузка не выполняется.
Чтобы включить обновление образа ядра отдельно от образа поставщика, включите CONFIG_MODVERSIONS
. Это позволяет вносить небольшие обновления ядра (например, исправления ошибок из LTS), сохраняя при этом совместимость с существующими модулями ядра в образе поставщика. Однако CONFIG_MODVERSIONS
сама по себе не устраняет поломку ABI. Если прототип экспортируемого символа в ядре изменяется либо из-за модификации исходного кода, либо из-за изменения конфигурации ядра, это нарушает совместимость с модулями ядра, использующими этот символ. В таких случаях модуль ядра необходимо перекомпилировать.
Например, структура task_struct
в ядре (определенная в include/linux/sched.h
) содержит множество полей, включенных условно в зависимости от конфигурации ядра. Поле sched_info
присутствует, только если включен CONFIG_SCHED_INFO
(что происходит, когда включены параметры CONFIG_SCHEDSTATS
или CONFIG_TASK_DELAY_ACCT
). Если эти параметры конфигурации изменяют состояние, меняется макет структуры task_struct
и изменяются любые экспортированные из ядра интерфейсы, использующие task_struct
(например, set_cpus_allowed_ptr
в kernel/sched/core.c
). Совместимость с ранее скомпилированными модулями ядра, использующими эти интерфейсы, нарушается, что требует пересборки этих модулей с новой конфигурацией ядра.
Дополнительные сведения о CONFIG_MODVERSIONS
см. в документации в дереве ядра по адресу Documentation/kbuild/modules.rst
.