RFC-0173:Component Framework API 中的結構化設定

RFC-0173:元件架構 API 中的結構化設定
狀態已接受
領域
  • 元件架構
說明

定義對外公開的基本結構化設定功能實作方式。

問題
毛皮變化
  • 668417
作者
審查人員
提交日期 (年-月-日)2022-04-11
審查日期 (年-月-日)2022-06-30

摘要

元件架構 API 和結構化實作變更 此外還會從 0 自動調整資源配置 您完全不必調整資源調度設定

提振精神

結構化設定已在 RFC-0127 中獲得核准,具體說明 功能,但並未指定 導入 元件架構 RFC 標準RFC-0146 說明 CML 這個語法是用來宣告設定結構定義,而 RFC-0158 說明瞭 使用者產生的用戶端程式庫。

結構化設定的初始原型位於 fuchsia.git 中。 Component Framework 團隊正在等待正式發布功能 ,直到這個 RFC 中的 API 和行為完成狀態為止。

相關人員

講師:leannogasawara@google.com

審查者:

  • geb@google.com (元件架構)
  • jsankey@google.com (RFC-0127 作者)

顧問:hjfreyer@google.com、xbhatnag@google.com、aaronwood@google.com、 mcgrathr@google.com、shayba@google.com

社交化:此 RFC 是與元件相關的設計審查產品。 架構團隊、在原型設計過程中進行後續程式碼審查,以及 從早期採用者的意見回饋。

範圍

此 RFC 說明元件架構中要實作「第 1 階段」的變更和 「階段 2」的部分請參閱 RFC-0127 實作計畫,涵蓋 只有「靜態價值」以及功能型錄的受限版本 家長」在測試環境中使用 RealmBuilder

設計

元件架構有幾個新的責任:

  • 編譯的元件資訊清單包含設定值來源
  • 元件解析器會擷取元件的設定值
  • 元件管理服務會將元件設定編碼為永久的 FIDL 訊息
  • 元件執行器將經過編碼的設定傳送給元件
  • RealmBuilder 可讓您設定測試中已啟動子項的設定值

設定值

每個具備設定結構定義的元件都必須有設定 值。這些會儲存和在元件的各部分之間轉移 fuchsia.component.config.ValuesData 的架構:

library fuchsia.component.config;

type ValuesData = table {
    1: values vector<ValueSpec>:MAX;
    2: checksum fuchsia.component.decl.ConfigChecksum;
};

// NOTE: table to allow defining mutability in future revisions
type ValueSpec = table {
    1: value Value;
};

type Value = flexible union {
    1: single SingleValue;
    2: vector VectorValue;
};

type SingleValue = flexible union {
    1: bool bool;
    2: uint8 uint8;
    3: uint16 uint16;
    4: uint32 uint32;
    5: uint64 uint64;
    6: int8 int8;
    7: int16 int16;
    8: int32 int32;
    9: int64 int64;
   10: string string:MAX;
};

type VectorValue = flexible union {
    1: bool_vector vector<bool>:MAX;
    2: uint8_vector vector<uint8>:MAX;
    3: uint16_vector vector<uint16>:MAX;
    4: uint32_vector vector<uint32>:MAX;
    5: uint64_vector vector<uint64>:MAX;
    6: int8_vector vector<int8>:MAX;
    7: int16_vector vector<int16>:MAX;
    8: int32_vector vector<int32>:MAX;
    9: int64_vector vector<int64>:MAX;
   10: string_vector vector<string:MAX>:MAX;
};

值的儲存順序與編譯中的對應欄位相同 資訊清單。

每個設定結構定義都包含一個總和檢查碼,後者是所有欄位的雜湊。 名稱和類型ValuesData 中的總和檢查碼必須與 。

我們已考慮並拒絕其他儲存方式 定義值 (使用與傳送至元件本身相同的編碼)。

元件值來源

如果是封裝元件,設定值會儲存在「設定值」中 檔案」。設定值檔案是 fuchsia.component.config.ValuesData

由於設定值不會儲存在元件資訊清單中 元件架構必須在解析時知道值的位置 這個元件新欄位會新增至已編譯設定的表示法 結構定義:

library fuchsia.component.decl;

