RFC-0232:多個 API 級別的 FIDL 繫結

RFC-0232:適用於多個 API 級別的 FIDL 繫結
狀態已接受
領域
  • FIDL
說明

啟用建構 FIDL 繫結,與多個 API 級別相容

問題
  • 135677
毛皮變化
作者
審查人員
提交日期 (年-月-日)2023-09-27
審查日期 (年-月-日)2023 年 10 月 24 日

摘要

今天產生 FIDL 繫結時,我們會在樹狀結構中指定 LEGACY, 編號的 API 級別本文件旨在說明 已過時的 LEGACY 方法,可讓您一次指定多個 API 級別。這個 我們一開始只能用在樹狀結構中,但可能會遇到 這在樹狀結構中很實用

背景

從原始設計 FIDL 的版本管理中,您將無法移除 元素,同時保留對其 ABI 的支援。舉例來說,如果 CL 標示了方法 與 removed=5 一樣,還必須刪除該方法的實作。 這是因為我們已在 HEAD 上建構 Fuchsia 平台,以及此方法的伺服器 繫結不再存在於 HEAD 中,因為其超過 5 個。

為解決這個問題,我們修訂 RFC-0083 並 LEGACY 版本和 legacy 引數。LEGACY 版本就像 HEAD。 否則會重新加入標示為 legacy=true 的元素。

提振精神

LEGACY 有幾個問題:

  • 也就是本身沒有任何資訊的虛擬版本。繫結 凍結的 API 級別 N 包含屬於 N 的所有 API,但 LEGACY 包含任何看起來標示為 removed 且帶有 legacy=true 的項目 時 (除了 HEAD 中的所有內容)。

  • 舊版支援須依個別 API 而定,且會隨時間改變。這個 也很難保證平台版本實際上可以支援 指定的舊版 API 級別

  • 您無法指定特定 API 級別 (也就是 HEAD 以外的目標) 並包含舊版支援

  • 只解決一小部分相容性難題,也就是 Fuchsia 面臨的挑戰 平台是溝通的一面會說出各種通訊協定 但若是並非如此

  • 這等同於 Fuchsia 單聲道存放區的權限,因此更難分割 以及發布流程之外的元件

相關人員

講師:abarth@google.com

審查人員:hjfreyer@google.com、wilkinsonclay@google.com、ddorwin@google.com

諮詢:Wez@google.com、sethladd@google.com

社交:我與 FIDL 團隊和平台討論了這個想法 在寫入 RFC 之前的版本管理工作群組。

設計

建議您在產生 FIDL 時一次指定多個 API 級別 繫結。舉例來說,使用 --available fuchsia:10,15 叫用 fidlc 目標 API 級別 10 和 15,導致繫結結合 兩個層級如果特定名稱元素的定義低於 10 而 15,我們使用第 15 級的定義,因為這是較新的版本。

這會遮蓋 LEGACY 版本。建構 Fuchsia 平台時 指定 LEGACY 繫結為目標,我們會指定支援的 API 級別組合。 也無需使用 legacy=true 標示個別 API。

詳細資料

  • 移除 LEGACY 版本和 @available 屬性的 legacy

  • 將 fidlc 的 --available 指令列引數語法從 <platform>:<target_version><platform>:<target_versions>,其中 <target_versions> 是以逗號分隔的版本清單。例如:

    • --available fuchsia:10
    • --available fuchsia:10,11
    • --available fuchsia:10,20,HEAD
  • <target_versions> 清單必須排序,且不得包含重複項目。 這是我們要強調的是,版本會產生線性歷史,之後 系統會優先處理各個版本

  • <target_version> 清單決定了一組候選元素

    • 如果符合以下情況,標示為 @available(added=A) 的元素就是候選元素 <target_versions>{v | v >= A} 相交。

    • 標示為 @available(added=A, removed=R) 的元素是候選元素 如果 <target_versions>{v | A <= v < R} 相交。

    • 請注意,這個 RFC 需視 RFC-0231: FIDL 版本管理取代模式運作 語法為確定候選元素 系統會將 replaced 視為與 removed 相同。

  • 如果 (1) 是候選元素,就會包含在繫結中。 名稱相同的所有候選字詞之間,added 版本的成效最高。

  • 如果標示為 @available(..., deprecated=D, ...) 的元素包含在以下位置: 如果參照 <target_versions>{v | v >= D} 相交。這不會影響 但日後可能會發生 (https://fxbug.dev/42156877)。

  • 和先前一樣,--available 標記可以多次用於多個 平台。這兩項功能之間沒有顯著的互動 (多個平台和多個目標版本)。

  • 和先前一樣,編譯成功或失敗,必須在 主要程式庫平台的 --available 旗標。視實際情況而定, 其他平台依附元件的 --available 旗標上。)例如: 如果使用 --available fuchsia:15,16 編譯成功,則保證能 也成功運用 --available fuchsia:10,100,HEAD 達成目標同樣地, 失敗則保證會失敗,並顯示相同的錯誤組合。

  • 建構 Fuchsia 平台時,將 --available fuchsia:LEGACY 替換為 --available fuchsia:<target_versions> (其中 <target_versions> 包含所有項目) 執行階段支援的 API 級別、開發中 API 級別,以及 HEAD

