RFC-0108:元件繫結通訊協定

RFC-0108:元件繫結器通訊協定
狀態已接受
區域
  • 元件架構
說明

允許元件啟動其他元件的架構提供的通訊協定。

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

摘要

這個 RFC 引進了全新的架構提供的通訊協定 fuchsia.component.Binder,該通訊協定將允許元件啟動其他公開此架構的元件。

提振精神

fuchsia.sys2.Realm 通訊協定是架構提供的 API,可讓元件在執行階段操控其「運作範圍」。透過這個通訊協定,元件可建立子元件,並繫結至其公開功能,而這些元件是由執行階段決策所驅動,而非只有靜態宣告。叫用 BindChild 方法即可繫結至子項的功能。這個方法會在成功執行後啟動,提供的子元件 (如果尚未啟動),並開啟連線,連線至由子項元件公開目錄支援的 fuchsia.io.Directory 通訊協定執行個體。子項的公開目錄是一個目錄,包含子項在資訊清單中公開的所有功能。

此方法有兩個缺點。首先,由於它會執行兩個用途,因此目前超載。這可讓元件繫結至子項元件的功能,「同時」也允許元件啟動子項元件。其次,它與元件架構的能力模型無關。大多數元件會先啟動,以滿足能力的要求。以不同方式共享元件,元件會繫結至功能,而非提供這些功能的元件。這是封裝的重要功能,因為如果元件與功能互動 (而非直接元件),則實作元件可在不影響用戶端的情況下替換。

因此,BindChild 會遭到淘汰。系統將在 fuchsia.sys2.Realm 通訊協定中加入替代方法 OpenExposedDir,讓父項可繫結至其子項的功能。這個方法和 BindChild 之間的明顯差異在於,在新方法中,只有在父項與其中一個功能繫結時,才會啟動子項。語意中的這項變更更符合元件架構的設計原則。這項遷移作業已開始,可透過 fxr/531142 追蹤。

不過,將 BindChild 替換為 OpenExposedDir 就已足夠。考量到數量和重要性的層面,許多用途都仰賴 BindChild 的自動啟動行為。在這些情況下,父項元件不會繫結至子項公開的任何功能,或者父項啟動的元件不會公開任何功能。在特定整合測試、驅動程式和工作階段元素中,可以觀察到這個模式。針對這個用途,元件架構團隊必須提供客戶啟動元件的解決方案。

設計

元件架構將引進新的架構提供的通訊協定 fuchsia.component.Binder。這項能力可讓作者宣告元件為直接可繫結。想要啟動其他元件的元件,如同其他能力一樣使用通訊協定。元件管理員位於這個通訊協定的伺服器端,建立連線後,元件管理員就會啟動提供這項能力的元件。只要在連線的用戶端上觀察 ZX_CHANNEL_PEER_CLOSED,即可擷取目標元件的終止情形。

library fuchsia.component;

/// A framework-provided protocol that allows components that use it to start the
/// component that exposes it.
///
/// Note: The component doesn't need to serve this protocol, it is implemented
/// by the framework.
[Discoverable]
protocol Binder {};

元件作者只需要公開通訊協定:

{
    expose: [
        {
            protocol: "fuchsia.component.Binder",
            from: "framework", // Note that this is implemented by the framework on the component's behalf.
        },
    ],
}

會啟動這些元件的元件將繫結至已公開的能力:

{
    use: [
        {
            protocol: "fuchsia.component.Binder",
            from: "parent",
        },
    ],
}

本提案的主要好處是,直接開始可成為元件 API 的一部分。可直接啟動的元件 (尤其是未公開功能的元件) 可在資訊清單檔案中稽核。此外,啟動另一個元件並不限於啟動直接子項的父項元件。而是像其他功能一樣,轉送 fuchsia.component.Binder 通訊協定。

實作

實作這項設計不需要許多變更。引進這個通訊協定應進行一或兩項 Gerrit 變更。

這項功能發布後,系統會根據用途,將 BindChild 的使用者遷移至使用 OpenExposedDir 或建議的 fuchsia.component.Binder 通訊協定。

遷移完 BindChild 的所有用途後,我們就會從 fuchsia.sys2.Realm 通訊協定中移除此方法。

效能