type ConfigSchema = table {
    // ...existing fields...

    3: value_source ConfigValueSource;
};

type ConfigValueSource = flexible union {
    /// The path within the component's package at which to find config value files.
    1: package_path string:MAX;
};

彈性聯集可用來新增設定值來源 長期下來。

按照慣例,值檔案會封裝至 meta/${manifest_basename}.cvf。適用對象 舉例來說,如果元件的資訊清單封裝在 meta/foo.cm,其值檔案 將於 meta/foo.cvf 封裝。

為了產生結構化設定而建構規則,必須確保元件 資訊清單內含元件設定的封裝路徑。 例如,樹狀結構內 GN 建構作業需要設定值,才能達成上述目標 參照元件目標,讓他們達成套件目標 位置:

import("//build/components.gni")

# NOTE: results in a package path of `meta/my_component.cm`
fuchsia_component("my_component") {
  manifest = "meta/my_component.cml"
  deps = [ "..." ]
}

# NOTE: internally calls `get_target_outputs(":my_component")` to determine
# the correct packaging path
fuchsia_structured_config_values("my_config_values") {
  component = ":my_component"
  values_source = "config/my_component.json5"
}

fuchsia_package("my_package") {
  deps = [
    ":my_component",
    ":my_config_values",
  ]
}

我們發現替代選項為商店狀態,因此遭到拒絕 設定資訊清單中的值

我們發現替代文案, 值檔案的位置,該檔案位於 資訊清單。

系統已考量並拒絕新增索引的替代文案 blob 至套件,並指向元件資訊清單與值檔案。

元件解析度

元件解析器會負責擷取元件的封裝值 並將這些元素傳回元件管理服務工具 fuchsia.sys2.Component 資料表:

library fuchsia.sys2;

// NOTE: This type is returned by fuchsia.component.resolution.Resolver/Resolve.
type Component = resource table {
    // ... existing fields ...

    /// Binary representation of the component's configuration values
    /// (`fuchsia.component.config.ValuesData`).
    4: config_values fuchsia.mem.Data;
};

系統會以 fuchsia.mem.Data 的形式傳回 ValuesData,以符合元件 資訊清單會從解析器傳回。這樣一來 處理多個資訊清單和設定值 zircon 管道訊息。

這需要元件解析器剖析元件資訊清單,才能正確解讀 值來源,而先前的解析器則能 原始位元組會直接傳送至元件管理服務,而不瞭解已編譯的 資訊清單表示法

編碼設定值

元件管理員取得設定結構定義和值後,就必須將 將元件的設定結構定義總和檢查碼傳送給 元件的執行元件,用於在執行階段特定的執行階段佈建元件 存取 API

VMO 內容

元件設定值已編碼為永久的 FIDL 結構 欄位的順序與已編譯的資訊清單相同。已拒絕 替代則是將最終設定編碼為 FIDL 資料表,而非結構體。我們也考量到 已拒絕

這需要元件管理服務瞭解 FIDL 線格式,才能執行 產生的 FIDL 可能成功剖析的訊息執行階段編碼 繫結。

元件管理服務會使用下列程式碼,將編碼的設定寫入 VMO 內容:

  • 位元組 0..1 包含總和檢查碼的長度為 N 的小端子 整數
  • 位元組 2..2+N 包含總和檢查碼
  • 位元組 3+N..ZX_PROP_VMO_CONTENT_SIZE 包含永久 FIDL 訊息: 編碼為結構體的設定值

核對和會以可變長度的部分儲存在標頭中,以便分離 與任何特定雜湊函式輸出大小相同的 VMO 編碼 變更用來導出檢查碼的雜湊演算法,不需任何變更 變更為 VMO 編碼

將 VMO 傳送給執行器

設定 VMO 建立完畢後,系統會將 VMO 做為執行器欄位傳遞給執行元件 fuchsia.component.runner.ComponentStartInfo:

library fuchsia.component.runner;

