RFC-0222:隆重推出 Fuchsia 控制器

RFC-0222:導入 Fuchsia 控制器
狀態已接受
區域
  • 開發人員
  • FIDL
  • 測試
說明

新增 Fuchsia 控制器,用於主機端指令碼編寫和 Fuchsia 裝置測試

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2022-11-17
審查日期 (年-月-日)2023-06-13

摘要

Future Fuchsia Experience (FFX) 工具提供從主機與 Fuchsia 裝置通訊的方法。FFX這會使用 Fuchsia 介面定義語言 (FIDL),呼叫各種服務以進行開發和測試。為工具新增更多功能,FFX 支援子工具,這些是獨立的二進位檔,可擴充 FFX 的指令列介面和功能。這項工具完全以 Rust 編寫。

如要在 Fuchsia 裝置上存取 FIDL 通訊協定,使用者可以為 FFX 編寫外掛程式、使用 Fuchsia 的指令碼層 (SL4F),或在系統上編寫元件。

這些選項都不適合輕量型實驗、快速疊代或彈性調整。FFX 外掛程式需要以 Rust 編寫工具,並進行編譯。SL4F 不僅不受支援,還會依附於不安全的傳輸方式,且與其介接時,您必須為計畫呼叫的每個 FIDL 介面,以 Rust 撰寫外觀。

這些方法都無法讓使用者遵守「自備執行階段」原則。

這項 RFC 提議透過 FFX 內現有的程式庫 (稱為 Fuchsia 控制器),提供額外的裝置存取方法。包括:

  • 穩定的 ABI,可透過 FIDL 控制代碼模擬與 Fuchsia 裝置互動,不必變更 FFX 本身。
  • 至少支援一種熱門指令碼語言,並利用上述穩定 ABI (目前選擇 Python)。
  • 以該指令碼語言編寫的高階程式庫,專為撰寫重要測試用途而最佳化。

提振精神

目前沒有支援的機制,可將主機裝置的互動指令碼傳送至 Fuchsia 裝置 (透過 SDK、樹狀結構內或其他方式)。

如要使用 FFX 與 Fuchsia 裝置互動,使用者必須提供服務定義,以便編譯至工具中。如果樹狀結構外部定義了服務,使用者就無法存取該服務。如果已定義服務,使用者必須編寫 FFX 外掛程式並進行編譯。

使用者可透過 Fuchsia 控制器與 Fuchsia 裝置互動,快速進行高度疊代,並輕鬆自動化。支援穩定的 ABI 可讓使用者選擇是否要自行導入執行階段,因為幾乎所有熱門程式設計語言都支援使用 C ABI 進行擴充。

利害關係人

協助人員:

未定

審查者:

jeremymanson@google.com (Tools) mgnb@google.com (FFX) ianloic@google.com (FIDL) chok@google.com (lacewing) jzgriffin@google.com (SL4F)

已諮詢:

EngProd 團隊 FFX 團隊 FIDL 團隊

社交:

Fuchsia 控制器是 Tools、FFX、FIDL 和 EngProd 團隊經過數月討論的產品。其他團隊包括元件架構和測試架構團隊。作者也已撰寫並展示概念驗證和高階試用版,當中採用實作章節所述的技術。

設計

總覽

Fuchsia 控制器由三部分組成:

  • FFX 用戶端程式庫。
  • 特定語言的擴充程式庫。
  • 使用擴充功能程式庫的較高層級一級程式庫。

這些工具都會與 FFX 搭配運作,以便處理與 Fuchsia 裝置的連線。

Alt_text:Fuchsia 控制器圖表。Fuchsia 控制器堆疊從較高層級的 Python 開始,饋入主要 Python 繫結,然後饋入 FFX 繫結。FIDL 會從這裡傳遞至 FFX 精靈監控的 Unix 網域通訊端。FFX 精靈會使用通道式 FIDL 連線與 Fuchsia 裝置互動。這個範例概述一般互動,也就是取得 Remote Control Service 公開的元件 Proxy

