Zircon 是为 Fuchsia 提供支持的核心。 它由内核和一小组用户空间服务、驱动程序和库组成,这些服务、驱动程序和库对启动等核心系统功能至关重要。
虽然 Zircon 采用了微内核普及的许多概念,但并不力求尽可能小。相反,Zircon 类似微内核的架构使 Fuchsia 能够将系统中运行的可信代码量减少到几个核心功能:
- 内存管理
- 调度
- 进程间通信
系统调用
用户空间代码使用系统调用与内核空间中的对象进行交互。Zircon 具有系统调用来执行低级操作,例如:
- 内存管理
- 任务和进程管理
- 进程间通信 (IPC) 和同步
- 异常处理
- 硬件支持服务(时钟、熵、设备 I/O)
libzircon.so
Zircon vDSO 是一种 ELF 格式的共享库,内核会将其映射到每个新进程的地址空间。此库被视为“虚拟”库,因为它由内核映像直接公开,而不是从文件加载。
大多数系统调用都直接与一个或多个句柄一起操作。句柄是指对位于内核空间中的对象的进程本地引用,表示为 32 位整数 (zx_handle_t
)。每个句柄都会声明持有者必须对句柄本身或引用的对象执行操作的权限或权利。
作业、进程和线程
Zircon 公开了三个主要的 kernel 对象来运行代码:
进程构成了系统功能的基础。每个进程都会通过其持有的各种句柄获得一组功能。
Fuchsia 软件可以在单个进程内运行,也可以在多个进程内运行。借助作业,您可以将由多个进程组成的“应用”作为单个实体进行控制。
进程间通信
由于进程默认处于隔离状态,因此内核需要提供一种方式,让进程能够安全地相互通信。Zircon 包含以下用于进程间通信 (IPC) 的内核对象类型:
- 事件:两个进程之间的信号接口。
- 套接字:流式数据传输,类似于管道。
- 流:可跳转的流式数据传输,例如文件。
- 通道:基于消息的传输,能够传递数据和一组句柄。
- FIFO:用于共享内存访问的控制平面,针对小型数据载荷进行了优化。
在这些对象中,通道特别适合帮助启动新进程,因为它们能够将句柄(以及功能)转移到另一个进程。
通道只有两个端点句柄,每个句柄都由单独的进程拥有。只有所有者可以读取或写入消息,但端点的所有权可以在一个进程之间转移。将句柄写入通道后,系统会将其从发送进程中移除。从通道读取包含句柄的消息时,系统会将句柄添加到接收进程中。
Zircon 通道是服务级 IPC 协议的基础,这些协议由 Fuchsia 接口定义语言 (FIDL) 描述。 FIDL 协议是 Fuchsia 程序使用的 IPC 主要方法。稍后,您将详细了解如何创建和使用 FIDL 协议。
练习:作业和进程
我们来探索正在运行的系统中的一些基本概念。在本练习中,您将了解作业和进程如何相互作用以形成树状结构。
启动模拟器
如果您还没有运行的实例,请启动模拟器:
ffx emu start --headless
启动完成后,模拟器会输出以下消息并返回:
Logging to "$HOME/.local/share/Fuchsia/ffx/emu/instances/fuchsia-emulator/emulator.log"
Waiting for Fuchsia to start (up to 60 seconds)........
Emulator is ready.
转储进程列表
连接到设备 shell 提示符,然后使用 ps
命令转储正在运行的作业和进程的列表。
fx shell ps
下面是一个经过修剪的输出示例:
TASK PSS PRIVATE SHARED STATE NAME
j: 1027 507.8M 507.4M root
p: 1061 564.4k 564k 36k bin/bootsvc
p: 1150 4264.4k 4264k 36k bin/component_manager
j: 1479 228.4k 228k
p: 1583 228.4k 228k 36k pwrbtn-monitor.cm
j: 1484 532.4k 532k
p: 1599 532.4k 532k 36k svchost.cm
j: 1544 402.4k 304k
p: 1633 402.4k 304k 232k netsvc.cm
j: 1681 296.4k 296k
p: 1733 296.4k 296k 36k console-launcher.cm
j: 1799 7232.4k 7232k
p: 1825 7232.4k 7232k 36k archivist.cm
j: 1927 660.4k 660k
p: 1955 660.4k 660k 36k base-resolver.cm
j: 2072 1016.4k 1016k
p: 2088 1016.4k 1016k 36k driver_manager.cm
j: 2239 348.4k 348k
p: 2252 348.4k 348k 36k device-name-provider.cm
j: 2364 275.3M 275.3M
p: 2380 1012.4k 1012k 36k fshost.cm
p: 6544 252.1M 252.1M 36k /pkg/bin/blobfs
p: 10205 9744.4k 9744k 36k /pkg/bin/minfs
p: 10475 12.8M 12.8M 36k pkgfs
现在,我们先重点关注输出中的两个列:
- TASK:此字段用于指明每个条目是作业 (
j
) 还是进程 (p
),后跟其唯一 ID。 - NAME:此选项可提供系统哪部分在那里运行的更多详细信息。
我们来根据前面讨论的内容,详细了解一些有趣的事情:
- 每个进程都与一个父级作业相关联。某些作业有多个进程。
- 所有作业都会追溯到
root
作业作为最终父级,形成一个树状结构。 - 在启动期间,系统会直接将一些进程启动到
root
作业中。大多数其他进程都是在其自己的父作业下启动的。 - 完成初始启动工作后,许多条目都带有
.cm
扩展名。这些是指组件,您稍后会详细了解它们。 - 其中一些组件是核心服务,例如文件系统 (
fshost.cm
) 和驱动程序 (driver_manager.cm
),它们位于用户空间中,与内核分离。
接下来,我们将探讨 Zircon 如何实现 Fuchsia 安全模型的基础。