RFC-0101:含編號控制代碼的動態元件

RFC-0101:含有編號控點的動態元件
狀態已接受
區域
  • 元件架構
說明

提供將編號控點傳遞至動態元件的方法。

變更
作者
審查人員
提交日期 (年/月)2021-05-18
審查日期 (年/月)2021-06-02

摘要

本文件提議在 fuchsia.sys2.Realm/CreateChild 中新增參數。此參數將包含一組有編號的控制代碼。系統要求執行元件時,已建立的元件的執行器會收到這些控點。您提供的帳號代碼僅適用於在具備新型耐用性類型的集合中執行的元件:single-run。集合中具有 single-run 耐用性的元件會在停止時啟動,並遭到刪除。這會將提供的控點限制為元件的單一執行。

提振精神

Starnix 是執行 Fuchsia 上的 Linux 二進位檔的元件架構 v2 執行器。Starnix 會實作 Linux 系統介面,藉此在未經修改的情況下執行這些二進位檔。

Starnix 提供 ffx 外掛程式,可讓使用者透過主機指令列執行 Linux 元件。Starnix 想要將 Linux 元件的 stdin/stdout/stderr 連線至三組通訊端控點。這個元件不會藉由公開 FIDL 通訊協定與系統互動。而是透過提供的通訊端與使用者互動。

設計

背景

元件架構中生命週期轉換有兩種維度。首先必須和元件的執行作業 (CreatedDestroyed) 相關。第二種與元件的執行作業 (StartedStopped) 相關。在其他作業系統中,只有程序而非元件,這些維度是相等的:建立程序與啟動程序相同,程序在停止執行時就會遭到刪除。

為元件提供引數時,CreatedStarted 之間的區別非常重要。通常可以多次啟動及停止單一元件執行個體,因此元件管理員必須儲存引數,才能在元件執行時提供這些引數。如果引數是處理此情況,由於並非所有控點都可以複製,因此可能會產生問題。因此,任何不可重複的帳號代碼都會「消耗」元件一次。

通訊協定更新

如「背景」中所述,建立元件與啟動元件並不相同。因此,提供給 CreateChild 的帳號代碼必須是:

  1. 每次啟動元件時都可使用。
  2. 範圍限定為元件的單次執行。

由於並非所有帳號代碼都可以重複執行 (儲存在元件管理員中,後續執行作業都會儲存在元件管理員中),因此 (1) 只有在每次執行時都是從來源代碼擷取新帳號代碼時,才會發生這樣的情況。如要瞭解啟動時未選擇擷取處理方法的原因,請參閱轉送控制代碼。幸好 (2) 是適用於使用情境的可行解決方案。

系統會建立新的資料表 ChildArgs,並將其新增為 Realm/CreateChild 的參數:

protocol Realm {
  /// If args contains numbered_handles, the collection must have a durability
  /// of type `single-run`.
  CreateChild(CollectionRef collection, ChildDecl decl, ChildArgs args)
      -> () error fuchsia.component.Error;
}

resource table ChildArgs {
  /// The numbered handles for the component instance.
  ///
  /// Only PA_FD and PA_USER* handles are valid arguments, and inclusion of any other
  /// handles will result in an error.
  1: vector<fuchsia.process.HandleInfo>:N numbered_handles;
}

此外,fuchsia.component.runner.ComponentStartInfo 資料表將會更新以加入編號控點:

resource table ComponentStartInfo {
  6: vector<fuchsia.process.HandleInfo>:N numbered_handles;
}

執行器會將這些控點提供給元件,如果執行元件不支援為元件提供編號控點,則可關閉這些控點並傳回錯誤。

系列產品耐用性

透過 Realm 通訊協定建立的元件位於集合。集合包含 durability 註解,指出集合中元件的生命週期語意。

系統會加入新的集合 durabilitysingle-run,指出集合中的元件會在建立時立即啟動,並在停止時刪除。ChildArgs.numbered_handles 只能與標示為 single-run 的集合搭配使用。這會將 ChildArgs 中的引數範圍限制為元件一次執行。

collections: [
    {
         name: "playground",
         durability: "single-run",
    }
],

實作

元件管理員會更新為儲存 ChildArgs,直到傳遞至執行元件並處理 single-run 集合語意為止。

回溯相容性

變更在執行者方面具有回溯相容性:執行者不一定要使用提供的編號控點。如果執行元件不支援編號控點,則應關閉控點。

這項變更與 Realm 用戶端無法回溯相容。

該變更與 CML 的回溯相容性:唯一的變更是新增的耐用性列舉。

效能

由於系統會將控制代碼直接提供給元件管理員,因此效能不會受到影響。

安全性考量

