| RFC-0008:移除 zx_clock_get 和 zx_clock_adjust | |
|---|---|
| 状态 | 已接受 |
| 区域 |
|
| 说明 | 定义了弃用然后移除 zx_clock_get 和 zx_clock_adjust 系统调用的计划。 |
| 问题 | |
| Gerrit 更改 | |
| 作者 | |
| 审核人 | |
| 提交日期(年-月-日) | 2020-10-12 |
| 审核日期(年-月-日) | 2020-10-29 |
摘要
我们建议通过以下五个步骤来弃用 zx_clock_get 和 zx_clock_adjust 系统调用,将剩余用户迁移到自 2019 年以来一直可用的替代系统调用,最后移除原始系统调用。
设计初衷
Fuchsia 目前包含两组独立的系统调用,用于与时间进行交互:
- 原始设计使用
zx_clock_get读取由内核维护的单调时钟、UTC 时钟和线程时钟,并使用zx_clock_adjust写入 UTC 时钟。此设计无法实现时钟调速、在不同产品上定义其他时钟或传达时钟状态。 - 2019 年,添加了
zx_clock_create、zx_clock_read、zx_clock_update和zx_clock_get_details系统调用,以对时钟对象执行丰富的管理,从而让用户空间定义和维护任意数量的时钟。还添加了zx_clock_get_monotonic以读取内核的单调时钟。
Fuchsia 目前定义了两个不同的 UTC 时钟:一个可使用 zx_clock_get 读取的内核 UTC 时钟,以及一个可使用 zx_clock_read 读取的用户空间 UTC 时钟。时间同步系统会尝试使这些时钟保持一致,但由于它们提供的功能不同,因此不可避免地会出现一些差异。
此提案定义了原始时间系统调用的弃用计划,完成了 2019 年开始的迁移,当时添加了替代系统调用的设计。移除这些系统调用可解决维护两种半兼容的时间管理方式所带来的持续(且不断增加)的运营和认知成本。
实现
zx_clock_get 和 zx_clock_adjust 各自接受一个 clock_id 实参,用于指定应使用三个可能的时间轴中的哪一个。最好分别考虑这三个时间段的迁移:
ZX_CLOCK_MONOTONIC- 对zx_clock_get(ZX_CLOCK_MONOTONIC)的调用可以直接替换为对zx_clock_get_monotonic的调用。此替换系统调用更易于使用,并且通常可提供更好的性能。ZX_CLOCK_THREAD- 对zx_clock_get(ZX_CLOCK_THREAD)的调用可能会被对使用主题ZX_INFO_THREAD_STATS的zx_object_get_info的调用替换。这种替换方式可提供更高的灵活性,并且更符合将线程执行时间作为线程属性的理念。ZX_CLOCK_UTC- 在 2019 年的时间系统调用中,UTC 由 Fuchsia 平台在用户空间中管理,而不是直接由内核管理。大多数语言运行时已修改为读取用户空间 UTC 时钟,因此在大多数情况下,对zx_clock_get(ZX_CLOCK_UTC)的调用应替换为语言运行时中的标准 UTC 调用。如有必要,可以使用zx_utc_reference_get函数获取只读时钟句柄,以传递给zx_clock_read。对zx_clock_adjust(ZX_CLOCK_UTC)的调用可能会被对zx_clock_update的调用所取代,后者使用从fuchsia.time.Maintenance获取的读/写时钟句柄。
我们建议您按以下五步流程移除 zx_clock_get 和 zx_clock_adjust:
- 更新文档,将系统调用标记为已弃用
- 将所有已知用户迁移到替换系统调用
- 停止维护内核 UTC 时钟并移除
zx_clock_adjust - 从 SDK 中移除了
zx_clock_get声明 - 从 Zircon 中移除了
zx_clock_get实现
第 1 步 - 更新文档,将系统调用标记为已弃用
此步骤已完成。zx_clock_get 和 zx_clock_adjust 调用已明确标记为已弃用,并且文档中包含我们上面推荐的替代解决方案。
第 2 步 - 将所有已知用户迁移到替换系统调用
此步骤正在进行中。fxr/433865 最近将标准语言运行时 UTC 函数移到了用户空间 UTC 时钟。这已移除大部分 zx_clock_get 用法,但仍有大量不同代码库中各种不同的调用点。
我们将使用代码搜索在全局集成中找到词干和花瓣的这些剩余使用情况,并使用 syscalls_zx_clock_get_type_* kcounter 来跟踪我们的进度。鉴于可用资源有限,并且将上游更改滚动到下游代码库通常需要数周或数月的时间,因此这是一个漫长的过程。
如果语言运行时提供 zx_clock_get 或 zx_clock_adjust 的封装容器(例如 Rust 中的 fuchsia_zircon::Time::get 函数),我们将移除不再有任何客户端使用的封装容器。
第 3 步 - 停止维护内核 UTC 时钟并移除 zx_clock_adjust
为了在 ZX_CLOCK_UTC 中保持准确的时间,需要从驱动程序和多个测试组件调用 zx_clock_get 和 zx_clock_adjust。在完成第 4 步后,这些调用将不再可行,因此我们不再将维护内核 UTC 作为单独的步骤。
在第 3 步中,我们将移除 ZX_CLOCK_UTC 同步,导致尝试读取 ZX_CLOCK_UTC 的任何客户端崩溃,并完全移除 zx_clock_adjust 系统调用(此系统调用仅用于设置 UTC,并且仅由少数特权客户端调用)。
完成第 2 步后,我们应该已经有很高的信心,认为全局集成中没有剩余的组件使用 UTC,但导致客户端在读取尝试时崩溃可以让我们快速检测到任何遗漏。
具体而言,我们将:
- 移除所有验证
ZX_CLOCK_UTC的测试。 - 修改
zx_clock_get(ZX_CLOCK_UTC)以将来电者标记为政策违规者。 - 从实时时钟驱动程序中移除了对
zx_clock_adjust的调用(并完全移除了后备 RTC 驱动程序,因为这是它的唯一用途) - 完全移除
zx_clock_adjust。
第 4 步 - 从 SDK 中移除 zx_clock_get 声明
在步骤 3 之后,我们可能已成功移除了头部的所有 zx_clock_get 调用,但仍需要支持依赖于 zx_clock_get 的旧版预构建二进制文件。在这种情况下,我们将在 SDK 中移除 zx_clock_get 声明,但不会移除 zircon 实现。在此阶段,任何尝试使用 zx_clock_get 编译代码的行为都会导致编译失败。
如果没有预构建的二进制文件依赖于 zx_clock_get,我们将直接进入第 5 步。
第 5 步 - 从 Zircon 中移除 zx_clock_get 实现
一旦没有预构建的二进制文件依赖于 zx_clock_get(根据其符号导入确定),我们将完全移除 zx_clock_get 以及相关文档。
性能
此提案将通过鼓励更广泛地使用更高效的 zx_clock_get_monotonic 系统调用并简化 RTC 驱动程序的运行,从而使整体系统性能得到微幅提升。
安全注意事项
此提案不会影响单调时间或线程时间管理的安全性。
在其他操作系统中,UTC 管理漏洞已被利用来执行各种回滚攻击。此提案通过提供更精细的访问权限控制,提高了管理 UTC 时间的安全性。
使用 zx_clock_adjust 系统调用时,需要根资源来更改 UTC 时间。这意味着,需要调整时间的组件也会获得强大的无关功能,并且任何具有根资源的组件都有权修改 UTC,无论它是否需要此权限。
此提案实施后,修改 UTC 的唯一方法是通过 fuchsia.utc.Maintenance 分发的读/写时钟句柄。此协议明确仅路由到需要它的组件,并且这些组件不会通过此句柄获得任何其他功能。
隐私注意事项
此提案在实施时不会影响隐私权。
此提案将允许在未来移除 UTC 时间作为环境授权(进程可以在没有用户空间 UTC 时钟句柄的情况下启动,并且不再有权访问内核 UTC 时钟)。这可能有助于提高某些类型数据处理的隐私保护程度。
测试
目前,每个时间管理系统调用以及依赖于它们的时间同步基础架构都已通过单元测试、集成测试和端到端测试覆盖。移除这两个系统调用和第二个 UTC 时钟后,这些测试会变得简单一些。
文档
文档更新已包含在上面的“实现”部分中。
缺点、替代方案和未知因素
此提案的成本很低 - 我们估计,在 1-3 个季度内,组件平台和内核团队的 2-3 名工程师每周只需花费几个小时。
替代方案主要围绕不清理或减少清理此技术债务;例如,可以停止维护内核 UTC 时钟,但不移除关联的系统调用。这些替代方案可在短期内降低成本,但从长远来看会大幅增加成本。
在先技术和参考资料
kernel_objects/clock 清楚地概述了用户空间时钟的运行情况,建议您阅读。