整理组件

系统中的所有组件都会组成一个已启用 root 权限的 组件实例树。树中的父组件负责 将其他组件的实例声明为其子组件并提供这些组件 功能。同时,子组件可以公开各种功能 返回给父级。这些组件实例和功能关系 设置组件拓扑

在树中,任何父级组件及其所有子级构成一个组,称为 realm。借助 Realm,父级可以控制哪些功能会流入和流出其组件子树,从而创建功能边界。这个 通过封装,我们可以在内部重新组织领域,而不会影响 依赖于其公开的功能。

显示组件实例如何组织为树和父级的示意图
决定每个子组件可用的功能,
“功能路由”

在上图中,fuchsia.example.Foo 的协议功能被路由 通过组件实例树从提供程序传输到客户端组件 使用 use 关键字声明其所需功能:

{
    // Information about the program to run.
    program: {
        // Use the built-in ELF runner to run core binaries.
        runner: "elf",
        // The binary to run for this component.
        binary: "bin/client",
    },

    // Capabilities required by this component.
    use: [
        { protocol: "fuchsia.example.Foo" },
    ],
}

组件使用 capabilities 部分。这样一来, 其提供程序是组件框架已知的请参阅以下 provider.cml 示例:

{
    // Information about the program to run.
    program: {
        // Use the built-in ELF runner to run core binaries.
        runner: "elf",
        // The binary to run for this component.
        binary: "bin/provider",
    },

    // Capabilities provided by this component.
    capabilities: [
        { protocol: "fuchsia.example.Foo" },
    ],
    // Capabilities routed through this component.
    expose: [
        {
            protocol: "fuchsia.example.Foo",
            from: "self",
        },
    ],
}

expose 关键字使相应功能可将功能从此组件提供给其他组件 这些领域,其中可能还包括此 子组件的子级。在本例中, capability 的来源为 self 因为此组件是提供程序

父级组件控制领域内的 capability 路由,从客户端组件到提供程序创建显式路径。请参阅以下内容 parent.cml 清单示例:

{
    children: [
        {
            name: "provider",
            url: "fuchsia-pkg://fuchsia.com/foo-package#meta/provider.cm",
        },
        {
            name: "client",
            url: "fuchsia-pkg://fuchsia.com/foo-package#meta/client.cm",
        },
    ],
    offer: [
        {
            protocol: "fuchsia.example.Foo",
            from: "#provider",
            to: [ "#client" ],
        },
    ],
}

父组件声明 Realm 中的子组件集, 使用 offer 关键字向它们路由功能。这样,父级 确定每个子级功能的范围和来源。这还支持拓扑中的多个组件提供相同的功能,因为组件框架依赖于显式路由来确定如何解析来自每个客户端的请求。

功能类型

Fuchsia 组件支持许多不同类型的功能。到目前为止,本模块中的示例展示了两种不同的 capability 类型:runnerprotocol。您可能已经注意到,protocol capability 需要路由路径,但 runner capability 不需要。

有些功能由其父级显式路由到组件,而 使用 environments。环境使框架能够预配功能 这样毫无意义。默认情况下 组件会继承其父级的环境。组件还可以声明 为孩子打造全新的环境

下表列出了组件可用的功能类型, 以及它们是必须从父组件显式路由,还是 由环境提供:

类型 说明 提供方
directory 其他组件提供的共享文件系统目录。 路由
event 由组件管理器生成的事件,例如组件启动或功能请求。 路由
protocol 其他组件或框架提供的 FIDL 协议。 路由
resolver 一种组件,能够解析指向组件清单的网址。 环境
runner 用于执行特定组件的运行时。 环境
service 执行常规任务的相关 FIDL 协议的命名组。 路由
storage 每个组件的独立文件系统目录都是唯一的。 路由

识别组件

组件通过网址进行标识。该框架将组件网址解析为 组件解析器进行组件声明。解析器本身就是组件,能够处理特定网址方案并提取组件清单、程序和资源。

大多数组件都是在 Fuchsia 软件包中发布,因此组件网址是 对该软件包内的组件清单的引用。请参阅以下示例:

fuchsia-pkg://fuchsia.com/foo-package#meta/foo-component.cm

组件实例由拓扑路径引用(称为标识名)标识。组件的标识符以绝对路径或相对路径的形式指示其在组件实例树中的位置。例如,名称路径 /core/system-updater 是指已存在的 system-updater 实例 在 core 领域中。

