RFC-0106:Fuchsia SDK 中的元件資訊清單 | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 建立 SDK 中的元件資訊清單,其中包含分散的 sysroot,並將其發布至樹狀結構外整合器。 |
問題 | |
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2021-05-12 |
審查日期 (年-月-日) | 2021-06-23 |
摘要
本文件建議將元件資訊清單碎片新增至整合器開發套件 (IDK)。這麼做可為發布元件資訊清單碎片給樹狀結構外 (OOT) 的開發人員建立標準操作空間,並建立常見模式,讓資訊清單碎片可在不同開發人員環境之間移植。
讀者應熟悉下列項目:
- 元件資訊清單
- 特別是元件資訊清單中的
include
語法。
提振精神
在各環境中調整工作流程
自推出以來,元件資訊清單區塊和 cml
和 cmx
中的 include
語法已廣泛採用。這些功能可用於各種工作,例如減少固定格式、封裝實作詳細資料、簡化開發人員工作流程,以及領域變化版本。
目前處理資訊清單的機制包含依賴 Fuchsia 樹狀結構的來源版面配置。這適用於位於 Fuchsia 樹狀結構中的資訊清單,但無法順利移植至 OOT 開發。例如,請參閱這份在 C/C++ 元件中記錄資料的指南。指南一開始會指示開發人員在元件資訊清單中新增下列內容:
{
include: [ "sdk/lib/diagnostics/syslog/client.shard.cml" ],
}
不過,指南指出上述做法僅適用樹狀結構內 (IT)。由於 OOT 開發人員也是本指南的目標對象,因此指南會指示這些開發人員改為在元件資訊清單中加入下列內容,有效地將分割區的內容內嵌:
{
use: [
{ protocol: "fuchsia.logger.LogSink" },
],
}
其他地方也出現相同問題。舉例來說,Test Runner Framework 的測試執行程式清單 (可支援 Fuchsia 上的各種測試,例如 C/C++ GoogleTest、Rust libtest、Go 上的 gotest 等) 包含僅適用於 IT 的操作說明。這會阻礙良好的測試做法傳播給 OOT 開發人員。
這個折衷方案會破壞一開始加入資訊清單碎片的目的,因為用戶端會暴露 Fuchsia 記錄功能的實作細節。此外,這也會讓日後協調大規模變更的難度提高,例如日後預計採用不同通訊協定,以便從元件發布記錄。最後,這會增加 IT 和 OOT 開發人員工作流程之間的摩擦。
隱藏實作詳細資料
如果我們回顧 LogSink
區塊範例,建議 syslog 程式庫的用戶端納入這個區塊,因為這個區塊會將用戶端程式庫運作所需的功能帶入元件的沙箱。
目前這組功能非常簡單,只有單一通訊協定,但日後可能會有所變動。舉例來說,我們可以推出系統,以專屬格式將結構化資料寫入 VMOs,並在用戶端和伺服器之間輪替,這與目前追蹤功能的運作方式類似。
隱藏這些細節可降低元件作者的認知負擔,因為他們只想寫入 syslog (從他們的角度來看是常見的工具),而不會在意這些細節。但這也讓 syslog 維護者能夠隨著時間推移改進這些詳細資料,而不需要元件擁有者的注意。
這項功能也適用於反向方向 (從元件公開功能,而非使用功能),以及不同類型的功能 (例如目錄功能,而非通訊協定功能)。例如,請參考這份檢查發現和代管指南。指南說明開發人員必須在元件資訊清單中加入下列項目:
{
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 發行版中封裝資訊清單區塊
您可以將包含路徑 (透過 --include-directory
或 -I
標記指定給編譯器) 設為一或多個目錄,這些目錄包含特別巢狀的子目錄和標頭檔案階層。這樣一來,包含 Fuchsia 專屬標頭的程式碼就能在 IT 和 OOT 版本之間移植。
舉例來說,以下這行 C 程式碼在 IT 和 OOT 中皆有效:
#include <lib/zx/process.h>
這是因為鎖定 Fuchsia 的 IT 建構作業和 OOT 建構作業都會在其包含目錄中加入路徑,該路徑下方有 lib/zx/process.h
檔案。在 Fuchsia 檢出的情況下,對應的包含目錄為 //zircon/system/ulib/zx/include/
,但在 OOT 版本中,這個路徑必須是 $FUCHSIA_SDK/pkg/zx/include/
。另請參閱:IDK 版面配置。
在包含路徑中設定目錄,讓包含指令可移植,也稱為設定「sysroot」。
我們會以類似的方式部署元件資訊清單區塊,在概念上與區塊目的相關聯的子路徑中,位於 $FUCHSIA_SDK/pkg/
下方,並在 IT 和 OOT 建構中,相應地在 cmc
中設定 --includepath
旗標。
舉例來說,上述範例中使用的 Syslog 區塊可能會是:
- 如下所示:
include: [ "syslog/client.shard.cml" ]
。 - 在
//sdk/lib/syslog/client.shard.cml
底下找到 IT,因此我們會使用--includepath $FUCHSIA_CHECKOUT/sdk/lib/
設定cmc
IT。 - 在
$FUCHSIA_SDK/pkg/syslog/client.shard.cml
底下找到 OOT,因此我們會使用--includepath $FUCHSIA_SDK_ROOT/pkg/
設定cmc
OOT。
可攜式分割區與本機分割區
預期部分分割區會提供給 OOT 開發人員,而其他分割區則僅供 IT 使用。上述範例說明瞭可用於 OOT 的資料分割區。舉例來說,這個區塊就是只對 IT 有用的區塊,可用於在兩個元件定義之間共用大量複雜的能力轉送,其中一個是系統元件,另一個則是該元件的測試影本。這個特定分割區 OOT 沒有用途。
因此,部分分片應可移植並在 IDK 中發布,而其他分片則應保留在特定存放區中。
我們建議使用相對路徑和絕對路徑的通用符號,將這項差異編碼化。資訊清單 include
指令中用於解析可攜式區塊的路徑,不應有開頭 //
,例如 syslog/client.shard.cml
。系統會根據分割區的 sysroot 解析這些項目。另一方面,如果某個分割區是特定存放區的純本機,其路徑應以 //
開頭,並且會針對該存放區的來源根目錄 (或檢出根目錄) 解析。舉例來說,這個區塊應透過路徑 //src/sys/test_manager/meta/common.shard.cml
加入 IT。
使用 cmc
建構系統整合
樹狀結構內 GN 和 Ninja 建構等建構系統,以及任何以 Fuchsia 為目標的樹狀結構外建構,都已與 cmc
整合。這類整合功能必須修正,才能支援新的 include 行為。具體來說,以下 cmc
子指令:
compile
include
check-includes
cmc
的叫用作業需要指定下列標記:
--includeroot
:路徑,用於解析含有//
前置字元的包含路徑。--includepath
:零個或多個路徑,用於對其他路徑進行解析,並依照指定的順序 (先比對)。
以 SDK 原子做為分片
建構系統會將區塊納入 IDK,這與處理其他 IDK 元素的方式類似。我們會重複使用現有的 sdk_atom()
範本,根據我們希望的 IDK 版面配置指定 id
參數。
新增切片至 IDK 的程序
分片可指定可能與平台途徑重疊的合約預期。舉例來說,系統記錄片段會參照 Fuchsia 命名空間中的通訊協定 - fuchsia.logger.LogSink
- 而這項通訊協定眾所皆知是由 Fuchsia 系統元件提供。因此,在 IDK 中發布的區塊會視為 API 和 SDK 原子,並透過與目前用於新增或修改 IDK 中發布的 FIDL 檔案相同的程序進行 API 審查。您也可以使用類別的 sdk_atom()
概念,例如先將區段設為「內部」(不應分發至 OOT),然後透過現有程序將其提升至曝光率較高的類別。
日後的作業
通訊埠 expect_includes()
Fuchsia 的 GN 版本提供範本,可讓依附元件在資訊清單中加入特定區塊 (請參閱這份指南)。這項功能提供的其中一個好處是,如果開發人員新增了依附元件 (例如特定服務的用戶端程式庫),這項功能會引導他們在元件中加入資訊清單區段,確保程式庫可存取在執行階段需要的功能,以便正確運作。
IT 開發人員對此給予非常正面的意見回饋,部分 OOT 開發人員也表示有興趣。這個範本或概念可使用 GN 中繼資料移植至 GN SDK,以及使用 Bazel 層面或 Bazel 供應者移植至 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 中預先建構為套件。它是完全密封的,無需任何外部依附元件即可執行。可從指令列叫用,不需要建構系統整合。
回溯相容性
一旦新建的 OOT 元件採用最新的 IDK 版本,變更 IDK 中的區塊就會影響這些元件,但不會影響舊的預先建構項目。請務必小心避免造成破壞性的變更,並使用平台變更的標準做法:在多個版本中進行軟性轉換、支援視窗,以及與利益相關者溝通。
如同所有平台演進作業,變更都應經過徹底測試,而重大變更也應以可因應變更的做法加以管理,例如使用某些版本控制機制。請注意,平台版本控制的問題,以及這項問題的子集 (例如 FIDL 版本控制),目前仍未解決,且不在本 RFC 的範圍內。
安全性考量
元件資訊清單會定義能力轉送和沙箱,這會直接影響安全性。不過,資訊清單的目標並非最終產生不同的資訊清單,而是以更符合人體工學的方式產生相同的資訊清單。只要在處理包含項目後產生相同的最終資訊清單,就不會影響安全性。
為了協助開發人員瞭解在處理包含項目後,其資訊清單會是什麼樣子,他們可以使用上述的 cmc include
。
測試
cmc
中的現有功能已涵蓋單元和整合測試。cmc
的測試涵蓋率為 >90%,其中「include」子指令的涵蓋率已完成。任何需要對 Fuchsia IDK 或 OOT 整合進行的未完成變更,都會按照 SDK 團隊的指示和期望進行測試。
就 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
。