Como parte dos requisitos do kernel do módulo introduzidos no Android 8.0, todos os kernels system-on-chip (SoC) devem oferecer suporte a módulos de kernel carregáveis.
Opções de configuração do kernel
Para oferecer suporte a módulos de kernel carregáveis, 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 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 os módulos do fornecedor GKI. Nos dispositivos necessários para dar suporte à inicialização verificada, o Android exige que os módulos do kernel estejam nas partições que têm o dm-verity ativado. Isso elimina a necessidade de assinar módulos individuais para sua autenticidade.
Locais de arquivos
Embora o Android 7.xe inferior não exija contra 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 suporte a periféricos específicos da placa em potencial necessário em três modos de inicialização do Android.
Modo de inicialização | Armazenar | Exibição | 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 inicialização e montagem de 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 do kernel do fornecedor do SoC que são 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 que são 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 do kernel do fornecedor do SoC e do ODM que são necessários para o modo de recuperação devem estar localizados nas
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 de kernel do fornecedor de SoC não devem depender de módulos de 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 tomadas 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 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 cuida da execução do 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 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 recusa a carregar o módulo). CONFIG_MODVERSIONS
fornece uma solução alternativa detectando interrupções 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 falha.
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 quebra de ABI por si só. Se o protótipo de um símbolo exportado no kernel mudar, seja 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 somente 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
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 quebra, 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
.