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

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

新增 Fuchsia Controller,用於主機端指令碼和測試 Fuchsia 裝置

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

摘要

Future Fuchsia Experience 工具 FFX 可讓您透過主機機器與 Fuchsia 裝置通訊。這會使用 Fuchsia Interface Definition Language 的 FIDL 呼叫各種服務,以便進行開發和測試。為了在工具中新增更多功能,FFX 支援子工具,這類工具是用於擴充 FFX 指令列介面和功能的獨立二進位檔。這項工具完全以 Rust 編寫。

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

這些方法都不適合用於輕量實驗、快速疊代或彈性。FFX 外掛程式需要 Rust 的寫入工具並進行編譯。SL4F 不僅不支援,也需要使用不安全的傳輸,而且在 Rust 中,也必須針對每個您打算呼叫的 FIDL 介面編寫一個門面,才能與 SL4F 互動。

上述方法均無法讓使用者遵守「自備執行階段」原則。

此 RFC 提議透過 FFX (稱為 Fuchsia Controller) 內的現有程式庫,提供另一種存取裝置的方法。其中包括:

  • 穩定 ABI,可透過 FIDL 控制方式與 Fuchsia 裝置互動,而無需變更 FFX 本身。
  • 針對至少一種採用穩定 ABI 的熱門指令碼語言提供第一級支援 (目前選擇是 Python)。
  • 上述指令碼語言的較高層級程式庫,已針對編寫重要測試用途進行最佳化。

提振精神

目前還沒有支援的機制可以編寫從主機裝置到 Fuchsia 裝置的互動指令碼 (透過 SDK、樹狀結構內或其他方式)。

如果使用者想要使用 FFX 與 Fuchsia 裝置互動,就必須具有可編譯至工具的服務定義。如果服務是在樹狀結構外定義的,使用者無法存取該服務。如果服務已定義,則使用者必須編寫 FFX 外掛程式並進行編譯。

Fuchsia Controller 可讓使用者以快速、高度疊代且輕鬆地自動與 Fuchsia 裝置互動。支援穩定的 ABI 將允許使用者自行選擇實作執行階段,因為使用 C ABI 即可擴充幾乎所有常見的程式設計語言。

相關人員

講師:

未定

審查者:

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

顧問:

EngProd 團隊 FFX 團隊 FIDL 團隊

社群媒體化:

Fuchsia Controller 是由 Tools、FFX、FIDL 和 EngProd 團隊長達數個月的對話產品。其他團隊包括元件架構和測試架構團隊作者也運用實作章節所述的技巧編寫並示範概念驗證和高階示範。

設計

總覽

Fuchsia Controller 由三個部分組成:

  • FFX 用戶端程式庫。
  • 語言專屬的擴充功能程式庫。
  • 使用擴充功能程式庫的較高層級第一類別程式庫。

這些所有項目都會與 FFX 搭配使用,以處理連線至 Fuchsia 裝置。

Alt_text: Fuchsia 控制器的圖表。Fuchsia Controller 堆疊從較高層級 Python 開始,並會饋送至主要 Python 繫結,然後轉換成 FFX 繫結。在這裡的 FIDL 會傳遞到 FFX Daemon 監控的 Unix 網域通訊端。從這裡的 FFX Daemon 使用通道 FIDL 與 Fuchsia 裝置進行互動。這個範例概述一般互動方式,也就是取得 Proxy 存取遠端控制服務公開的元件

你必須先完成一些前置作業,再繼續操作。

FFX 背景

FFX 是一項主機端工具 (在寫入時) 使用「Daemon」,在此情況下,該工具是在背景中執行的自身分支副本,會在網路上發現這些裝置時,透過 SSH 主動連線至 Fuchsia 裝置。探索裝置的方法有很多種,但實際成效已超出本文件的範圍。

FFX Daemon 可讓 FFX 工具的使用者在主機和 Fuchsia 裝置之間開啟模擬的 FIDL 頻道。訊息會從 FFX 用戶端叫用、Daemon,再轉送至 Fuchsia 裝置。

