子打包组件

软件包可以“包含”其他软件包(称为 子软件包 s),从而生成嵌套软件包的层次结构。 组件可以利用子打包来整理由 组件,其中每个组件 封装在其自己的软件包中,并附带自己的一组依赖项。

子软件包支持

  • 封装的依赖项(封装组件声明其直接 依赖项)
  • 隔离的 /pkg 目录(已分组的组件不需要合并其 文件、库和元数据移到一个共享命名空间)
  • 可靠的依赖项解析(系统和构建工具可确保子软件包 始终“旅行”他们的软件包)

与 Fuchsia 组件的关系

Fuchsia 利用软件包来“分发”(例如,加载 安装到设备上)。不包含依赖项的单个组件 通常包含在单个软件包中。一个组件,用于启动 组件可以定义包含特定版本(确定于 构建时间)。

以这种方式组织时,子软件包层次结构会镜像组件 父子关系。儿童 然后,系统会从父文件已声明的子软件包中加载 组件包。它封装了 ABI 依赖项 软件包边界

组件还可以使用子软件包来声明对 非可执行组件(不含 program 声明的组件),并获取访问权限 并使用目录功能向其中的 /pkg 数据添加数据。通过公开软件包 数据作为标准目录功能,组件使用 功能路由,用于限制对特定软件包子目录的访问权限, 因此遵守最小特权原则。

软件包依赖项镜像组件依赖项

Fuchsia 系统由组件层次结构定义。首先, 第一个组件(层次结构的根部),组件用于向 通过启动提供这些功能的 children(子组件)来启动系统。 每个组件都有机会启动自己的组件子树。

为了实例化 child 组件,父项需要标识子项的来源 (实施软件)按其在软件包系统中的位置使用 “组件网址”(软件包网址与软件包内资源位置相结合) 组件清单的名称);例如 fuchsia-pkg://fuchsia.com/package#meta/component.cm

重要的是,在组件框架下,组件只能引用 一个运行时依赖项。组件 网址不用于定义对对等组件或任何其他 位于其本地子树外