影響

這項設計可讓您針對指定 任意組合,無論程式庫如何隨著時間進化。 這項限制是重大的,因為 FIDL 版本管理可以代表任何 語法有效變更。具體來說,Fidlc 可包含多個 只要版本範圍不會重疊,即可使用相同名稱來共存。時間 <target_versions> 會包含多個此類元素,我們只加入 是最新的元素這支援三種一般的演化模式:

  • 生命週期。元素為 added,可能為 removed。我們會將它納入 繫結至任何版本。範例:

    @available(added=1, removed=5)
    flexible Method() -> ();
    
  • 替換。元素為 added,後置的 replaced 和 不同的定義概念上來說,這代表單一元素 而不是兩個不同元素我們假設更換裝置的設計為 可與原始元素相容,並且只加入替換品 元素。範例:

    @available(added=1, replaced=5)
    flexible Method() -> ();
    @available(added=5)
    flexible Method() -> () error uint32;
    
  • 名稱重複使用。元素設為 removed 後,其名稱即可重複用於新的 added 元素。這與 replacement 類似,但這兩個元素 而且生命週期之間也有所差異我們會假設 偏好新的元素,且只將它納入繫結中。範例:

    @available(added=1, removed=5)
    flexible Method();
    @available(added=10)
    flexible Method() -> ();
    

    請注意,以這種方式重複使用元素名稱時,參照該元素無法 藉此跨越兩項定義舉例來說,這樣無法編譯:

    @available(added=1, removed=5)
    type Args = struct {};
    @available(added=10)
    type Args = table {};
    
    @available(added=2)
    protocol Foo {
        Method(Args); // ERROR: 'Method' exists at versions 5 to 10, but 'Args' does not
    };
    

範例

請考慮使用以下 FIDL 程式庫:

@available(added=1)
library foo;

@available(replaced=2)
type E = strict enum { V = 1; }; // E1
@available(added=2)
type E = flexible enum { V = 1; }; // E2

@available(added=3, removed=6)
open protocol P {
    @available(removed=4)
    flexible M() -> (); // M1

    @available(added=5)
    flexible M(table {}) -> (); // M2
};

選取單一版本時,繫結中包含下列項目:

--available E1 E2 P M1 M2
foo:1 ✔︎
foo:2 ✔︎
foo:3 ✔︎ ✔︎ ✔︎
foo:4 ✔︎ ✔︎
foo:5 ✔︎ ✔︎ ✔︎
foo:6 ✔︎
foo:HEAD ✔︎

以下是選取多個版本時的內容:

--available E1 E2 P M1 M2
foo:1,2 ✔︎
foo:1,HEAD ✔︎
foo:1,3 ✔︎ ✔︎ ✔︎
foo:1,2,3 ✔︎ ✔︎ ✔︎
foo:3,6 ✔︎ ✔︎ ✔︎
foo:3,HEAD ✔︎ ✔︎ ✔︎
foo:2,4,6 ✔︎ ✔︎ ✔︎
foo:1,3,5 ✔︎ ✔︎ ✔︎
foo:1,2,3,4,5,6,HEAD ✔︎ ✔︎ ✔︎

