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

嗯,事实并非完全正确。

Clang 通过 availability 属性(将版本表示为 VersionTuple)确定兼容性。VersionTuple 将表示版本的四个整数 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 内部 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 内的基数为 10 的数字的 UTF-8 字符串都是 API 级别的字符串表示形式(例如 "7")。
  • 特殊 API 级别可以用其名称表示,其名称采用大写形式(例如 "HEAD")。
  • 工具不应接受 "0016""0x20" 等更深奥的值,因为这样做会产生歧义。例如,"0016" 是八进制还是十进制?"2A" 可能是十六进制,但如果能被这样接受,那么 "29" 是十六进制还是十进制?不过,字符串解析逻辑通常由各个工具作者无法控制的库处理,因此工具可以接受这些值。

每个 API 级别只有一个规范字符串表示形式

  • 对于“常规”API 级别,以 10 为基准的 UTF-8 字符串表示法就是规范格式(例如 "13")。
  • 对于“特殊”API 级别,大写名称是规范名称(例如 "NEXT")。

需要知道某个 API 级别的规范字符串表示法的工具如果需要获取预留的 API 级别(即大于或等于 0x80000000 的级别)的规范表示法,但不知道其特殊名称,则必须返回错误。

特殊 API 级别

以下 API 级别有特殊名称:

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

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

    PLATFORM 仅适用于同时在 OS 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 级别,每个级别之间包含 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 的版本控制方案不合适?

有多个成功的平台(例如 Chromium 和 Android)都使用单个整数来对其 API Surface 进行版本控制。我们有充分的理由相信,即使遵循相同的策略,我们也不可能取得成功。


  1. Clang 使用 minorsubminorbuild 的最高有效位作为标记。