| RFC-0106:Fuchsia SDK 中包含的元件資訊清單 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 建立元件資訊清單,在 SDK 中加入分片 sysroot,並將其發布給樹狀結構外的整合人員。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2021-05-12 |
| 審查日期 (年-月-日) | 2021-06-23 |
摘要
本文建議在整合人員開發套件 (IDK) 中新增元件資訊清單分片。這會建立標準的供應項目,將元件資訊清單分片發布給樹狀結構外 (OOT) 開發人員,並建立通用模式,讓資訊清單分片可在不同開發人員環境之間移植。
讀者應熟悉下列項目:
- 元件資訊清單
- 特別是元件資訊清單中的
include語法。
提振精神
在不同環境中調整工作流程
自推出以來,元件資訊清單分片和 include 語法已在 cml 和 cmx 中廣泛採用。可用於各種工作,例如減少樣板、封裝實作詳細資料、簡化開發人員工作流程,以及核心領域變異。
目前處理資訊清單的機制包括依賴 Fuchsia 樹狀結構的來源版面配置。這項做法適用於 Fuchsia 樹狀結構中的資訊清單,但不適合 OOT 開發。舉例來說,請參閱這份指南,瞭解如何在 C/C++ 元件中記錄。指南一開始會指示開發人員在元件資訊清單中新增下列內容:
{
include: [ "sdk/lib/diagnostics/syslog/client.shard.cml" ],
}
不過,指南指出上述做法僅適用於樹狀結構內 (IT)。由於本指南的目標對象也包括 OOT 開發人員,因此指南會指示這些開發人員改為在元件資訊清單中加入下列內容,有效內嵌分片內容:
{
use: [
{ protocol: "fuchsia.logger.LogSink" },
],
}
其他地方也有相同問題。舉例來說,測試執行器架構的測試執行器清單 (用於支援 Fuchsia 上的各種測試類型,例如 C/C++ GoogleTest、Rust libtest、Go 上的 gotest 等),只有 IT 才能使用的指令。這會阻礙 OOT 開發人員採用良好的測試做法。
這項妥協會導致用戶端暴露於 Fuchsia 記錄的實作細節,因此無法達到在第一個位置加入資訊清單分片的用意。此外,這也會導致日後更難協調大規模變更,例如日後計畫軟性轉換至其他通訊協定,以便從元件發布記錄。最後,這會導致 IT 和 OOT 開發人員工作流程之間產生摩擦。
隱藏實作詳細資料
如果我們重新檢視 LogSink 分片範例,建議 syslog 程式庫的用戶納入這個分片,因為這會將用戶端程式庫運作所需的各項功能帶入元件的沙箱。
目前這組功能非常簡單,只有單一通訊協定,但預計日後會有所變更。舉例來說,我們可能會導入一種系統,將特定格式的結構化資料寫入 VMO,並在用戶端和伺服器之間輪替,而不是採用目前的通訊協定,讓用戶端將插座連線至系統記錄,然後將字元緩衝處理至該插座以記錄字元,這與目前的追蹤方式類似。
將這些詳細資料隱藏在分片後方,可減輕元件作者的認知負擔,他們只想寫入系統記錄 (從他們的角度來看,這是常見的公用程式),並不在意這些詳細資料。但這也讓系統記錄維護人員能夠隨著時間演進這些詳細資料,而不需要元件擁有者注意。
這也適用於反向操作 (從元件公開功能,而非取用功能),以及不同類型的功能 (例如目錄功能,而非通訊協定功能)。舉例來說,請參閱這份檢查探索和代管指南。該指南說明開發人員必須在元件資訊清單中加入下列內容:
{
capabilities: [
{
directory: "diagnostics",
rights: [ "connect" ],
path: "/diagnostics",
},
],
expose: [
{
directory: "diagnostics",
from: "self",
to: "framework",
},
],
}
或者,開發人員也可以直接加入分片。這樣一來,開發人員就省下 14 行樣板、不必處理將目錄能力公開給架構等概念的模糊性 (大多數元件開發人員不需要熟悉這些概念),以及日後需要變更這項機制時的麻煩。最後,如果可在 IT 和 OOT 元件資訊清單之間移植分片,檢查指南就不必為 IT 和 OOT 開發人員指定一組不同的指令,因此會大幅縮短。
簡化系統功能的使用方式
另一個更複雜的例子是,直接以 FIDL 用戶端 (而非透過用戶端程式庫,如上一個範例所示) 使用網頁引擎時,可能需要的各種功能。網頁執行階段功能強大且穩定,只要具備必要功能,現今的網頁應用程式就能執行許多具備權限的裝置作業。fuchsia.web 定義網頁引擎實作項目必須具備的不同功能,才能代管特定網頁應用程式。
為了簡化從環境取用這些相同功能,然後提供給網路引擎的程序,我們將這些功能依常見類別切分成多個分片。舉例來說,這個分片定義了網頁引擎所需的「基本」功能集:
{
"sandbox": {
"services": [
"fuchsia.device.NameProvider",
"fuchsia.fonts.Provider",
"fuchsia.intl.PropertyProvider",
"fuchsia.logger.LogSink",
"fuchsia.memorypressure.Provider",
"fuchsia.process.Launcher",
"fuchsia.sysmem.Allocator",
]
}
}
這個分片定義了額外功能,如果網路應用程式並非本機應用程式,且/或需要網路,則必須使用這些功能:
{
"sandbox": {
"services": [
"fuchsia.net.name.Lookup",
"fuchsia.net.interfaces.State",
"fuchsia.posix.socket.Provider"
]
}
}
但如要在 Scenic View 中算繪網頁應用程式,則必須使用這個分片:
{
"sandbox": {
"services": [
"fuchsia.accessibility.semantics.SemanticsManager",
"fuchsia.ui.input.ImeService",
"fuchsia.ui.input.ImeVisibilityService",
"fuchsia.ui.scenic.Scenic"
]
}
}
例如,執行個體可使用額外的分片,解鎖圖像的硬體加速功能,或使用硬體媒體編解碼器。
這並非微不足道的資訊量。將其保留在自己的分片中,比新增至元件沙箱中其他服務的堆疊更整齊。此外,這也再次簡化了演進過程。
請注意,這只是假設的例子。這些分片目前存在於 IT 中。這項探索是為了瞭解是否能將這些分片移至 IDK,以便 OOT 提供,並非承諾會這麼做。此外,上述分片的內容仍在變動,這裡僅做為說明範例,而非參考文件。
實作
在 IDK 發布中封裝資訊清單分片
如要以 Fuchsia 為目標開發 C/C++,請將 include 路徑 (透過 --include-directory 或 -I 標記指定給編譯器) 設為一或多個目錄,這些目錄包含特別巢狀的子目錄和標頭檔案階層。這樣一來,包含 Fuchsia 專屬標頭的程式碼,就能在 IT 和 OOT 建構之間移植。
舉例來說,下列 C 程式碼行在 IT 和 OOT 中都有效:
#include <lib/zx/process.h>
這是因為以 Fuchsia 為目標的 IT 建構作業和 OOT 建構作業,都會在 include 目錄中加入路徑,而該路徑下方有 lib/zx/process.h 檔案。在 Fuchsia 結帳中,對應的 include 目錄為 //zircon/system/ulib/zx/include/,而在 OOT 建構中,這個路徑必須為 $FUCHSIA_SDK/pkg/zx/include/。另請參閱:IDK 版面配置。
在 include 路徑中設定目錄,讓 include 指令可攜式使用,又稱為設定「sysroot」。
我們會以類似方式部署元件資訊清單分片,在概念上與分片用途相關的子路徑中,位於 $FUCHSIA_SDK/pkg/ 下方,並在 IT 和 OOT 建構版本中,相應地在 cmc 中設定 --includepath 旗標。
舉例來說,上述範例使用的系統記錄分片可能是:
- 包括:
include: [ "syslog/client.shard.cml" ]。 - 我們在
//sdk/lib/syslog/client.shard.cml下方找到 IT,因此會使用--includepath $FUCHSIA_CHECKOUT/sdk/lib/設定cmcIT。 - 在
$FUCHSIA_SDK/pkg/syslog/client.shard.cml下找到 OOT,因此我們會使用--includepath $FUCHSIA_SDK_ROOT/pkg/設定cmcOOT。
可攜式分片與本機分片
預計部分分片會提供給 OOT 開發人員,其他分片則僅供 IT 使用。上文介紹了幾個可直接使用的分片範例。舉例來說,只有 IT 實用的分片是這個分片,用於在兩個元件定義之間共用大部分的複雜能力轉送,其中一個是系統元件,另一個是該元件的測試替身。這個特定分片 OOT 沒有用途。
因此,部分分片應可攜帶並發布至 IDK,其他分片則應保留在特定存放區中。
我們建議使用相對和絕對路徑的通用標記,將這項差異編碼。資訊清單 include 指令中使用的路徑應解析為可攜式分片,且不得有開頭的 //,例如 syslog/client.shard.cml。這些項目會根據分片的 sysroot 進行解析。
另一方面,純粹屬於特定存放區的碎塊路徑應以 // 開頭,並根據存放區的來源根目錄 (或結帳根目錄) 解析。舉例來說,這個分片應透過路徑 //src/sys/test_manager/meta/common.shard.cml 納入 IT。
使用 cmc 建構系統整合
建構系統 (例如樹狀結構內 GN 和 Ninja 建構,以及以 Fuchsia 為目標的任何樹狀結構外建構) 已與 cmc 整合。這類整合項目必須經過修正,才能支援新的納入行為。以下列 cmc 子指令為例:
compileincludecheck-includes
cmc 的呼叫需要指定下列標記:
--includeroot:用來解析以//為前置字元的 include 路徑。--includepath:零或多個路徑,用於解析其他路徑 (依指定順序,先比對先符合)。
將分片視為 SDK 原子
建構系統會將分片納入 IDK,與處理其他 IDK 元素的方式類似。我們會重複使用現有的 sdk_atom() 範本,並根據所需的 IDK 版面配置指定 id 參數。
將分片新增至 IDK 的程序
碎片可以指定合約預期行為,這可能與平台介面重疊。舉例來說,系統記錄分片會參照 Fuchsia 命名空間中的通訊協定 - fuchsia.logger.LogSink - 這個通訊協定是由 Fuchsia 系統元件提供,因此廣為人知。因此,IDK 中發布的分片會視為 API 和 SDK 原子,並透過與目前相同的程序進行 API 審查,例如新增或修改 IDK 中發布的 FIDL 檔案。您也可以使用「類別」sdk_atom()概念,例如先將分片設為「內部」(不透過 OOT 發布),然後透過現有程序將其提升至曝光度較高的類別。
之後的作業
通訊埠 expect_includes()
Fuchsia 的 GN 建構作業提供範本,可預期依附元件會在資訊清單中包含特定分片 (請參閱這份指南)。這項做法的優點之一,是可引導開發人員在元件中加入資訊清單分片,確保程式庫在執行階段能存取運作所需的各項功能,例如特定服務的用戶端程式庫。
IT 開發人員對此給予高度正面評價,部分 OOT 開發人員也表示有興趣。這個範本或相關概念可使用 GN 中繼資料移植至 GN SDK,也可以使用 Bazel Aspect 或 Bazel Provider 移植至 Bazel/Blaze SDK。
另請參閱:https://fxbug.dev/42156975
效能
這項提案不會影響執行階段效能,因為所有工作都是在建構階段完成。
處理作業包括在建構時新增一些額外工作。不過,這項異動預期不會影響乾淨建構的實際時間。先前的研究顯示,建構作業中不屬於關鍵路徑的工作通常不會導致建構延遲,而且直接衍生自來源 (例如 cmc 呼叫、fidlc 呼叫等) 的工作幾乎不會出現在關鍵路徑上,因為這類工作可以順利平行處理,且排程非常彈性。
舉例來說,請參考這項變更,其中 cmc 中的常見作業速度提升了約 300 毫秒,但儘管在建構中呼叫 cmc 數千次,我們測量到的建構實際時間卻沒有任何影響。
人體工學
我們致力於確保資訊清單包含的機制簡單明瞭。舉例來說,您可以使用簡單的指令,產生後續處理的元件資訊清單,並將 include 指令替換為所含檔案的內容 (如有需要,可遞移)。
fx cmc include manifest --includepath $(fx get-src-dir)這項原則與在 C/C++ 原始碼上執行 C 前置處理器類似 (請參閱:man cpp)。
此外,cmc 會產生簡單的錯誤,方便排解問題,包括包含週期等異常錯誤情況。所有支援的錯誤都會經過單元測試。
cmc 工具本身已在 Fuchsia IDK 中預先建構並封裝。這項工具完全密封,執行時不需要任何外部依附元件。可從指令列叫用,不需要整合建構系統。
回溯相容性
變更 IDK 中的分片會影響新建立的 OOT 元件 (一旦這些元件採用最新版 IDK),但不會影響舊的預先建構元件。請務必避免重大變更,並採用平台變更的標準做法:在多個版本中進行軟轉換、支援視窗,以及與利害關係人溝通。
與所有平台演進事項一樣,變更應經過徹底測試,且應以某種方式管理重大變更,以因應中斷情況,例如使用某種版本控管機制。請注意,平台版本控管和這個問題的子集 (例如 FIDL 版本控管) 目前仍未解決,且不在本 RFC 的範圍內。
安全性考量
元件資訊清單會定義能力轉送和沙箱,這會直接影響安全性。不過,資訊清單包含項目的目標並非最終產生不同的資訊清單,而是以更符合人體工學的方式產生相同的資訊清單。只要在處理 include 後產生相同的最終資訊清單,就不會對安全性造成影響。
為協助開發人員瞭解處理包含項目後資訊清單的樣貌,他們可以使用上述cmc include。
測試
單元和整合測試已涵蓋 cmc 中的現有功能。cmc 的測試涵蓋範圍超過 90%,且 include 子指令的涵蓋範圍完整。SDK 團隊會按照指示,測試 Fuchsia IDK 或 OOT 整合功能中任何待處理的變更。
就 CTS 測試涵蓋範圍而言,IDK 中的元件資訊清單應視為任何其他 IDK 構件。
說明文件
include 語法已記錄在文件中。
cmc include 指令會透過 cmc help include 自行記錄。
現有文件目前指示 OOT 開發人員使用資訊清單的替代項目,一旦不再需要區分 IT 和 OOT 開發,這些文件就會更新。
缺點、替代方案和未知事項
不執行任何動作
我們可以維持現狀,但這樣就無法解決上述動機部分所述的問題。
將 IDK 中的分片整理為頂層構件
除了在 IDK 中各種可能的位置發布元件資訊清單分片 (例如 $FUCHSIA_SDK_ROOT/pkg 或 $FUCHSIA_SDK_ROOT/fidl 下方,視分片的邏輯關聯而定),我們也探索了為元件資訊清單分片建立單一基本目錄的替代方案。例如:$FUCHSIA_SDK_ROOT/component_manifests/。這與所有 .fidl 檔案在 $FUCHSIA_SDK_ROOT/fidl/ 下的整理方式類似,也就是說,這些檔案是依類型 (FIDL 檔案) 彙整,而非依其他邏輯關聯 (例如 pkg/async/、pkg/memfs/、pkg/zx/)。
根據 SDK 客戶的回饋,他們偏好 SDK 內容的邏輯關聯,而非將不同類型的檔案分散在不同的基本目錄中,因此我們拒絕了這項替代方案。接受的設計允許執行個體將元件資訊清單分片放在使用 syslog 的位置,旁邊是 C++ 標頭,可從以 C++ 編寫的元件寫入 syslog。
既有技術和參考資料
元件資訊清單包含的內容是參考 C/C++ 包含項目。
cmc include 指令的靈感來自 cpp 指令,後者會對指定檔案執行 C 前置處理器,並列印後續處理結果。詳情請參閱:
man cpp。