RFC-0246:API 級別為 32 位元

RFC-0246:API 級別為 32 位元
狀態已接受
區域
  • 一般
說明

將 API 級別重新定義為 32 位元數字,而非 64 位元

Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2024-04-01
審查日期 (年-月-日)2024-04-29

摘要

這項提案將 API 級別定義變更為不帶正負號的 32 位元整數。這項定義取代了 RFC-0002,後者將其定義為不帶正負號的 64 位元整數。

提振精神

目前可以在 target_api_level.gni 中找到下列程式碼 (為求清楚,已改寫):

if (override_target_api_level == -1) {
    clang_fuchsia_api_level = 4294967295
    fidl_fuchsia_api_level = "LEGACY"
}

大致來說,這表示在 fuchsia.git 中建構時,如果未指定 API 級別,則 clang_fuchsia_api_level 應設為 0xFFFFFFFF,而 fidl_fuchsia_api_level 應設為字串值 "LEGACY"。這個字串稍後會由 fidlc 解譯為值 0xFFFFFFFFFFFFFFFF 的別名,如 RFC-0083 所定義。

這會造成兩個問題:

  1. 有「clang API 級別」和「FIDL API 級別」,兩者通常會採用不同的值。
  2. API 級別有時會以字串表示,有時則以整數表示。

clang 與 FIDL 的比較?

RFC-0002 將 API 級別定義為 64 位元整數,後續 RFC 則分配了特定 64 位元整數,並賦予名稱和意義。舉例來說,LEGACY 是由 0xFFFFFFFFFFFFFFFF 識別。但根據上述程式碼,我們會改為將 0xFFFFFFFF 傳遞至 Clang,因為很遺憾,Clang 的 API 級別僅限 32 位元。

嗯,這不太正確。

Clang 會透過 availability 屬性推斷相容性,該屬性會將版本表示為 VersionTupleVersionTuple 會將代表版本的四個整數 major[.minor[.subminor[.build]]] 元組封裝到 128 位元結構中。Fuchsia API 級別在這個結構中會以「主要版本」的形式呈現,因此限制為 32 位元。

Clang 是 Fuchsia 平台版本控管的重要環節,因此必須解決這項不一致的問題。

string vs int vs... ?

主機工具和建構系統在用於表示 API 級別的型別方面不一致。即使在 fuchsia.git 的建構系統中,也存在不一致的情況,如上方的程式碼區塊所示。

這不一定會造成問題,且這項 RFC 並未完全解決問題。 不過,我們會盡量提供指引,協助您釐清這些模糊不清之處。

利害關係人

協助人員:abarth@google.com

審查者:

  • ddorwin@google.com
  • mkember@google.com
  • haowei@google.com

已諮詢:

  • chaselatta@google.com
  • phosek@google.com
  • ianloic@google.com

社交:

與平台版本控管工作小組和工具鍊團隊成員討論 Google 內部錯誤

需求條件

API 級別必須可表示為字串,包括在指令列上,以及在檔案和目錄名稱中。

API 級別必須完全排序,因此我們可以說:「API 級別 N 新增了 Foo,因此 N <= M 是 API 級別 M 的一部分。」Foo

我們必須能夠為某些 API 層級指派特殊名稱和行為。本節中的其他規定也適用於這些「特殊」API 級別。

設計

整數表示法

API 級別將重新定義為不帶正負號的 32 位元整數。

這個空間的下半部 (即 API 級別低於 0x80000000) 視為「正常」API 級別。這個空間的上半部為保留區域,這項 RFC 和日後的 RFC 會定義大於或等於 0x80000000 的特定值意義。

如果工具一律將所有 API 級別視為相同,可能會忽略「一般」和保留值之間的差異,並將所有值視為無正負號的 32 位元整數,以一般方式排序。

如果工具具有特定 API 級別的特殊邏輯,應拒絕指定保留 ABI 級別值的輸入,因為工具無法解讀這些值。

字串表示法

API 級別可透過多種不同方式以字串表示:

  • 任何代表十進位數字的 UTF-8 字串 (間隔為 [0, 232)) 都是 API 級別的字串表示法 (例如 "7")。
  • 特殊 API 級別可以大寫名稱表示 (例如 "HEAD")。
  • 工具不應接受較為深奧的值,例如 "0016""0x20",因為這樣做可能會造成模稜兩可的情況。舉例來說,"0016" 是八進位還是十進位?"2A" 可能是十六進位,但如果系統接受,"29" 是十六進位還是十進位?不過,字串剖析邏輯通常是由個別工具作者無法控制的程式庫處理,因此工具可能會接受這類值。

每個 API 級別都只有一個標準字串表示法

  • 如果是「一般」API 級別,則以 10 為底的 UTF-8 字串表示法是標準的 (例如 "13")。
  • 如果是「特殊」API 級別,則大寫名稱為正規名稱 (例如 "NEXT")。

如果工具需要取得預留 API 級別 (也就是大於或等於 0x80000000 的級別) 的標準表示法,但不知道該級別的特殊名稱,就必須傳回錯誤。

特殊 API 級別