實作

  1. 實作 RFC-0231:FIDL 版本管理語法

  2. 在 fidlc 中實作新的 --available 功能。一併變更 「可用」屬性,以便為版本使用字串陣列。

  3. 變更所有現有的 legacy 引數,使其與新系統保持一致 (即 如在支援的最低 API 級別之前移除,則為 false;如果在系統支援的最低 API 級別之前移除,則設為 true 「安全」標誌如果出現大幅差異 替代方法:覆寫機制

  4. 變更樹狀結構內平台版本,以產生指定全部的繫結 支援的 API 級別、開發中 API 級別和 HEAD

  5. 移除 FIDL 檔案中的所有 legacy 引數。

  6. 從 fidlc 移除 LEGACY 支援。

  7. 淘汰 fidlc 錯誤代碼 fi-0182fi-0183

成效

此提案不會影響成效。

人體工學

本提案使 FIDL 版本管理變得更容易使用,因為沒有 不需要再擔心 legacy 引數

回溯相容性

本提案有助於達成 ABI 回溯相容性,因為 ABI 移除 個別 FIDL 程式庫作者提供 legacy=true 的負擔。此外, 能讓您更加瞭解我們先前「支援的 API 級別」組合,因為這些 API 的 API 級別 層級直接用於為平台產生繫結,(當然,到 請務必確保他們能接受測試)。

安全性考量

此提案不會影響安全性。

隱私權注意事項

此提案對隱私權沒有任何影響。

測試

必須先更新下列檔案,才能測試新行為:

  • tools/fidl/fidlc/tests/availability_interleaving_tests.cc
  • tools/fidl/fidlc/tests/decomposition_tests.cc
  • tools/fidl/fidlc/tests/versioning_tests.cc
  • tools/fidl/fidlc/tests/versioning_types_tests.cc

說明文件

下列說明文件頁面必須更新:

缺點、替代方案和未知

非問題:減少遷移的動機

這項提案可以視為減少 RFC-0002 中所述的獎勵計畫: 平台版本管理:遷移已淘汰的 API,因為 您可以指定多個層級,以存取新舊 API。不過, 「LEGACY」已成為今日可使用的工具。就像花瓣一樣 今天LEGACY,他們不能濫用這項新功能。

另外,花瓣粉透過 SDK 使用 fidlc,而不是直接叫用 只要使用 SDK 建構規則中的限制,即可緩解這種情況。舉例來說 可能會聲明目標版本字串不含半形逗號。

替代版本:版本範圍

與其允許使用任意版本組合,我們可能需 由兩個端點指定我拒絕這個替代方案的原因有幾個:

  • 一旦決定提高 API 級別的執行頻率, 仍要能長期支援其中一部分的做法如此一來 代表差異,而非範圍

  • 我們可能想要支援目標 API 級別的個別舊元件 N,不需重新編譯。如果其他設定均已從 API 停用 第 N 級至 M 級別,我們可能出現 {N+1, ..., M} 的落差。

  • 截至目前,尚未針對平台版本管理建構的任何項目都假設 從支援的 API 級別到 100 倍例如,version_history.json 包含 列出 API 級別,而非範圍

  • 使用範圍而非組合不會讓 fidlc 實作更加容易。 可能會讓效率稍微提升,但不太在意 練習。還有許多可促進最佳化的測試成果應該是問題 成效自然成為一大問題

替代方法:覆寫機制

此提案的一個缺點,是難以更新所有程式碼 停止對 API 級別的支援時,就會以 fuchsia.git 建立。為了拆分 或是完成多個步驟,我們可能需要用更精細的方式 也會包含在繫結中您有以下幾個選擇:

  1. 覆寫個別 fidl GN 目標中的 <target_versions>

  2. 新增排除元素的 @available 引數 unsupported=true 即使該代碼通常會包含它這與 legacy 類似,但 僅用於暫時 (最好)

  3. 變更 --available 引數,以接受 JSON 檔案。除了 <target_versions>,可以提供完整的元素名稱清單, 納入或排除。

我拒絕這個替代版本,因為我們不清楚自己需要這項機制。 相反地,我們應該先嘗試透過單一 CL 進行變更。如果沒有 應該嘗試使用條件式編譯來階段變更 僅在停止對 API 級別的支援之前包含實作。如果 如果測試失敗,我們可以重新造訪上述覆寫機制。

此外,我們也可以提高 API 級別的步調來緩解這個現象, 可降低每個 API 級別移除的次數不過,此方法 ,且不在此提案中。

替代方法:將 legacy 預設為 true

請參閱RFC-0233:預設使用 FIDL 舊版

這個替代方法可改善現狀。使用 false 做為預設值 忘記新增 legacy=true 可能會導致 ABI 中斷。以 true 做為 預設,忘記新增 legacy=false 只能導致 fidlc 編譯 錯誤或未使用的 API,較為嚴重的問題。

不過,這只是小幅變更,無法解決所有問題 相關單位。系統仍會根據 API 控制 legacy 狀態。 導致特定 API 級別的執行階段支援不一致,因而造成 難以判斷特定版本是否完整支援 API 級別。

既有藝術品和參考資料

Android SDK 可讓您指定 compileSdkVersionminSdkVersion。詳情請見 Android API 級別<uses-sdk> 說明文件