RFC-0215:結構化設定父項覆寫

RFC-0215:結構化設定父項覆寫
狀態已接受
領域
  • 元件架構
說明

允許父項元件在執行階段為子項提供設定。

問題
毛皮變化
作者
審查人員
提交日期 (年-月-日)2023-03-21
審查日期 (年-月-日)2023-04-26

摘要

允許父項元件覆寫子項結構中的值 此外還會從 0 自動調整資源配置 您完全不必調整資源調度設定

提振精神

依照 RFC-0127 的建議方向,父項元件 為子項提供設定值例如: 可以傳遞自己的設定對 starnix_runner 有幫助 值直接傳至 starnix_kernel 將不會建立設定目錄和動態優惠。

父項元件應能在啟動 動態子項。舉例來說,在 Rust 中實作的父項應能編寫 程式碼,例如:

let overrides = vec![ConfigOverride {
    key: Some("parent_provided".into()),
    value: Some(ConfigValue::Single(ConfigSingleValue::String(
        "foo".to_string(),
    ))),
    ..ConfigOverride::EMPTY
}];

connect_to_protocol::<RealmMarker>()
    .unwrap()
    .create_child(
        &mut CollectionRef { name: "...".into() },
        Child {
            // name, url, startup, ...
            config_overrides: Some(overrides),
            ..Child::EMPTY
        },
        CreateChildArgs::EMPTY,
    )
    .await
    .unwrap()
    .unwrap();

日後,父項元件應該就能設定 CML 中的靜態子項,並使用產生的 動態子項程式庫來降低詳細程度 確認覆寫值類型正確無誤

相關人員

講師:jamesr@google.com

審查者:

  • geb@google.com (CF)
  • ypomortsev@google.com (CF)
  • Markdittmer@google.com (安全性)

顧問:lindkvist@google.com、hjfreyer@google.com

社交:這份提案是由元件架構團隊相互流通 成員和潛在客戶,才能以 RFC 規定提交表單

需求條件

  1. 父項一開始可以為動態子項提供設定值 包括使用 RealmBuilder 的例項。最終應該 在 CML 中設定靜態子項,包括使用 父項設定
  2. 元件作者可能會更新內部/測試專用/開發人員專屬設定 ] 欄位並未與父項元件協調。
  3. 父項和子項元件可分開更新。兒童可能會更新 則必須與父項協調軟轉換,調整本身的設定結構定義 元件。

設計

為了使這項功能正常運作,我們必須定義下列項目:

可變動的父項設定欄位

根據規定 (2),家長只能覆寫設定 子項元件標示為可變動的欄位。

元件作者會在任何設定欄位中新增 mutable_by 屬性 ,此值必須允許接收覆寫值這項屬性會接受清單 字串,以因應日後的覆寫機制。一開始是唯一的字串 接受的生效日期為 "parent"。CML 範例:

{
    // ...
    config: {
        fields: {
            enable_new_feature: {
                type: "bool",
                mutable_by: [ "parent" ],
            },
        },
    }
}

我們會將可變動性指定為可能來源清單,方便您 為新的覆寫來源 (包括開發人員覆寫值) 擴充這個語法 將資料庫設為原始範圍由 RFC-0127 定義。

我們日後可以考慮的拒絕替代方案為:group 設定欄位的可變動性

字串鍵與偏移/座標

元件管理服務目前會使用 對已編譯設定結構定義中的欄位偏移,表示對局部最佳化 這需要元件的資訊清單、設定值和編譯 二進制,達成協議設定結構定義的確切配置。這不會 值的提供者和已設定的 元件是以不同 (但相容) 設定結構定義建構而成。

系統會改為檢查父項覆寫值,方法是檢查 子項結構定義中的鍵和提供的覆寫值,讓可以排序並 子項結構定義中要變更的欄位數量,不需子項 元件,用於指定明確的基因或父項元件來更新 覆寫值

這種做法的替代方法是使用整數 需要在子項元件明確選擇 序數

套件預設值

如果元件包含可變動的父項設定欄位,仍必須建立 並在其套件設定中提供預設值/底值。如此一來 新增可在父項可見的欄位,並提供柔和轉換效果。

