RFC-0131:FIDL 電匯格式的設計原則

RFC-0131:FIDL 線路格式的設計原則
狀態已接受
區域
  • FIDL
說明

我們將說明各種設計原則,這些原則是 FIDL 線路格式的基礎。

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-06-15
審查日期 (年-月-日)2021-09-29

摘要

我們將說明目前 (2021 年 9 月) 的設計原則,這些原則是 FIDL 傳輸格式的基礎。

提振精神

FIDL 傳輸格式會指定訊息的編碼 (和解碼) 方式,以及傳輸層級中繼資料的格式,例如交易訊息標頭。線路格式規格隱含理論界限,最佳實作方式可達到此界限。就像資料結構會對作業隱含特定的大 O 邊界一樣,連線格式也是如此。

在 Fuchsia 中,處理序間通訊 (至少是控制層) 無所不在,且是透過 FIDL 進行,或預計透過 FIDL 進行。因此,連線格式會對作業系統的整體目標效能造成重大影響。同樣地,線路格式在多層防禦隱私權和安全性的機制中,也扮演重要角色。

2017 年 3 月,「FIDL 2.0」的設計完成。與後續開發項目相比,FIDL 2.0 是更靜態的版本。如需更多歷史背景資訊,請參閱 RFC-0027:用多少付多少

線路格式規格的目標如下1

  • 在程序之間有效率地傳輸訊息。
  • 一般用途,適用於裝置驅動程式、高階服務和應用程式。
  • 僅針對 Zircon IPC 進行最佳化,可攜性並非目標。(這項目標後來已放寬)。2
  • 針對直接記憶體存取進行最佳化;機器間傳輸並非目標。
  • 僅針對 64 位元環境進行最佳化,不適用於 32 位元環境。
  • 使用主機位元組順序的未壓縮原生資料型別、元素的第一個合適封裝,以及正確對齊,支援訊息內容的就地存取。
  • 與 C 結構的記憶體內配置相容 (具有適當的欄位排序和封裝註解)。
  • 結構為固定大小且內嵌;大小可變的資料會儲存在行外。
  • 結構體不會自行描述,而是由 FIDL 檔案描述內容。
  • 結構沒有版本控管,但介面可透過新方法擴充,以利通訊協定演進。(這項目標後來已放寬。)[^2]
  • 不需要計算偏移量,算術運算很少,可能發生溢位。
  • 支援快速單次編碼和驗證 (合併作業)。
  • 支援快速單次解碼和驗證 (做為合併作業)。

雖然線路格式的持續演進遵循非常具體的設計原則 (如上所述),但這些原則不一定會連同基本原理一併寫下來。這份 RFC 嘗試清楚地寫下這些設計原則。

設計

我們將說明 FIDL 線路格式的各種設計原則。

先顯示低價位等級

如果為了支援低階程式設計而必須犧牲高階程式設計 (或反之),我們通常會選擇支援低階程式設計。

