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 應設為 0xFFFFFFFFfidl_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 平台版本控制功能的重要部分,因此必須解決這項不一致性問題。

stringint 比較?

主機工具和建構系統在用於表示 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 級別必須完全排序,因此我們可以說:「Foo 是在 API 級別 NN <= M 時新增,因此 Foo 屬於 API 級別 M。」

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

設計

整數表示法

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

這個範圍的下半部 (也就是 API 級別低於 0x80000000) 視為「一般」API 級別。這個空間的上半部已保留,這個 RFC 和日後的 RFC 將定義大於或等於 0x80000000 的特定值的意義。

將所有 API 級別一視同仁的工具可能會忽略「正常」和保留值之間的差異,並將所有值視為未簽署的 32 位元整數,以一般方式排序。

針對特定 API 級別提供特殊邏輯的工具,應拒絕指定不瞭解的保留 ABI 級別值的輸入內容。

字串表示法

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

  • 任何代表 10 進制數的 UTF-8 字串 (範圍為 [0, 232]) 都是 API 級別的字串表示法 (例如 "7")。
  • 特殊 API 級別可用其名稱表示,且必須以大寫字母表示 (例如 "HEAD")。
  • 工具不應接受 "0016""0x20" 等較難解讀的值,因為這可能會造成模糊不清的情況。例如,"0016" 是八進位還是十進位?"2A" 可能是十六進位,但如果系統接受這個值,"29" 是十六進位還是十進位?不過,字串剖析邏輯通常由個別工具作者無法控制的程式庫處理,因此工具「可能」會接受這類值。

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

  • 對於「一般」API 級別,十進制 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 = 4291821568NEXT 已在 RFC-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 級別,都應在兩個相鄰 API 級別之間新增。在最糟的情況下,我們可以將每個間隔細分 20 次。

安全性考量

這項變更不會影響安全性。

隱私權注意事項

這項變更不會影響隱私權。

測試

這份 RFC 主要與 Fuchsia 的建構系統和 SDK 中的程式碼相關。無論好壞,對該程式碼的專屬自動化測試都很少。不過,在實際情況中,如果建構系統發生問題,系統會在測試失敗、建構作業中斷,以及本機開發流程出現異常時,很快就會察覺。

說明文件

NEXTHEADPLATFORM 的含義和值將納入 RFC-0239 中介紹的概念的即將推出的說明文件。

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

缺點:32 位元是否足夠?

如果依序分配,即使我們每小時發布一個新的 API 級別,也需要約 245,000 年才能用完此 RFC 中保留的 231 個 API 級別。這似乎就夠了。

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

使用 64 位元 API 級別時,即使我們分配的 API 級別非常稀疏 (例如,在連續版本之間保留數千、數百萬或數十億的間隔,就像 Clang 對 VersionTuple 所做的那樣),也難以想像會用完。

在 32 位元 API 級別中,我們必須更謹慎地分配資源。

我知道這樣會讓自己成為歷史笑柄,但還是要說:232 API 級別應該足以滿足所有人的需求。

替代做法:改用 Major.Minor 配置

VersionTuple.h 的編寫方式明確表明,功能可在類似 12.530.1.2.3 的版本中新增或移除。以這種方式建構版本的平台最多可代表 21251 個獨立版本。或許 Fuchsia 只能使用這些值的 232,這表示 Fuchsia 的版本命名方案不適合?

多個成功的平台都會使用單一整數來為 API 途徑命名 (例如 Chromium 和 Android)。我們沒有足夠的理由相信,我們無法透過相同的策略取得成功。


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