在 Fuchsia 中,命名空间是文件访问和服务发现的支柱。
定义
命名空间是文件、目录、套接字、服务、设备以及提供给组件的其他已命名对象的复合层次结构。
让我们来深入解析一下。
对象已命名:命名空间包含对象,您可以通过名称枚举和访问这些对象,与列出目录或打开文件非常相似。
复合层次结构:命名空间是对象树,由其他命名空间中的对象的子树组合成一个复合结构来组合而成的对象树,按照惯例,其中每个部分都指定了路径前缀。
每个组件的命名空间:每个组件都有自己的专属命名空间,专门为满足自己的需求而量身定制。它还可以发布自己的对象以包含在其他命名空间中。
虽然本文档重点介绍绑定到组件的典型用法,但命名空间也可以独立于组件创建和使用。
命名空间实例
您可能已经花时间了解 Fuchsia 命名空间;它们无处不在。如果在命令行 shell 提示符中输入 ls /
,则会看到可从 shell 的命名空间访问的一些对象的列表。
与其他操作系统不同,Fuchsia 没有“根文件系统”。如前所述,命名空间是按组件定义的,而不是全局或按进程定义的。
这样做有一些有趣的启发:
- 没有全局“根”命名空间。
- 不存在“在支持 chroot 的环境中运行”的概念,因为每个组件实际上都有自己的私有“根”。
- 组件会收到根据其特定需求量身定制的命名空间。
- 对象路径可能在命名空间边界之间没有意义。
- 一个进程可以同时访问多个不同的命名空间。
- 用于控制文件访问权限的机制也可用于按组件控制对服务和其他已命名对象的访问。
物件
命名空间中的项称为对象。它们有各种不同的风格,包括:
- 文件:包含二进制数据的对象
- 目录:包含其他对象的对象
- 套接字:打开时建立连接的对象,例如已命名的管道
- Service:打开时提供 FIDL 服务的对象
- 设备:提供硬件资源访问权限的对象
访问对象
如需访问命名空间中的某个对象,您必须已拥有另一个对象。在命名空间转移期间,组件通常会收到其命名空间范围内对象的通道句柄。
您也可以通过实现适当的 FIDL 协议来凭空创建新的对象。
知道对象的渠道后,您就可以向该对象发送一条 FIDL 消息,其中包含标识所需子对象的对象相对路径表达式,从而为其其中一个子对象打开渠道。这与打开目录中的文件非常相似。
请注意,您只能访问已有权访问的对象。没有 Ambient 权能。
现在,我们将定义对象名称和路径的构建方式。
对象名称
对象名称是本地唯一标签,对象在容器(例如目录)中可依据该标签找到。请注意,该名称是容器的子对象表的属性,而不是对象本身的属性。
例如,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
:由供应商定义的服务
dev/
:设备树(根据需要对特权组件可见的相关部分)class/
...
config/
:组件的配置数据build-info/
:build 信息文件的规范路径。ssl/
:SSL 证书的规范路径tzdata/
:时区数据文件。第一个子路径应该是数据格式名称,例如tzif2/...
或icudata/...
。
命名空间参与者
以下是与 Fuchsia 命名空间协议交互和支持的一些抽象的更多信息。
文件系统
文件系统能让文件在命名空间中可用。
文件系统只是一个从其他人的命名空间发布类文件对象的组件。
协议
协议句柄是由 FIDL 协议实现提供支持的通道对象,可使用命名空间发现该协议。协议名称对应于命名空间的 /svc
分支内的一个路径,组件可从该路径中访问实现。
例如,默认的 Fuchsia 日志记录协议是 fuchsia.logger.Log
,其在命名空间中的路径是 /svc/fuchsia.logger.Log
。
如需详细了解协议和组件,请参阅协议功能。
服务
服务句柄是包含相关 FIDL 协议的目录。可以使用命名空间发现这些协议的实现。服务名称对应于命名空间的 /svc
分支内的一个路径,组件可从该路径中访问实现。
如需详细了解服务和组件,请参阅服务功能。
组件
组件将使用和扩展命名空间。
组件是指已在某些拓扑中实例化并指定了命名空间的可执行程序对象。
组件以两种方式参与 Fuchsia 命名空间:
- 它可以使用提供给它的命名空间中的对象,例如传入协议和服务或它自己的软件包内容。
- 它可以通过其传出目录(以命名空间的形式)将对象publish到其他组件。