Módulos de kernel carregáveis

Como parte dos requisitos de kernel do módulo introduzidos no Android 8.0, todos os kernels de sistema em chip (SoC) devem oferecer suporte a módulos de kernel carregáveis.

Opções de configuração do kernel

Para dar suporte a módulos de kernel carregáveis, o android-base.cfg em todos os kernels comuns inclui as seguintes opções de configuração do kernel (ou seu equivalente na versão do kernel):

CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y

Todos os kernels de dispositivo devem habilitar essas opções. Os módulos do kernel também devem suportar o descarregamento e o recarregamento sempre que possível.

Assinatura do módulo

A assinatura do módulo não é compatível com os módulos do fornecedor GKI. Em dispositivos necessários para dar suporte à inicialização verificada, o Android exige que os módulos do kernel estejam nas partições com dm-verity ativado. Isso elimina a necessidade de assinar módulos individuais para sua autenticidade. O Android 13 introduziu o conceito de módulos GKI. Os módulos GKI usam a infraestrutura de assinatura de tempo de compilação do kernel para diferenciar entre GKI e outros módulos em tempo de execução. Os módulos não assinados têm permissão para carregar, 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 de módulos GKI durante a compilação GKI usando o par de chaves de tempo de compilação do kernel, a configuração do kernel GKI habilitou CONFIG_MODULE_SIG_ALL=y . Para evitar a assinatura de módulos não GKI durante as compilações do kernel do dispositivo, você deve adicionar # CONFIG_MODULE_SIG_ALL is not set as part of your kernel config fragments.

Locais de arquivo

Embora o Android 7.xe inferior não obrigue a módulos do kernel (e inclua suporte para insmod e rmmod ), o Android 8.xe superior recomenda o uso de módulos do kernel no ecossistema. A tabela a seguir mostra o possível suporte a periféricos específicos da placa necessários em três modos de inicialização do Android.

Modo de inicialização Armazenar Tela 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 os módulos do kernel estiverem sendo usados, os requisitos para sua colocação no sistema de arquivos são os seguintes:

  • Todos os kernels devem ter suporte embutido para inicializar e montar partições.
  • Os módulos do kernel devem ser carregados de uma partição somente leitura.
  • Para dispositivos que precisam ter inicialização verificada, os módulos do kernel devem ser carregados 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 de kernel do fornecedor de 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 de kernel do ODM necessários para os modos Android ou Charger completos devem estar localizados em /odm/lib/modules . Caso contrário, esses módulos devem estar localizados em /vendor/lib/modules .
  • Os módulos de kernel do fornecedor de SoC e ODM necessários para o modo de recuperação devem estar localizados no ramfs de recuperação em /lib/modules .
  • Os módulos de kernel necessários para o modo de recuperação e os modos Android ou Charger completos devem existir tanto no rootfs de recuperação quanto 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.xe inferior, as partições /vendor e /odm não são montadas antecipadamente. No Android 8.xe superior, para possibilitar o carregamento do módulo dessas partições, foram feitas provisões 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 Charger.

Suporte ao sistema de compilação do 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 na 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 cuida da execução de depmod para gerar os arquivos modules.dep necessários em /vendor/lib/modules e /lib/modules ( recovery ramfs ).

Carregamento e controle de versão do módulo

Carregue todos os módulos do kernel em uma passagem de 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 recusa a carregar o módulo). CONFIG_MODVERSIONS fornece uma solução alternativa detectando quebras na interface binária do aplicativo (ABI). Esse 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 enquanto mantém a compatibilidade com os módulos existentes do kernel na imagem do fornecedor. No entanto, CONFIG_MODVERSIONS não corrige uma quebra de ABI por si só. Se o protótipo de um símbolo exportado no kernel mudar, devido à modificação da fonte ou porque a configuração do kernel mudou, isso quebra 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 ativado (o que ocorre quando CONFIG_SCHEDSTATS ou CONFIG_TASK_DELAY_ACCT estão ativados). Se essas opções de configuração mudarem de estado, o layout da estrutura task_struct mudará 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 quebra, exigindo que esses módulos sejam reconstruídos com a nova configuração do kernel.

Para mais detalhes sobre CONFIG_MODVERSIONS , consulte a documentação na árvore do kernel em Documentation/kbuild/modules.rst .