当子组件由绝对组件网址(如 fuchsia-pkg://fuchsia.com/package#meta/component.cm,组件开发者 转移对该依赖项实现的控制,待确定 (有可能)在产品组装时或运行时使用临时来源 (软件包服务器)。

借助子打包功能,开发者可以使用 构建时解决方案,即“烘焙”预期的组件实现 包括已知的 ABI 和行为,而不影响封装和 软件包边界的隔离优势。这样可以确保 组件依赖项的实现是封闭的,其行为 如果不重新构建父组件的 软件包。

子打包的组件网址还可以避免绝对组件固有的问题 网址:如果父组件是从(例如)备用仓库加载的 如 fuchsia-pkg://alt-repo.com/package#meta/parent.cm,则其 该 alt-repo 中也可能包含子项,因此无法静态地 定义可从 fuchsia.comalt-repo.com(或其他)在运行时未知。

通过使用相对软件包路径,子打包的子组件的实现 由包含子包名称(子包)的相对组件网址标识。 网址,其中包含指定组件清单路径的 URI 片段,例如 some-child#meta/default.cm。子软件包名称“some-child”的映射为 并在构建时进行解析,方法是将 子软件包的软件包哈希(位于父组件的软件包元数据中),映射到 子软件包名称

<ph type="x-smartling-placeholder">

依赖项具有传递性且已封装

组件软件实现不会 use 其他组件。组件 use 功能。组件的功能可能来自其父级 (由父级直接或间接转送,而对方不知情 组件)或从子文件导入。重要的是,由子节点公开的 capability 可以 也可以是直接或间接子级的实现已封装, 因此它公开的功能可以由该子级实现,也可以作为路由 。

子打包允许组件完全封装其实现, 包括子组件的任何依赖项。

当组件使用绝对组件网址声明子组件时, 会在运行时选择该子级的实现方式。对于 但需要权衡的是父组件 封闭:在新环境中很难重复使用父组件。 分发和移植非封闭代码需要跟踪 同时确保依赖项始终 新环境中的可用情况

    children: [
        {
            name: "intl_property_provider",
            url: "fuchsia-pkg://fuchsia.com/intl_property_manager#meta/intl_property_manager.cm",
        },
        ...
    ]

当不需要运行时解析时,父组件可以更新其 子项使用相对路径网址,并声明子组件的软件包 作为子软件包依赖项,在构建时解析。这样,当某个组件 子软件包与子组件相关联,那么子级的软件包会将其所有 而不需要将这些依赖关系暴露给其他云环境, 可能使用它的组件和运行时环境。

    children: [
        {
            name: "intl_property_provider",
            url: "intl_property_manager#meta/intl_property_manager.cm",
        },
        ...
    ]

未通过 /pkg 目录进行环境授权

为了满足 Fuchsia 组件的基本运行时要求, 组件可以通过 /pkg 目录功能。

如上所述,子打包允许软件包声明其组件 封装为分层的组件包此模型 不要求每个组件使用单独的软件包,但确实鼓励这样做,并且 Fuchsia 运行时和工具旨在完成声明、 以自然、高性能的方式构建和运行单独打包的组件。

相反,单个软件包中组合的多个组件共享一个 合并了 /pkg 目录。将多个组件捆绑到一个软件包中 每个组件不仅可以访问相同的数据,还可以访问 该软件包中的其他组件, 路由。

在某些情况下,当多个组件共享相同数据的访问权限时, 可能很方便不过,如果组件需要访问 一组数据,或者某个组件使用了不应向 其他,将组件组合在一起可能会破坏最低限度原则 权限,因而更适合子软件包。

<ph type="x-smartling-placeholder">

组件可能无法充分利用 更重要的是特权而非救济,因为这种特权并不一定总能得到 而这一特权也为一个组件带来了意想不到的机会 来利用另一个组件的数据

<ph type="x-smartling-placeholder">

相对于在单个软件包中使用多个组件的优势

目前,Fuchsia 允许单个软件包包含多个组件。这个 功能早在子包存在之前就已出现,它提供了一种 通过相对网址声明子组件;通过 URI 片段 通过组件清单的资源路径标识组件。答 #meta/some-child.cm 形式的组件网址会通知 Fuchsia 组件 以便从同一个some-child 包含父组件清单的 包中。

用于共享软件包资源的内置访问权限控制

组件框架有助于强制执行 Fuchsia 的功能访问控制 政策,要求组件明确声明其功能需求, 并通过使父组件负责路由任何外部 功能(包括资源)从已知功能来源(来自 父亲的父亲或子女),或其他子女的一样。

如果某个组件需要另一个组件包中的资源, 组件框架功能路由声明允许源组件 公开特定的子目录,以便目标组件可以访问 仅包含必需的内容,并且由其父组件明确提供。

这支持任何可通过 从常用软件包访问共享 /pkg 目录时,不会公开 整个 /pkg 目录。

与组件框架结合使用的子软件包隔离 /pkg 目录 功能路由提供与 Fuchsia 架构一致的方法来控制访问 资源包资源和共享资源

更改了传递依赖项以避免破坏封装

将组件依赖项合并到单个软件包中时,所有组件 共享单个平面命名空间,并且传递依赖项也必须 包括在内。

例如,如果单个软件包 SP 捆绑了组件 A 和组件 B,但 B 还依赖于相对 URI 片段 (#meta/C.cm) 的 C(软件包 SP) 必须捆绑 ABC。如果稍后修改了 B,将 C 替换为两个 新组件 DE,软件包 SP 的定义必须更改为 bundle ABDE,并丢弃 C除非(出于参数原因) DE(或两者)也依赖于 C

尽管有些构建环境允许组件构建目标 传递组件依赖项,这种做法会增加合并风险 将这些组件的内容转移到单个命名空间中。如果组件或任何 依赖项发生更改,新文件可能会覆盖来自其他 位于该软件包中组件子树任何部分的任何部分,从而破坏 以不确定且可能具有灾难性的方式实现。

子软件包通过将其封装在 每个子软件包的定义,因此软件包 SP 可替换为软件包 A(包含组件 A)仅依赖于子软件包 B (包含组件 B)。软件包 A 不需要其他依赖项,并且 不会改变,即使 B 的依赖项发生变化也是如此。

子打包实现可保证构建时

使用相对 URI 片段组件网址(例如 #meta/some-child.cm)会 实际上并不能保证父级和子级之间的 ABI 甚至 API 兼容性 组件“在同一个软件包中”因为它们实际上可以从 该软件包的不同版本

(从软件包服务器)临时解析软件包。新版 可以重新发布同一资源包 并在需要和加载子组件时进行解析。通过 子级实现可能与 原始版本的文件包。

这种情况并不罕见或虚构的用例:在组件框架中,组件是 (默认情况下)仅在需要时解析。公开一个 服务 S 不会加载,除非有其他组件 需要服务:S。根据程序的业务逻辑,S 可能 在父组件被调用的几分钟或几小时(或更长时间)后调用 。

示例

向子软件包声明 build 依赖项

支持 Fuchsia 的构建框架应包含一个用于声明 Fuchsia 软件包及其内容。如果也启用了子包支持功能 软件包声明将直接列出其所依赖的子软件包 限制。

例如,在 fuchsia.git 中,用于声明 Fuchsia 软件包的 GN 模板 支持两个可选列表:subpackages 和(不太常用) renameable_subpackages。可以包含其中之一或同时添加两者。renameable_ version 可允许包为子包分配包特定名称, 在通过包网址或组件网址引用子包时使用:

fuchsia_test_package("subpackage-examples") {
  test_components = [ ":subpackage-examples-component" ]
  subpackages = [
    "//examples/components/routing/rust/echo_client",
    ":echo_client_with_subpackaged_server",
    "//src/lib/fuchsia-component-test/realm_builder_server:pkg",
  ]
  renameable_subpackages = [
    {
      name = "my-echo-server"
      package = "//examples/components/routing/rust/echo_server"
    },
  ]
}

subpackages 列表包含一系列 GN fuchsia_package build 目标。修改者 默认情况下,子软件包名称(包含的软件包将用于引用的名称) 传递到软件包)来自子软件包的已定义的 package_name fuchsia_package目标。

您也可以使用 package 变量来声明子软件包目标, renameable_subpackages 列表。renameable_targets 还包含一个可选的 name 变量,用于替换子软件包的默认名称。

声明子打包的子项

子文件包仅对其父文件包可见,且子文件包中的组件 软件包。因此,子软件包名称必须在 父级软件包。如果两个子文件包目标具有相同的名称(或 父级可以自由分配自己的子软件包名称(通过 例如 GN 中的 renameable_subpackages)。

在 CML 中声明子打包的子组件时,url 应为 相对的子打包组件网址,如以下示例所示:

children: [
    {
        name: "echo_server",
        url: "echo_server#meta/default.cm",
    },
],

子打包的子组件也可以在运行时声明中引用, 例如在通过 Realm Builder API 声明子项时。例如:

// Add the server component to the realm, fetched from a subpackage
let echo_server = builder
    .add_child("echo_server", "my-echo-server#meta/default.cm", ChildOptions::new())
    .await
    .unwrap();

// Add the client component to the realm, fetched from a subpackage, using a
// name that is still scoped to the parent package, but the name matches the
// package's top-level name. In `BUILD.gn` the subpackage name defaults to
// the referenced package name, unless an explicit subpackage name is
// declared.
let echo_client = builder
    .add_child("echo_client", "echo_client#meta/default.cm", ChildOptions::new().eager())
    .await
    .unwrap();