FFX 幾乎完全是在 Rust 中編寫。此外,用於寫入和讀取主機端模擬 FIDL 管道的程式庫也會在 Rust 中編寫。

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

定義字詞

下列各節提供的定義:

  • 「隔離」是指使用 FFX 的方式,即具有單獨執行的 FFX Daemon 執行個體,而不使用通用通訊端位置或任何常見的 FFX 設定值。除非明確叫用,否則 FFX Daemon 不會與 Fuchsia 裝置進行通訊。
  • 「Daemon 通訊協定」是指 FFX Daemon 處理的主機端 FIDL 通訊協定。從提供套件、到網路上的 Fuchsia 裝置,到 Fuchsia 裝置通訊埠轉送都不同。Daemon 本身可視為類似於公開多個 Daemon 通訊協定的元件。
  • 當管道、帳號代碼和通訊端提及「zircon」時,系統會透過內部網路模擬主機端。但日後,這些物件可能會做為實際的 Zircon 物件使用在 Fuchsia 裝置上。

FFX 用戶端程式庫

FFX 用戶端程式庫會透過 C ABI 公開支援下列項目:

  • 建立、讀取、寫入和關閉 Zircon 頻道。
  • 建立、讀取、寫入及關閉 zircon 通訊端。
  • 訊號 控點 (主要用於事件組合)。
  • 將 Zircon 頻道連結至 Fuchsia 裝置上的元件。
  • 將 Zircon 頻道連結至 FFX Daemon 通訊協定。

同時還可支援其他功能,例如:

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

語言專屬的擴充功能

這牽涉到 FFX 用戶端程式庫上方的簡單抽象化機制,以共用程式庫的形式實作,方便您在一流的指令碼程式庫中使用。

實作

如前所述,這項操作將建立兩個共用程式庫。

  • 各語言通用的「FFX 用戶端」程式庫會公開與 FFX 通訊的函式及 zircon 控點。
  • 語言繫結 (本例中為 Python) 共用資料庫。

另外,我們也會針對人體工學 FIDL 提供 Python 繫結。

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

與 SDK 一起發布 Python 是另一個主題,不在本文的討論範圍內,可能會封裝在其 RFC 中。

FFX 用戶端程式庫

本節中的 C 定義會放在 Fuchsia SDK 一併提供的標頭檔案中。由於 C 中缺少命名空間,因此這些函式名稱將較為冗長。函式名稱也不一定要是最終名稱。

ABI 的模式是為了讓大多數函式使用輸出參數傳回呼叫端的結構,回傳值會是無效或錯誤。

可能的類型 (例如 zx_status_tzx_handle_t) 將用於與現有 C 程式庫 (例如 Zircon 程式碼集) 保持一致。

讀取管道的函式範例可能如下所示 (這不是最終實作或說明文件來源):

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 值可以指向包含現有 FFX 環境相關資訊 (執行目錄、SDK 位置、設定值,以及與我們通訊的 Fuchsia 裝置) 相關資訊的 Rust 物件。

