本页介绍通用内核映像 (GKI) 的版本控制方案。通用内核映像 (GKI)具有称为内核版本的唯一标识符。内核版本由内核模块接口(KMI)版本和子级别组成。内核版本特定于要发布的映像,而 KMI 版本代表构建版本的接口。一个 KMI 版本可以支持多个内核版本。内核版本仅与一个 KMI 版本相关联。在内核模块接口必须更改的不太可能发生的情况下,将迭代 KMI 生成以反映 KMI 版本的更改。
术语摘要
下表总结了本页和 GKI 更新中使用的重要术语。
姓名 | 象征 | 例子 | 描述 |
---|---|---|---|
内核发布 | wxy-zzz-k-后缀 | 5.4.42-android12-0-foo | GKI 版本的唯一标识符。这是uname 返回的值。 |
KMI 版本 | wx-zzz-k | 5.4-android12-0 | 描述 GKI 和动态可加载内核模块 (DLKM) 之间的内核模块接口 (KMI)。 |
子级 | 是的 | 42 | 描述同一 KMI 版本中内核版本的发布顺序。 |
下表列出了其他相关术语作为参考。
姓名 | 象征 | 例子 | 描述 |
---|---|---|---|
wxy | wxy | 5.4.42 | 有关详细信息,请参阅Linux 内核 Makefile (搜索“KERNELRELEASE”)。 wxy在本文档中直接使用。这通常也称为三部分版本号。 VINTF 中使用的术语kernel version可能会与其他术语混淆,尤其是w 。 此变量在libkver中称为kernel_version_tuple 。 此元组不得因任何更新(包括 OTA 或主线)而减少。 |
内核分支 | zzz-wx | 安卓12-5.4 | 该术语用于通用内核分支类型。 |
版本 | w | 5 | 本文档中未使用该术语。此变量在libkver中称为版本。 |
补丁级别 | X | 4 | 本文档中未使用该术语。此变量在libkver 中称为 patch_level 。 |
安卓版本 | zzz | 安卓12 | 这是与内核关联的 Android(甜点)版本号。 比较 Android 版本号不得因任何更新(包括 OTA 或主线)而减少。 |
KMI 生成 | ķ | 0 | 这是一个额外的数字,用于处理不太可能发生的事件。如果安全错误修复需要更改同一 Android 版本中的 KMI,则会增加 KMI 生成。 KMI 代号从 0 开始。 |
版本控制设计
内核发布
定义
对于带有 GKI 的设备,内核版本定义如下:
KernelRelease :=
Version.PatchLevel.SubLevel-AndroidRelease-KmiGeneration-suffix
w .x .y -zzz -k -something
有关更多信息,请参阅从设备确定内核版本。
以下是内核版本的示例。
5.4.42-android12-0-00544-ged21d463f856
描述
内核版本是 GKI 版本的唯一 ID。如果两个 GKI 二进制文件具有相同的内核版本,则它们必须按字节相同。
内核版本由 KMI 版本、子级别和后缀组成。出于本文档的目的,KMI 生成后的后缀将被忽略。
KMI 版本
定义
KMI 版本定义如下:
KmiVersion :=
Version.PatchLevel-AndroidRelease-KmiGeneration
w .x -zzz -k
请注意,子级别y
不是 KMI 版本的一部分。对于Kernel release中的示例,KMI 版本为:
5.4-android12-0
描述
KMI 版本描述了 GKI 和动态可加载内核模块 (DLKM) 之间的内核模块接口 (KMI)。
如果两个内核版本具有相同的 KMI 版本,则它们实现相同的内核模块接口。与一个兼容的 DLKM 也与另一个兼容。
任何 OTA 更新都不得降低 KMI 版本。
子级
子级别y
描述了同一 KMI 版本中内核版本的发布顺序。
对于具有相同 KMI 版本但分别具有子级别 Y1 和 Y2 的两个内核版本:
- 如果 Y1 小于或等于 Y2,则运行 Y1 的设备可以接收到 Y2 的更新。
- 如果 Y1 大于 Y2,则运行 Y1 的设备无法更新为 Y2。
也就是说,如果 KMI 版本没有变化,则子级别不得因任何 OTA 更新而降低。
从设备确定内核版本
完整的内核版本可以通过执行uname -r
或使用以下代码片段的uname(2)
找到:
std::string get_kernel_release() {
struct utsname buf;
return uname(&buf) == 0 ? buf.release : "";
}
一个示例输出是:
5.4.42-android12-0-00544-ged21d463f856
就本文档而言,在提取内核信息时会忽略 KMI 生成之后的任何内容。更正式地说, uname -r
的输出用以下正则表达式解析(假设 zzz 总是以“android”开头):
^(?P<w>\d+)[.](?P<x>\d+)[.](?P<y>\d+)-(?P<z>android\d+)-(?P<k>\d+).*$
被忽略的信息可能包括诸如ci.android.com 内部版本号、基线内核上的补丁数量以及 git 提交的 SHA 哈希等信息。
libkver
库 libkver 提供了一个 C++ 接口来解析内核版本或 KMI 版本字符串。有关 libkver 公开的 API 列表,请参阅packages/modules/Gki/libkver/include/kver
。
VINTF 检查
对于 Android 11 或更低版本,KMI 版本的 Android 发布部分由设备制造商在设备清单中手动指定。有关详细信息,请参阅VINTF 内核匹配规则。
从 Android S 开始,KMI 版本的 Android 发布部分可以从内核中提取出来,并在构建时注入到设备清单中。
因为内核配置要求通常不会改变,所以不需要在兼容性矩阵中对k
进行编码。但是,在极少数情况下确实需要更改内核配置要求,请确保以下内容:
- 兼容性矩阵中的相应要求被删除。
- 添加了额外的 VTS 测试以检查以 KMI 生成为条件的新要求。
OTA 元数据中的启动映像版本
即使引导映像通过 OTA 更新进行更新,它也必须以 OTA 有效负载格式payload.bin
进行包装。 OTA 有效负载为每个分区编码一个version
字段。当update_engine
处理 OTA 负载时,它会比较此字段以确保分区没有降级。
为避免混淆,OTA 元数据中启动分区的version
字段称为boot image version
。
因为 ramdisk 总是从头开始构建的,所以使用ramdisk 时间戳足以描述整个引导映像。无需在引导映像版本中编码内核版本,除非您将来将旧的引导映像拼接到新的内核二进制文件中。
在 OTA 更新之前,OTA 客户端以与任何其他分区相同的方式检查启动映像版本。