RFC-0222:引入 Fuchsia Controller | |
---|---|
狀態 | 已接受 |
區域 |
|
說明 | 新增 Fuchsia Controller,以便在主機端進行 Fuchsia 裝置的劇本編寫和測試 |
問題 |
|
Gerrit 變更 | |
作者 | |
審查人員 | |
提交日期 (年-月-日) | 2022-11-17 |
審查日期 (年-月-日) | 2023-06-13 |
摘要
未來 Fuchsia 體驗工具 FFX 提供一種方法,可透過主機與 Fuchsia 裝置通訊。這項工具會使用 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 (工具) 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 裝置的作業。
繼續之前,請先瞭解一些必要事項。
FFX 的背景
FFX 是主機端工具,在撰寫本文時使用「Daemon」,在本例中,Daemon 是執行在背景的衍生副本,會在網路上發現 Fuchsia 裝置時,主動透過 SSH 連線至這些裝置。有許多方法可以探索裝置,但這些方法不在本文件的討論範圍內。
FFX Daemon 可讓 FFX 工具使用者在主機和 Fuchsia 裝置之間開啟模擬的 FIDL 管道。訊息會從 FFX 用戶端叫用,經由 Daemon 轉送至 Fuchsia 裝置。
FFX 幾乎完全以 Rust 編寫。此外,用於寫入及讀取主機端模擬 FIDL 管道的程式庫,也是以 Rust 編寫。
總而言之,FFX 可讓使用者透過 FIDL 與 Fuchsia 裝置進行介面連結,並使用以 Rust 編寫的插件,這些插件與 FFX 的實作方式緊密結合。
定義條款
以下是各節的定義:
- 「隔離」是指以 FFX 的方式使用 FFX,讓 FFX 可擁有獨立的 FFX 守護程序,讓其自行執行,而不需要使用一般通訊端位置或任何一般 FFX 設定值。FFX 守護程式例項並未與 Fuchsia 裝置隔離 (除非明確叫用)。
- 「Daemon Protocol」是指 FFX Daemon 處理的主機端 FIDL 通訊協定。這些測試項目包括套件服務、檢查網路上的 Fuchsia 裝置,以及 Fuchsia 裝置埠轉送。這個守護程式本身可視為類似於公開多個守護程式通訊協定的元件。
- 當提到「zircon」的管道、句柄和 Socket 時,這些項目會透過 overnet 在主機端模擬。不過,這些物件日後可能會以實際的 zircon 物件形式在 Fuchsia 裝置上使用。
FFX 用戶端程式庫
FFX 用戶端程式庫會透過 C ABI 公開函式,以支援下列項目:
- 建立、讀取、寫入及關閉 zircon 管道。
- 建立、讀取、寫入及關閉 zircon 套接字。
- 信號 zircon 句柄 (主要用於事件組合)。
- 將 zircon 管道連結至 Fuchsia 裝置上的元件。
- 將 zircon 管道連結至 FFX Daemon 通訊協定。
也將支援其他功能,例如:
- 建立 FFX Daemon 的隔離例項。
- 宣告 FFX 設定鍵/值組合。
語言專屬擴充功能
這項作業涉及在 FFX 用戶端程式庫上建立簡單的抽象層,並以共用程式庫的形式實作,然後在第一流的 Shell 程式庫中使用。
實作
如先前所述,這會涉及建立兩個共用程式庫。
- 不依賴語言的「FFX 用戶端」程式庫,會公開與 FFX 和 zircon 句柄通訊的函式。
- 語言繫結 (在本例中為 Python) 共用程式庫。
此外,我們也會提供 Python 繫結,方便使用者以符合人體工學的方式使用 FIDL。
實作內容不會涉及任何未包含在 Fuchsia 來源樹狀結構中的第三方依附元件。我們預期可以使用 FFX 用戶端程式庫支援其他語言 (可能需要額外的第三方依附元件工作),但這不在本 RFC 的範圍內。
將 Python 與 SDK 一併發布是另一個不在本文討論範圍內的主題,很可能會在專屬的 RFC 中加以封裝。
FFX 用戶端程式庫
本節中的 C 定義會放置在標頭檔案中,並隨 Fuchsia SDK 提供。由於 C 中缺少命名空間,因此這些函式名稱會相當冗長。函式名稱也不一定是最終名稱。
ABI 的模式旨在讓大多數函式使用輸出參數為呼叫端傳回結構,傳回值則為空值或錯誤。
zx_status_t
和 zx_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 類似,只是省略了選項參數。與 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"
)。
透過支援的 Socket/管道讀取和寫入功能,以及事件訊號,您將能夠複製 FFX 和 Overnet 目前支援的所有 FIDL 功能,但以 Python 為基礎。
Python 語言繫結
Python 語言繫結會定義使用已建立 create*/close*/destroy* 呼叫的物件,這些呼叫以 C++ 編寫,並提供 FFX 用戶端程式庫的薄型包裝函式。也會使用 ffx_error_str()
匯出錯誤類型。
如要查看這項 (略有不同) 實作的範例,請參閱這裡的 Fuchsia Controller 原型。
較高層級繫結
如要實際使用 FIDL 通訊協定,您可以使用更高層級的程式庫。它會使用 importlib
鉤掛至 FIDL 中介表示法 (IR),匯入分散式 .pyz
中可用的任何 IR,這些 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 網域 Socket 讀取/寫入作業,以及往返 Fuchsia 裝置的網路連線。
除此之外,FFX 用戶端程式庫會將 FIDL 讀取內容複製兩次,一次是跨越 Rust ABI 邊界,另一次是將 C++ 程式碼中的資料載入至 Python 物件。如果這項問題日後變成問題,我們會再處理。
一般用途會涉及 FIDL 的低負載用途,也就是使用結構體呼叫簡單函式。在撰寫本文時,主機不支援較複雜的 FIDL (例如 VMOs),因此不應成為效能方面的疑慮來源。
人體工學
FFX 用戶端 ABI
FFX 用戶端二進位檔會以盡可能小的設定檔實作,以免在其他語言中實作繫結時產生過多繁文。
較高層級的 Python 繫結
較高層級的 Python 繫結會使用 FIDL IR,在執行階段建立類別繫結。這樣一來,您不僅可以以與其他 FIDL 語言繫結 (例如 Rust、Dart 或 C++) 一致的方式使用 Python 程式碼,還可以在執行階段嘗試使用 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 指向第一個具有繫結的語言。
未知
FIDL IR
使用 SDK 將 FIDL IR 提供給使用者樹狀結構外,由於必須產生這項資訊,因此要正確取得這項資訊並不容易。因此,您可能需要為 Bazel 新增額外的建構規則,以簡化依附元件。
SDK 中的 FFX
由於 FFX FIDL 通訊協定尚未納入 SDK,因此使用 FFX 守護程式通訊協定的上述範例無法在樹狀結構外運作。API 審查已部分完成,但仍需完成。由於 FFX 仍有廣泛的 FIDL 介面要涵蓋,且通常也是不斷變動的目標,因此很難評估這項作業可能需要多久的時間。
FIDL 轉碼器
您可能根本不需要在最終結果中使用 fidl_codec
。使用這項功能時,也必須在 Python 共用程式庫中新增更多介面,並逐步淘汰這些介面。
考慮的替代方案如下:
- 產生的程式碼 (例如,這是 C++ 和 Rust 處理此問題的方式)。
- 以 Python 實作的
fidl_codec
類比。