| RFC-0241:SDK 介面中明確的平台 / 外部分割 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 更精確地表達 Fuchsia 介面的哪些部分可在 Fuchsia 平台以外實作。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2024-01-29 |
| 審查日期 (年-月-日) | 2024-04-09 |
摘要
Fuchsia IDK 並未指定外部元件是否應為定義的各種 FIDL 通訊協定實作用戶端或伺服器。因此難以正確評估 Fuchsia API 變更對回溯相容性的影響。本 RFC 建議以人類和機器都能判讀的方式,在 FIDL 中表示這項資訊。這有助於提升以 Fuchsia 為基礎的產品正確性和穩定性。
提振精神
Fuchsia 系統介面的大部分內容都以 FIDL 表示,做為一組通訊協定,以及透過這些通訊協定交換的型別。通訊協定是不對稱的,有用戶端和伺服器端,但 SDK/IDK 提供的 FIDL 宣告並未指定 Fuchsia 平台向產品提供的外部元件呈現的介面,是適用於這些通訊協定的伺服器端、用戶端或兩端。
如果對 Fuchsia 平台 (通常是外部元件) 的實作方式一無所知,就無法安全地對 Fuchsia 系統介面進行變更,因此精確度不足會大幅限制可進行的變更類型。在實務上,大多數通訊協定只會在 Fuchsia 平台中實作伺服器或用戶端,但這項資訊無法以工具可檢查或終端開發人員可探索的方式表示。
舉例來說,如果屬於系統介面的型別包含 string:100 (以 UTF-8 編碼時最多為 100 個位元組的字串),而我們後來發現需要支援較長的字串,如果該類型只會從外部元件傳送至平台元件 (在通訊協定方法要求中),則可安全地增加長度限制,因為解碼含有該字串訊息的元件,一律會與編碼該字串的元件一樣新。如果平台元件可能會將該類型傳送至外部元件,則長度無法安全增加,因為針對平台中較新 API 級別建構的元件,可能會不慎將格式錯誤的訊息傳送至外部元件。
利害關係人
誰會受到這項 RFC 是否通過的影響?
協助人員:
由 FEC 指派,負責在 RFC 程序中引導此 RFC 的人員。
審查者:
- abarth@google.com
- chaselatta@google.com
- hjfreyer@google.com
已諮詢:
- aaronwood@google.com
- awolter@google.com
- crjohns@google.com
- mkember@google.com
- pesk@google.com
- surajmalhotra@google.com
- wittrock@google.com
社交:
向負責平台版本控管的人員發放一份單頁文件,說明問題和提案。
需求條件
本文中的「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」和「OPTIONAL」等關鍵字,應按照 IETF RFC 2119 的說明解讀。
我們「必須」能夠表示哪些系統介面通訊協定「可能」在平台或外部元件中實作用戶端、伺服器或兩者。這項資訊必須以工具可存取的方式呈現,以便評估平台變更的相容性。
這項資訊「應」提供給軟體組裝時執行的工具,且「可能」在執行階段提供給元件架構。這項資訊「應」透過產生的 API 說明文件和建構時間檢查,向終端開發人員顯示。
如要評估 Fuchsia 平台與建構於其上的元件之間的相容性,外部元件必須以平台支援的穩定 API 級別為基礎建構。
設計
分析
平台 ABI 介面整體相容性可細分為考量外部元件和平台元件之間交換的個別型別相容性,包括透過管道的通訊協定,以及序列化和頻外交換。
元件之間的所有 FIDL 資料交換作業,都以下列其中一項為基礎:
- 透過元件架構通訊協定功能交換的 FIDL 通訊協定。這些項目會標示
@discoverable屬性。 - 透過非 FIDL 方法 (例如 process args) 交換的 FIDL 通訊協定,
- 在檔案 (例如元件資訊清單) 或自訂 IPC 傳輸中序列化及交換的 FIDL 型別。
如果我們掌握整個 Fuchsia 系統介面 FIDL 的檢視畫面,就能針對每個根項收集可能從用戶端傳送至伺服器,以及從伺服器傳送至用戶端的型別集。
通訊協定
如果我們知道每個「根」通訊協定的用戶端和伺服器是否可在外部元件或平台元件中實作,就能收集可能從外部元件傳送至平台元件、從平台元件傳送至外部元件、在平台元件之間,以及在外部元件之間傳送的型別集。
通訊協定:
@discoverable
protocol {
M(Req) -> (Resp);
}
根據我們允許實作用戶端和伺服器的位置,可以看出要求 (Req) 與回應 (Resp) 中的型別,可能會在外部元件 (E) 和平台元件 (P) 之間流動:
| 用戶端 | 伺服器 | E 到 P | P 到 E | P 對 P | E 到 E |
|---|---|---|---|---|---|
| E | E | Req、Resp | |||
| E | P | Req | Resp | ||
| E | P、E | Req | Resp | Req、Resp | |
| P | E | Resp | Req | ||
| P | P、E | Resp | Req | Req、Resp | |
| P、E | E | Resp | Req | Req、Resp | |
| P、E | P | Req | Resp | Req、Resp | |
| P、E | P、E | Req、Resp | Req、Resp | Req、Resp | Req、Resp |
平台程式碼保證會使用外部程式碼使用的通訊協定版本超集,因此我們可以針對是否能緊縮或放寬型別限制,做出以下判斷:
| 寄件者 | 接收器 | 限制 |
|---|---|---|
| 外部 | 平台 | 無法調緊 |
| 平台 | 外部 | 無法鬆開 |
| 外部 | 外部 | 無法變更 |
因此,我們必須限制用戶端和伺服器的實作位置。
幾乎所有根層級的通訊協定,都是透過元件架構功能交換。如果不是,就是低階或隱性問題。包括 fuchsia.io.Directory 和 fuchsia.posix.socket 中的幾個網路插座控制管道通訊協定。我們不應發明新的方式來將這些通訊協定標示為通訊的根,而應擴充 @discoverable 的意義,將這些通訊協定納入其中。事實上,fuchsia.posix.socket 中有通訊協定名稱的常數,一旦標示為 @discoverable,系統就會自動產生這些常數。
類型
目前,任何元件 (外部或平台) 程式碼都可以從原始位元組序列化或還原序列化任何非資源類型。為讓相容性工具瞭解哪些 FIDL 型別不會在某些環境中序列化或還原序列化,我們應明確標記在正常 FIDL IPC 以外的元件之間傳遞的型別。
語法
通訊協定
可探索屬性將擴充,以表示可探索通訊協定的實作位置。根據預設,標示為 @discoverable 的通訊協定可能同時有外部元件和平台元件實作的用戶端和伺服器。
server 和 client 選用屬性會列出可能實作該類端點的元件種類。根據預設,任何元件都可以實作這兩個端點。
例如:
// All servers in the platform, all clients in external components.
@discoverable(client="external", server="platform")
protocol P {};
// All servers in external components, all clients in the platform.
@discoverable(client="platform", server="external")
protocol Q {};
// Only clients allowed in external components, both clients and servers allowed in the platform.
@discoverable(client="platform,external", server="platform")
protocol R {};
// Servers are only allowed in platform components. Clients are allowed anywhere.
// If both clients and servers are allowed that argument can (and should) be omitted.
@discoverable(server="platform")
protocol S {};
類型
FIDL 會新增 @serializable 屬性,標示可在 FIDL 協定外部的元件之間序列化及傳遞的型別。
這項屬性僅適用於非 resource struct、table 和 union。
這項函式有兩個選用引數,分別是 read 和 write。這些函式都會採用以半形逗號分隔的 platform 和 external 清單,指出平台元件或外部元件是否會讀取或寫入該型別。每個引數的預設值為 "platform,external",表示可從該類型的元件讀取及寫入。
實作
FIDL 工具鍊
fidlc 會更新為接受 @discoverable 的引數和新屬性 @serializable。FIDL 繫結產生器 (fidlgen_*) 目前不會修改。
Fuchsia 系統介面
partner 和 partner_internal 程式庫中所有可探索的 FIDL 通訊協定都會更新。大多數都會標示 @discoverable(server="platform"),表示外部元件應只實作用戶端,但平台元件可以實作用戶端和伺服器。有些 (例如 fuchsia.io 中的許多) 會標示 @discoverable(),表示任何元件都可以實作用戶端和伺服器。其中有幾個 (大多是驅動程式) 會標示 @discoverable(client="platform", server="external"),表示外部元件應只實作伺服器,平台元件則應只實作用戶端。
經過一些實驗和原型設計後,似乎沒有直接計算每個通訊協定所屬類別的方法。元件圖的執行階段檢查和 CML 分片的靜態評估都不清楚。我們會查看外部元件的資訊清單,瞭解這些元件使用及提供的通訊協定功能。
如果是獨立資料型別,我們會尋找各種語言繫結的明確序列化 API 呼叫,並適當註解所用的型別。
相容性工具
我們正在開發工具,評估 Fuchsia 系統介面 FIDL IPC 部分不同版本的相容性。這項作業會針對 FIDL IR 執行,並納入可探索屬性的資訊。這項工具將實作的相容性規則完整說明,將在另一份 RFC 中提供。
未來商機
這項 FIDL 語法強化功能背後的主要優先事項,就是相容性工具。不過,這項有關 Fuchsia 系統介面的豐富資訊可能在其他地方派上用場。
FIDL 繫結
FIDL 繫結產生器可以瞭解繫結是否以平台元件或外部元件為目標,並調整產生的程式碼,鼓勵開發人員只在有相容性保證的環境中實作通訊協定的用戶端和伺服器。
禁止使用任何不支援的用戶端或伺服器會適得其反,因為開發人員需要在測試中模擬同層級,但或許我們可以設置防護措施,避免在非測試情境中使用。
獨立序列化程式碼可以更新,只允許傳入標示為 @serializable 的型別。
元件架構
在元件架構中,通訊協定功能沒有型別。這些名稱通常會以所攜帶的 FIDL 通訊協定命名,但這只是一種慣例,而且經常遭到違反。如果工具要推斷元件與同層級元件通訊時使用的通訊協定,就必須根據功能名稱猜測使用的通訊協定。
如果元件架構將通訊協定類型新增至模型,這些工具就會更簡單、更健全且更正確。
軟體組裝
軟體組裝會根據設定、平台元件和外部元件,產生 Fuchsia 系統映像檔。這項工具可能會使用平台元件或外部提供的通訊協定資訊,拒絕組裝違反這些規則的產品。這樣一來,產品負責人就不會在無意間建構產品,並保證與 Fuchsia 不支援的項目相容,平台開發人員也能避免以不打算支援的方式公開功能。
安全性
瞭解哪些通訊協定功能端點會跨越外部/平台界線進行路由,有助於評估系統的安全屬性。您可以臨時執行這項操作,也可以整合至現有工具。
效能
效能不會受到影響。
人體工學
這需要明確指出系統中的部分假設,雖然前期工作量會稍微增加,但可讓系統更容易瞭解及使用。
回溯相容性
現有的 FIDL 程式庫不會受到影響。@discoverable (不含引數) 仍是有效屬性。
一開始,我們不會為可探索和可序列化的屬性設定版本,因為這些屬性是版本設定的輸入內容,不會影響來源或執行階段的相容性,而且需要廣泛採用才能發揮效益。如果我們根據可探索的引數更新 FIDL 繫結,就必須考慮版本控管,因為變更繫結可能會導致現有原始碼中斷。
安全性考量
未來可能會有機會,進一步提升整體系統安全性。
隱私權注意事項
無
測試
這項做法會明確編碼我們保證相容的通訊協定端點,有助於確保我們為 Fuchsia 平台提供完整的相容性測試。
我們會為所有 fidlc 變更新增 fidlc 測試。
在組裝時驗證所有元件是否遵循 FIDL 檔案中表示的規則之前,我們無法確定 SDK 中表示的外部/平台分割是否符合 Fuchsia 產品的實際情況。
說明文件
需要更新幾份 FIDL 說明文件:
缺點、替代方案和未知事項
我們可以維持現狀,但這樣一來,我們能支援的變更類型就會受到大幅限制,工具在檢查變更安全性時的信心程度也會受到影響。
我們可以在 API 工具中,於 FIDL 語言外部表示外部 / 平台分割 (就像我們對 SDK 類別所做的那樣),但由於這種分類是在宣告層級進行,因此會感覺較不符合人體工學,且較有可能過時。
我們可以使用等效屬性來表示通訊協定,例如 fuchsia.io.Directory,而不是使用 @discoverable,這樣既能確保相容性,也不會支援通訊協定功能。這感覺像是必要的複雜性。
我們不必新增 @serializable 來標記頻外交換的型別,只要編寫使用這些型別的預留位置 FIDL protocol,並以適當的屬性標記 @discoverable,即可表示這些型別的讀取和寫入位置。這表示通訊協定永遠不會說出口,而且通常難以正確且清楚地傳達。
我們曾使用 @discoverable(platform="server", external="client"),但目前使用的語法似乎更容易理解。@discoverable(server="platform", client="external")
既有技術和參考資料
不適用