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

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

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

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

摘要

我們將說明 FIDL 線路格式目前 (截至 2021 年 9 月) 的設計原則。

提振精神

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

在 Fuchsia 中,跨程序通訊 (至少是控制層) 普遍會透過 FIDL 進行,或至少會以此為目標。因此,線路格式會對作業系統的整體目標效能造成重大影響。同樣地,在隱私權和安全性層層防護中,線路格式也扮演著重要角色。

在 2017 年 3 月,我們完成了「FIDL 2.0」的設計。與後續開發版本相比,FIDL 2.0 是較為靜態的 FIDL 版本。如需其他歷史背景資訊,請參閱 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. 自此之後,我們已放寬部分目標 (可攜性、不對結構進行版本化),或加強部分目標 (endianness)。