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

RFC-0101:具有編號句柄的動態元件
狀態已接受
區域
  • 元件架構
說明

提供一種方法,可將編號句柄傳遞至動態元件。

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

摘要

本文件建議在 fuchsia.sys2.Realm/CreateChild 中新增參數。這個參數會包含一組編號為號碼的句柄。當系統要求執行元件時,所建立元件的 runner 會收到這些句柄。提供的句柄僅適用於在集合中以新類型耐用性運作的元件:single-run。在建立時啟動,停止時銷毀的元件,其收集項目的耐用性single-run。這會將提供的處理常式範圍限制為元件的單一執行作業。

提振精神

Starnix 是元件架構 v2 執行器,可在 Fuchsia 上執行 Linux 二進位檔。Starnix 會實作 Linux 系統介面,讓您不必修改就能執行這些二進位檔。

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

設計

背景

元件架構中包含兩種生命週期轉換維度。第一個維度與存在性有關 (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 資料表也會更新,以便包含編號為 1 的句柄:

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 傳遞至執行元件之前儲存 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 連線至 Fuchsia 裝置。解決方法是「盡可能」轉送,然後讓「edge」元件透過專用機制擷取句柄,再將其傳回元件架構。這對想要使用這項功能的開發人員來說,是額外的負擔。

途徑提供者無法區分來自特定能力途徑的途徑要求。具體來說,請考慮以下激勵用途:

  1. 使用者在不同的終端機中,從主機啟動兩個 Linux 元件。
  2. 元件會在集合中例項化。
  3. 句柄供應器會收到兩個相同句柄的要求。

此時,句柄供應器無法得知哪個元件與哪個句柄要求相關聯。您可以透過引入其他機制來識別用戶端,但這比建議的設計複雜得多。

這個解決方案比建議的設計更複雜,也需要投入更多心力。不過,這項設計不會阻止或與日後對編號句柄的明確路由產生衝突。

StartChild

這個替代方案建議在 Realm 上對 StartChild 呼叫新增編號句柄做為引數。這與建議的設計類似,但缺點是,在元件繫結至元件提供的能力 (會啟動元件) 與 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 與繫結至元件公開的任何其他能力之間引入競爭。此外,由於用戶端不一定是父項,因此不一定能重新啟動元件來提供引數,因此排序問題會更加嚴重。您可以透過在通訊協定中新增停止方法來解決這個問題。

用戶端也需要在啟動通訊協定和領域通訊協定之間協調子項管理作業,而非僅透過領域通訊協定管理子項。