Linux 内核是几乎所有的 Android 设备上极其重要的软件组成部分。本部分介绍了 Linux 内核开发和版本模型(如下)、稳定的长期支持 (LTS) 内核(包括所有 Android 设备都应使用稳定版本而非择优挑选补丁程序的原因)、内核配置和加固、接口和模块化内核要求(在 Android O 中推出)、内核调试和网络测试以及 SquashFS。
Linux 内核开发
Linux 内核是迄今为止最大的协同软件项目。在 2016 年,超过 450 家不同公司的 4000 多名开发者对该项目做出了贡献。该项目共有 6 个版本,每个版本都包含 12000 到 16000 项不同的更改。在 2016 年底,Linux 内核的规模刚好超过 56000 个文件,其中包括 2200 万行代码、编译脚本和文档(内核版本 4.9)。(要查看完整的 Linux 开发统计信息,请参阅 https://kernelnewbies.org/DevelopmentStatistics。)
虽然 Linux 内核包含其支持的所有不同芯片架构和硬件驱动程序的代码,但各个系统仅运行一小部分代码库。一台普通的笔记本电脑需要使用来自 5000 个文件的大约 200 万行内核代码才能正常运行;而 Pixel 手机需要使用来自 6000 个文件的 320 万行内核代码才能正常运行(因为 SoC 的复杂性有所增加)。
Linux 内核版本
Linux 内核使用的版本模型与标准 AOSP 版本大不相同。随着 2.6 内核在 2003 年 12 月发布,内核开发者社区从之前具有单独开发和稳定内核分支的模型迁移到“仅限稳定”的分支模型。在此模型中,每 2-3 个月发布一次新版本,内核开发者社区声明该版本“稳定”,并建议所有用户运行该版本。开发模型出现这种变化的原因在于:2.6 版本内核之前的版本周期非常长(将近 3 年),且同时维护两个不同的代码库分支难度很高。
内核版本的编号从 2.6.x 开始,其中 x 是个数字,会在每次发布新版本时递增(除了表示此版本比上一内核版本更新之外,该数字的值不具有任何意义)。自那时起,内核版本现在已发展到 4.x,其中发生了 2 次重大版本变更。维护人员采用这些版本号只是为了避免更高的次要版本号令用户感到困惑。
稳定的内核版本和更新
由于之前的内核开发模型(每 2-3 个月发布一次新版本)被认为无法满足大多数用户的需求,Linux 内核稳定版模型于 2005 年随之诞生。用户希望实际用到在 2-3 个月内提交的错误修复程序,但 Linux 发行方发现,如果没有内核社区的反馈,很难确保内核保持最新状态。一般情况下,努力确保各个内核的安全并及时集成最新的错误修复程序对各方而言不仅任务艰巨,而且令人颇感困惑。
稳定的内核版本直接基于 Linus Torvalds 的版本,一般每周发布一次,具体取决于各种外部因素(处于一年中的哪个时间、可用的补丁程序、维护人员的工作量等)。稳定版本的编号开头为内核版本编号,末尾再添加一个数字。例如,Linus 发布了 4.4 内核,则基于此内核的稳定内核版本编号为 4.4.1、4.4.2、4.4.3,依此类推。表示稳定内核版本树时,该序列号通常简写为 4.4.y。每个稳定的内核版本树由一位内核开发者维护,该开发者负责为该版本挑选所需的补丁程序以及管理审核/发布流程。
稳定内核的维护期限为当前开发周期。Linus 发布新内核后,上一个稳定内核版本树就会停止维护,用户必须转为使用新发布的内核。
长期稳定的内核
这种新的稳定版本流程在采用一年之后,很多不同的 Linux 用户都表示希望延长对内核的支持,而不只是几个月时间。因此,长期支持 (LTS) 内核版本应运而生,第一个 LTS 内核 (2.6.16) 在 2006 年诞生。从那时起,每年都会选择一个新的 LTS 内核,并且内核社区会为该内核提供最少 2 年的维护支持。
在撰写本文之时,LTS 内核版本为 4.4.y 和 4.9.y,并且每周发布一个新内核。为了满足某些用户和发行方的需求,内核开发者会额外维护一些较旧的内核,但会延长发布周期。如需有关所有长期稳定内核、内核负责方以及维护时长的信息,请访问 kernel.org 版本页面。
LTS 内核版本每天平均会接纳 6-8 个补丁程序,而常规稳定内核版本每天则接纳 10-15 个补丁程序。考虑到相应开发内核版本的当前时间和其他外部不定因素,每个版本的补丁程序数量也会有所不同。LTS 内核的版本越旧,对应的补丁程序数量就越少,这是因为很多最新的错误修复程序与旧版内核无关。不过,内核版本越旧,向后移植那些需要采纳的更改就越难,这是因为代码库发生了变化。因此,虽然采纳的总体补丁程序数量比较少,但维护 LTS 内核所需的工作量要高于维护常规稳定内核所需的工作量。
稳定内核补丁程序规则
对于哪些内容可添加到稳定内核版本方面,相关规则自稳定内核版本模型推出后几乎没有发生任何变化,这些规则可总结为以下几点:
- 必须明显正确无疑且经过测试。
- 不得超过 100 行。
- 必须只修复一个问题。
- 必须修复已得到报告的问题。
- 可以是新的设备 ID 或硬件 quirk,但不可以添加主要新功能。
- 必须已合并到 Linus Torvalds 树中。
Documentation/process/stable_kernel_rules.rst
内核文件。
最后一条规则“必须已合并到 Linus Torvalds 树中”可防止内核社区遗漏修复程序。该社区不希望那些不在 Linus Torvalds 树中的修复程序进入稳定内核版本,以使升级的任何用户都绝不会遇到回归问题。这样可避免给维护稳定开发分支的其他项目人员带来诸多问题。
内核更新
Linux 内核社区以前曾向其用户群承诺,任何升级都不会破坏当前在上一个版本中运行正常的任何功能。这个承诺如今依然有效。回归确实会发生,但属于优先级最高的错误,要么快速对其进行修复,要么从 Linux 内核树快速还原那些导致回归的更改。
这一承诺既适用于稳定内核的渐增式更新,也适用于每 3 个月进行一次的大规模重要更新。不过,内核社区只能对已合并到 Linux 内核树的代码做出此承诺。如果在合并到设备内核的任何代码中,有任何代码不在 kernel.org 版本中,则均属于未知代码,社区无法规划(甚至考虑)与这些代码的互动。
由于各版本之间发生了大量更改(每个版本有 10000-14000 项更改),因此包含大型补丁程序集的基于 Linux 的设备在更新到新版内核时可能会遇到严重问题。由于 SoC 补丁程序集的体积大、对架构专用内核代码(有时甚至是核心内核代码)的修改较多,在更新到新版内核时尤其容易出现问题。因此,大多数 SoC 供应商开始使用 LTS 版本对其设备进行标准化,使这些设备能够直接从 Linux 内核社区接收错误和安全更新。
安全
在发布内核时,Linux 内核社区几乎从不将具体更改声明为“安全修复程序”。这是因为存在一个基本问题,那就是在开发错误修复程序时难以确定其是否为安全修复程序。此外,很多错误修复程序要经过很长时间之后才能确定为与安全相关,因此内核社区强烈建议始终接纳已发布的所有错误修复程序。
注意:要详细了解 Linus Torvalds 关于安全修复程序的声明,请参阅相关 电子邮件会话。内核社区收到安全问题的报告时,便会尽快进行修复并将相应代码公开推送到开发树和稳定版本。如上所述,这些更改几乎从来都不会被描述为“安全修复程序”,而是看起来与内核的其他错误修复程序别无二致。这样做是为了让相关方能够在问题报告者将相应问题公诸于世之前更新其系统。
要详细了解如何向内核社区报告安全错误以使其尽快得到解决和修复,请参阅《Linux 内核用户和管理员指南》(www.kernel.org) 中的安全错误部分。
由于内核团队不会公布安全错误,因此 Linux 内核相关问题的 CVE 编号通常在修复程序合并到稳定开发分支后的几周、几个月甚或几年后发布。
确保系统安全
部署使用 Linux 的设备时,强烈建议制造商采纳所有 LTS 内核更新,在适当的测试表明更新没有什么问题后,将其推送给用户。这样做有多项优势:
- 内核开发者已整体审核发布的版本,而不是单独审核各个组件。
- 很难(即使能够)确定哪些补丁程序修复的是“安全”问题,哪些修复的不是安全问题。几乎所有 LTS 版本都至少包含一个已知的安全修复程序,以及很多暂时“未知”的安全修复程序。
- 如果测试表明有问题,则内核开发者社区会迅速采取应对措施以解决问题。
- 如果在更改的代码中,尝试仅过滤出您运行的那些代码,会导致内核树无法与未来的上游版本正确合并。
Android 通用内核
AOSP 通用内核是长期支持 (LTS) 内核的下游,包含与 Android 社区相关但尚未合并到 LTS 的补丁程序。这些补丁程序可能包括:
- 针对 Android 需求定制的功能(例如交互式
cpufreq
调节器)。 - 由于实现方面的问题而被上游拒绝的功能(例如 MTP/PTP、Paranoid Networking)。
- 可供 Android 设备使用但仍处于开发上游阶段的功能(例如 Energy Aware Scheduling/EAS)。
- 对其他方有用的供应商/OEM 功能(例如
sdcardfs
)。
通用内核列表
要查看 Android 通用内核列表,请访问 https://android.googlesource.com/kernel/common/(如下所示)。
图 1. Android 通用内核列表。
与 LTS 的区别
与 LTS (4.4.40) 相比,Android 通用内核更改了 679 行,插入了 56172 行并删除了 3340 行(截止 2017 年 2 月)。
图 2. 各个版本的 Android 特定代码。
最大的特性包括:
- 13.8% SoC (arch/arm64, arch/x86)
- 9.2% USB (drivers/usb)
- 8.2% Energy Aware Scheduling (kernel/sched)
- 8.2% Atomic Display Framework (drivers/video/adf)
- 8.0% 网络 (net/netfilter)
- 6.2% sdcardfs (fs/sdcardfs)
- 5.0% Verity (drivers/md)
- 3.7% 输入 (drivers/input/misc)
- 3.3% FIQ 调试程序 (drivers/staging/android/fiq_debugger)
- 2.4% Cpufreq (drivers/cpufreq)
- 2.2% Goldfish 模拟器 (drivers/platform/goldfish)
要求
所有 AOSP 通用内核必须提供以下各项:
- 用于下游合作伙伴及时获取最新更新(包括所有 LTS 补丁程序)的方法。
- 用于确保新功能开发不会影响从 AOSP 通用内核合并的机制(即使之前的 Android 版本也不受影响)。
- 用于下游合作伙伴轻松识别属于 Android 安全公告 (ASB) 范围内的安全补丁程序的方法。如果 OEM 尝试包含公告中未列出的补丁程序,则满足运营商有关全面重新认证的要求。
此外,必须在 AOSP 通用内核上定期执行测试,并且在分支通过测试时对其进行标记。
LTS 合并
为确保下游合作伙伴能够及时获取最新更新(包括所有 LTS 补丁程序),android-X.Y 将从 LTS 获取定期合并,并通过自动 VTS、CTS 和编译/启动测试进行验证。
Android-dessert 版本分支
为确保新功能开发不会影响从 AOSP 通用内核合并(即使之前的 Android 版本也不受影响),android-X.Y-androidRel 是从 Android-dessert 最初版本之前的 android-X.Y 克隆的,它会从 LTS 获取定期合并,并基于相关的 Android 版本进行测试。例如,android-4.4-n 分支从 LTS 4.4.y 分支获取合并。
Android-release 版本分支
为确保下游合作伙伴能够轻松识别属于 ASB 范围内的安全补丁程序,android-X.Y-androidRel-type 是从 Android 版本发布时的 android-X.Y-androidRel 克隆的,并且只能获取公告中列出的补丁程序。
在确认与公告相关的补丁程序合并到版本分支之后,相应分支将用 ASB 级别进行标记。例如,标记 ASB-2017-10-05 表示相应版本分支包含 2017 年 10 月 5 日发布的 Android 安全公告中的补丁程序。父分支包含这些安全补丁程序,因此,如果 android-4.4-o-release 分支标记为 ASB-2017-10-01,则 android-4.4-o 和 android-4.4 也是用相应公告中的补丁程序进行更新的最新版本。例如:
- 在发布 Android N MR1 之前,android-4.4-n-mr1 是从 android-4.4-n 克隆的。
- 只有 ASB 中列出的补丁程序才会进行合并,允许 OEM(运营商对其有严格的要求,旨在避免对安全更新进行全面重新认证)查找公告中列出的补丁程序。
- android-4.4-n-mr2 将由 android-4.4-n-mr1 以及这两个版本之间合并的 LTS 补丁程序构成。
- 每个月 ASB 公开发布时,相应版本分支都会使用公告中提及的所有上游补丁程序进行更新(公告中提及的设备特定补丁程序不会应用于通用内核)。
定期测试
所有 AOSP 通用内核都会定期接受测试,并且测试结果将公开发布。具体而言:
- 在 LTS 更新或其他补丁程序合并之后,将会运行 VTS 以及一部分 CTS,相关结果将在 https://qa-reports.linaro.org/lkft 上公布。
- 为持续测试各种架构和版本中的编译/启动中断,将会运行
kernelci
,相关结果将在 https://kernelci.org/job/android 上公布。
分支层次结构 (android-4.4)
android-4.4 内核的分支层次结构使用了以下结构:
图 3. android-4.4 内核的分支层次结构。
准则
Android 实现应使用以下内核准则:
- 将新的 AOSP 通用内核用作上游合并源。
- 要从 LTS 获取补丁程序,需从 android-X.Y 合并。
- 在开发阶段定期合并。
- 将设备更新至新的 Android 版本时,需从 android-X.Y 分支或目标版本的版本分支合并(例如,要更新至 Nougat MR2,需从 android-4.4-n-mr2 分支合并)。
- 如果运营商对安全更新补丁程序有限制,则需从版本分支合并,以便进行安全更新。
- 要从 LTS 获取补丁程序,需从 android-X.Y 合并。
- 将修复程序发送至上游主线内核、LTS 内核或 AOSP 通用内核。