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
对阵... ?
主机工具和构建系统在用于表示 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 位整数。
此空间的下半部分(即低于 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 = 4293918720
。PLATFORM
发挥之前由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 = 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 级别,每个级别之间包含 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 进行版本控制。我们有充分的理由相信,即使遵循相同的策略,我们也不可能取得成功。
-
Clang 使用
minor
、subminor
和build
的最高有效位作为标记。↩