日後我們可能會允許元件 提供一些設定值。

無須超額佈建

家長提供的設定值檔案中只能包含欄位值 這些值皆位於子項元件設定中,且可由父項變更 結構定義。避免超額佈建設定,將提供可預測的 且無需手動驗證孩子的身分 可正常運作

父項值的優先順序

元件設定:「個人化元件的行為」 與執行中的情境不同這意味著 官方設定值應是 掌握元件執行個體背景的知識

根據 RFC-0127 規定,元件管理服務會解析每項設定的值 欄位,偏好各個來源,按照以下順序排列:

  1. 開發人員覆寫服務 (日後) 傳送的值
  2. 來自元件父項的值
  3. 從元件自身套件指定的值

負責開發工程版本的元件開發人員可以具備學習技術的知識 發生在系統上運作的所有物件 具公信力父項可以瞭解為子項提供的背景資訊。 最後,因為元件本身套件中的值只能將 請務必提供所有其他資訊 從外部來源提供

Realm.CreateChild 中提供值

我們將擴充 fuchsia.component.decl/Child,以便指定特定設定 覆寫值:

library fuchsia.component.decl;

@available(added=HEAD)
type ConfigOverride = table {
    1: key ConfigKey;
    2: value ConfigValue;
};

type Child = table {
    // ...

    @available(added=HEAD)
    6: config_overrides vector<ConfigOverride>:MAX;
};

雖然家長可以調整動態子項的設定 但如果我們將這個欄位加進 fuchsia.component.CreateChildArgs 提供了為靜態定義的元件指定上層覆寫值的路徑我們建議的做法可確保 由父項提供的單一值,讓元件管理服務在

在執行階段提供值的父項元件必須與宣告的類型 輸入設定欄位無類型推論、轉換或整數 就會執行促銷活動

實作

提議的設計已經過原型設計

fuchsia.component.decl FIDL 程式庫需要具備 Value 的存取權 類型,目前位於 fuchsia.component.config。不過 fuchsia.component.config 目前依附於 fuchsia.component.decl 要等一段時間才能反轉與軟體的依附元件關係 轉場效果而是將所有 fuchsia.component.config 移至 目前 API 級別的 fuchsia.component.decl,淘汰中,最終將淘汰 正在移除「fuchsia.component.config」。合併兩個程式庫時 適當類型的 Config* 前置字串,例如:Value 會變成 ConfigValue

這項提案的新定義的 FIDL API 介面只能在 API 使用 第 HEAD 級,直到我們獲得功能和樹狀結構外服務經驗為止 也能運用結構化設定

除了元件宣告變更外,RealmBuilder 用戶端還 程式庫必須更新,才能以下列方式傳遞設定覆寫: 屬於 Child 依附元件的一部分

成效

此 RFC 提議讓元件管理服務使用字串等式比對 覆寫值,因此作業速度會比 目前用於解析封裝設定值的 O(1) 索引/偏移比較。 這會在元件啟動時增加極小的運算量,但不太可能 而且元件啟動時間通常位於 只會執行數百毫秒的排序背景資訊 元件對任何面向使用者來說 產品品質問題。

人體工學

在這項功能的第一個疊代中,父項元件必須知道 要覆寫的設定欄位的確切類型,但並非人體工學 因為我們最終能產生這項功能舉例來說,元件作者 需符合數字設定的確切整數寬度和帶正負號 ] 欄位。我們日後可以定義較寬鬆的型式解析規則 支援設定靜態子項 從子項的設定結構定義產生程式碼 將允許語言編譯器代您檢查欄位名稱和型別 開發人員。

無法描述元件設定的版本序列 結構定義演變是手動作業社交流程。不一定 日後

部分元件的多個欄位可能會共用相同的可變動性 規定, 每個欄位中的值我們目前還沒有符合這個模式的用途,因此 能夠解決這個問題的語法 但日後可能會選擇再次處理。

反向 &轉送相容性

元件作者應負責協調及移交 修改可變動的父項元件時 設定結構定義本節說明安全的新版程序 或是修改設定結構定義

