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 位整数,并为其指定了名称和含义。例如,LEGACY0xFFFFFFFFFFFFFFFF 标识。但根据上面的代码,我们将改为将 0xFFFFFFFF 传递给 Clang,因为遗憾的是,Clang 中的 API 级别仅限于 32 位。

这并不完全正确。

Clang 通过 availability 属性推断兼容性,该属性将版本表示为 VersionTupleVersionTuple 会将一个四个整数 major[.minor[.subminor[.build]]] 的元组(表示版本)打包到一个 128 位结构中。在此结构中,Fuchsia API 级别被建模为“主要版本”,因此仅限于 32 位。

Clang 是 Fuchsia 平台版本控制流程的关键部分,因此必须解决此不一致性问题。

stringint 与... ?

主机工具和 build 系统在用于表示 API 级别的类型方面不一致。即使在 fuchsia.git 的构建系统中,也存在不一致性,如上面的代码块所示。

这并不一定是个问题,而且本 RFC 也无法完全解决此问题。不过,它会尝试提供相关指导,帮助您应对这种模糊性。

利益相关方

主持人:abarth@google.com

Reviewers:

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

咨询了

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

社交

与平台版本控制工作组和工具链团队的成员讨论了 Google 内部 bug

要求

API 级别必须可表示为字符串,包括在命令行和文件和目录的名称中。

API 级别必须是完全有序的,因此我们可以这样说:“Foo 在 API 级别 NN <= M 中添加,因此 Foo 属于 API 级别 M。”

我们必须能够为某些 API 级别分配特殊名称和行为。本节中的其他要求也适用于这些“特殊”API 级别。

设计

整数表示法

API 级别将重新定义为无符号 32 位整数。

此空间的下半部分(即低于 0x80000000 的 API 级别)被视为“正常”API 级别。此空间的上半部分已被预留。本 RFC 和未来的 RFC 将定义大于或等于 0x80000000 的特定值的含义。

对所有 API 级别采用统一处理方式的工具可能会忽略“正常”值和预留值之间的区别,并将它们都视为无符号 32 位整数,并按典型方式对其进行排序。

针对特定 API 级别具有特殊逻辑的工具应拒绝指定其不理解的预留 ABI 级别值的输入。

字符串表示法

API 级别可以通过字符串以多种不同的方式表示:

  • 表示 [0, 232) 范围内的十进制数的任何 UTF-8 字符串都是 API 级别的字符串表示法(例如 "7")。
  • 特殊 API 级别可以用其名称表示,名称应采用大写形式(例如 "HEAD")。
  • 工具不应接受 "0016""0x20" 等更深奥的值,因为这样可能会造成歧义。例如,"0016" 是采用八进制还是十进制?"2A" 可能是十六进制,但如果接受十六进制,"29" 是十六进制还是十进制?不过,字符串解析逻辑通常由超出单个工具作者控制的库处理,因此工具可能会接受此类值。

每个 API 级别都有唯一的规范字符串表示法

  • 对于“正常”API 级别,十进制 UTF-8 字符串表示法是规范的(例如 "13")。
  • 对于“特殊”API 级别,规范名称为大写名称(例如 "NEXT")。

如果需要了解 API 级别的规范字符串表示形式的工具需要获取未知特殊名称的预留 API 级别(即大于或等于 0x80000000 的级别)的规范表示形式,则必须返回错误。

特殊 API 级别

以下 API 级别具有特殊名称:

  • PLATFORM = 0xFFF00000 = 4293918720PLATFORM 会发挥之前由 LEGACY 提供的角色,即默认情况下,平台将在 API 级别 PLATFORM 构建。以前,LEGACY 在 FIDL 中的值为 0xFFFFFFFFFFFFFFFF,无法在 Clang 中表示。

    RFC-0232 已废弃 LEGACY,并且正在从 FIDL 中移除该功能,但即使完成这项工作,平台 build、C++ 和 Rust 代码仍会使用 PLATFORM 检测正常的平台 build。

    PLATFORM 仅适用于同时在操作系统 build 和 IDK 中使用的代码。在这种库中,目标 API 级别低于 PLATFORM 意味着代码是作为 SDK 的一部分构建的,并且只能使用 build 定位到的特定 API 级别中提供的 API 元素。如果目标 API 级别等于 PLATFORM,则代码将作为操作系统的一部分进行构建,并且必须支持处于“受支持”或“弃用”阶段的所有 API 级别。如需了解详情,请参阅 RFC-0239

  • HEAD = 0xFFE00000 = 4292870144。以前,HEAD 在 FIDL 中的值为 0xFFFFFFFFFFFFFFFE,在 Clang 中的值为 0xFFFFFFFF

  • NEXT = 0xFFD00000 = 4291821568RFC-0239 中介绍了 NEXT,但未为其分配数字值。

此集合可能会随着时间的推移按需增加或缩减。

最初,这些值将硬编码到支持定位到 HEADNEXT 的 SDK 中,但最终应在 //sdk/version_history.json 中定义这些值。

何时使用整数与字符串

命令行工具接受输入并以字符串的形式生成输出,因此,它们应接受上述 API 级别的任何字符串表示法,并且应优先使用规范字符串形式输出 API 级别。不过,有时这并不可行或非常不方便,因此不需要使用规范字符串形式。例如,Clang 不知道特殊 Fuchsia API 级别的名称,因此必须以整数的形式提供 -ffuchsia-api-level 的值。

在构建工具的实现中,最好以整数形式存储 API 级别。

构建系统可以采用对该构建系统最自然的方式表示 API 级别。

性能

这项更改应该不会对性能产生任何影响。

向后兼容性

严格来说,LEGACYHEAD 的数值变化不向后兼容。不过,之前的 64 位值实际上只在 fidlc 中使用,对 Fuchsia SDK 用户来说基本上不可见。

在 C++ 代码中将 HEAD 定义为 0xFFFFFFFF 的当前定义在理论上对 SDK 用户是可见的,但由于 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 级别,每个 API 级别之间有 1048576 个未使用的 API 级别。这样可以吗?

对于 64 位 API 级别,很难想象会耗尽 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 的每个最有意义的位用作标志。