// NOTE: Passed to fuchsia.component.runner.ComponentRunner/Start.
type ComponentStartInfo = resource table {
    // ... existing fields ...

    /// Binary representation of the component's configuration.
    ///
    /// # Layout
    ///
    /// The first 2 bytes of the data should be interpreted as an unsigned 16-bit
    /// little-endian integer which denotes the number of bytes following it that
    /// contain the configuration checksum. After the checksum, all the remaining
    /// bytes are a persistent FIDL message of a top-level struct. The struct's
    /// fields match the configuration fields of the component's compiled manifest
    /// in the same order.
    7: encoded_config fuchsia.mem.Data;
};

我們也考慮並拒絕了延遲編碼為 Runner 改為使用 FIDL 描述 VMO

執行具有編碼設定的元件

每個執行器都必須與執行元件簽訂合約 來授予他們存取編碼設定的權限這份合約經過修訂 存取子程式庫

ELF 執行元件

ELF 執行元件提供設定 VMO 做為啟動控制代碼:

// in //zircon/system/public/zircon/processargs.h:
#define PA_VMO_COMPONENT_CONFIG 0x1Du

驅動程式執行元件

驅動程式庫執行元件提供設定 VMO 做為 fuchsia.driver.framework.DriverStartArgs 資料表:

library fuchsia.driver.framework;

// NOTE: Passed directly to a driver upon starting.
type DriverStartArgs = resource table {
    // ... existing fields ...
    7: config zx.handle:VMO;
};

測試執行工具

我們尚未在測試執行器中實作結構化設定支援功能, 尚未發現有明確動機的用途,可限制及引導 以及某個設計

使用 RealmBuilder 覆寫設定值

RealmBuilder 支援控制元件的設定值 發布內容。使用者可以提供個別欄位的值;根據預設,這些欄位的值 必須為元件架構中所有欄位指定值。這將 鼓勵元件本身的整合測試,完整列舉 需要測試的設定選項

RealmBuilder 也可以允許測試作者為 元件,可使用多個值批發或覆寫個別欄位。這個 舉例來說,您可以讓測試啟用 部分測試以外的使用者沒有用處,同時使用其餘測試版本的 「Production」設定該元件

這些方法會新增至 RealmBuilder:

    LoadPackagedConfigValues(struct {
        name fuchsia.component.name;
    }) -> (struct {}) error RealmBuilderError2;

    SetConfigValue(struct {
        name fuchsia.component.name;
        key fuchsia.component.decl.ConfigKey;
        value fuchsia.component.config.ValueSpec;
    }) -> (struct {}) error RealmBuilderError2;

我們會擴充 RealmBuilder 用戶端程式庫,藉此公開這項資訊 功能。

實作

此 RFC 原本提議的內容已屬於實驗性質 並提供給 fuchsia.git 的初始許可清單下方 讓使用者瞭解「元件架構」可能造成中斷 符合此 RFC 最終設計的變更將降至最低 ,然後再將結構化設定提供給樹狀結構外客戶。

成效

此 RFC 中的設計可能即時影響系統執行階段的效能 需要解析及啟動元件,但對於 對作者的瞭解,到目前為止,產品品質卻一直陷入瓶頸 與 Fuchsia 共同打造。我們確實在 而我們也將繼續監控 但在原型設計階段尚未發現 而不是每個特徵的分數

如果設定副本,採用的架構可能會增加系統記憶體用量, 這種設計會將設定儲存在 VMO 會在剖析內容轉換為 網域專屬類型。

回溯相容性

這個 RFC 假設平台版本管理已足夠 我們才發現需要支援 改善設定如何編碼成傳遞至元件的 VMO

RealmBuilder 的覆寫實作允許測試用在 啟動元件,以在元件設定上執行執行階段依附元件 結構定義,以及用於其他模型的元件作者這些測試需要在 變更設定欄位的類型或移除 設定欄位的值

安全性考量

結構化設定可用於控管 元件,因此實作時務必要提供正確的值。

元件設定的來源與資訊清單的來源相同,但 我們日後可能會擴充現有的元件解析器,或是建立新的解析器 這能讓兩者之間拉近距離我們需要練習 確保元件設定始終模糊不清 可稽核。

隱私權注意事項

根據 RFC-0127,結構化設定的設計目的並非儲存使用者 產生的資料。

測試

在本次設計中,最敏感的部分是動態 FIDL 編碼器, 元件管理服務其原型已整合為「語言後端」英吋 FIDL 的 GIDL 合規套件,確保其支援的部分類型 這會產生與靜態類型 FIDL 繫結相同的配置訊息。

