组件是 Fuchsia 中运行的软件的基本构建块。每个组件都是一个可组合、沙盒化模块,可通过 capability 与其他组件交互。这有助于提高系统安全性,并在各个组件之间创建清晰的接口,从而更易于更新或替换这些组件。
在 Fuchsia 中,几乎所有内容都是组件。通过之前对 Zircon 的讨论,我们特意将内核的表面区域设计得很小,而大多数核心服务都是在用户空间中实现的。这意味着,在 Fuchsia 上运行的大多数软件都是使用组件框架实现的,包括:
- 面向用户的应用
- 设备驱动程序
- 文件系统
- 媒体编解码器
- 网络堆栈
在内核之外,只有少数底层异常不使用组件框架,例如引导加载程序和 userboot
进程。
组件管理器
组件框架的核心是组件管理器。它负责协调所有组件实例的执行、为它们提供功能,以及在组件之间中介连接。
组件可以显式启动(例如通过网址),也可以通过针对特定 capability 的请求隐式启动。组件管理器会执行必要的解析,以确定是启动新组件还是将请求路由到现有实例。为了实现此路由,每个组件都必须声明它向系统提供的所有 capability 以及它使用的所有 capability。
组件管理器会解析每个组件的声明,以确定如何运行组件并提供必要的功能。组件通常通过组件软件包中的组件清单文件向系统声明。
下面是一个简单的组件清单示例,其中描述了 ELF 可执行文件,以及一些额外的命令参数:
program: {
runner: "elf",
binary: "bin/hello",
args: [ "Hello", "World!" ],
},
请注意运行时声明,它会告知组件管理器此组件需要 ELF 运行程序。这是 capability 的示例!
组件功能
组件通过功能获得访问更广泛系统各个部分的权限。每个组件都可以声明它们向系统提供的新功能以及它们正常运行所需的其他组件(或框架)提供的功能。
正如您刚才所看到的,runner
就是声明组件所使用的运行时的 capability 示例。常见 capability 类型的其他示例包括用于访问文件系统资源的 directory
,以及用于与其他组件通信的 protocol
。
开发者使用组件清单声明组件所需的 capability 类型。以下示例展示了一个请求两项功能的组件清单:对 example-data
目录和 fuchsia.example.Foo
FIDL 协议描述的服务的读取访问权限。
use: [
{
directory: "example-data",
rights: [ "r*" ],
path: "/example/data",
},
{
protocol: "fuchsia.example.Foo",
},
]
组件管理器使用 capability 声明为每个组件的命名空间填充必要的目录句柄。在本例中,组件将在其命名空间中接收 /example/data
和 /svc/fuchsia.example.Foo
。
组件组织
系统中的所有组件都会组合到一个根组件实例树中。此树结构会管理组件行为的几个重要方面。
树中的父级组件负责创建其他组件的实例作为其子级,并为它们提供必要的功能。同时,子组件可以将功能公开回给父级。您可以通过以下两种方式之一创建子组件:
- 静态:父级在其自己的组件声明中声明子级的存在。
- 动态:父级使用
fuchsia.component.Realm
协议在运行时将子级添加到组件集合。
任何父级组件及其所有子级组件都会在树中形成一个名为领域的组。借助 Realm,父级可以控制哪些功能会流入和流出其组件子树,从而创建功能边界。组件会使用 expose
关键字决定是否将功能导出到其所在领域之外:
expose: [
{
protocol: "fuchsia.example.Foo",
from: "self",
},
],
将 capability 公开给 realm 后,父级可以与同一 realm 中的其他组件共享该 capability。这是使用 offer
关键字实现的:
offer: [
{
protocol: "fuchsia.example.Foo",
from: "self",
},
],
组件管理器:负责通过提供相应功能的组件解析对某项功能(例如目录或协议)的访问请求。这称为 capability routing。组件管理器只能解析在同一领域内公开和提供的功能。
练习:组件
在本练习中,您将探索组件实例树,并详细了解使用一些核心系统组件实现功能路由的运作方式。
启动模拟器
如果您尚未运行实例,请启动模拟器:
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.
探索系统组件
打开另一个终端窗口,并使用 component list
命令转储系统的组件树:
ffx component list
您应该会看到类似于以下(截断)列表的输出:
/
/bootstrap
/bootstrap/archivist
/bootstrap/base_resolver
/bootstrap/console
/bootstrap/console-launcher
/bootstrap/decompressor
/bootstrap/device_name_provider
/bootstrap/driver_manager
/bootstrap/fshost
/bootstrap/kernel_debug_broker
/bootstrap/miscsvc
/bootstrap/netsvc
/bootstrap/power_manager
/bootstrap/ptysvc
/bootstrap/pwrbtn-monitor
/bootstrap/shutdown_shim
/bootstrap/sysinfo
/bootstrap/virtual_console
/core
/core/activity
...
/core/detect
/core/font_provider
/core/log-stats
/core/remote-control
/core/sampler
/core/system-update-committer
/core/temperature-logger
/core/test_manager
/core/full-resolver
/startup
此列表代表组件实例树,bootstrap
、core
和 startup
等组织组件在根下面形成了子树。
component show
命令会提供有关每个组成部分的更多详细信息。
使用以下命令查看 http-client
(提供 HTTP 请求服务的组件)的详细信息:
ffx component show http-client.cm
该命令会输出以下报告:
Moniker: /core/network/http-client
URL: #meta/http-client.cm
Type: CML static component
Component State: Resolved
Incoming Capabilities: config
fuchsia.logger.LogSink
fuchsia.net.name.Lookup
fuchsia.posix.socket.Provider
pkg
Exposed Capabilities: fuchsia.net.http.Loader
Merkle root: d9e73f5b061f2f227e596e2e0079ff3a095fc69e192cf85e0d7621826c76356c
Execution State: Running
Start reason: '/core/feedback' requested capability 'fuchsia.net.http.Loader'
Running since: ...
Job ID: 41268
Process ID: 41311
Outgoing Capabilities: fuchsia.net.http.Loader
请注意此处报告的一些详细信息:
- 组件实例的唯一标识符(称为名称)。
- 此组件加载的软件包网址。
- 组件的执行状态。
- 实例正在运行的当前作业/进程 ID。
- 组件请求的一组公开功能。
跟踪 capability 路线
在上面的输出中,列出了三个 capability 组:
- 传入功能:组件使用
use
声明的功能。这些信息会通过组件的命名空间提供给组件。 - 传出功能:组件发布到其传出目录的功能。
- 公开的功能:组件使用
expose
声明的功能。这些是组件的公开服务。
http-client
向其父 realm 公开的功能之一是 fuchsia.net.http.Loader。这样,其他组件就可以发出 HTTP 请求了。
使用 component capability
命令确定与此功能交互的组件数量:
ffx component capability fuchsia.net.http.Loader
该命令会列出所有匹配的组件:
Exposed:
/core/network/http-client
/core/network
Used:
/core/cobalt
/core/feedback
/core
这表示 cobalt
和 feedback
组件使用此 capability(即将其列在“Incoming Capabilities”下)。这些组件之间的共同祖先是 core
,它负责将此 capability 路由到必要的子项。