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
社會化:
在平台版本管理團隊中,發送一份 1 頁的說明文件,說明問題和提案。
需求條件
本文件中的關鍵字「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」和「OPTIONAL」應依 IETF RFC 2119 所述進行解讀。
我們必須能夠表示哪些系統介面通訊協定可能在平台或外部元件中實作用戶端或伺服器,或同時實作這兩者。這項資訊必須以可供評估平台變更相容性的工具存取的方式呈現。
這項資訊應可供在軟體組裝期間執行的工具使用,且可能可供元件架構在執行階段使用。這項資訊應透過產生的 API 說明文件和建構期間檢查,向最終開發人員顯示。
為了讓這項資訊在評估 Fuchsia 平台與其上建構的元件之間的相容性時有所助益,外部元件必須以平台支援的穩定 API 級別建構。
設計
分析
平台 ABI 介面的相容性整體而言可分為外部元件和平台元件之間交換的個別類型相容性,包括透過管道和序列化的通訊協定,以及離線交換。
元件之間的所有 FIDL 資料交換都會以以下任一項目為基礎:
- 透過元件架構通訊協定功能交換的 FIDL 通訊協定。這些會標示
@discoverable
屬性。 - 透過非 FIDL 方式交換的 FIDL 通訊協定,例如程序參數
- 序列化並在檔案 (例如元件資訊清單) 或自訂 IPC 傳輸中交換的 FIDL 類型。
在整個 Fuchsia 系統介面 FIDL 的檢視畫面中,我們可以針對每個根目錄收集可能從用戶端傳送至伺服器,以及從伺服器傳送至用戶端的類型集合。
通訊協定
如果我們知道每個「根」通訊協定,其用戶端和伺服器是否可在外部元件或平台元件中實作,我們就能收集可能從外部元件傳送至平台元件、從平台元件傳送至外部元件、平台元件之間和外部元件之間的類型集合。
針對通訊協定:
@discoverable
protocol {
M(Req) -> (Resp);
}
我們允許在哪些位置實作用戶端和伺服器,就能瞭解在外部元件 (E) 和平台元件 (P) 之間,請求 (Req) 和回應 (Resp) 的類型可能會流向哪裡:
用戶端 | 伺服器 | 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 類別所做的那樣),但由於這類分類作業是在宣告層級執行,因此使用者體驗較差,且更有可能過時。
我們可以使用等同的屬性,而非使用 @discoverable
標示 fuchsia.io.Directory
等通訊協定,這樣在相容性方面也一樣,但不包含對通訊協定功能的支援。這似乎是必要的複雜性。
我們可以不將 @serializable
新增至用於標示離線交換類型的類型,而是直接編寫使用這些類型的預留位置 FIDL protocol
,並在標示 @discoverable
時加上適當的屬性,以暗示這些類型可讀取和寫入的位置。這表示您必須使用從未發言的通訊協定,而這類通訊協定通常很難正確使用,且會造成混亂。
我們曾經短暫使用 @discoverable(platform="server", external="client")
取代 @discoverable(server="platform", client="external")
的語法,但目前的語法似乎更容易理解。
既有技術與參考資料
不適用