Fuchsia 命名空间

在 Fuchsia 中,命名空间是文件访问和服务发现的支柱。

定义

命名空间是文件、目录、套接字、服务、设备和其他提供给组件的已命名对象的复合层次结构。

我们来分析一下。

对象有命名:命名空间包含可以按名称枚举和访问的对象,与列出目录或打开文件非常相似。

复合层次结构:命名空间是一棵对象树,它通过将来自其他命名空间的对象子树组合成一个复合结构,按照惯例为其每个部分分配一个路径前缀。

每个组件的命名空间:每个组件都有自己的专属命名空间,以满足自己的需求。它还可以发布自己的对象以包含在其他命名空间中。

命名空间也可以独立于组件创建和使用,不过本文档重点介绍绑定到组件的典型用法。

命名空间实例

您可能已经花时间探索了 Fuchsia 命名空间;这些命名空间无处不在。如果在命令行 shell 提示符中输入 ls /,则会看到可从 shell 的命名空间访问的一些对象的列表。

与其他操作系统不同,Fucsia 没有“根文件系统”。如前所述,命名空间是按组件定义的,而不是全局或按进程定义的。

这会产生一些有趣的影响:

  • 没有全局“根”命名空间。
  • 不存在“在具备 chroot 权限的环境中运行”的概念,因为每个组件实际上都有自己的私有“根”
  • 组件会收到根据其特定需求量身定制的命名空间。
  • 跨命名空间边界的对象路径可能没有意义。
  • 一个进程可以同时访问多个不同的命名空间。
  • 用于控制文件访问权限的机制也可用于按组件控制对服务和其他已命名对象的访问。

物体

命名空间中的项称为对象。它们有多种类型,包括:

  • 文件:包含二进制数据的对象
  • 目录:包含其他对象的对象
  • 套接字:在打开时建立连接的对象,例如已命名的管道
  • 服务:在打开时提供 FIDL 服务的对象
  • 设备:提供硬件资源访问权限的对象

访问对象

如需访问命名空间中的某个对象,您必须已拥有另一个对象。在命名空间转移期间,组件通常会收到其命名空间范围内对象的渠道句柄。

您还可以通过实现适当的 FIDL 协议来凭空创建新对象。

给定对象的渠道,您就可以向其发送一条 FIDL 消息(其中包含标识所需子对象的对象相对路径表达式)来为其某个子对象开通一个渠道。这类似于在目录中打开文件。

请注意,您只能访问已有权访问的对象。无环境授权。

现在,我们将定义如何构建对象名称和路径。

对象名称

对象名称是本地唯一的标签,对象在容器(例如目录)中根据该标签位于容器(例如目录)。请注意,该名称是容器子对象表的属性,而不是对象本身的属性。

例如,cat 指定位于 Open() 请求的某个未指定收件人中的毛绒对象。

对象本质上是无名的,但也有人称其为许多名称。

对象名称以二进制八位字节字符串(任意字节序列)表示,并受到以下限制:

  • 最小长度为 1 字节。
  • 长度上限为 255 个字节。
  • 不包含 NUL(零值字节)。
  • 不包含 /
  • 不等于 ...
  • 始终使用逐字节相等性的方式进行比较(意味着区分大小写)。

对象名称是容器的 Open() 方法的有效参数。请参阅 FIDL 协议

应将对象名称编码和解释为人类可读的 UTF-8 图形字符序列,但命名空间本身并不强制执行此属性。

因此,客户端负责决定如何向用户显示包含无效、无法显示或不明确的字符序列的名称。

对象相对路径表达式

对象相对路径表达式是对象名称或由 / 分隔的对象名称序列,用于指定要遍历的一系列嵌套对象,以便在容器(例如目录)中查找某个对象。

例如,house/box/cat 指定其所属对象内一个名为 box 的毛绒对象,该对象位于其所属对象(名为 house)内,位于 Open() 请求的某个未指定接收方内。

对象相对路径表达式始终会遍历命名空间更深层。值得注意的是,命名空间不直接支持从容器向上遍历(例如通过 ..),但客户端可能会部分模拟此功能(见下文)。

对象相对路径表达式具有以下额外限制条件:

  • 最小长度为 1 字节。
  • 长度上限为 4095 个字节。
  • 不能以 / 开头或结尾。
  • 所有细分均为有效的对象名称。
  • 始终使用逐字节相等性的方式进行比较(意味着区分大小写)。

对象相对路径表达式是容器的 Open() 方法的有效参数。请参阅 FIDL 协议

客户端解释的路径表达式

