Google 致力于为黑人社区推动种族平等。查看具体举措
此页面由 Cloud Translation API 翻译。
Switch to English

通用内核映像

Android通用内核(ACK)是所有Android产品内核的基础。供应商和设备内核位于ACK的下游。供应商通过修改内核源代码和添加设备驱动程序来增加对SoC和外围设备的支持。这些修改可能很广泛,以至于设备上运行的代码中多达50%是树外代码(不是来自上游Linux或AOSP通用内核)。

因此,设备内核包括:

  • 上游:kernel.org的Linux内核
  • AOSP:来自AOSP通用内核的其他特定于Android的补丁
  • 供应商:供应商提供的SoC和外围设备启用及优化补丁
  • OEM /设备:其他设备驱动程序和自定义项

几乎每个设备都有一个自定义内核。这是内核碎片。

Android内核层次结构导致碎片化

图1. Android内核层次结构导致碎片化

分散的成本

内核碎片会对Android社区产生一些负面影响。

安全更新是劳动密集型的

必须将Android安全公告(ASB)中引用的安全补丁反向移植到每个设备内核中。但是,由于内核碎片,在现场将安全修复程序传播到Android设备非常昂贵。

难以合并长期支持的更新

长期支持(LTS)版本包括安全修复程序和其他重要的错误修复程序。事实证明,与LTS发行版保持最新是提供安全修复程序的最有效方法。在Pixel设备上,已经发现ASB中报告的90%的内核安全问题已针对保持最新状态的设备解决。

但是,利用设备内核中的所有自定义修改,很难仅将LTS修订合并到设备内核中。

禁止Android平台版本升级

碎片化使得很难将需要更改内核的新Android功能添加到现场设备中。 Android Framework代码必须假定最多支持五个内核版本,并且未对新平台版本进行任何内核更改(Android 10支持3.18、4.4、4.9、4.14和4.19内核,在某些情况下还不支持)自2017年推出Android 8以来具有新功能进行了增强)。

难以将内核更改贡献回上游Linux

在对内核进行了所有更改之后,大多数旗舰设备附带的内核版本已经存在至少18个月了。例如,4.14内核由kernel.org于2017年11月发布,而首批使用4.14内核的Android手机于2019年春季发布。

上游内核发行和产品之间的这种长时间延迟使得Android社区很难将所需的功能和驱动程序提供给上游内核,因此解决碎片化问题具有挑战性。

修复碎片:通用内核映像

通用内核映像Generic Kernel Image ,GKI)项目通过统一核心内核并将SoC和板卡支持从核心内核转移到可加载模块中,从而解决了内核碎片问题。 GKI内核为内核模块提供了稳定的内核模块接口(KMI),因此可以独立更新模块和内核。

GKI:

  • ACK资源建成。
  • 每个架构,每个LTS版本的单内核二进制文件以及相关的可加载模块(当前仅适用于android11-5.4android12-5.4 arm64)。
  • 所支持的相关ACK所有的Android平台版本进行测试。 GKI内核版本的生存期没有功能弃用
  • 暴露了稳定KMI给定LTS内的驱动程序。
  • 不包含SoC或主板特定的代码。

这是实施GKI的Android设备的外观。

GKI架构

图2. GKI架构

GKI是一项复杂的更改,将从Android 11平台版本中的v5.4内核开始分几个阶段进行。

GKI 1.0 — GKI兼容性要求

对于使用Android 11平台版本启动的某些设备,与Treble的兼容性要求对运行v5.4内核的设备进行GKI测试。

GKI兼容性测试分区

图3.用于GKI兼容性测试的分区

该设备通过GKI兼容性手段VTS和CTS-上-GSI + GKI测试与通用系统映像(GSI)和由GKI引导映像闪烁到安装GKI内核boot在分区和GSI系统映像system分区。设备可以附带其他产品内核,并且可以使用GKI不提供的可加载模块。但是,产品和GKI内核都必须从相同的vendor_bootvendor分区加载模块。因此,所有产品内核都必须具有相同的二进制内核模块接口(KMI)。供应商可以扩展产品内核的KMI,只要它与GKI KMI兼容即可。无需在GKI 1.0中卸载供应商模块。

GKI 1.0目标

  • 当产品内核替换为GKI内核时,请勿在VTS或CTS中引入回归。
  • 减轻OEM和供应商的内核维护负担,使其能够及时了解AOSP通用内核。
  • 无论设备是升级到新的Android平台版本还是新推出的,都应在内核中包含Android的核心更改。
  • 永远不要破坏Android用户空间。
  • 将特定于硬件的组件与核心内核分开,作为可加载模块。

