Zircon 基础知识

<0x

虽然 Zircon 应用了许多由微内核普及的概念,但它并不追求极简。相反,Zircon 的类微内核架构使 Fuchsia 能够将系统中运行的可信代码量减少到几个核心功能:

  • 内存管理
  • Scheduling
  • 进程间通信

数据表,显示了 Fuchsia 和典型操作系统中内核服务的比较,表明 Fuchsia 内核中包含的服务较少。

系统调用

用户空间代码使用系统调用与内核空间中的对象进行交互。Zircon 具有用于执行低级别操作的系统调用,例如:

  • 内存管理
  • 任务和进程管理
  • 进程间通信 (IPC) 和同步
  • 异常处理
  • 硬件支持服务(时钟、熵、设备 I/O)

用户空间进程通过 libzircon.so 访问系统调用,libzircon.soZircon vDSO 是 ELF 格式的共享库,内核会将其映射到每个新进程的地址空间中。此库被视为“虚拟”库,因为它是由内核映像直接公开的,而不是从文件中加载的。

大多数系统调用直接与一个或多个句柄(以 32 位整数 [zx_handle_t] 表示的对内核空间中对象的进程本地引用)进行交互。每个句柄都声明了持有者对句柄本身或所引用对象执行操作的权限或权利

作业、进程和线程

Zircon 公开了三个用于运行代码的主要内核对象:

  • 线程:给定地址空间内的执行线程。
  • 进程:在私有隔离的地址空间中运行的一组可执行指令。
  • 作业:相关进程和作业的组。所有作业构成一个单根树。

树状图,用于说明 Fuchsia 的进程层次结构。进程分组为作业,作业最终归 Root Job 所有。

进程是系统功能的基础。每个进程都通过其持有的各种句柄获得一组功能。

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

我们先重点关注输出中的两列:

  • 任务:此列会显示每个条目是作业 (j) 还是进程 (p),后跟它们的唯一 ID。
  • NAME:此列提供有关相应位置运行的系统组件的更多详细信息。

根据我们目前讨论的内容,下面我们来分析一下这里的一些有趣之处:

  1. 每个进程都与一个父作业相关联。有些作业有多个进程。
  2. 所有作业最终都追溯到 root 作业,形成一个树状结构。
  3. 在启动期间,系统会直接将一些进程启动到 root 作业中。大多数其他进程都是在其自己的父作业下启动的。
  4. 完成初始启动工作后,许多条目都带有 .cm 扩展名。这些条目是指组件,您将在稍后详细了解它们。
  5. 其中一些组件是核心服务,例如文件系统 (fshost.cm) 和驱动程序 (driver_manager.cm),它们位于与内核分开的用户空间中。

接下来,我们将探讨 Zircon 如何实现 Fuchsia 安全模型的基础。