套件可以「包含」其他套件 (稱為「巢狀套件」),產生巢狀套件的階層。元件可利用子套件來整理巢狀元件階層,其中每個元件都會封裝在其專屬的套件中,並帶來專屬的依附元件組合。
子檔案包啟用:
- 封裝的依附元件 (已封裝的元件只會宣告直接依附元件)
- 隔離的
/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.com
或 alt-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
必須將 A
、B
和 C
打包。如果 B
之後經過修改,以兩個新元件 D
和 E
取代 C
,則套件 SP
的定義必須變更為套件 A
、B
、D
和 E
,並捨棄 C
,除非 (為了方便說明) D
或 E
(或兩者皆是) 也依附於 C
。
雖然某些建構環境允許元件建構目標宣告傳遞元件依附元件,但這項做法會增加將這些元件內容合併至單一命名空間的風險。如果元件或其任何依附元件發生變更,新檔案可能會覆寫該套件中元件子樹狀結構任何部分的其他元件檔案,以未定且可能會造成災難性影響的方式中斷實作。
子套件會在每個子套件的定義中封裝傳遞依附元件,大幅簡化傳遞依附元件,因此套件 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();