客户端解释的路径表达式是对象相对路径表达式的泛化,但包含可由客户端代码模拟的可选功能,以增强与需要类似 Root 文件接口的程序的兼容性。

从技术上讲,这些功能超出了 Fuchsia 命名空间协议本身的范围,但它们经常被使用,因此我们在此介绍它们。

  • 客户端可以指定其某个命名空间充当其“根”。此命名空间以 / 表示。
  • 客户端可以通过添加单个 / 来构造相对于其指定的根命名空间的路径。
  • 客户端可以通过一个称为客户端“规范化”的过程,使用 .. 路径段将各个段折叠在一起(假设容器的路径已知),从而构建从容器向上遍历的路径。
  • 这些功能可能会组合在一起。

例如,/places/house/box/../sofa/cat 指定位于某个客户端指定的“根”容器内位于 places/house/sofa/cat 的毛绒对象。

包含这些可选功能的客户端解释路径表达式不是容器的 Open() 方法的有效参数;客户端必须在与命名空间通信之前对其进行转换。请参阅 FIDL 协议

例如,fdio 实现了对文件操作 API(如 open()stat()unlink() 等)中的 .. 路径的客户端解释。

命名空间转移

启动组件时(例如启动其进程),组件会收到一个将一个或多个命名空间路径前缀映射到对象句柄的表。

按照惯例,表中的路径前缀会对关联对象的预期重要性进行编码。例如,pkg 前缀应与某个目录对象相关联,该对象包含组件自己的二进制文件和资源。

下一部分将对此进行详细介绍。

命名空间惯例

本部分介绍了在 Fuchsia 上运行的典型组件的常规命名空间布局。

组件命名空间的确切内容和组织方式会因组件的角色、类型、身份、范围、与其他组件的关系以及权限而有很大差异。如需了解如何使用命名空间为组件创建沙盒,请参阅沙盒

如需详细了解组件可能会接收的命名空间,请参阅与您要实现的组件类型相关的文档。

典型对象

组件命名空间可能包含一些典型对象:

  • 组件软件包中的只读可执行文件和资源。
  • 专用本地永久性存储空间。
  • 私有临时存储空间。
  • 由系统、组件框架或启动组件的客户端提供给组件的服务。
  • 设备节点(针对驱动程序和特权组件)。
  • 配置信息。

典型的目录结构

  • pkg/:当前程序软件包的内容,与软件包签名时的内容
    • bin/:软件包中的可执行二进制文件
    • lib/:软件包中的共享库
    • data/:软件包中的数据(例如资源)
  • data/:本地永久性存储空间(读写,仅对组件可见)
  • tmp/:临时存储空间(读写,仅对组件可见)
  • svc/:向组件提供的协议和服务
    • fuchsia.process.Launcher:启动进程
    • fuchsia.logger.Log:日志消息
    • vendor.topic.Interface:由 vendor 定义的服务
  • dev/:设备树(根据需要向特权组件可见的相关部分)
    • class/...
  • config/:组件的配置数据
    • build-info/:版本信息文件的规范路径。
    • ssl/:SSL 证书的规范路径
    • tzdata/:时区数据文件。第一个子路径应该是数据格式名称,例如 tzif2/...icudata/...

命名空间参与者

以下是一些与 Fuchsia 命名空间协议交互并支持它们的抽象的更多信息。

文件系统

文件系统能让文件在命名空间内可用。

文件系统就是一个从他人的命名空间发布类文件对象的组件。

协议

协议

协议句柄是由 FIDL 协议实现提供支持的通道对象,可使用命名空间发现该协议。协议名称对应于命名空间的 /svc 分支内的一条路径,组件可从该路径中访问实现。

例如,默认的 Fuchsia 日志记录协议是 fuchsia.logger.Log,其命名空间中的路径为 /svc/fuchsia.logger.Log

如需详细了解协议和组件,请参阅协议功能

服务

服务

服务句柄是包含相关 FIDL 协议的目录。可以使用命名空间发现这些协议的实现。服务名称对应于命名空间的 /svc 分支内的一个路径,组件可从该路径中访问实现。

如需详细了解服务和组件,请参阅服务功能

组件

组件将使用和扩展命名空间。

组件是可执行程序对象,已在某种拓扑中实例化并指定了命名空间。

组件以两种方式加入 Fuchsia 命名空间:

  1. 它可以使用提供给它的命名空间中的对象,例如传入协议和服务或它自己的软件包内容。
  2. 它可以通过其传出目录以命名空间的形式将对象publish到其他组件。