繼續之前,請先瞭解一些必要事項。

FFX 背景

FFX 是主機端工具,(撰寫本文時) 使用「Daemon」,也就是在背景執行的自身分叉副本,在網路上探索到 Fuchsia 裝置時,會透過 SSH 主動連線至這些裝置。發現裝置的方法有很多種,但不在本文的討論範圍內。

FFX Daemon 可讓 FFX 工具使用者在主機和 Fuchsia 裝置之間開啟模擬 FIDL 管道。訊息會從 FFX 用戶端呼叫,透過 Daemon 傳送至 Fuchsia 裝置。

FFX 幾乎完全以 Rust 編寫,此外,用於寫入及讀取主機端模擬 FIDL 通道的程式庫,也是以 Rust 撰寫。

總而言之,使用者可以透過 FIDL,使用與 FFX 實作緊密結合的 Rust 撰寫外掛程式,透過 FFX 與 Fuchsia 裝置互動。

定義條款

以下各節會用到一些定義:

  • 「隔離」是指以某種方式使用 FFX,讓 FFX 精靈可能擁有獨立執行個體,不使用通用通訊端位置或任何通用 FFX 設定值。FFX 精靈的執行個體不會與 Fuchsia 裝置通訊隔離 (除非明確叫用)。
  • 「Daemon Protocol」是指 FFX Daemon 處理的主機端 FIDL 通訊協定。包括提供套件、檢查網路上的 Fuchsia 裝置,以及 Fuchsia 裝置通訊埠轉送。這個精靈本身可以視為類似於元件,會公開多個精靈通訊協定。
  • 提及管道、控制代碼和插槽的「zircon」時,這些都會透過 overnet 在主機端模擬。不過,這些物件日後可能會在 Fuchsia 裝置上做為實際的 Zircon 物件使用。

FFX 用戶端程式庫

FFX 用戶端程式庫會透過 C ABI 公開函式,支援下列功能:

  • 建立、讀取、寫入及關閉 Zircon 管道。
  • 建立、讀取、寫入及關閉 Zircon Socket。
  • 發出鋯石控制代碼信號 (主要用於事件配對)。
  • 將鋯石通道連線至 Fuchsia 裝置上的元件。
  • 將 Zircon 管道連線至 FFX Daemon 通訊協定。

此外,還會支援其他功能,例如:

  • 建立 FFX Daemon 的獨立執行個體。
  • 宣告 FFX 設定鍵/值組合。

特定語言的擴充功能

這項作業涉及 FFX 用戶端程式庫頂端的簡單抽象化,以共用程式庫的形式實作,然後用於一流的指令碼程式庫。

實作

如先前所述,這會涉及建立兩個共用程式庫。

  • 與語言無關的「FFX 用戶端」程式庫,可公開與 FFX 通訊的函式,以及 Zircon 控制代碼。
  • 語言繫結 (本例為 Python) 共用程式庫。

此外,還會有 Python 繫結,方便使用 FIDL。

實作作業不涉及 Fuchsia 來源樹狀結構中未包含的任何第三方依附元件。我們預期可使用 FFX 用戶端程式庫實作其他語言的支援功能,我們可能會支援這些語言 (且可能需要額外的第三方依附元件作業),但這不在本 RFC 的範圍內。

將 Python 連同 SDK 一併發布是另一個主題,不在本文討論範圍內,且可能封裝在專屬的 RFC 中。

FFX 用戶端程式庫

本節中的 C 定義會放在標頭檔案中,並隨附於 Fuchsia SDK。由於 C 中缺少命名空間,這些函式名稱會相當冗長。函式名稱也不一定會是最終名稱。

ABI 的模式應確保大多數函式會使用輸出參數,為呼叫端傳回結構,而傳回值則為空白或錯誤。

如果可以,系統會使用 zx_status_tzx_handle_t 等已建立的型別,與 Zircon 程式碼集等現有 C 程式庫保持一致。

