Módulos de kernel carregáveis

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 .