组件生命周期

在添加和移除组件实例时,组件实例会随之创建和销毁 在组件拓扑中可能通过以下两种方式之一发生:

  • 静态:在组件清单中将实例声明为子实例 另一个组件的创建。静态组件只会创建并 在更新更改组件拓扑时被销毁。
  • 动态:在组件 collection 中添加或移除实例 在运行时使用 fuchsia.component.Realm 协议。动态组件 它们会在系统关闭时被销毁

组件销毁后,框架将移除其持久状态 (例如本地存储)。

当另一个组件尝试执行下列操作时,框架将启动一个组件实例: 打开相应的频道当连接到 相应功能连接到组件 会重复使用正在运行的实例

组件可通过退出程序(由 组件的 runner),或者框架可能会在出现以下情况时停止该组件: 系统关闭。

显示组件如何具有两种不同状态的示意图:实例和
执行。这些状态共同描述了“组件生命周期”。

练习:集成组件

要调用组件,组件必须存在于有效 组件拓扑在本练习中,您将向 ffx-laboratory - 用于开发的受限集合, 产品的核心领域。通过集合,组件可以动态地 是在运行时创建和销毁的

启动模拟器

如果您还没有运行的实例,请启动具有网络支持的 FEMU:

ffx emu start workstation_eng.x64 --headless

发布软件包

软件交付相关的召回 Fuchsia 设备通过软件包代码库按需解析软件包。

使用 bazel run 命令构建和发布 echo 组件软件包:

bazel run //fuchsia-codelab/echo:pkg.publish -- \
    --repo_name fuchsiasamples.com

此命令将软件包发布到名为 fuchsiasamples.com 的代码库; 创建代码库(如果不存在)并使用目标注册该代码库。

添加到组件拓扑

使用以下命令创建 echo 组件的新实例:

ffx component create /core/ffx-laboratory:echo \
    fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm

此命令接受两个参数:

  • /core/ffx-laboratory:echo:这是组件名称, 表示组件实例的组件拓扑内的路径。
  • fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm:这是 组件网址,指示 Fuchsia 应如何从 软件包服务器。

拓扑中现在存在一个名为 echo 的新组件实例。显示 新实例的详细信息:

ffx component show echo

您应该会看到以下输出内容:

               Moniker: /core/ffx-laboratory:echo
                   URL: fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm
                  Type: CML dynamic component
       Component State: Unresolved
       Execution State: Stopped

请注意,实例已创建,但组件网址尚未 已解决。当框架尝试启动实例时,就会发生解析。

启动组件实例

使用以下命令启动新的 echo 组件实例:

ffx component start /core/ffx-laboratory:echo

此命令接受一个参数:

  • /core/ffx-laboratory:echo:这是组件名称, 表示组件实例的组件拓扑内的路径。

这会使组件实例启动,在日志中输出问候语。 然后退出。打开一个新的终端窗口,然后过滤设备日志以查找示例中的相关消息:

ffx log --filter echo

您应该会在设备日志中看到以下输出:

[ffx-laboratory:echo][I] Hello, Alice, Bob, Spot!

探索实例

使用以下命令再次显示 echo 实例的详细信息:

ffx component show echo

您现在应看到以下输出:

               Moniker: /core/ffx-laboratory:echo
                   URL: fuchsia-pkg://fuchsiasamples.com/echo-example#meta/echo.cm
                  Type: CML dynamic component
       Component State: Resolved
 Incoming Capabilities: fuchsia.logger.LogSink
                        pkg
       Execution State: Stopped

组件状态已更改为 Resolved,您可以看到更多详情 组件功能

组件没有访问系统其他部分的环境感知功能。 组件需要的每项功能都必须通过 组件拓扑或由其环境提供。

echo 组件需要 fuchsia.logger.LogSink capability 才能写入系统日志。您已成功查看日志输出 因为此功能是提供给 ffx-laboratory 中的组件的 来自 core 大区的合集:

{
    collections: [
        {
            name: "ffx-laboratory",
        },
    ],
    offer: [
        {
            protocol: [ "fuchsia.logger.LogSink" ],
            from: "parent",
            to: "#ffx-laboratory",
        },
    ],
}
<ph type="x-smartling-placeholder">

销毁实例

使用以下命令清理 echo 实例:

ffx component destroy /core/ffx-laboratory:echo