說明文件

原型的說明文件目前僅適用於樹狀結構內 開發人員。

缺點、替代方案和未知

替代方法:以型別格式儲存值

比起未輸入的 fuchsia.component.config.ValuesData,我們可以儲存 並在 元件架構使用 FIDL 編碼酬載,類型與 元件的結構定義,與直接傳入的 VMO 所使用的編碼類似 這個元件

這很可能會在磁碟上表現得略為複雜,例如 而且在視覺上與最終解碼器的輸入酬載一致 元件狀態

此 RFC 提議的設計讓各種工具得以瞭解設定 不必重新導入動態類型的 FIDL 剖析器日後, 如果 FIDL 工具鍊提供更多通用工具,可能會重新考慮這項決定 代表「反思」透過訊息傳送更多資料

替代做法:在資訊清單中儲存值

在資訊清單中儲存值會簡化 免除元件解析器的責任 。

替代方法:根據副檔名尋找值檔案

我們不會在元件資訊清單中加入值來源,而是透過 找出值檔案的位置封裝慣例。這會 不理想的執行階段依附關係。

替代方法:透過套件元件索引尋找值檔案

在套件中新增第三個 blob 可讓我們管道讀取 產生更簡潔的建構圖表 簡化資訊清單編譯程序的一些元素,並允許元件 解析器會較簡單的檔案格式,不用剖析整個 元件資訊清單。

不過,這會增加系統映像檔的大小, 元件解析方式會讓使用者看見的變更。

替代方法:將設定編碼為 FIDL 資料表

相較於 FIDL 結構,設定欄位可以編碼為資料表,如 被建議為 RFC-0127 中的選項。資料表有許多 執行演進作業時,但也需要剖析器會假設 欄位可省略採用結構化設定後,元件管理服務 可以持續提供所有欄位,且呼叫端不需處理 如未提供任何值,就會發生此情況。

FIDL 結構體在傳送相同資料時佔用的位元組數較少,但速度會稍快一些 剖析。

替代做法:使用非 FIDL 編碼設定值

FIDL 以外的編碼是可行的,但 FIDL 電匯格式可以正常運作 所以選擇其他編碼是淨增值 瞭解 Fuchsia 所需的概念數量。使用 FIDL 編碼 符合元件架構的期望,以便與 FIDL 進一步整合 讓系統使用 FIDL 產生的繫結做為實作項目 存取子,讓結構化設定可享受 先前就達到的效能和二進位檔大小最佳化 好在那裡。

替代做法:執行器編碼設定

我們不需要在元件管理服務中將設定 VMO 編碼,而是可以將前者編碼 在每個執行元件中訓練這樣一來,在不同程度的跑者上 抽象化機制提供不同格式的設定。舉例來說 的 JavaScript 程式碼可以將設定當做物件使用該語言 不必讓各個 JavaScript 元件剖析 VMO。

不過,如同「測試」一文所述,FIDL 是最敏感的編碼方式 在正確性方面進行設計今天有多名跑者 設定會使用 FIDL 編碼,也就是說, 可構成多個二進位檔 (以及實作程式設計語言), 這種敏感性任務集中處理 元件管理服務能讓我們限制實作方式,達成 經由大量測試,對整體功能產生信心。

提出的設計建議會導致執行元件難以設定 作為每個執行元件一樣,都是根據元件的結構化設定值決定行為 就需要根據元件的宣告結構定義剖析已編碼的 FIDL。 這與使每個執行元件負責 同樣是不理想的編碼方式設定執行者時 並透過元件設定設計獨立的介面 將元件設定的值改為執行元件定義 執行元件設定介面的優點還包括 元件設定命名空間

替代做法:使用 FIDL 說明 VMO/核對和版面配置

除了將設定總和檢查碼編碼為 VMO 中的標頭位元組外 以 FIDL 的術語描述 VMO 的 ABI:

type ConfigVmo = struct {
    checksum bytes:MAX;
    contents bytes:MAX;
};

這會在每項設定的 VMO 中佔用較多空間,因此需要更多空間 週遊 contents 的位元組兩次。