將元件分包

元件可以利用子封裝來整理巢狀元件的階層,其中每個元件都會封裝在其專屬套件中,並可提供自己的一組依附元件。

子套件能啟用以下功能:

  • 封裝的依附元件 (套件元件僅宣告其直接依附元件)
  • 隔離的 /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 的對應會在建構設定中宣告,並在建構期間透過將子套件的套件雜湊儲存在父項元件的套件中繼資料中,其對應至子套件名稱。

依附元件具有遞移性及封裝

元件軟體實作不會use其他元件。元件 use 功能。元件的功能可能來自父項 (直接或間接經由父項傳遞,無須瞭解元件) 或子項。重要的是,子項公開的能力也可能是直接或間接。子項的實作會封裝,因此其公開的能力可由該子項實作,或可能從子項的其中一個子項轉送。

子封裝可讓元件完全封裝其實作,包括子元件的所有依附元件。

當元件使用絕對元件網址宣告子項時,系統會在執行階段選取該子項的特定實作。在某些情況下,這或許是必要做法,但需要注意的是,父項元件並不密封,可能難以在新環境中重複使用父項元件。發布及移植非密封的程式碼時,也需要追蹤所有外部依附元件,然後確保依附元件一律會在任何新環境中提供使用。

    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 目錄。在單一套件中封裝多個元件,讓每個元件不僅可以存取相同的資料,也能存取該套件中其他元件的中繼資料,而無需明確的能力轉送。

在某些情況下,多個元件會共用相同資料的存取權。在這種情況下,這可能非常方便。不過,如果元件需要存取不同的資料集,或某個元件使用不應公開的資料,將元件封裝在一起可能會破壞最低權限原則,使子套件更加適用。

事實上,元件可能無法利用這項連帶權限比救濟更重要,因為這可能不是每次都會發生,而且權限會讓一個元件陷入意料之外的機會,來利用其他元件的資料。

在單一套件中使用多個元件的優點

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 套件的定義必須變更為 ABDE 套件,而「除非」 (為了引數) 也取決於 C,而除非 (為了引數) 也捨棄 CDE

雖然部分建構環境允許元件建構目標宣告遞移元件依附元件,但這種做法可以放大將這些元件內容合併到單一命名空間的風險。如果元件或任何依附元件有所變更,新檔案可能會覆寫該套件中元件子樹狀結構中其他元件的檔案,以未定義且可能災難的方式破壞實作。

子套件會在每個子套件的定義中封裝 SP 套件,藉此大幅簡化遞移依附元件,因此套件 SP 可以替換為 A 套件 (包含元件 A),且「僅」子套件 B (包含元件 B) 具有依附元件。A 套件不需要任何其他依附元件,也不會變更,即使 B 依附元件變更也一樣。

子封裝實作為建構時間保證

使用相對 URI 片段元件網址 (例如 #meta/some-child.cm) 無法保證「同一套件中」父項和子項元件之間的 ABI 甚至 API 相容性,因為它們實際上可以從該套件的不同版本解析。

如果套件是暫時解析 (來自套件伺服器)。從父項元件解析開始,到稍後需要子項元件並載入的這段期間,相同套件可重新發布。子項實作可能與原始套件內含的實作不同。

這並不是罕見或連續的用途:在元件架構中,元件預設只會在必要時解析元件。除非有其他元件需要服務 S,否則系統不會載入公開單一服務 S 的元件。視程式的商業邏輯而定,系統可能會在父項元件啟動的數分鐘或數小時後呼叫 S

範例

為子套件宣告建構依附元件

啟用 Fuchsia 的建構架構應包含宣告 Fuchsia 套件及其內容的模式。如果啟用了支援子套件的功能,套件宣告就會根據直接納入項目列出依附的子套件。

例如,在 fuchsia.git 中,用於宣告 Fuchsia 套件的 GN 範本支援兩個選用清單:subpackages 和 (較少用) renameable_subpackages。您可以加入其中一個,或兩者同時加入。renameable_ 版本可讓套件指派特定套件名稱給子套件,在依據套件網址或元件網址參照子套件時使用:

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 建構目標清單。根據預設,子套件名稱 (內含套件用來參照套件的名稱) 取自子套件 fuchsia_package 目標中定義的 package_name

您也可以使用 renameable_subpackages 清單中的 package 變數宣告子套件目標。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();