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 中所定义。
这说明了两个问题:
- 有“clang API 级别”和“FIDL API 级别”,它们通常具有不同的值。
- API 级别有时表示为字符串,有时表示为整数。
clang 与 FIDL 与... ?
RFC-0002 将 API 级别定义为 64 位整数,后续的 RFC 分配了特定的 64 位整数,并为其指定了名称和含义。例如,LEGACY
由 0xFFFFFFFFFFFFFFFF
标识。但根据上面的代码,我们将改为将 0xFFFFFFFF
传递给 Clang,因为遗憾的是,Clang 中的 API 级别仅限于 32 位。
这并不完全正确。
Clang 通过 availability
属性推断兼容性,该属性将版本表示为 VersionTuple
。VersionTuple
会将一个四个整数 major[.minor[.subminor[.build]]]
的元组(表示版本)打包到一个 128 位结构中。在此结构中,Fuchsia API 级别被建模为“主要版本”,因此仅限于 32 位。
Clang 是 Fuchsia 平台版本控制流程的关键部分,因此必须解决此不一致性问题。
string
与 int
与... ?
主机工具和 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 级别 N
和 N <= 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 = 4293918720
。PLATFORM
会发挥之前由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 = 4291821568
。RFC-0239 中介绍了NEXT
,但未为其分配数字值。
此集合可能会随着时间的推移按需增加或缩减。
最初,这些值将硬编码到支持定位到 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 级别都应添加在相邻两个 API 级别的中间位置。在最糟糕的情况下,我们将能够将每个时间间隔细分 20 次。
安全注意事项
此更改应该不会对安全性产生影响。
隐私注意事项
这项变更应该不会对隐私造成影响。
测试
此 RFC 主要涉及 Fuchsia 的构建系统和 SDK 中的代码。无论好坏,对该代码的专用自动化测试都很少。不过,在实践中,如果构建系统出现故障,那么当测试失败、构建中断以及本地开发流程混乱时,我们会很快发现这一点。
文档
NEXT
、HEAD
和 PLATFORM
的含义和值将在 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)。我们没有充分的理由认为自己也无法通过采用相同的策略取得成功。
-
Clang 会将
minor
、subminor
和build
的每个最有意义的位用作标志。 ↩