| RFC-0246:API 级别为 32 位 | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 将 API 级别重新定义为 32 位数字,而不是 64 位数字 |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2024-04-01 |
| 审核日期(年-月-日) | 2024-04-29 |
摘要
此提案将 API 级别的定义更改为无符号 32 位整数。此提案取代了 RFC-0002,后者将 API 级别定义为无符号 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 中所定义。
这说明了两个问题:
- 存在“clang API 级别”和“FIDL API 级别”,并且它们通常被赋予不同的值。
- API 级别有时表示为字符串,有时表示为整数。
clang 与 FIDL 与... ?
RFC-0002 将 API 级别定义为 64 位整数,后续 RFC
分配了特定的 64 位整数,并为其命名和赋予含义。例如,LEGACY 由 0xFFFFFFFFFFFFFFFF 标识。但根据上面的代码,我们将改为向 Clang 传递 0xFFFFFFFF,因为遗憾的是,在 Clang 中,API 级别仅限于 32 位。
嗯,这并不完全正确。
Clang 通过 availability
属性来推断兼容性,该属性将版本表示为
VersionTuples。VersionTuple 将包含四个整数的元组 major[.minor[.subminor[.build]]](表示一个版本)打包到 128 位结构中。Fuchsia API 级别在此结构中被建模为“主要版本”,因此仅限于 32 位。
Clang 是 Fuchsia 平台版本控制的关键部分,因此必须解决此不一致问题。
string 与 int 与... ?
主机工具和构建系统在用于表示 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 级别 N 中添加的
,并且 N <= M,因此 Foo 是 API 级别 M 的一部分。”
我们必须能够为某些 API 级别分配特殊名称和行为。本部分中的其他要求也适用于这些“特殊”API 级别。
设计
整数表示法
API 级别将被重新定义为无符号 32 位整数。
此空间的下半部分(即 API 级别小于 0x80000000)被视为“正常”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 级别(即大于或等于 0x80000000 的 API 级别)的规范表示法,但不知道其特殊名称,则必须返回错误。
特殊 API 级别
以下 API 级别被赋予特殊名称:
PLATFORM = 0xFFF00000 = 4293918720。PLATFORM扮演着之前由LEGACY扮演的角色,即默认情况下,平台将以 API 级别PLATFORM构建。之前,LEGACY在 FIDL 中的值为0xFFFFFFFFFFFFFFFF,无法在 Clang 中表示。LEGACY已被 RFC-0232 废弃,目前正在从 FIDL 中移除 ,但即使这项工作完成后,平台构建、C++ 和 Rust 代码仍将使用PLATFORM来检测正常平台构建。PLATFORM仅在操作系统构建和 IDK 中使用的代码中才有用。在此类库中,小于PLATFORM的目标 API 级别表示代码正在作为 SDK 的一部分构建,并且只能使用构建所面向的特定 API 级别中可用的 API 元素。如果目标 API 级别 等于PLATFORM,则代码正在作为操作系统的一部分构建,并且必须为“受支持”或“日落”阶段的 所有 API 级别提供支持。如需了解详情,请参阅 RFC-0239。HEAD = 0xFFE00000 = 4292870144。之前,HEAD在 FIDL 中的值为0xFFFFFFFFFFFFFFFE,在 Clang 中的值为0xFFFFFFFF。NEXT = 0xFFD00000 = 4291821568。NEXT在 RFC-0239 中描述,但 未分配数值。
此集合可能会随着时间的推移按需增大或缩小。
最初,这些值将硬编码到支持面向
HEAD 或 NEXT 的 SDK 中,但最终应在
//sdk/version_history.json中定义。
何时使用整数与字符串
命令行工具接受输入并生成字符串形式的输出,因此,它们应接受上述任何 API 级别的字符串表示法,并且应优先使用规范字符串形式输出 API 级别。
不过,有时这样做不可行或非常不方便,因此不要求使用规范字符串形式。例如,Clang 不知道特殊 Fuchsia API 级别的名称,因此 -ffuchsia-api-level 的值必须以整数形式提供。
在构建工具的实现中,最好以整数形式存储 API 级别。
构建系统可以以最适合该构建系统的方式表示 API 级别。
性能
此项更改不应影响性能。
向后兼容性
严格来说,LEGACY 和 HEAD 的数值更改不向后兼容。不过,之前的 64 位值实际上仅在 fidlc 中使用,并且对于 Fuchsia SDK 的用户来说基本上是不可见的。
目前在 C++ 代码中将 HEAD 定义为 0xFFFFFFFF 在理论上对 SDK 用户可见,但由于 Fuchsia 源代码树之外的任何代码目前都不面向 HEAD 或 LEGACY,因此这项更改也应不会被注意到。LSC 预提交将确认这一点。
之所以选择 PLATFORM(之前为 LEGACY)、HEAD 和 NEXT 的新值,是为了在它们之间提供较大的差距。这样,我们就可以创建其他特殊 API 级别,而无需重新定义现有级别。我们创建的任何此类新 API 级别都应添加到两个相邻 API 级别的中间。在最坏的情况下,我们将能够将每个区间细分为 20 个区间。
安全注意事项
此项更改不应影响安全性。
隐私注意事项
此项更改不应影响隐私。
测试
此 RFC 主要与 Fuchsia 的构建系统和 SDK 中的代码有关。无论好坏,对该代码的专用自动化测试都很少。不过,在实践中,如果构建系统出现故障,当测试失败、构建中断和本地开发流程出错时,很快就会被注意到。
文档
NEXT、HEAD 和 PLATFORM 的含义和值将包含在即将发布的有关 RFC-0239 中引入的概念的文档中。
缺点、替代方案和未知事项
缺点:32 位是否足够?
如果按顺序分配,即使我们每小时发布一个新的 API 级别,也 需要大约 245,000 年才能用完此 RFC 中预留的 231 个 API 级别。这似乎足够了。
不过,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)。没有充分的理由相信我们无法通过遵循相同的策略取得成功。
-
Clang 使用
minor、subminor和build中每个值的最高有效位作为标志。 ↩