什么是平台可更新性?
由于产品要求会随时间推移而发生变化,因此 Fuchsia 必须能够更改产品来满足这些要求。
新平台版本可能会提供新功能和修复问题。与 Fuchsia 平台集成的产品所有者可能需要在新平台 build 之上对现有产品组进行 rebase 操作。根据产品的性质和更新交付方式,最终用户甚至可能会直接从 Fuchsia 项目接收平台更新。根据组装产品的性质,产品所有者可能无法将现有应用软件移植到新的平台版本,并且必须依赖现有应用预构建版本继续支持新平台预构建版本。
Fuchsia 旨在让平台的各种元素能够随时间推移而发生变化和更新,同时支持现有产品和新产品。产品生命周期中涉及的不同软件供应商可能都有自己的开发和发布时间表,彼此互不影响。本文档介绍了支持这种分离更新的机制。
平台可更新性如何运作?
Fuchsia 采用多种机制来提升平台随时间的更新能力。下面,我们将调查最主要的机制及其部分应用。
严格定义的接口
接口充当不同软件之间的协定。Fuchsia 定义了平台与其运行的软件之间的此类协定。平台的应用二进制接口 (ABI) Surface 已准确定义和枚举,ABI 接口包括内核的入口点、与平台服务的所有交互以及其他惯例和协议。开发者可以编写软件以与 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
沙盒通常以组件清单的形式进行定义。组件清单集合可以定义沙盒中存在哪些功能以及如何满足这些功能。不过,这些详细信息对沙盒内的组件不可见。组件的父级可将某项 capability 路由到由某个组件或另一组件提供的其子级,它会随时间改变实现细节,但沙盒的形状保持不变。
沙盒有助于促进松散耦合,并且允许在客户端不知情的情况下更改实现细节。例如,当 Netstack3 取代 Netstack2 时,理想情况下使用网络功能的组件不会注意到这种差异。这也有助于进行测试,因为测试作者可以向被测组件未检测到的组件注入一个测试替身。
打包
软件包是 Fuchsia 上软件分发的单位。软件包在给定的目录布局中包含一个或多个文件。这些依赖项可能符合系统 ABI 一部分的打包惯例。
打包与命名空间协同作用,形成一种沙盒形式。从软件包解析的组件将有权访问其命名空间中的打包内容。因此,组件作者可能会将其他文件与其组件(例如本地化资源)打包在一起。反之,它们通常不会直接访问其他软件包中的文件。例如,系统字体通过 FIDL 协议提供,而不是作为直接文件访问方式。或者,开发者可以打包自己的字体文件。
违规处置
如果可以规避在两个系统之间使用给定接口的行为,那么这两个系统的耦合可能会更紧密,无法相互独立更改。Fuchsia 使用各种机制来强制观察和遵循平台接口。
- 内核定义一个用于从用户模式代码进入内核的 ABI,即系统调用 ABI。不过,该 ABI 位于内核与 vDSO 之间。应用需要调用 vDSO 的导出符号,而不是直接执行系统调用。由于内核和 vDSO 可以一起进行版本控制,因此要求应用调用 vDSO 可让系统调用 ABI 无缝更改,而不会被应用开发者检测。为了强制执行此属性,内核会在系统调用入口点检查调用方的地址,并确保它位于调用方地址空间中 vDSO 映射的范围内。
- 内核提供用于创建进程的系统调用。不过,程序加载的细节很复杂,因此需要将它们抽象出来,用于进程启动器实现。为了确保应用开发者不会接触到这些细节,组件不能直接创建进程,而是可以通过 FIDL 协议提供进程启动器。这样一来,程序加载的细节会随着时间的推移而变化。
- 任何文件系统目录都可以用作进程命名空间的根目录。这些命名空间可确保程序只能访问一组已知且枚举的文件,以防止它们形成意外的 ABI。为确保目录路径充当不可转义的根目录,Fuchsia 文件系统不会实现“..”。