概览
Fuchsia 系统接口是 Fuchsia 操作系统向其运行的软件呈现的二进制接口。该接口的基础是 vDSO,它提供对系统调用的访问权限。不允许程序直接发出系统调用(例如,通过陷入内核)。而是使用 vDSO 与内核交互。
系统接口的大部分内容通过进程间通信协议提供,这些协议通常使用 FIDL 定义。这些协议通过各种内核基元(包括通道和套接字)进行通信。
fuchsia.io
FIDL 库为文件和目录操作提供了协议。Fuchsia 使用 fuchsia.io
协议为组件提供命名空间,以便组件通过该命名空间访问系统服务和资源。这些命名空间中的名称遵循特定的惯例,这些惯例是系统 ABI 的一部分。如需了解详情,请参阅namespaces。
软件包本身还会在目录结构和文件格式方面提供一个系统接口。系统会使用此信息来初始化这些软件包中存储的组件在其中执行的进程。
术语
系统的应用编程接口 (API) 是系统的源级接口。您通常会编写直接使用此接口的软件。系统 API 发生更改后,您可能需要更新源代码,以适应 API 的更改。
系统的应用二进制接口 (ABI) 是系统的二进制级接口。通常,您不会编写直接使用系统 ABI 的软件。而是根据系统 API 编写软件。编译软件时,编译器创建的二进制工件会通过 ABI 与系统交互。对系统 ABI 进行更改时,您可能需要重新编译源代码,以反映 ABI 中的更改。
ABI Surface
本部分介绍了 Fuchsia 组件的各种 ABI Surface。
vDSO
vDSO 是一个虚拟共享库,可提供对内核的访问权限。具体而言,vDSO 是一个名为 libzircon.so
的 ELF 共享库,用于使用 C 调用惯例导出多个符号。这些符号的可信来源是 //zircon/vdso。文档中介绍了它们的语义。
FIDL 协议
大部分系统接口都是在 Fuchsia 接口定义语言 (FIDL) 中定义的。FIDL 编译器会针对各种目标语言生成特定于语言的 API 和运行时库(称为 FIDL 绑定)。这些绑定提供了一种惯用接口,用于通过 Zircon 通道(和其他基元)发送和接收进程间通信消息。
线格格式
FIDL 协议定义本身以及编译器生成的特定于语言的绑定属于系统 API,但不属于系统 ABI。相反,序列化消息的格式(称为线格式)构成了 ABI。FIDL 线格式由规范定义。
用户信号
除了发送的消息之外,某些 FIDL 协议还会使用底层内核对象上的用户信号。目前,这些信号未在 FIDL 中声明。通常,任何关联的用户信号的语义都会以文字形式记录在 FIDL 定义的注释中。
命名空间惯例
并提供 命名空间和传出目录中的名称遵循特定的惯例,这些惯例是系统 ABI 的一部分。
命名空间
在启动期间提供,并允许组件与系统的其余部分发布的功能进行交互。
以及通过此命名空间中的 /svc
条目(其中列出了这些服务在知名名称下的名称)来发现这些服务。
同样,按照惯例,pkg
命名空间条目会映射到解析组件所在的软件包。
发件人目录
并使用此目录中的 /svc
条目(其中列出了这些服务在知名名称下的列表)将其公开给其他组件。
数据格式
某些命名空间包含包含数据的文件。这些文件使用的格式也属于系统 ABI 的一部分。例如,组件通过包含 certs.pem
文件的命名空间条目访问根证书。因此,pem
数据格式是系统 ABI 的一部分。
软件包惯例
Fuchsia 软件包的目录结构遵循特定的命名惯例。这些惯例也是系统 ABI 的一部分。本部分提供了两个重要的打包惯例示例。
Meta
按照惯例,软件包中的 meta
目录包含用于描述软件包的元数据文件。此元数据的结构,包括这些文件使用的以下数据格式:
lib
按照惯例,软件包中的 lib
目录包含软件包中组件使用的共享库。当系统从软件包中运行可执行文件时,系统会相对于此 lib
目录解析对共享库的请求。
Fuchsia 与其他操作系统之间的一个重要区别在于,共享库本身是由软件包创建者提供的,而不是由系统本身提供。因此,共享库本身(包括 libc
)不属于系统 ABI。
系统确实提供了两个共享库:vDSO 和 Vulkan ICD。如需了解详情,请参阅这些部分。
流程结构
Fuchsia 上的进程非常灵活,在很大程度上受进程中运行的可执行文件的控制,但进程的一些初始结构由系统和系统 ABI 的一部分控制。
如需了解详情,请参阅程序加载。
ELF 加载器
Fuchsia 使用 ELF 数据格式来处理可执行文件。将可执行文件加载到进程中时,加载器会将可执行文件的内容解析为 ELF。加载器会从可执行文件中读取 INTERP
指令,并将该名称解析为包含可执行文件的软件包的 lib
目录中的文件。然后,加载器会将 INTERP
文件的内容解析为 ELF 共享库,重新定位该库,并将该库映射到新创建的进程中。
启动消息
在启动进程的过程中,进程的创建者会向进程提供消息,其中包含命令行参数、environ
、初始句柄和进程的命名空间等信息。(传出目录包含在进程的初始句柄集中。)
此消息的格式(包括命令行参数和 environ
等字段的长度限制)属于系统 ABI 的一部分,消息内容的相关惯例也是如此。例如,按照惯例,PWD
环境变量是创建者建议进程用作其当前工作目录的名称。
初始句柄与数字标识符相关联。与这些标识符相关的惯例属于系统 ABI 的一部分。例如,按照惯例,PA_PROC_SELF
句柄是新创建进程的进程对象的句柄。除了这些句柄的类型之外,与这些句柄关联的权限也属于系统 ABI 的一部分。
VMAR 结构
在启动进程之前,创建者会修改进程的根 VMAR。例如,创建者会映射 vDSO 并为初始线程分配一个堆栈。进程启动时的 VMAR 结构是系统 ABI 的一部分。
作业政策
进程在作业中运行,作业可以将政策应用于其包含的进程和作业。应用于进程的作业政策是系统 ABI 的一部分。例如,组件在将 ZX_POL_NEW_PROCESS
设置为 ZX_POL_ACTION_DENY
的进程中运行。这会强制组件使用 fuchsia.process.Launcher
协议创建进程,而不是直接发出 zx_process_create
系统调用。
Vulkan ICD
使用 Vulkan API 进行硬件加速图形的组件会与 libvulkan.so
链接,并在其清单中指定 vulkan
功能。此库由包含相应组件的软件包提供,因此不属于系统 ABI 的一部分。不过,libvulkan.so
会加载另一个共享库,称为 Vulkan 可安装客户端驱动程序 (Vulkan ICD)。Vulkan ICD 使用 fuchsia.vulkan.loader.Loader
加载,这意味着该库由系统本身提供,而不是由包含该组件的软件包提供。因此,Vulkan ICD 是系统 ABI 的一部分。
Vulkan ICD 是一个 ELF 共享库,只导出三个符号。这些符号预留供 Vulkan ICD 使用,不应直接使用。
vk_icdGetInstanceProcAddr
vk_icdNegotiateLoaderICDInterfaceVersion
vk_icdInitializeOpenInNamespaceCallback
此外,Vulkan ICD 共享库有一个 NEEDED
部分,其中列出了 Vulkan ICD 依赖的多个共享库。包含该组件的软件包必须提供这些共享库。
Vulkan ICD 还会导入一些符号。这些导入符号的相关惯例(例如其参数和语义)属于系统 ABI 的一部分。
目前,Vulkan ICD 的 NEEDED
部分和导入符号列表都比我们预期的要大。希望我们能够尽可能减少系统 ABI 的这些方面。
套接字
数据报封装
用于网络连接的数据报套接字包含一个帧,用于指定与数据报关联的网络地址。此帧也是系统 ABI 的一部分。
终端协议
在终端中运行的程序使用 Fuchsia 终端协议与终端通信,该协议是一种类似于 vt100
的文本协议。此协议还通过 ssh
在网络上公开,由预期传入 ssh
连接支持此协议的客户端和预期传出 ssh
连接支持此协议的服务器使用。