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

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

架構提供的通訊協定,可讓元件啟動其他元件。

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

摘要

本 RFC 會介紹新的架構提供的通訊協定 fuchsia.component.Binder,讓元件能夠啟動公開該通訊協定的其他元件。

提振精神

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

這種方法有兩個缺點。首先,由於此類別可滿足兩種用途,因此目前已超載。這可讓元件繫結至子元件的功能,也能讓元件啟動子元件。其次,這與元件架構的能力模型不相容。大多數元件都是為了滿足某項能力的要求而啟動。換句話說,元件會繫結至功能,而非繫結至提供這些功能的元件。這是封裝的重要功能,因為如果元件與功能互動 (而非直接與元件互動),實作元件即可換出,而無須對用戶端進行任何變更。

因此,BindChild 將遭淘汰。OpenExposedDir 替代方法會新增至 fuchsia.sys2.Realm 通訊協定,讓家長能夠綁定子項的功能。這項方法與 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 撰寫說明文件,並在 Component Framework Realm Docs 中進一步說明這項功能。

缺點、替代方案和未知事項

單執行元件

相關的 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;
};

雖然這個選項可讓啟動觸發事件更明確,也就是在回應方法呼叫時,而不是連線至通訊協定,但它不如提案可行,因為它會為用戶端增加額外障礙。必須先設定事件配對物件,才能呼叫方法,且不會取得任何額外功能。

Binder 功能

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

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

新能力可帶來許多好處,例如:

  1. 使用獨特類型有助於區分啟動功能。舉例來說,我們可以針對與通訊協定不同的 Binder 功能,推廣命名慣例。
  2. 與其他功能一致,可轉換為繫結 (連線 == 繫結)
  3. 不會忘記 framework 關鍵字 (雖然我們可以為此新增 cmc 檢查)。

不過,儘管有這些優點,導入新能力也會增加概念性額外負擔,也就是開發人員需要學習和瞭解的新事物,以及 CF 需要支援的新事物。架構提供的通訊協定更直接,也更容易概念化。