不含 mutable_by 屬性的設定欄位不需要任何 請特別留意版本管理,因為您只能為這些欄位提供值 從元件自己的套件中嵌入

在未來,這些步驟可能會由基於 FIDL 的中介因素進行中介 版本管理

新增可變動的父項欄位,為現有欄位新增可變動性

由於所有設定欄位仍會 基本/預設值必須位於元件本身的封裝值檔案中。 這個欄位出現在元件的設定結構定義中後,父項就會 可為欄位提供值。

移除可變動的父項設定鍵,移除可變動性修飾符

從元件的元件中安全地移除可變動的父項設定欄位 結構定義必須先與父項元件合作,確保不會 停止對要移除的欄位傳遞任何覆寫值。

例如,要從元件中移除 parent_provided 設定欄位 設定介面:

  1. 元件作者傳達「淘汰」和「移除」的意圖 parent_provided
  2. 父項元件會停止指定 parent_provided 的值
  3. 元件作者將 parent_provided 從設定結構定義中移除

重新命名可變動的父項欄位

重新命名欄位等同於同時新增 &應該將 通常不會在單一步驟中執行

變更可變動且父項欄位的類型

變更欄位類型等同於同時新增 &移除和 通常不應在單一步驟中執行

變更可變動且父項欄位的限制

提高欄位的 max_lenmax_size 限制一律是安全的。

只有在符合以下條件的情況下,才能降低欄位的 max_lenmax_size 限制 父項提供的值位於新範圍內。

安全性考量

scrutiny 工具可以斷言最終 建構系統映像檔這很重要 防護機制,可防範意外設定錯誤 建構及組合程序

我們將擴充 scrutiny,以拒絕下列兩者的設定欄位: 有政策強制執行的值,且可由父項變更。如此能確保 父項永遠無法變更安全的重要設定欄位 元件。

隱私權注意事項

父項覆寫功能可讓元件將執行階段資料做為設定值傳遞。 雖然部分元件可能會選擇使用這項功能傳送使用者資料。 目前沒有可自動記錄結構化內容的 記錄檔、指標或遙測設定值不應有隱私權 對實作這項功能的影響

測試

config_encoder 程式庫的用途是解析元件中的設定 管理員、scrutiny及相關工具其單元測試的適用範圍為 確保佈建錯誤的父項覆寫 (不明金鑰、類型錯誤、 缺少可變動性) 將遭到拒絕

我們會擴充結構化設定整合測試,確保 父項元件可以使用 Realm 通訊協定和 RealmBuilder

系統將擴充 scrutiny 項測試,確保拒絕父項可變動的欄位 其政策檔案內含靜態宣告值。

說明文件

CML 參考說明文件將會更新,以符合更新後的設定結構定義 語法。

將會編寫結構化設定結構定義演變指南。涵蓋內容 新增及移除欄位的最佳做法其中包含 可以管理柔和轉換

新增結構化設定值來源及其 優先順序原則

現有說明文件,解釋如何驗證建構的映像檔的安全性屬性 進一步說明,為何不可使用父項可變動的欄位 以保護安全相關設定

未來工作

產生的覆寫繫結

上述提案暗示,上層元件的作者必須使用 字串鍵和「動態輸入」提供覆寫值這將 產生一些樣板,並讓父項可以 輸入錯誤的鍵/值,或是忘記更新會產生覆寫值的 codepath 如果有新的欄位可用佈建有誤導致的錯誤 只有在啟動子項時,畫面上才會顯示設定值 元件。

我們最終可以允許來自 的作者,改善開發人員的使用體驗 來產生「父項覆寫」程式庫這些 可供父項元件的作者使用,減少所輸入的字元, 的編譯器檢查是否已正確覆寫子項的 設定:

let overrides = FooConfigOverrides {
    parent_provided: Some("foo".to_string()),
    ..FooConfigOverrides::EMPTY
};
connect_to_protocol::<RealmMarker>()
    .unwrap()
    .create_child(
        &mut CollectionRef { name: "...".into() },
        Child {
            // name, url, startup, ...
            config_overrides: overrides.to_values(),
            ..Child::EMPTY
        },
        CreateChildArgs::EMPTY,
    )
    .await
    .unwrap()
    .unwrap();