下列 API 級別有特殊名稱:

  • PLATFORM = 0xFFF00000 = 4293918720PLATFORM 會扮演先前由 LEGACY 提供的角色,也就是預設會在 API 級別 PLATFORM 建構平台。先前 LEGACY 在 FIDL 中的值為 0xFFFFFFFFFFFFFFFF,無法以 Clang 表示。

    LEGACY 已由 RFC-0232 淘汰,目前正在從 FIDL 中移除,但即使這項工作完成後,平台建構、C++ 和 Rust 程式碼仍會使用 PLATFORM 偵測一般平台建構。

    PLATFORM 僅適用於 OS 建構和 IDK 部分使用的程式碼。在這種程式庫中,目標 API 級別低於 PLATFORM 表示程式碼是 SDK 的一部分,只能使用建構目標 API 級別中提供的 API 元素。如果目標 API 級別等於 PLATFORM,則程式碼會建構為 OS 的一部分,且必須支援「支援」或「淘汰」階段的所有 API 級別。詳情請參閱 RFC-0239

  • HEAD = 0xFFE00000 = 4292870144。先前,HEAD 在 FIDL 中具有 0xFFFFFFFFFFFFFFFE 值,在 Clang 中則具有 0xFFFFFFFF 值。

  • NEXT = 0xFFD00000 = 4291821568NEXTRFC-0239 中有所說明,但未獲派數值。

這組字串可能會視需要隨著時間增加或減少。

一開始,這些值會以硬式編碼方式寫入支援指定 HEADNEXT 的 SDK,但最終應在 //sdk/version_history.json 中定義。

整數與字串的使用時機

指令列工具會接受輸入內容,並以字串形式產生輸出內容,因此應接受上述任何 API 級別的字串表示法,並優先使用標準字串形式輸出 API 級別。不過,有時這並不可行或非常不方便,因此不一定要使用標準字串形式。舉例來說,Clang 不知道特殊 Fuchsia API 級別的名稱,因此 -ffuchsia-api-level 的值必須以整數形式提供。

在建構工具的實作中,建議以整數形式儲存 API 級別。

建構系統可能會以最適合該建構系統的方式表示 API 級別。

效能

這項異動對成效應不會造成影響。

回溯相容性

嚴格來說,LEGACYHEAD 的數值變化並不具備回溯相容性。不過,先前的 64 位元值實際上只會在 fidlc 中使用,對於 Fuchsia SDK 使用者而言,基本上是看不到的。

理論上,SDK 使用者可以看到 C++ 程式碼中 HEAD 的目前定義 0xFFFFFFFF,但由於 Fuchsia 來源樹狀結構以外的程式碼目前不會指定 HEADLEGACY,因此這項變更應該不會引起注意。LSC 預先提交會確認這點。

我們選擇了 PLATFORM (先前為 LEGACY)、HEADNEXT 的新值,確保這些值之間有顯著的差距。這樣一來,我們就能建立額外的特殊 API 級別,不必重新定義現有級別。我們建立的任何這類新 API 級別,都應新增至兩個相鄰 API 級別的中間。最糟的情況是,我們最多可將每個間隔細分為 20 個間隔。

安全性考量

這項異動不會影響安全性。

隱私權注意事項

這項異動不會影響隱私權。

測試

這項 RFC 主要與 Fuchsia 建構系統和 SDK 中的程式碼有關。無論好壞,該程式碼的專屬自動測試作業都很少。不過,在實務上,如果建構系統發生問題,測試失敗、建構作業中斷,以及本機開發流程出錯時,很快就會發現。

說明文件

NEXTHEADPLATFORM 的意義和值將納入 RFC-0239 概念的後續說明文件中。

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

缺點:32 位元是否足夠?

如果依序分配,即使我們每小時發布一個新的 API 級別,用完這份 RFC 中預留的 231 個 API 級別,也需要大約 245,000 年。這應該夠用了。

不過,API 級別不一定需要密集分配。這項 RFC 定義了 3 個特殊 API 級別,每個級別之間有 1048576 個未使用的 API 級別。這樣可以嗎?

有了 64 位元 API 級別,即使我們分配的級別非常稀疏 (例如在連續版本之間留下數千、數百萬或數十億個間隙,如同 Clang 處理 VersionTuple 的方式),也很難想像會用完級別。

如果是 32 位元 API 級別,我們就必須更謹慎地分配。

我冒著成為歷史笑柄的風險,在此大膽預言:232 個 API 級別應該就足夠了。

替代方案:改用 Major.Minor 結構

VersionTuple.h 顯然是根據功能可能會在 12.5 或甚至 30.1.2.3 這類版本中導入或移除的假設所編寫。以這種方式建構版本的平台最多可表示 21251 個不同版本。或許 Fuchsia 只能使用 232 個值,表示 Fuchsia 的版本控管機制不適當?

許多成功的平台都會使用單一整數為 API 介面設定版本 (例如 Chromium 和 Android)。我們沒有理由相信,採用相同策略不會成功。


  1. Clang 會使用 minorsubminorbuild 的最高有效位元做為旗標。