Fuchsia命名空间
在Fuchsia系统中,命名空间是文件访问和服务发现的基础。
定义
命名空间是关于文件、目录、socket套接字、服务、设备和其他命名对象的复合层次结构,这些对象由对应的环境提供给组件。让我们对此定义依次解释:
对象被命名:命名空间包含了能够通过名字被枚举和访问的对象,这种方式很像其他操作系统上列出目录和打开文件等操作。
复合层次结构:命名空间是一个对象树,它通过将来自其它命名空间的对象的子树组合在一起组成复合结构,其中每个部分按惯例分配了一个路径前缀。
每个组件的命名空间:每个组件都会收到自己的命名空间,以满足自己的需求。它还可以发布自己的对象,使其被包含其它命名空间中。
由环境构造:负责实例化组件的环境在作用域内为该组件构造适当的命名空间。 命名空间也可以独立于组件单独创建和使用,而本文档重点介绍其在组件上的典型用法。
命名空间实战
你可能已经花了一些时间探索Fuchsia的某个命名空间,因为他们无处不在。如果在命令行shell提示符下键入ls /
,你将看到一些可从shell命名空间访问的对象的列表。
与其他操作系统不同,Fuchsia没有”根文件系统”。如前所述,命名空间是按组件定义的,而不是全局或按进程定义的。以下是一些有趣的含义:
- 没有全局的“根(root)”命名空间。
- 没有诸如“在chroot环境中运行”的概念,因为每个组件实际上都有自己的私有“root”(英文原文)。
- 组件可接收根据其特定需求定制的命名空间。
- 跨命名空间边界的对象路径可能是没有意义的。
- 进程可以同时访问多个不同的命名空间。
- 用于控制对文件的访问的机制还可用于控制对每个组件的服务和其他命名对象的访问。
对象
命名空间中的项称为对象(Object),根据种类不同,它们有各自的特点,包括:
- 文件:包含二进制数据的对象
- 目录:包含其他对象的对象
- socket套接字:打开时建立连接的对象,如命名管道
- 服务:打开时提供FIDL服务的对象
- 设备:提供对硬件资源的访问的对象
访问对象
要访问命名空间中的对象,你必须已拥有另一个对象。组件通常通过命名空间传输的方式接收通道(channel)句柄,来访问该命名空间作用域内的对象。你还可以通过实现适当的FIDL接口,凭空创建新对象。
通过给定对象的通道,你可以通过向其发送FIDL消息来打开它某个子对象的通道,该消息包括标识所需子对象的对象相对路径表达式,因此这很像其他操作系统上打开目录中文件的操作。
请注意,你只能访问可从你有权限访问的对象开始访问其它对象,因此避免了ambient authority问题。接下来将定义如何构造对象名称和路径。
对象名称
对象名称是本地对象唯一标签,通过该标签,对象可以位于容器(例如目录)中。请注意,名称是容器本身的子对象表的属性,而不是对象本身的属性。例如,cat
可以指定一个位于Open()
请求的某个未指定接收者中的对象。
对象本身是无名的,但是它可能又被其他对象以多个不同的名称调用。对象的名称表示为二进制八位字符串(即任意字节序列),但受以下约束限制:
- 最小长度为1个字节。
- 最大长度为255个字节。
- 不包含NUL(零值字节)。
- 不包含
/
。 - 不能等于
.
或..
。 - 始终使用逐字节进行比较(意味着区分大小写)。
对象名是容器的Open()
方法的有效参数。请参见FIDL接口一节。对象名称旨在可以编码并解释为UTF-8的人类可读序列,但此属性并不由命名空间本身强制执行。因此,客户端需要负责决定如何向用户呈现可能包含无效、不可显示的或模糊字符序列的对象名称。
TODO(jeffbrown):记录如何呈现名称的具体策略.
对象相对路径表达式
对象相对路径表达式是对象名称或对象名称的/
分割序列,指定要遍历的嵌套对象序列,以便在容器(例如目录)中定位对象。例如,house/box/cat
指定一个位于名为house
的容器对象中,其名称为box
的封装对象,同时该对象位于Open()
请求的某个未指定的接收者中。
对象相对路径表达式总是向下遍历命名空间。而值得注意的是,命名空间不直接支持向上遍历容器(例如,通过..
),但客户端可以部分模拟此功能(见下文)。对象相对路径表达式具有以下附加约束:
<!—
- Minimum length of 1 byte.
- Maximum length of 4095 bytes.
- Does not begin or end with
/
. - All segments are valid object names.
Always compared using byte-for-byte equality (implies case-sensitive). —>
最小长度为1个字节。
- 最大长度为4095字节。
- 不以
/
开头或结尾。 - 所有段都是有效的对象名称。
- 始终使用逐字节字节进行比较(意味着区分大小写)。
对象相对路径表达式是容器的Open()
方法的有效参数,具体请参见FIDL接口。
客户端解释路径表达式
客户端解释的路径表达式是对象相对路径表达式的泛化行为,其包括可由客户端代码模拟的可选特征,以增强与具有根文件的类似接口的程序的兼容性。从技术上讲,这些功能超出了Fuchsia命名空间协议本身的范围,但它们经常被使用,所以我们在这里特意一并描述它们。 <!—
- A client may designate one of its namespaces to function as its “root”.
This namespace is denoted
/
. - A client may construct paths relative to its designated root namespace
by prepending a single
/
. - A client may construct paths which traverse upwards from containers using
..
path segments by folding segments together (assuming the container’s path is known) through a process known as client-side “canonicalization”. - These features may be combined together. —>
- 客户端可以指定其命名空间之一作为其“root”,该命名空间用
/
表示。 - 客户端可以通过添加单个
/
来构造相对于其指定的根命名空间的路径。 - 客户端可以通过称为客户端“规范化”的过程:将段折叠在一起(假设容器的路径已知),构造使用
..
路径段并从容器自下向上遍历的路径。 - 以上功能可以组合在一起。
例如,在某些客户端指定的“root”容器内,/places/house/box/../sofa/cat
指定了位于places/house/sofa/cat
的封装对象。
包含这些可选功能的客户端解释路径表达式不是容器的Open()
方法的有效参数; 它们必须在与命名空间通信之前由客户端进行翻译。具体请参见FIDL接口。例如,fdio
在文件操作API中实现了..
路径的客户端解释,例如这些操作包括open()
、stat()
和unlink()
等。
命名空间传输
当在环境中实例化组件(例如,启动进程)时,它接收将一个或多个命名空间路径的前缀到对象句柄的映射表,该表中的路径前缀按惯例编码其关联对象到预定意义上。例如,pkg
前缀应该与包含组件自己的二进制文件和资源的目录对象相关联。
更多相关内容将在下一节中介绍。
命名空间约定
本节描述了在Fuchsia上运行的典型组件的常规命名空间布局。相对于其他部件和权限,组件命名空间的准确内容和组织,根据组件的角色、类型、标识和作用域不同而有很大差异。有关如何使用命名空间为组件创建沙箱的信息,请参见Fuchsia沙箱文档。
有关组件可以从其环境接收的命名空间的更多信息,请参见与你正在实现的组件类型相关的文档。
典型对象
组件的命名空间可能包含一些典型的对象,例如:
- 组件包中的只读可执行文件和资源。
- 私有的本地持久化存储。
- 私有临时存储。
- 系统、组件的框架或者启动组件的客户程序为组件提供的服务。
- 设备节点(为驱动或者特权组件)。
- 配置信息
典型目录结构
pkg/
:当前程序包的内容bin/
:程序包的可执行二进制文件lib/
:程序包中的共享库data/
:程序包中的数据,例如资源等
data/
:临时持久存储(可读写,程序包私有)svc/
:为组件提供的服务fuchsia.process.Launcher
:启动进程fuchsia.logger.Log
:记录消息vendor.topic.Interface
:供应商定义的服务
dev/
:设备树(根据需要对特权组件可见的相关部分)class/
,……
hub/
:内省系统,请参阅hub.md (英文原文)(仅限特权组件)config/
:组件的配置数据
命名空间参与者
以下是一些支持Fuchsia命名空间协议并与之交互的抽象的更多信息。
文件系统
文件系统使得文件在命名空间中可见。而文件系统只是一个发布类文件对象的组件,而这些对象包含在其他的命名空间中。
服务
服务存在于命名空间中。服务是一种众所周知的对象,它提供可以使用命名空间发现的FIDL接口的实现。服务名称对应于命名空间的svc
分支内的路径,组件可以从该路径访问服务的实现。
例如,Fuchsia默认的日志服务的名称是fuchsia.logger.Log
,它在命名空间中的位置是svc/fuchsia.logger.Log
。
组件
组件使用并扩展了命名空间。组件是已在某些环境中实例化并给定命名空间的可执行程序对象。组件以如下两种方式参与Fuchsia命名空间:
- 它可以使用从其环境接收的命名空间中的对象,特别是访问其自己的包内容和传入的服务。
- 它可以以命名空间的形式通过其环境发布对象,这些命名空间的部分环境随后可根据请求提供给其他组件。
以上就是组件实现服务的方式。
环境
环境构建了命名空间。环境是组件的容器,每个环境负责构造其组件将收到的命名空间。同时,环境决定了组件可以访问哪些对象,以及组件按名称对服务的请求将如何绑定到特定的实现上。
配置
组件可能具有不同类型的配置数据,这具体取决于其组件清单(英文原文)中所列出的功能。它们作为/config
命名空间条目中的文件的方式进行公开,而这些都是由组件的功能集所定义。
FIDL接口
TODO(jeffbrown): 解释命名空间的接口是如何工作的。