Como parte dos requisitos do kernel do módulo introduzidos no Android 8.0, todos os kernels do sistema no chip (SoC) devem oferecer suporte a módulos de kernel carregáveis.
Opções de configuração do kernel
Para suportar módulos de kernel carregáveis, android-base.config em todos os kernels comuns inclui as seguintes opções de configuração de kernel (ou sua versão equivalente do kernel):
CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y
Todos os kernels de dispositivos devem habilitar essas opções. Os módulos do kernel também devem suportar descarregamento e recarregamento sempre que possível.
Assinatura do módulo
A assinatura de módulo não é compatível com módulos do fornecedor GKI. Em dispositivos necessários para suportar inicialização verificada, o Android exige que os módulos do kernel estejam nas partições que tenham o dm-verity ativado. Isso elimina a necessidade de assinar módulos individuais para verificar sua autenticidade. O Android 13 introduziu o conceito de módulos GKI. Os módulos GKI usam a infraestrutura de assinatura em tempo de construção do kernel para diferenciar entre GKI e outros módulos em tempo de execução. Módulos não assinados podem ser carregados, desde que usem apenas símbolos que aparecem na lista de permissões ou fornecidos por outros módulos não assinados. Para facilitar a assinatura dos módulos GKI durante a construção do GKI usando o par de chaves de tempo de construção do kernel, a configuração do kernel do GKI habilitou CONFIG_MODULE_SIG_ALL=y
. Para evitar a assinatura de módulos não GKI durante a construção do kernel do dispositivo, você deve adicionar # CONFIG_MODULE_SIG_ALL is not set
como parte dos fragmentos de configuração do kernel.
Locais de arquivos
Embora o Android 7.x e versões anteriores não sejam obrigatórios contra módulos do kernel (e incluam suporte para insmod
e rmmod
), o Android 8.x e versões superiores recomendam o uso de módulos do kernel no ecossistema. A tabela a seguir mostra o potencial suporte periférico específico da placa necessário em três modos de inicialização do Android.
Modo de inicialização | Armazenar | Mostrar | Teclado | Bateria | PMIC | Tela sensível ao toque | NFC, Wi-Fi, Bluetooth | Sensores | Câmera |
---|---|---|---|---|---|---|---|---|---|
Recuperação | |||||||||
Carregador | |||||||||
Android |
Além da disponibilidade nos modos de inicialização do Android, os módulos do kernel também podem ser categorizados por quem os possui (o fornecedor do SoC ou o ODM). Se módulos do kernel estiverem sendo usados, os requisitos para seu posicionamento no sistema de arquivos são os seguintes:
- Todos os kernels devem ter suporte integrado para inicialização e montagem de partições.
- Os módulos do kernel devem ser carregados de uma partição somente leitura.
- Para dispositivos que necessitam de inicialização verificada, os módulos do kernel devem ser carregados a partir de partições verificadas.
- Os módulos do kernel não devem estar localizados em
/system
. - Os módulos GKI necessários para o dispositivo devem ser carregados de
/system/lib/modules
que é um link simbólico para/system_dlkm/lib/modules
. - Os módulos do kernel do fornecedor do SoC necessários para os modos Android ou Charger completos devem estar localizados em
/vendor/lib/modules
. - Se existir uma partição ODM, os módulos do kernel do ODM necessários para os modos Android ou Charger completos deverão estar localizados em
/odm/lib/modules
. Caso contrário, esses módulos deverão estar localizados em/vendor/lib/modules
. - Os módulos do kernel do fornecedor SoC e ODM necessários para o modo de recuperação devem estar localizados nos
ramfs
de recuperação em/lib/modules
. - Os módulos do kernel necessários para o modo de recuperação e os modos Android ou Charger completos devem existir nos
rootfs
de recuperação e nas partições/vendor
ou/odm
(conforme descrito acima). - Os módulos do kernel usados no modo de recuperação não devem depender de módulos localizados apenas em
/vendor
ou/odm
, pois essas partições não são montadas no modo de recuperação. - Os módulos do kernel do fornecedor SoC não devem depender dos módulos do kernel ODM.
No Android 7.x e versões anteriores, as partições /vendor
e /odm
não são montadas antecipadamente. No Android 8.xe superior, para tornar possível o carregamento de módulos a partir dessas partições, foram tomadas providências para montar partições antecipadamente para dispositivos não A/B e A/B . Isso também garante que as partições sejam montadas nos modos Android e Carregador.
Suporte ao sistema de compilação Android
Em BoardConfig.mk
, a compilação do Android define uma variável BOARD_VENDOR_KERNEL_MODULES
que fornece uma lista completa dos módulos do kernel destinados à imagem do fornecedor. Os módulos listados nesta variável são copiados para a imagem do fornecedor em /lib/modules/
, e, após serem montados no Android, aparecem em /vendor/lib/modules
(de acordo com os requisitos acima). Exemplo de configuração dos módulos do kernel do fornecedor:
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
Neste exemplo, um repositório pré-construído do módulo do kernel do fornecedor é mapeado para a compilação do Android no local listado acima.
A imagem de recuperação pode conter um subconjunto dos módulos do fornecedor. A compilação do Android define a variável BOARD_RECOVERY_KERNEL_MODULES
para esses módulos. Exemplo:
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
A compilação do Android se encarrega de executar depmod
para gerar os arquivos modules.dep
necessários em /vendor/lib/modules
e /lib/modules
( recovery ramfs
).
Carregamento e versionamento de módulos
Carregue todos os módulos do kernel em uma única passagem do init.rc*
invocando modprobe -a
. Isso evita a sobrecarga de inicializar repetidamente o ambiente de tempo de execução C para o binário modprobe
. O evento early-init
pode ser modificado para invocar modprobe
:
on early-init exec u:r:vendor_modprobe:s0 -- /vendor/bin/modprobe -a -d \ /vendor/lib/modules module_a module_b module_c ...
Normalmente, um módulo do kernel deve ser compilado com o kernel com o qual o módulo será usado (caso contrário, o kernel se recusará a carregar o módulo). CONFIG_MODVERSIONS
fornece uma solução alternativa detectando falhas na interface binária do aplicativo (ABI). Este recurso calcula um valor de verificação de redundância cíclica (CRC) para o protótipo de cada símbolo exportado no kernel e armazena os valores como parte do kernel; para símbolos usados por um módulo do kernel, os valores também são armazenados no módulo do kernel. Quando o módulo é carregado, os valores dos símbolos usados pelo módulo são comparados com os do kernel. Se os valores corresponderem, o módulo será carregado; caso contrário, a carga falhará.
Para habilitar a atualização da imagem do kernel separadamente da imagem do fornecedor, habilite CONFIG_MODVERSIONS
. Isso permite que pequenas atualizações no kernel (como correções de bugs do LTS) sejam feitas, mantendo a compatibilidade com os módulos do kernel existentes na imagem do fornecedor. No entanto, CONFIG_MODVERSIONS
não corrige uma falha de ABI por si só. Se o protótipo de um símbolo exportado no kernel for alterado, seja devido à modificação da fonte ou porque a configuração do kernel foi alterada, isso quebrará a compatibilidade com os módulos do kernel que usam esse símbolo. Nesses casos, o módulo do kernel deve ser recompilado.
Por exemplo, a estrutura task_struct
no kernel (definida em include/linux/sched.h
) contém muitos campos incluídos condicionalmente dependendo da configuração do kernel. O campo sched_info
está presente apenas se CONFIG_SCHED_INFO
estiver habilitado (o que ocorre quando CONFIG_SCHEDSTATS
ou CONFIG_TASK_DELAY_ACCT
estão habilitados). Se essas opções de configuração mudarem de estado, o layout da estrutura task_struct
será alterado e quaisquer interfaces exportadas do kernel que usam task_struct
serão alteradas (por exemplo, set_cpus_allowed_ptr
em kernel/sched/core.c
). A compatibilidade com módulos do kernel compilados anteriormente que usam essas interfaces é interrompida, exigindo que esses módulos sejam reconstruídos com a nova configuração do kernel.
Para obter mais detalhes sobre CONFIG_MODVERSIONS
, consulte a documentação na árvore do kernel em Documentation/kbuild/modules.rst
.