内核模块概述

内核模块分为两种类型:硬件无关型 GKI 模块和硬件专用型 供应商模块。本页面概述了这两种类型的模块。

GKI 模块

通用内核映像 (GKI) 模块用于交付独立于通用核心内核的非启动必需内核功能。借助 GKI 模块,您可以选择要使用的特定内核功能,这通常可以减小内核映像大小和运行时内存消耗。尺寸的减小使 GKI 非常适合 Android Go 设备和其他资源受限的外形尺寸。

GKI 模块还提供了一种机制,让供应商可以在 KMI 冻结里程碑后整合新的上游功能。内置代码在不构建另一个映像的情况下无法替换,而作为模块交付的代码可以被另一个模块替换。

GKI 模块使用内核的构建时签名基础架构来区分运行时 GKI 和其他模块。只要未签名模块仅使用允许列表上显示的符号或由其他未签名模块提供的符号,就允许加载这些模块。

GKI 模块有两种逻辑类型:受保护的 GKI 模块未受保护的 GKI 模块

受保护的 GKI 模块

受保护的 GKI 模块由 Google 交付,不受任何方式的限制,并且在加载后表现得好像是使用内核构建的一样。此外,受保护的 GKI 模块还具有以下特点

  • 受保护的 GKI 模块有权访问非 KMI 内核符号,这些符号对于供应商模块或未受保护的 GKI 模块不可用。
  • 只要符号在符号列表中被引用,受保护的 GKI 模块就可以导出成为 KMI 表面一部分的符号。
  • 受保护的 GKI 模块无法被供应商模块覆盖。

受保护的 GKI 模块是 GKI 模块的默认类。在 KMI 冻结时,所有 GKI 模块都被视为受保护模块。

未受保护的 GKI 模块

未受保护的 GKI 模块可以被供应商模块覆盖。在 KMI 冻结后,如果 GKI 团队认为供应商需要使用包含来自上游 Linux 的新功能的版本来覆盖默认实现,则受保护的 GKI 模块可能会被重新分类为未受保护模块。在下一个 GKI 版本中,在上游代码登陆 Android 通用内核 (ACK) 后,未受保护的模块将被重新分类为受保护模块。未受保护的 GKI 模块具有以下特点

  • 未受保护的 GKI 模块与供应商模块具有相同的对导出符号的访问权限。
  • 未受保护的 GKI 模块无法导出受保护的 GKI 模块导出的符号。
  • 未受保护的 GKI 模块必须保留任何 KMI 接口,就像核心内核的一部分一样。
  • 未受保护的 GKI 模块可以被供应商模块覆盖。

供应商模块

供应商模块由合作伙伴交付,用于实现 SoC 和设备专用功能。任何未作为 GKI 内核一部分交付的现有内核模块都可以作为供应商模块交付。

由于 GKI 项目的主要目标之一是在核心内核中最大限度地减少特定于硬件的代码,因此供应商可以预期 GKI 内核不会包含明显管理其自身硬件的模块。例如,供应商 ABC 公司可以预期,诸如 CONFIG_ABC_SOC_SUPPORT 之类的配置在没有他们的支持下,既不会作为内置模块启用,也不会作为可加载的 GKI 模块启用。

如果 ACK 中存在内核驱动程序或框架,但未作为 GKI 内核的一部分交付,则供应商可以修改该驱动程序并将其作为供应商模块交付。对于非特定于供应商的模块,不鼓励进行此类修改,因为相同的功能可能会在未来的 GKI 版本中交付。当 GKI 内核包含供应商模块提供的功能时,供应商模块将不会加载。例如,Android 11 的 GKI 中未设置 CONFIG_GREYBUS,因此供应商可以交付 greybus 供应商模块。但是,CONFIG_GREYBUS 可能会在 Android 12 中作为 GKI 内置模块或模块启用,在这种情况下,greybus 供应商模块将不会加载。最佳实践是,如果非特定于供应商的驱动程序作为供应商模块交付,则应使用其上游版本。

您可以在 vendorvendor_boot 镜像中交付供应商模块。启动过程中早期需要的模块必须位于 vendor_boot 中。从 vendor_boot 加载模块存在启动时间成本。