什么是平台可更新性?
由于产品要求会随时间推移而发生变化,因此 Fuchsia 必须能够进行调整,以满足这些要求。
新平台版本可能会提供新功能和问题修复。然后,与 Fuchsia 平台集成的产品所有者可能需要在新平台 build 之上对现有的产品组件进行 rebase 操作。根据产品的性质和更新的提供方式,最终用户甚至可以直接从 Fuchsia 项目接收平台更新。根据要组装的产品的性质,产品所有者可能无法将现有应用软件移植到新平台版本,并且必须依赖于现有预编译的应用继续适用于新预编译的平台。
Fuchsia 旨在让平台的各种元素随着时间的推移而变化和更新,同时支持现有产品和新产品。参与产品生命周期的不同软件供应商可能都有各自的开发和发布时间表,彼此相互独立。本文档介绍了支持这种分离的可更新的机制。
平台可更新性如何运作?
Fuchsia 有多种机制,可提升平台随时间更新的能力。下面我们将调查最主要的机制及其部分应用。
严格定义的接口
接口充当不同软件之间的协定。Fuchsia 定义了平台与其运行的软件之间的此类协定。该平台的应用二进制接口 (ABI) Surface 经过精确定义和枚举。ABI Surface 包含内核的入口点、与平台服务的所有交互以及其他惯例和协议。开发者可以编写软件来与 Fuchsia 进行交互,例如使用基于 Fuchsia 集成商开发套件 (IDK) 的软件开发套件 (SDK)。Fuchsia IDK 包含接口定义和客户端库,这些库提供源自同一平台协定的应用编程接口 (API)。
接口定义语言
Fuchsia ABI 主要根据 Fuchsia 接口定义语言 (FIDL) 进行定义。
- 内核 vDSO 中的系统调用(系统调用)和系统调用 ABI以 FIDL 表示。请注意,传递到系统调用以及从系统调用传递的结构目前尚未在 FIDL 中定义。
- 有各种 FIDL 协议用于与用户模式平台服务进行通信。
- 常用 API 根据 FIDL 实现。
FIDL 工具链可使用多种编程语言为客户端和服务器生成绑定代码。该工具链旨在让您轻松扩展对更多语言的支持。
FIDL 旨在支持跨版本兼容性并简化接口更改。FIDL 具有兼容性保证,并准确列出哪些更改与二进制文件兼容(ABI 稳定)和/或明确列出哪些更改与源代码兼容(API 稳定)。
作为一种接口定义语言,FIDL 具有特殊功能,可帮助开发者随时间更改协议和类型,同时保持向后和向前兼容性。这些过渡有时也称为软过渡。
- 开发者可能会逐步添加和移除方法。
- 开发者可以使用灵活联合类型,允许旧客户端忽略新数据。
- 开发者可以在不破坏 ABI 兼容性的情况下重命名类型。
通过根据 FIDL 定义 Fuchsia 系统接口的大部分内容(尤其是预计会随时间变化的部分),Fuchsia 可以更好地利用 FIDL 的特殊修订功能。
版本控制和兼容性元数据
Fuchsia 定义了一个平台版本控制方案,以指明 Fuchsia IDK 的 API 级别和 Fuchsia 平台的 ABI 修订版本。Fuchsia IDK 的每个版本或 Fuchsia 平台可能会分别引入 API 或 ABI 修订版本,在这种情况下,版本以递增的版本表示。带版本号的版本可支持将一系列版本作为向后/向前兼容性窗口。
Fuchsia 接口的属性可以用其各自的版本控制元数据进行注解。
- 在指定版本中,属性已添加,但可能已移除。这将根据编号版本定义该属性的支持期限。
- 属性可能会在特定版本中被标记为“已弃用”。弃用表示最终移除某个属性的意图,但不会影响 ABI。
- 已废弃的属性可能会附加人类可读形式的附加备注。该备注通常会向开发者指明在移除属性后应采取哪些措施来避免服务中断。
接口的不同元素可能会以不同的方式添加注释。例如,协议中的不同方法或联合中的字段可能在不同版本中添加、废弃或移除。
FIDL 是 Fuchsia 上接口定义的通用语言。支持版本控制注释。为了帮助更改平台 FIDL 文件的开发者检测其更改是否会为 API 引入可能不兼容的修订版本,系统会基于 FIDL 文件生成 API 摘要。可以将摘要与已保存的引用(即黄金文件)进行比较,以识别破坏性更改并确保通过显式 intent 引入这些更改。
命名空间
传统上,进程是线程和受保护资源(如虚拟内存区域)的容器。在 Fuchsia 上,可能还会为进程分配本地命名空间。命名空间是sandbox的基础,可确保程序只能以指定的资源(例如内核对象、FIDL 协议或文件的形式)访问相应资源。这些功能构成了程序在运行时可能会使用的不同功能。capabilities
沙盒通常根据组件清单进行定义。组件清单的集合可以定义沙盒中显示的功能以及如何满足这些功能。但是,这些详细信息对沙盒内的组件不可见。组件的父项可能会将某项功能路由到其由一个组件或另一个组件提供的子项,从而随时间改变实现细节,但沙盒的形状保持不变。
沙盒有助于促进松散耦合,并允许实现细节在客户端不知情的情况下更改。例如,当 Netstack3 取代 Netstack2 时,理想情况下使用网络功能的组件不会注意到这种差异。这也有助于进行测试,因为测试作者可能会向被测组件未检测到的组件注入一个测试替身。
打包
软件包是 Fuchsia 上的软件分发单元。软件包在给定的目录布局中包含一个或多个文件。这些软件包可能符合系统 ABI 中的打包惯例。
打包功能与命名空间协同发挥作用,共同打造出一种沙盒化形式。从软件包解析的组件将能够访问其命名空间中的打包内容。因此,组件作者可以将其他文件与其组件打包在一起,例如本地化资源。反之,它们通常也无法直接访问其他软件包中的文件。例如,系统字体通过 FIDL 协议提供,而不是作为直接文件访问。或者,开发者可以打包自己的字体文件。
违规处置
如果可以规避在两个系统之间使用给定接口的行为,那么这两个系统的耦合可能会更紧密,并且无法相互独立更改。Fuchsia 使用各种机制来强制观察和遵循平台接口。
- 内核会定义一个用于从用户模式代码进入内核的 ABI,即系统调用 ABI。不过,该 ABI 位于内核和 vDSO 之间。应用需要调用 vDSO 的导出符号,而不是直接执行系统调用。由于内核和 vDSO 可以一起进行版本控制,因此要求应用调用 vDSO 可让系统调用 ABI 无缝更改,而不会被应用开发者检测到。为了强制执行此属性,内核会在系统调用入口点检查调用方的地址,并确保该地址落在 vDSO 在调用方的地址空间中映射到的范围内。
- 内核提供用于创建进程的系统调用。不过,程序加载的细节比较复杂,因此它们被抽象为进程启动器实现。为了确保应用开发者不会接触到这些细节,组件不能直接创建进程,而是可以提供一个采用 FIDL 协议的进程启动器。这样一来,程序加载细节会随时间变化。
- 任何文件系统目录都可以用作进程命名空间的根目录。这些命名空间可确保程序只能访问一组已知且枚举的文件,从而防止它们形成意外的 ABI。为确保目录路径充当不可转义的根目录,Fuchsia 文件系统不会实现“..”。