讀取頻道的函式範例如下 (這並非最終實作或文件來源):

extern zx_status_t ffx_channel_read(void* ctx,
                                    zx_handle_t handle,
                                    void* buf,
                                    uint32_t buf_len,
                                    zx_handle_t* handles,
                                    uint32_t handles_len
                                    uint32_t* actual_bytes_count,
                                    uint32_t* actual_handles_count);

ctx 值可以指向 Rust 物件,其中包含現有 FFX 環境的相關資訊 (執行目錄、SDK 位置、設定值,以及我們通訊的 Fuchsia 裝置)。

這與現有的 zx_channel_read 類似,只是省略了選項參數。ABI 會明確寫入標頭,而非匯出與 Zircon 系統呼叫相同的符號,因此可清楚瞭解支援和不支援的功能 (因為這段程式碼一開始可能只會為主機編寫,而非 Fuchsia 裝置,因此可能會有一些特殊注意事項)。

以下函式是取得控制代碼的範例,可用於透過遠端控制 FIDL 定義,連線至 Fuchsia 裝置上的大多數元件。

extern zx_status_t ffx_connect_proxy(void* ctx, const char* endpoint_path,
                                     zx_handle_t* out);

這會將 FIDL 管道傳回給有問題的通訊協定。endpoint_path 應包含必要資訊,以便透過元件架構直接連線至裝置上的特定 FIDL 通訊協定 (撰寫本文時,格式為 "$moniker:expose:$protocol")。

支援插座/管道讀取和寫入作業,以及事件信號傳輸,因此可以複製 FFX 和 Overnet 目前支援的所有 FIDL 功能,但要使用 Python。

Python 語言繫結

Python 語言繫結會定義使用已建立的 create*/close*/destroy* 呼叫的物件,這些物件以 C++ 編寫,並提供 FFX 用戶端程式庫的精簡包裝函式。此外,系統也會使用 ffx_error_str() 匯出錯誤類型。

如需這個 (略有不同) 實作方式的範例,請參閱 Fuchsia 控制器原型

更高層級的繫結

如要實際使用 FIDL 通訊協定,請使用較高層級的程式庫。這項工具會使用 importlib 連結至 FIDL 中間表示法 (IR),並從分散式 .pyz (開發人員的 PYTHONPATH 中提供) 或手動提供的目錄匯入任何可用的 IR。這些掛鉤會建立在執行階段與 FIDL 互動的類別,類似於 C++ 或 Rust 執行編譯階段繫結時的情況。

範例如下:

import fidl.fuchsia_developer_ffx
from fuchsia_controller_py import Context

def main(ctx: Context):
  h = ctx.connect_daemon_protocol(fidl.fuchsia_developer_ffx.Echo.Marker)
  proxy = fidl.fuchsia_developer_ffx.Echo.Client(h)
  print(proxy.echo_string(value = 'foobar'))

if __name__ == '__main__':
  ctx = Context(None)
  main(ctx)

fidl. 匯入的內容會由程式庫掛鉤擷取,以便在現有的 FIDL IR 命名空間中搜尋符合 fuchsia.developer.ffx 的項目,並根據其中定義的結構體和通訊協定產生類別。

FIDL 線路格式編碼/解碼

在第一階段,實際編碼和解碼作業可能會使用 fidl_codec 程式庫完成,之後則完全以 Python 實作。

fidl_codec:包含根據 FIDL IR 定義讀取/寫入 FIDL 線路格式的程式碼,以及實用工具 (例如可用於從 FIDL 訊息建構物件的值訪客)。這個檔案用於 fidlcat 工具。使用 IR 產生的 Python 將 FIDL 結構體編碼為連線格式時,可以採用訪客模式,建立緩衝區,然後寫入 FIDL 控制代碼。

效能

FFX 用戶端程式庫 ABI

跨越 FFX 用戶端 ABI 邊界時,會遇到最多的效能負擔,也就是 Unix 網域插座讀取/寫入,以及與 Fuchsia 裝置之間的網路連線。