這類似於現有 zx_channel_read,只省略選項參數。請勿匯出與 Zircon 系統呼叫相同的符號,而是在標頭中明確寫入 ABI,以便清楚瞭解什麼是功能,以及不支援的功能 (因為程式碼一開始只會為主機機器編寫,而不是針對 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 目前支援 (但在 Python 中) 的所有 FIDL 功能。

Python 語言繫結

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

如需此 (稍有不同) 實作的範例,請參閱這個網頁的 Fuchsia Controller 原型設計。

更高層級繫結

實際使用 FIDL 通訊協定時,將可使用更高層級的程式庫。 這會使用 importlib 掛接到 FIDL 中繼表示法 (IR),匯入分散式 .pyz 中可用的任何 IR,可在開發人員的 PYTHONPATH 或手動提供的目錄中找到。這些掛鉤會在執行階段,建立與 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 工具。您可以使用訪客模式,將 FIDL 結構編碼為來自 IR 產生的 Python 的傳輸格式,藉此建立可以寫入 FIDL 控制代碼的緩衝區。

效能

FFX 用戶端程式庫 ABI

當跨越 FFX 用戶端 ABI 邊界 (亦即 Unix 網域通訊端讀取/寫入及透過 Fuchsia 裝置進行讀取/寫入及網路) 時,就會發生效能負擔。

除此之外,FFX 用戶端程式庫會複製 FIDL 讀取正好兩次,一次會跨越 Rust ABI 邊界,接著再從 C++ 程式碼將資料載入 Python 物件一次。日後如果這個問題變成問題,您可以解決。

在一般用途中,我們會使用 FIDL 的成本較低,也就是呼叫具有結構體的簡單函式。目前編寫較複雜 FIDL (例如 VMO) 時,主機不支援寫入,因此不應成為效能的疑慮來源。

人體工學

FFX 用戶端 ABI

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

更高層級的 Python 繫結

較高層級的 Python 繫結將使用 FIDL IR 在執行階段建立類別繫結。這不僅可讓 Python 程式碼的使用方式與其他 FIDL 語言繫結 (例如 Rust、Dart 或 C++) 完全相同,還能在執行階段測試 FIDL 通訊協定,進而實現更疊代的開發。

如果已在樹狀結構外定義 FIDL 服務,這也表示能透過 SDK 存取服務 (先產生 FIDL IR,然後匯入 Fuchsia Controller)。

安全性考量

這項 RFC 的主要安全性影響與 FFX 本身有關,這不屬於本文件的涵蓋範圍。

測試

FIDL 線路格式

FIDL 團隊有一套可以測試編碼和解碼的測試 (GIDL 和 DynSuite)。這適用於使用 fidl_codec 的情況 (因為該套件尚未針對這些套件進行測試),或者 Python 必須明確從傳輸格式寫入/讀取。

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

這些工作負載夠輕量,除了驗證是否符合特定例外條件之外,還有很多單元測試要完成的單元測試。如要測試 FFX 用戶端程式庫的 ffx_error_str(),您可以使用定義明確的錯誤,防止依賴 FFX 內部的特定字串。

這些程式碼片段的大部分測試都會進行整合和/或端對端測試。執行每段程式碼的簡單範例,是使用 Echo 通訊協定進行非 Fuchsia 裝置獨立測試。針對實際 Fuchsia 裝置的測試,使用者可以取得遠端控制服務 Proxy 的執行個體,並呼叫 IdentifyHost 函式。

說明文件

Fuchsia Controller 的說明文件會保存在 fuchsia.dev 網站上。

缺點、替代方案和未知

缺點

第一級 Python 支援

雖然 FFX 用戶端程式庫旨在支援其他語言的繫結,但 Python 並不適用於大型的實作專案。可以說,Python 可以快速編寫程式碼,並讓工作快速運作,但代價是維護和可讀性降低。

替代選項

何不使用 Golang、Java、Rust 或 Dart?

在我們與 e2e 測試團隊、面向產品開發人員以及連線團隊的初始討論中,強烈的偏好是提供能互動且易於使用的指令碼語言。這會讓第一個語言指向 Python,以便建立第一個語言的繫結。

未知

Fitbit

使用 SDK 將 FIDL IR 傳送至樹狀結構外的使用者並不容易,因為必須產生此項目。因此,您可能需要為 Bazel 新增額外的建構規則,以簡化依附元件。

在 SDK 中使用 FFX

以上使用 FFX Daemon 通訊協定的範例將無法在樹狀結構中運作,因為 FFX FIDL 通訊協定尚未傳送至 SDK。API 審查作業雖然已完成,但仍需完成。由於 FFX 仍然有廣泛的 FIDL 途徑要涵蓋,且通常也是動態目標,因此很難評估這可能需要多久時間。

FIDL 轉碼器

您不一定需要在最終結果中使用 fidl_codec。使用此方法也會在 Python 共用資料庫中增加更多介面,而這之後需要仔細停用。

建議替代方案如下:

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

先前的圖片和參考資料