在 CML 中設定子項

具有靜態子項的父項元件最終應能 在 CML 中宣告子項時設定值。例如:

{
    children: [
        {
            name: "...",
            url: "...",
            config: {
                parent_provided: "foo",
            },
        },
    ],
}

我們也想提供語法,讓家長可以自行轉寄自己的內容 設定值直接套用至靜態子項

我們必須決定是否允許 scrutiny 允許父項的可變動欄位 當提供的設定值是靜態資訊時。

如果我們為 CML 建構這項功能,傳送常值將需要設計 設法消除 JSON5 輸入數字和結構化格式之間的差異 設定的精確類型接著我們需要選擇 所有可能的 JSON5 的 fuchsia.component.decl.ConfigValue 表示法 我們必須定義規則,允許元件管理服務 這些值可能較狹窄的設定欄位 限制。如果等待 FIDL 為基礎,我們就能避免大部分的設計工作 表示父項/子項關係表示法,因為 fidlc 可 根據子項的設定結構定義精確檢查類型。這項設計工作 也不需要允許父項將本身的設定值傳送至 孩子。

來自父項的必要設定值

有些元件可能會要求父項提供特定的 也無法依賴封裝預設值

這就需要允許封裝值檔案省略值並教導 多個程式庫可解析設定方式

這不是符合目前用途的必要條件,但對 要在未來發展的領域

以 FIDL 為基礎的結構定義和版本管理

元件架構團隊已探索如何將 FIDL 用於元件 資訊清單。若實作這種做法,我們可能可以使用 FIDL 的服務供應情形 協調設定結構定義演變的註解。

使用字串鍵解析封裝設定

採用這份 RFC 中提議的方法後,元件管理服務會有兩部分 用於解析設定值的識別碼:

  1. 系統會使用編譯後的整數偏移,解析封裝值 設定結構定義
  2. 系統會使用設定中的字串鍵解析父項提供的值 結構定義

下文所述,基於理由, 父系偏好使用字串鍵進行覆寫,以及使用 計算封裝值時,整數偏移/序數對我們並沒有太大幫助。

我們應該將封裝值移至編碼字串鍵,以減少片段 都能找到元件管理服務這項變更基本上應該是 但會簡化設定解決與 簡化日後偵錯作業

模糊設定解析度

我們日後會為元件管理服務的資訊清單剖析和 元件解析度發生這種情況時,我們會 擴充模糊工具,納入父項元件的設定值 聲明系統會遵守可變動修飾符。

缺點、替代方案和未知

將具有共用可變動性限制的欄位分組

如果元件的許多欄位都具有相同的可變動性限制, 考慮允許元件作者將設定欄位分組 並且搭配共用屬性以 (非命令式) 範例為例 多個設定區段:

{
    // ...
    config: {
        // fields which can only be resolved from a component's package
    },
    parent_config: {
        // fields which are mutable by parent
    },
}

這個方向對人體工學有幫助,但因為任何 就能達成這個目標如果我們發現這種做法 詳細程度是實務上的重要課稅

請注意,這種方法可能會讓元件作者更難定義 含有多個可變動指定碼的設定欄位,例如「可變動的項目」 「父項和覆寫服務」

覆寫 API 的整數序數

由於歷來原因,封裝設定值會解析為 欄位。這麼做 相較於檢查字串,編碼效率更高,執行階段負擔更低 等於

為了讓上層覆寫功能獲得相同的優勢,我們需要來自 子項元件,以便為欄位明確選擇序數,類似於 FIDL 資料表。上層元件作者必須指定其覆寫值 直接傳送這些字串的值,或使用產生的 程式庫

我們也必須設計機制,引導子項元件作者 而重複使用的整數序數則應該位於 使用容易出錯的風險較低

最終,我們得以解決二進位檔大小和執行階段負擔 在應用程式預計的使用規模下,整數鍵和索引鍵的用量可以忽略不計 結構化設定使用字串金鑰可讓我們延遲產生的繫結,並 模擬子元件作者的複雜程度 對系統效能最低的花費。