本页概述了 Fuchsia 上 UTC 时钟的行为。如需详细了解世界协调时间 (UTC),请参阅 UTC 概览;如需了解 Fuchsia 上提供的其他时钟,请参阅时间概览。
UTC 时间由分发给组件的内核时钟对象提供。除非在启动时向进程传递时钟句柄,否则进程无法读取 UTC 时间。由组件管理器启动的所有组件都会收到时钟的句柄。
Timekeeper通过与实时时钟 (RTC) 或通常可通过网络访问的外部来源同步来设置和维护 UTC 时钟。
与其他操作系统的区别
Fuchsia 上的 UTC 时间与大多数其他操作系统上的时间不同,因为它会强制执行后备时间。回退时间设置为 build 中包含的最新提交时间,并用作“已知”时间。Fuchsia 绝不会报告早于后备时间的时间,即使某些时间源报告的时间更早也是如此。此后备机制旨在限制攻击者操纵设备上时间的攻击。例如,此类攻击可用于强制设备接受已过期的 TLS 证书。
在首次同步 UTC 时间之前,Fuchsia 可用的唯一 UTC 时间估算值是后备时间。回退时间本身并不是可靠的时间估算值,因为在提交时间和设备启动时间之间可能会经过任何时间。为了传达这种不确定性,在首次同步之前,UTC 时钟可能不会运行,如果运行,则从固定的后备时间开始。UTC 时钟在未同步时是否可以运行是一个参数,每个 Fuchsia 产品都必须根据具体产品的要求进行设置。
总的来说,Fuchsia 上的 UTC 时钟具有以下状态。UTC 时钟从固定状态开始,并在某种运行状态下结束。
状态 | 说明 | 时钟行为 |
---|---|---|
固定 | 时间从未同步,不可靠 | 时间固定在回退点。 |
正在运行,未同步 | 时间未同步 | 时间开始倒计时,从后挡板开始。在此状态下,Fuchsia 上的 UTC 时钟的行为与其他操作系统上的时钟类似。进入此状态时,系统会使 ZX_CLOCK_STARTED 信号有效。 |
正在运行,同步 | 时间已至少同步一次 | 时间不多了。在此状态下,UTC 时钟读数会跟踪外部时间源。进入此状态时,系统会断言 ZX_USER_SIGNAL_0 。 |
属性
UTC 时钟始终具有以下属性:
- 后备时间 - 创建时钟时,后备时间设为 build 中的上次提交时间。时钟绝不会报告早于后备时间的时间。
- UTC 时钟既非单调递增,也非连续递增。由于 UTC 时间必须从外部来源同步,因此如果 Timekeeper 发现其估算的 UTC 时间与外部来源相差太远,则可能会向后跳转时间。
在 Timekeeper 首次同步时间之前,设备上可用的 UTC 时间的最佳估算值为后备时间。因此,请务必注意,在此状态下,报告的 UTC 时间可能会包含任意大小的错误。
不过,无论其读数是否与实际的 UTC 时间戳相符,时钟都可能在运行。请参阅上文中的时钟行为,通过观察 UTC 时钟句柄上的适当事件来确定 UTC 时钟状态。
时间管理器同步时间后,会设置 UTC 时钟。这可能会导致时钟读数突然跳转。从此时起,计时器将继续通过调整时钟频率以略微加快或减慢运行速度,或将时钟跳转到新时间来更新时钟。虽然不同产品和时间同步方法的精确度各不相同,但在运行后,时钟通常与实际世界协调时间相差几百毫秒。请注意,即使 RTC 和/或网络可用,UTC 时钟也可能永远无法同步,因为它必须通过不可靠的协议从不可靠的来源检索。
可观察行为
由于上述属性,您可能会观察到以下行为:
- UTC 时间的运行速度可能比单调时间快或慢几百个百万分之一 (ppm)。当 Timekeeper 以较慢或较快的速度旋转时钟以补偿振荡器误差或更正小误差时,就会发生这种情况。
- UTC 时间可能会向前或向后跳跃无限时长。如果 Timekeeper 需要更正较大的错误,就会发生这种情况。首次同步时间时,时间可能会大幅跳跃。后续向前和向后跳跃应该非常罕见,通常是由时间源错误导致的。
- UTC 时间可能未运行。这可能发生在首次同步之前。
处理非同步状态的策略
在设备启动后立即启动的组件或需要在任何网络可用之前运行的组件都可能会遇到 UTC 时钟尚未与实际 UTC 同步的情况。在极少数情况下,时间同步永远不会成功,之后启动的组件也会看到未同步的时钟。下面列出了一些示例策略:
忽略未同步状态并读取世界协调时间 (UTC)。 此策略适用于 UTC 时间不严格要求准确的情况,例如出于调试目的生成时间戳。如果已知组件在时间同步之前不会运行,此方法也适用。这种策略的缺点是,您可能会看到连续的时间戳都报告了相同的时间。
请等待 UTC 时间同步,然后再读取时钟。 此策略适用于 UTC 时间准确性至关重要的情况,例如使用 UTC 时间来验证凭据。请注意,这并不总是首选策略,因为 UTC 时间可能永远不会同步。
检查时钟属性
您可以先获取对 zircon 时钟对象的句柄,然后将句柄传递给适当的系统调用,以检查时钟属性。例如,如果您需要在读取时钟之前检查时间是否已同步,这会很有用。对于 TLS 证书验证等应用,这一点尤为重要,因为需要一些合理准确的时间来验证到期日期。
您可以使用 <zircon/utc.h>
中提供的 zx_utc_reference_get
方法检索提供给运行时的 UTC 时钟的句柄。
当时钟正在运行时,系统会断言 ZX_CLOCK_STARTED
信号。在首次同步时,系统会断言 SIGNAL_UTC_CLOCK_SYNCHRONIZED
(或等效的 ZX_SIGNAL_USER_0
)。
您可以使用以下任一方法检查或等待任一信号:
您可以使用 zx_clock_get_details
检查时钟的误差边界等详细信息。对于 UTC 时钟,误差边界定义为 95% 置信区间的一半。换句话说,对于随机选择的 Fuchsia 设备上的随机时间,UTC 的真实值在 reported_utc - error_bound
和 reported_utc + error_bound
之间的概率至少为 95%。在系统估算出 error_bound
之前,error_bound
会设为 ZX_CLOCK_UNKNOWN_ERROR
。在某些情况下,如果 Fuchsia 设备运行异常工作负载或硬件有缺陷,真实的 UTC 时间可能会超出 error_bound
定义的范围。如需详细了解如何计算误差边界,请参阅如何限制时钟误差?部分。如需详细了解 UTC 时钟,请参阅内核时钟参考文档,查看通过 zx_clock_get_details
提供的详细信息列表。
请注意,组件会被提供一个只读句柄,无法使用所提供的句柄修改时钟。
如需了解特定于语言的绑定和示例,请参阅语言支持。