這項變更引進了父項將任意編號控點傳遞至子項的方法。這些控點的交換作業會由元件管理員和執行元件進行中介。只有在標示為 single-run 的集合中執行的元件,才能以這種方式接收控點。

測試

CreateChild 的現有測試將會排除,以涵蓋新的引數。

缺點、替代方案和未知

缺點

相較於下列替代方案,建議的解決方案有以下幾個缺點:

  • 這是啟動元件的新方式:元件的生命週期不會受到能力繫結的影響。
  • 提供的控點不透明,對於元件架構的靜態 CML 分析。
  • 由於接收控點的元件會在停止時遭到刪除,因此其永久儲存空間也會一併抹除。因此,使用永久儲存空間的元件不適合這項功能。

轉送號碼控制代碼做為功能

元件架構可以明確執行轉送編號控點。

有幾種不同的方式可以達到這個目的,但它們都有下列的「形狀」。

推出會由編號控點來源實作的通訊協定:

protocol HandleProvider {
    Get(string handle_name) -> (fuchsia.process.HandleInfo handle);
}

這個通訊協定隨後會轉換為能力:

capabilities: [
    {
        handle_provider: "stdin",
        path: "/svc/fuchsia.component.HandleProvider",
    },
],
expose: [
    {
        handle_provider: "stdin",
        from: "self",
    },
],

然後,系統便能透過 CML 轉送到目的地,就像其他功能一樣。

好處

  • 經過演化後,就能支援更多類型的帳號代碼資訊。
  • 讓元件架構明確看到控制代碼轉送。

缺點

系統擷取控點後才能啟動元件。即使元件管理工具中的快取控點可以縮減效能影響,動力用途也不會因此受益,因為元件每次執行時使用的控點並不相同。在建議的設計中,主機程式碼可能會「啟動後忘記」啟動元件的要求,並以呼叫成功的方式繼續執行。在此替代方式中,主機程式碼必須坐下來並旋轉,等待相關聯的帳號代碼回應恢復。

有時無法透過靜態轉送的方式與帳號代碼供應商聯繫。在激勵用途中,處理程式提供者位於主體機器上,並透過 Overnet 連線至 Fuuchsia 裝置。如要解決這個問題,請將轉送「盡可能」轉送到「邊緣」元件,然後讓「邊緣」元件透過臨時機制擷取控點,再將控點傳回元件架構。對於想要使用這項功能的開發人員而言,這會帶來額外的負擔。

控制代碼供應器無法區分處理要求與特定能力路徑。具體來說,請思考激勵用途:

  1. 使用者在不同終端機中從主機啟動兩個 Linux 元件。
  2. 這些元件會在集合中執行個體化。
  3. 帳號代碼供應者會收到針對同一個帳號代碼的兩項要求。

此時,控制代碼供應器無法得知哪個元件與哪個處理要求相關聯。您可以導入額外的用戶端識別機制來解決這個問題,但比建議的設計更複雜。

這項解決方案的承諾使用規模較大,而且比提議的設計更複雜。也就是說,提議的設計不會防止日後的明確轉送編號控點或衝突。

起始孩童

這個替代做法建議將編號控點新增為 RealmStartChild 呼叫中的引數。這與提議的設計類似,但撤銷了在元件繫結至元件提供的能力 (會啟動元件) 與發出 StartChild 呼叫之間的競爭情況。具體來說,只有在 StartChild 呼叫贏得競賽時,元件才會收到編號處理方式,因為如果元件已開始執行時,我們不知道該如何傳送帳號代碼。

啟動條件通訊協定

傳遞編號控點可透過 Starter 通訊協定完成。啟動條件通訊協定可用來啟動元件、由元件管理員代表元件實作,而且可以像其他通訊協定一樣轉送 (也就是說,元件可以透過非其父項的元件啟動)。

這個通訊協定可以像任何其他通訊協定一樣轉送,因此用戶端能使用這個通訊協定來啟動位於元件階層中任意位置的元件。

啟動條件通訊協定中的方法可接受以編號控點做為引數的方法:

[Discoverable]
protocol StarterWithArgs {
    /// Start the component that is bound to this protocol.
    /// If the component is already running, the call returns an error.
    Start(StartArgs start_args) -> () error fuchsia.component.Error;
};

這個提案與 StartChild 非常類似,以這種方式公開的通訊協定有利於稽核和加入許可清單,但也會在呼叫 Start 和繫結至元件公開的任何其他能力之間產生競爭。此外,用戶端並非一定是父項,因此不一定能重新啟動元件來提供引數,所以排序問題變得更加嚴重。如要解決這個問題,請在通訊協定中新增停止方法。

用戶端也必須協調啟動條件通訊協定和領域通訊協定之間的子項管理作業,而不是只透過領域通訊協定管理子項。