這個通訊協定會加入效能迴歸現象。目前,父項元件可能會呼叫 BindChild 來啟動子項元件。本提案之後,父項元件必須呼叫 OpenExposedDir,然後開啟 fuchsia.component.Bind 才能達到相同效果。不過,由於這些事件很少發生,因此不應採用這種迴歸方式。

安全性考量

這個通訊協定不應提出安全疑慮。這個通訊協定將可轉送,因此系統會檢查資訊清單檔案,找出啟動哪些其他元件可以稽核的元件。

隱私權注意事項

這個通訊協定不應引發隱私權疑慮,因為這只是允許機制啟動其他元件。

測試

這項功能將使用單元和整合測試進行測試。

此外,這項功能可讓元件作者更輕鬆地測試其他元件的副作用。舉例來說,在「診斷」中,多項整合測試會宣告檢查 VMO 的狀態。在這類情況下,驅動程式庫元件會啟動用於操控 VMO 的木偶元件,然後驅動程式庫元件會宣告 VMO 的內容。你提議的功能可讓驅動程式庫元件在無需不必要的 FIDL 通訊協定的情況下啟動木偶元件。

說明文件

FIDL API 將會記錄,我們會在元件架構運作文件中更詳細地說明。

缺點、替代方案和未知

單一執行元件

近期已接受相關的 RFC,允許元件啟動子項元件。該提案將可滿足部分由 BindChild 填入的用途。值得注意的是,透過提議的機制啟動的元件必須存放在集合中,而 fuchsia.component.Binder 適用於所有元件。

fuchsia.sys2.Realm/StartChild

另一個選項是新增啟動子項的方法,藉此擴充 fuchsia.sys2.Realm 通訊協定。這個方法 (StartChild) 會採用一個參數 ChildRef,該參數將做為靜態宣告子項或動態建立的方法 (集合) 的參照。這與 BindChild 接收的參數相同,且 OpenExposedDir 會採用該參數。此方法會傳回 Zircon 事件物件,並在子項元件停止時發出訊號。子項元件的生命週期會與父項元件相連結。如果父項元件停止,則子項也會停止。

library fuchsia.sys2;

[Discoverable]
protocol Realm {
    /// Start child component instance, if it isn't already. Returns a Zircon
    /// Event object that clients can use to observe when the child component stops.
    /// When the child component stops, Component Manager will set this object's
    /// ZX_EVENT_SIGNALED bit.
    StartChild(ChildRef child) -> (zx.handle:EVENT event) error fuchsia.component.Error;
};

最後,由於這類替代方案允許任何元件直接啟動,因此並不理想。除非元件宣告,否則不可直接啟動,而不是從能力繫結啟動的副作用。由於 StartChild 會採用 ChildRef,因此系統會允許啟動「任何」元件。使用集合時,開始的元件只能在執行階段觀察。

繫結方法

最後,與其採用上述空白的 Binder 通訊協定,您還可使用方法觸發啟動作業。

library fuchsia.component;

[Discoverable]
protocol Binder {
    /// Start the associated component instance.
    /// This method is reentrant and safe for concurrency.
    /// Calling `Bind` on an already-binded component is a no-op.
    /// When the child component stops, the `ZX_EVENTPAIR_PEER_CLOSED` signal
    /// will be asserted on the `event` object.
    Bind(zx.handle:EVENTPAIR event) -> () error fuchsia.component.Error;
};

雖然這個選項可讓啟動觸發條件更明確 (例如,做為方法呼叫的回應,而非與通訊協定連線),但這個選項會為用戶端額外造成額外障礙,因此可行性較低。您必須先設定事件組合物件,才能呼叫方法,而不取得任何新增功能。

繫結機制

元件架構也可以引進新的能力,由建議的 fuchsia.component.Binder 通訊協定支援。

// a.cml
{
    capabilities: [
        {
            binder: "a",
        },
    ],
    expose: [
        {
            binder: "a",
            from: "self",
        },
    ],
}

新能力提供許多好處,例如:

  1. 不同的類型有助於區分啟動功能。例如,我們可以宣傳與通訊協定不同的繫結器功能的命名慣例。
  2. 與其他功能一致,亦即會轉譯為繫結 (連線 == 繫結)
  3. 這樣您就不會忘記 framework 關鍵字 (儘管我們可以加入 cmc 檢查)。

不過,儘管導入新能力的好處在於,新功能會造成概念上的負擔,例如讓開發人員學習和理解的新事物,並讓 CF 能夠支援。架構提供的通訊協定更簡單且更容易概念。