RFC-0106:Fuchsia SDK 中包含的元件資訊清單

RFC-0106:Fuchsia SDK 中包含的元件資訊清單
狀態已接受
區域
  • 元件架構
說明

建立元件資訊清單,在 SDK 中加入分片 sysroot,並將其發布給樹狀結構外的整合人員。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-05-12
審查日期 (年-月-日)2021-06-23

摘要

本文建議在整合人員開發套件 (IDK) 中新增元件資訊清單分片。這會建立標準的供應項目,將元件資訊清單分片發布給樹狀結構外 (OOT) 開發人員,並建立通用模式,讓資訊清單分片可在不同開發人員環境之間移植。

讀者應熟悉下列項目:

提振精神

在不同環境中調整工作流程

自推出以來,元件資訊清單分片和 include 語法已在 cmlcmx廣泛採用。可用於各種工作,例如減少樣板封裝實作詳細資料簡化開發人員工作流程,以及核心領域變異

目前處理資訊清單的機制包括依賴 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/ 設定 cmc IT。
  • $FUCHSIA_SDK/pkg/syslog/client.shard.cml 下找到 OOT,因此我們會使用 --includepath $FUCHSIA_SDK_ROOT/pkg/ 設定 cmc OOT。

可攜式分片與本機分片

預計部分分片會提供給 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 子指令為例

  • compile
  • include
  • check-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