Como parte dos requisitos do kernel do módulo introduzidos no Android 8.0, todos os kernels do sistema-em-chip (SoC) precisam 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.config em todos os kernels comuns inclui as seguintes opções de kernel-config (ou equivalentes da versão do kernel):
CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODVERSIONS=y
Todos os kernels do dispositivo precisam ativar essas opções. Os módulos do kernel também precisam oferecer suporte ao descarregamento e à recarga sempre que possível.
Assinatura de módulo
A assinatura de módulo não é compatível com módulos de fornecedores do GKI. Em dispositivos que precisam
oferecer suporte à inicialização verificada, o Android exige que os módulos do kernel estejam nas partições
com o dm-verity ativado. Isso elimina a necessidade de assinar módulos
individuais para verificar a autenticidade deles.
O Android 13 introduziu o conceito de módulos de GKI. Os módulos do GKI usam a infraestrutura de assinatura do tempo de build
do kernel para diferenciar o GKI de outros módulos no momento da execução.
Os 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 de módulos do GKI durante o build do GKI usando o par de chaves do kernel,
a configuração do kernel do GKI ativou CONFIG_MODULE_SIG_ALL=y
.
Para evitar a assinatura de módulos que não são GKI durante builds do kernel do dispositivo, adicione
# 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 exijam módulos do kernel (e incluam
suporte a insmod
e rmmod
), o Android 8.x e
versões mais recentes recomendam 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ário em três
modos de inicialização do Android.
Modo de inicialização | Armazenamento | Tela | Teclado | Bateria | PMIC | Tela touchscreen | 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 a colocação deles no sistema de arquivos são os seguintes:
- Todos os kernels precisam ter suporte integrado para inicialização e montagem de partições.
- Os módulos do kernel precisam ser carregados de uma partição somente leitura.
- Para dispositivos que precisam ter inicialização verificada, os módulos do kernel precisam ser carregados de partições verificadas.
- Os módulos do kernel não podem estar localizados em
/system
. - Os módulos GKI necessários para o dispositivo precisam 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 que são necessários para o Android completo ou
os modos de carregador precisam estar localizados em
/vendor/lib/modules
. - Se uma partição ODM existir, os módulos do kernel do ODM que forem necessários
para os modos Android completo ou carregador precisam estar localizados em
/odm/lib/modules
. Caso contrário, esses módulos precisam 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 precisam estar localizados no
ramfs
de recuperação em/lib/modules
. - Os módulos do kernel necessários para o modo de recuperação e os modos de carregador ou
Android completo precisam existir na
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 podem depender de módulos localizados
apenas em
/vendor
ou/odm
, porque essas partições não são montadas no modo de recuperação. - Os módulos do kernel do fornecedor do SoC não podem depender dos módulos do kernel do ODM.
No Android 7.x e versões anteriores, as partições /vendor
e /odm
não são montadas antecipadamente. No Android 8.x e versões mais recentes,
para tornar possível o carregamento de módulos dessas partições, foram feitas
provisões para montar partições com antecedência 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 build do Android
No BoardConfig.mk
, o build 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, depois de 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é-criado de módulo do kernel do fornecedor é mapeado para o build do Android no local listado acima.
A imagem de recuperação pode conter um subconjunto dos módulos do fornecedor. O build 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
O build 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 única passagem de init.rc*
chamando
modprobe -a
. Isso evita a sobrecarga de inicialização repetida
do ambiente 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 precisa ser compilado com o kernel que o módulo
será usado. Caso contrário, o kernel se recusa a carregar o módulo.
O CONFIG_MODVERSIONS
oferece uma solução alternativa detectando falhas
na interface binária do aplicativo (ABI). Esse recurso calcula um valor de verificação
de redundância cíclica (CRC, na sigla em inglês) para o protótipo de cada símbolo exportado no
kernel e armazena os valores como parte dele. 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 ativar a atualização da imagem do kernel separadamente da imagem do fornecedor,
ative CONFIG_MODVERSIONS
. Isso permite pequenas atualizações do
kernel (como correções de bugs do LTS) mantendo a compatibilidade
com os módulos de kernel existentes na imagem do fornecedor. No entanto,
CONFIG_MODVERSIONS
não corrige uma interrupção de ABI por conta própria. Se o
protótipo de um símbolo exportado no kernel mudar, seja devido
à modificação da origem ou porque a configuração do kernel mudou, isso
vai interromper a compatibilidade com os módulos do kernel que usam esse símbolo. Nesses casos,
o módulo do kernel precisa 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
só está presente 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
vai mudar, e todas as 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 de kernel compilados anteriormente que usam essas
interfaces é interrompida, exigindo que esses módulos sejam recriados 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
.