GKI 2.0-GKI产品

GKI内核需要某些使用Android S(AOSP实验性) (2021)平台版本使用内核版本v5.10或更高版本启动的设备。签名的启动映像将可用,并通过LTS和严重的错误修复定期进行更新。因为将为KMI保持二进制稳定性,所以可以安装这些引导映像,而无需更改供应商映像。

GKI 2.0目标

  • 不要在GKI中引入明显的性能或功耗下降。
  • 使OEM无需供应商参与即可提供内核安全修复程序和错误修复程序(LTS)。
  • 降低更新设备的主要内核版本的成本(例如,从v5.10升级到2021 LTS内核)。
  • 通过使用清晰的升级过程更新内核版本,每个体系结构仅维护一个GKI内核二进制文件。

GKI设计

KMI内核分支

GKI内核是从ACK KMI内核分支构建的,在Android Common Kernels中对其进行了详细描述。 KMI由内核版本和Android平台版本唯一标识,因此分支名为<androidRelease>-<kernel version> 。例如, Android 11的5.4 KMI内核分支名为android11-5.4.可以预期,对于Android S(AOSP实验) (未提交并仅用于演示新分支模型的发展),将会有两个附加的KMI内核: android12-5.4和一个基于新LTS内核的内核。 ,应在2020年底宣布。

KMI内核层次结构

图4显示了5.10 KMI内核的分支层次结构。 android12-5.10是与Android S(AOSP实验)相对应的KMI内核,而android13-5.10Android T(AOSP实验)相对应的KMI内核(未提交,仅用于演示新的分支模型将如何发展)。

5.10的KMI内核层次结构

图4. 5.10的KMI内核层次结构

如图4所示,KMI分支通过三个阶段循环:开发(dev),稳定(stab)和冻结。这些阶段在Android Common Kernels中进行了详细描述。

冻结KMI内核后,除非发现严重的安全问题,而这不能在不影响稳定KMI的情况下得到缓解,则不会接受破坏KMI的更改。分支在其整个生命周期中都保持冻结状态。

只要不破坏现有的KMI,就可以在冻结的分支中接受错误修复和合作伙伴功能。只要不影响组成当前KMI的接口,就可以使用新导出的符号扩展KMI。将新接口添加到KMI后,它们会立即变得稳定,并且不会被将来的更改所破坏。

例如,不允许将字段添加到KMI接口使用的结构的更改,因为它会更改接口定义:

struct foo {
  int original_field1;
  int original_field2;
  int new_field; // Not allowed
};

int do_foo(struct foo &myarg)
{
  do_something(myarg);
}
EXPORT_SYMBOL_GPL(do_foo);

但是,添加新功能很好:

struct foo_ext {
  struct foo orig_foo;
  int new_field;
};

int do_foo2(struct foo_ext &myarg)
{
  do_something_else(myarg);
}
EXPORT_SYMBOL_GPL(do_foo2);

KMI稳定性

要实现GKI目标,保持驾驶员稳定的KMI至关重要。 GKI内核以二进制形式构建和交付,但可在供应商中加载的模块在单独的树中构建。生成的GKI内核和模块必须像它们一起构建一样工作。为了进行GKI兼容性测试,将包含内核的启动映像替换为包含GKI内核的启动映像,并且供应商映像中的可加载模块必须在任何一个内核下都能正常运行。

KMI不包括内核中的所有符号,甚至不包括所有30,000+个导出的符号。而是在内核树的根目录中公开维护的一组符号列表文件中明确列出了模块可以使用的符号。所有符号列表文件中所有符号的并集定义了保持稳定的KMI符号集。符号列表文件的示例是abi_gki_aarch64_db845c ,该文件声明了DragonBoard 845c所需的符号。

仅将符号列表中列出的符号及其相关结构和定义视为KMI的一部分。如果所需的符号不存在,则可以将更改发布到符号列表中。将新接口包含在符号列表中并因此成为KMI描述的一部分之后,它们将保持稳定,并且在冻结分支后不得从符号列表中删除或修改。

每个KMI内核树都有其自己的符号列表集。没有尝试在不同的KMI内核分支之间提供ABI稳定性。例如, android11-5.4的KMI完全独立于android12-5.4的KMI。