FIDL 必須符合 Fuchsia 中低階通訊協定的需求,有時會在啟動程序中使用,例如當 malloc 尚未提供時。如果 FIDL 無法滿足這些需求,替代做法是手動設計通訊協定。不過,在高階程式設計中,如果 FIDL 無法滿足需求,還有許多其他選項可供選擇 (例如 Protobuf、Cap'n Proto、JSON、Yaml 等)。

單次傳遞,且沒有堆積分配量

必須能夠在單一傳遞中編碼和解碼,且不得超出堆疊空間分配 (即不得動態分配堆積分配量)。

這項原則某種程度上是為了避免過度專注於低層級用途,並確保系統上的任何軟體都能充分參與 FIDL 生態系統。

由於 FIDL 提供「解碼 + 驗證」功能,因此單次傳遞需求應與提供還原序列化和驗證功能的類似系統比較,這類系統通常會分兩次傳遞 (驗證會在解碼形式上進行)。

不配置記憶體的要求也表示編碼和解碼作業會在原地完成,也就是透過原地修改。

與手動建立的資料結構一樣有效率

必須能夠編寫線路格式的實作項目,且效率與手動捲動的資料結構相同。

這是「用多少付多少」原則的特例,也就是說,FIDL 旨在提供的便利性和人體工學設計,不得以效能為代價。在實務上,許多實作方式會選擇降低效率,以提供額外的人體工學設計,但線路格式不會規定這項選擇。

標準表示法

FIDL 值必須有單一明確的表示法,也就是說,FIDL 值只能有一個編碼表示法,以及一個解碼表示法。

強制使用單一表示法時,線路格式自然會更加嚴格,這表示實作項目必須預期輸入內容的變異較少,並遵循更直接的路徑。這有助於確保正確性,減少資料差異造成的意外。有了標準形式,您就能檢查兩個值是否相等,不必瞭解結構定義,也就是說,值類型只要有 memcmp 就足夠 (資源類型的情況稍微複雜)。

另請參閱標準形式的缺點

指定每個位元組

編碼或解碼時,必須能夠在單一傳遞中遍歷訊息的每個位元組,且不會配置任何堆積

為確保資料不會在傳送者不知情的情況下從一個程序洩漏到另一個程序,我們同時確保所有位元組都能有效率地遍歷,且所有位元組都有指定值 (例如,填補必須為 0)。舉例來說,這有助於確保不會在程序界限間無意分享任何個人識別資訊 (PII),或避免洩漏可能含有指標值 (可用於破解位址空間配置隨機化 (ASLR)) 的未初始化記憶體。另一個例子是考慮「尾隨垃圾」無效,因為所有資料和控點都必須列入考量。

隨處驗證

為落實縱深防禦,我們希望 FIDL 線路格式在所有使用位置都能強制執行嚴格驗證 (例如邊界檢查、字串是否為格式正確的 UTF-8 程式碼單元序列、控制代碼是否為正確的類型和權限)。

嚴格驗證有助於確保平台安全,因此值得採用,而且可協助 API 作者在 API 結構定義中說明設計的假設和不變量。根據我們的經驗,如果較低層級沒有驗證,應用程式往往會自行驗證不變量,導致程式碼不夠清楚、效率較低,且更容易發生錯誤。

由於嚴格驗證可能會導致效能成本過高,且 FIDL 的用途是低階層,因此這類驗證必須有效率地完成,並設計成單次傳遞

沒有立即可用的反思功能

未明確選擇加入的情況下,不得允許同層級對通訊協定執行反映,無論是公開方法或公開型別。

舉例來說,如果對等互連端呼叫錯誤的 FIDL 方法,連線就會關閉,防止擷取任何有關對等互連端的資訊。建構這類功能似乎很方便,但可能會損害隱私權,而且難以復原 (使用者會開始根據這項功能建構負載功能)。

同樣地,缺乏自我描述格式的結構體也符合這項原則,目的是避免在互動同儕應互不信任的生態系統中,揭露超出必要的資訊。(避免使用自我描述格式也能大幅提升成效,這與低層級優先方法一致)。

由於我們已變更 FIDL 線路格式以支援演變 (例如表格),因此必須謹慎地在禁止反映與新增足夠的項目之間取得平衡,以便在沒有結構定義的情況下處理。

實作

請保持冷靜,並遵循原則。請參閱 RFC-0017

效能

FIDL 線路格式的大多數指導原則都以效能為目標,並過度專注於低階用途。效能是我們最重視的問題。

人體工學

人體工學設計不變。

回溯相容性

這裡列出的一些原則與 FIDL 的主要目標相衝突,也就是為穩定的 ABI 提供基礎,例如,如果沒有反射功能,實作向後相容的通訊協定就會很困難。FIDL 線路格式的設計在效能 (通常是剛性的結果) 和可演進性考量 (通常是彈性的結果) 之間取得平衡。如何平衡這些要素,就是遊戲的樂趣所在。

安全性考量

這份 RFC 說明瞭 FIDL 在 Fuchsia 多層式安全防護機制中扮演的角色。

隱私權注意事項

這份 RFC 說明 FIDL 在 Fuchsia 多層式隱私權做法中扮演的角色。

測試

測試沒有任何異動。

說明文件

視需要進行修改:

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

如文字所述。

標準形式的缺點

要求使用標準化形式可能會限制尋找合適資料表示法的問題,甚至捨棄其他有趣或可行的形式。

處理稀疏資料表時,標準化是最難滿足的限制之一,且直接與格式效能需求衝突。舉例來說,我們可以在使用者提供的順序中探索寫入成員,不需要第二次傳遞來重新排序這些成員,以滿足標準化需求。

既有技術和參考資料

如文字所述。


  1. 作者:Jeff Brown jeffbrown@google.com。 

  2. 部分目標後來已放寬 (可攜性、結構體無版本控管),或趨於嚴格 (位元組順序)。