内核模块有两种类型:与硬件无关的 GKI 模块和特定于硬件的供应商模块。本页将简要介绍这两种模块。
GKI 模块
通用内核映像 (GKI) 模块用于提供与通用核心内核分开且并非启动时必需的内核功能。借助 GKI 模块,您可以选择要使用的特定内核功能,这通常可以缩减内核映像大小和运行时内存消耗。缩减大小使得 GKI 非常适合 Android Go 设备和其他在资源方面受限的设备类型。
GKI 模块还提供了一种机制,让供应商能在 KMI 冻结里程碑之后吸纳新的上游功能。内置代码无法在不构建另一映像的情况下被替换,而作为模块提供的代码可被另一模块替换。
GKI 模块使用内核的构建时签名基础架构在运行时区分 GKI 模块和其他模块。允许加载未签名模块,前提是它们仅使用许可名单中显示的符号或由其他未签名模块提供的符号。
GKI 模块有两种逻辑类型:受保护的 GKI 模块和不受保护的 GKI 模块。
受保护的 GKI 模块
受保护的 GKI 模块由 Google 提供,各方面都不受限,加载后其行为和使用内核构建的模块类似。此外,受保护的 GKI 模块具有以下特征:
- 受保护的 GKI 模块可以访问供应商模块或不受保护的 GKI 模块不可用的非 KMI 内核符号。
- 受保护的 GKI 模块可以导出符号用于 KMI Surface 中,前提是这些符号已在符号列表中列出。
- 受保护的 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 Inc. 可能会认为,若 CONFIG_ABC_SOC_SUPPORT
等配置不受支持,将无法作为内置或可加载的 GKI 模块被启用。
如果内核驱动程序或框架存在于 ACK 中,但未作为 GKI 内核的一部分提供,供应商可以修改相应驱动程序并将其作为供应商模块提供。我们不建议对非供应商专用模块进行此类修改,因为在未来版本中,GKI 内核可能会提供相同的功能。当 GKI 内核包含供应商模块提供的功能时,供应商模块将不会加载。例如,Android 11 中没有为 GKI 设置 CONFIG_GREYBUS
,因此供应商可能会提供 greybus 供应商模块。不过,Android 12 中可能会将 CONFIG_GREYBUS
作为 GKI 内置或可加载的模块启用,在这种情况下,系统不会加载 greybus 供应商模块。如果内核驱动程序作为供应商模块提供,最佳实践是使用非供应商专用驱动程序的上游版本。
您可以在 vendor
或 vendor_boot
映像中提供供应商模块。启动过程早期所需的模块必须位于 vendor_boot
中。从 vendor_boot
加载模块时会产生启动时开销。