通常,Linux社区对主线内核的内核内ABI稳定性的概念不满意。面对不同的工具链,配置以及不断发展的Linux主线内核,在主线中保持稳定的KMI是不可行的。但是,在高度受限的GKI环境中还是有可能的。约束是:

  • KMI仅在相同的LTS内核(例如android11-5.4 )内稳定。
    • 没有为android-mainline保持KMI稳定性。
  • 只有AOSP中提供的,为相应分支定义的特定Clang工具链可用于构建内核和模块。
  • 仅监视已知由符号列表中指定的模块使用的符号的稳定性并考虑使用KMI符号。
    • 结果是模块必须仅使用KMI符号。如果需要非KMI符号,则通过模块加载失败来强制执行此操作。
  • 冻结KMI分支后,没有任何更改可以破坏KMI,包括:
    • 配置变更
    • 内核代码更改
    • 工具链更改(包括更新)

KMI监控

ABI监视工具在提交前的测试期间监视KMI的稳定性。破坏KMI的更改未通过预提交测试,因此必须进行重新处理以使其兼容。这些工具可供合作伙伴和公众使用,以集成到他们的构建过程中。 Android内核团队使用这些工具在开发过程中以及合并LTS版本时查找KMI损坏。如果在LTS合并期间检测到KMI损坏,则可以通过删除有问题的补丁或将补丁重构为兼容的方式来保留KMI。

如果以不兼容的方式修改了现有的KMI符号,则认为KMI损坏。例子:

  • 向KMI函数添加了新参数
  • 向KMI功能使用的结构添加了新字段
  • 添加了新的枚举值,该值更改了KMI函数使用的枚举的值
  • 配置更改,更改影响KMI的数据成员的存在

添加新符号不一定会破坏KMI,但是必须将使用的新符号添加到符号列表和ABI表示中。否则,将无法识别对KMI此部分的将来更改。

合作伙伴应使用ABI监视工具来比较其产品内核和GKI内核之间的KMI,并确保它们兼容。

可以从ci.android.comkernel_aarch64构建)下载最新的android11-5.4二进制GKI内核。

单一编译器

更改编译器可能会更改影响ABI的内部内核数据结构布局。由于保持KMI稳定至关重要,因此用于构建GKI内核的工具链必须与用于构建供应商模块的工具链完全兼容。 GKI内核是使用AOSP中包含的LLVM工具链构建的。

从Android 10开始,所有Android内核都必须使用LLVM工具链构建。使用GKI,用于构建产品内核和供应商模块的LLVM工具链必须生成与AOSP的LLVM工具链相同的ABI,并且合作伙伴必须确保KMI与GKI内核兼容。

Android内核构建文档描述了如何构建参考GKI内核。特别是,记录在案的过程可确保使用正确的工具链和配置来构建内核。鼓励下游合作伙伴使用相同的工具来生成最终内核,以避免由工具链或其他构建时依赖性导致的不兼容性。

内核配置

arch/arm64/configs/gki_defconfig内核是使用arch/arm64/configs/gki_defconfig 。因为这些配置影响KMI,所以对GKI配置的管理非常谨慎。对于冻结的KMI内核,只有在不影响KMI的情况下,才可以添加或删除配置。

必须将GKI内核配置为在各种设备上运行。因此,它必须对所有这些设备所需的所有子系统和选件具有内置支持,不包括用于启用硬件的可加载模块。合作伙伴应请求对开发内核进行必要的配置更改

开机变更

为了促进GKI和供应商组件之间的明确分离, boot分区仅包含通用组件,包括内核和带有GKI模块的ramdisk。定义了新版本的引导标头(v3),以指示符合GKI体系结构。引导映像的GKI版本由Google提供,并在测试GKI兼容性时替换了引导映像的供应商版本。

用于第一阶段的initrecoveryfastbootd的ramdisk是一个initramfs映像,该映像由引导加载程序连接的两个CPIO归档文件组成。第一个CPIO存档来自新的vendor_boot分区。第二个来自boot分区。

此处提供了更改摘要。有关详细信息,请参见供应商引导分区

引导分区

boot分区包括引导ramdisk通用部分的标头,内核和CPIO存档。

使用引导头v3 boot分区时,先前的boot分区的以下部分不再存在:

  • 第二阶段引导程序:如果设备具有第二阶段引导程序,则必须将其存储在其自己的分区中。
  • DTB:DTB存储在供应商引导分区中

boot分区包含带有GKI组件的CPIO归档文件:

  • 位于/lib/modules/ GKI内核模块
  • first_stage_init及其依赖的库
  • fastbootdrecovery (用于A / B和虚拟A / B设备)

GKI引导映像由Google提供,必须用于GKI兼容性测试

最新的arm64 android11-5.4 boot.img可从ci.android.com下载,位于aosp-master分支的aosp_arm64构建构件中。