此外,FFX 用戶端程式庫會複製 FIDL 讀取作業兩次,一次是跨越 Rust ABI 邊界,另一次是將資料從 C++ 程式碼載入 Python 物件。如果日後成為問題,可以再處理。

一般用途會涉及 FIDL 的低負擔使用,也就是呼叫具有結構體的簡單函式。撰寫本文時,主機不支援更複雜的 FIDL (例如 VMO),因此不應成為效能問題的來源。

人體工學

FFX 用戶端 ABI

FFX 用戶端二進位檔的實作設定檔盡可能小,可避免在其他語言中實作繫結時產生過多樣板。

較高層級的 Python 繫結

較高層級的 Python 繫結會使用 FIDL IR 在執行階段建立類別繫結。這樣一來,您不僅能以與 Rust、Dart 或 C++ 等其他 FIDL 語言繫結一致的方式使用 Python 程式碼,還能在執行階段實驗 FIDL 通訊協定,進而實現更具疊代性的開發作業。

如果 FIDL 服務是在樹狀結構外部定義,也可以使用 SDK 存取該服務 (先產生 FIDL IR,然後匯入 Fuchsia 控制器)。

安全性考量

本 RFC 的主要安全性影響與 FFX 本身有關,不在本文的討論範圍內。

測試

FIDL 線路格式

FIDL 團隊有一套測試 (GIDL 和 DynSuite),可用來測試編碼和解碼。無論是使用 fidl_codec (因為尚未針對這些套件進行測試),或是 Python 明確寫入/讀取連線格式,這項做法都適用。

FFX 用戶端程式庫和 Python C 繫結

這些函式相當輕量,因此除了驗證是否符合特定例外狀況條件外,單元測試不需要做太多事。如要測試 FFX 用戶端程式庫的 ffx_error_str(),可以使用明確定義的錯誤,避免依賴 FFX 內的特定字串。

這些程式碼片段的大部分測試都會在整合和/或端對端測試中進行。簡單的範例是使用 Echo 通訊協定,針對不依附 Fuchsia 裝置的測試,練習每一段程式碼。如要針對實際的 Fuchsia 裝置進行測試,可以取得遠端控制服務 Proxy 的例項,並呼叫 IdentifyHost 函式。

說明文件

Fuchsia 控制器的說明文件會保留在 fuchsia.dev 網站上。

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

缺點

一流的 Python 支援

FFX 用戶端程式庫的目標是支援其他語言的繫結,但 Python 不適合用於較大型的正式版專案。Python 雖然可快速編寫程式碼,並迅速讓程式運作,但維護和可讀性較差。

替代方案

為什麼不使用 Golang、Java、Rust 或 Dart?

在與端對端測試團隊、面向產品的開發人員和連線團隊進行初步討論時,我們發現大家偏好使用提供互動性和易用性的指令碼語言。這表示 Python 是第一個具有繫結的語言。

不明

FIDL IR

透過 SDK 將 FIDL IR 傳送給樹狀結構外的使用者時,由於必須產生 FIDL IR,因此很難確保正確性。因此,您可能需要為 Bazel 新增額外的建構規則,簡化依附元件。

SDK 中的 FFX

上述使用 FFX 精靈通訊協定的範例無法在樹狀結構外運作,因為 FFX FIDL 通訊協定尚未登陸 SDK。API 審查已完成部分程序,但仍需完成。FFX 仍有廣泛的 FIDL 介面需要涵蓋,且一般來說也是不斷變動的目標,因此很難評估可能需要多久時間。

FIDL Codec

最終結果可能完全不需要使用 fidl_codec。 使用這項功能也需要在 Python 共用程式庫中新增更多介面,因此必須謹慎逐步淘汰。

考慮的替代方案包括:

  • 產生的程式碼 (例如,在 C++ 和 Rust 中處理這項作業的方式)。
  • 以 Python 實作的 fidl_codec 類似項目。

既有技術和參考資料