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

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

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

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)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。這項能力可讓作者將元件宣告為可直接繫結。如要啟動其他元件,元件會使用該通訊協定,就像使用任何其他能力一樣。Component Manager 會位於這個通訊協定的伺服器端,連線建立後,就會啟動公開這項能力的元件。觀察連線的用戶端,即可擷取目標元件的終止狀態。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,才能達到相同效果。不過,由於這些事件本來就很少發生,因此這項回歸應該不會造成太大影響。

安全性考量

這個通訊協定不會引發安全疑慮。這個通訊協定可供路由,因此檢查資訊清單檔案即可稽核哪些元件啟動了哪些其他元件。

隱私權注意事項

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

測試

這項功能會透過單元測試和整合測試進行測試。

此外,元件作者也能更輕鬆地測試其他元件的副作用。舉例來說,在 Diagnostics 中,多項整合測試會判斷 Inspect VMO 的狀態。在這種情況下,驅動程式庫元件會啟動操控 VMO 的 Puppet 元件,然後驅動程式庫元件會對 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;
};

雖然這個選項可讓啟動觸發條件更明確 (即做為方法呼叫的回應,而非連線至通訊協定),但由於會為用戶端增加額外障礙,因此可行性不如提案。您必須先設定事件配對物件,再呼叫方法,否則不會取得任何新增功能。

裝訂功能

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

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

這項新能力可帶來許多優點,例如:

  1. 明確的類型有助於區分啟動功能。舉例來說,我們可以推廣與通訊協定不同的繫結器功能命名慣例。
  2. 與其他功能的一致性,就翻譯成繫結的內容而言 (連線 == 繫結)
  3. 不會忘記 framework 關鍵字 (雖然我們可以為此新增 cmc 檢查)。

不過,雖然好處多多,但導入新能力會增加概念上的負擔,也就是開發人員必須學習及瞭解的新事物,以及 CF 必須支援的新事物。架構提供的通訊協定更直接,也更容易理解概念。