可以从ci.android.com上的aosp_kernel-common-android11-5.4分支的kernel_aarch64构建工件中下载最新的arm64 android11-5.4内核映像( Image.gz )。

供应商启动分区

vendor_boot引入了vendor_boot分区。它与Virtual A / B进行了A / B合并,由标头,供应商ramdisk和设备树blob组成。供应商虚拟磁盘是一个CPIO存档,其中包含设备启动所需的供应商模块。这包括启用关键SoC功能的模块,以及引导设备和显示初始屏幕所需的存储和显示驱动程序。

CPIO存档包含:

  • 位于/lib/modules/第一阶段init供应商内核模块
  • 位于/lib/modules modprobe配置文件
  • modules.load文件,指示在第一阶段init期间要加载的模块

引导程序要求

引导加载程序必须紧随供应商ramdisk CPIO映像(来自vendor_boot分区)将通用ramdisk CPIO映像(来自boot分区)加载到内存中。解压缩后,结果是通用虚拟磁盘覆盖在供应商虚拟磁盘的文件结构之上。

GKI兼容性测试

对于Android 11平台版本,使用v5.4内核启动的设备必须使用Google提供的GKI引导映像运行VTS和CTS-on-GSI测试。

为GKI内核做贡献

GKI内核是从android11-5.4开始的AOSP通用内核构建的。所有提交的补丁程序必须符合这些贡献准则,其中记录了两种策略:

  1. 最好:对上游Linux进行所有更改。如果合适,请向后移植到稳定版本。这些补丁会自动合并到相应的AOSP通用内核中。如果该修补程序已经在上游Linux中,请发布符合以下修补程序要求的修补程序的反向端口。
  2. 不太好:从树上开发补丁程序(从上游Linux的角度来看)。除非修补程序修复了Android特定的错误,否则除非与kernel-team@android.com协调,否则极不可能接受这些修补程序

对于实施GKI的合作伙伴来说,可能有正当理由需要进行树外修补(尤其是必须满足芯片计划的情况)。对于这些情况,请提交Buganizer问题。

首先通过Gerrit将GKI更改提交到android-mainline分支,然后根据需要反向移植到其他发行版分支。

与可加载模块关联的源代码不需要添加到GKI内核源代码树中,但是强烈建议将所有驱动程序提交给上游Linux。

从主线请求反向移植

通常,可以将GKI合作伙伴所需的主线修补程序反向移植到GKI内核。按照贡献准则将补丁上传到Gerrit。

如果补丁已发布到上游,但尚未被接受,则建议等到接受为止。如果日程安排不允许等待上游接受补丁,请提交Buganizer问题。

添加和删​​除GKI配置

要在arch/arm64/configs/gki_defconfig请求添加或删除配置,请提交Buganizer问题,明确说明请求和理由。如果没有可访问的Buganizer项目,则将带有配置更改的补丁发布到Gerrit,并确保提交消息清楚地说明了需要配置的原因。

冻结的KMI内核中的配置更改不得影响KMI。

修改核心内核代码

不建议对AOSP通用内核中的核心内核代码进行修改。首先将补丁发送到上游Linux,然后反向移植它们。如果有必要更改核心内核,请提交Buganizer问题,明确说明请求和理由。没有Buganizer问题,不接受任何Android特定功能。如果您无法创建Buganizer问题,请发送电子邮件至kernel-team@android.com

通过EXPORT_SYMBOL_GPL()导出符号

不要向上游发送仅包含符号导出的补丁。要考虑用于上游Linux,添加EXPORT_SYMBOL_GPL()要求使用该符号的树内模块化驱动程序,因此在与导出相同的补丁集中包括新驱动程序或对现有驱动程序的更改。

当向上游发送补丁时,提交消息必须包含明确的理由,说明为什么需要补丁并对社区有益。使出口受益于树外驱动程序或功能不是上游维护者的有说服力的论据。

如果由于某种原因无法将补丁发送到上游,请提交Buganizer问题并解释为什么不能将补丁发送到上游。通常,作为内核子系统受支持的接口的符号可能会被接受为导出。但是,随机内部帮助程序功能不太可能被接受,并且系统会要求您重构代码以避免使用它们。

将符号添加到KMI符号列表

必须使用供应商模块使用的GKI内核符号来更新KMI符号列表。因为只有KMI符号保持稳定,所以如果GKI符号依赖于非KMI符号,则不允许模块加载。

extract_symbols脚本从内核构建树中提取相关符号,并可用于更新KMI符号列表。有关更多详细信息,请参考符号列表文档