系统时间自举:日期范围门、GNSS 校时与信任边界

作者:

在

结论:openpilot 的系统时间自举建立在几个纯日期范围检查上:Python 侧的 system_time_valid() 用本地墙钟在固定下界 2025-02-21 与固定上界 2035-01-01 之间做严格开区间比较,若找到 systemd 可执行文件,还会把它的修改时间加一天并与下界取较大值。「有效」只表示当前日期落在区间内,不等于可信 UTC、证书有效或各传感器时钟已对齐:一台时钟在区间内但快慢数天的设备同样能通过。本文为固定源码快照 c8fb906 的静态阅读与有限隔离探针,未修改系统时钟、未连接 GNSS 或访问网络。

公共日期门:范围检查而非可信时间

MIN_DATE 与 MAX_DATE 分别为 2025-02-21 和 2035-01-01。min_date() 若发现 systemd 可执行文件,会把该文件的修改时间按本地时间加一天,再与固定下界取较大值;system_time_valid() 用本地 datetime.now() 做严格开区间比较。它没有读 NTP 同步状态、GNSS 精度、硬件 RTC 来源或 TLS 证书有效期。

一个结构性边界是:若该文件的修改时间异常地进入未来,动态下界可能高于上界,导致整个有效区间为空。四项假路径探针确认了这一族行为:没有该文件或修改时间早于固定下界时仍用 2025-02-21;较新的修改时间会把下界抬到其本地日期加一天;恰好等于动态下界或 2035-01-01 上界均判无效;修改时间晚于上界可使整个有效区间为空。

原生 C++ 侧还有一条不同的判断:它的固定下界是 2024-08-26,也考虑该文件修改时间加一天,但没有 2035 上界,安装器依赖这一路径。两端不能被当作同一个时间状态。

项目 Python 侧 C++ 侧
固定下界 2025-02-21 2024-08-26
固定上界 2035-01-01 无
动态下界 systemd 文件修改时间的本地时间加一天,与固定下界取大 同样考虑该文件修改时间加一天
加一天的算术 先转本地无时区时间,再加一个日历日 直接对 epoch 秒加 86400,即固定 24 小时

两端的「加一天」也不完全等价:在使用夏令时的本地时区且这一天跨越切换点时,两个下界可差一小时。离线以 America/New_York 的 2026-03-07 12:00 为修改时间,Python 得到次日 12:00,固定秒数得到次日 13:00;2026-10-31 12:00 则分别得到次日 12:00 与 11:00。这只验证时区算术差异,目标设备是否配置夏令时尚未验证。

timed 的 GNSS 校时链

定位服务按启动时的一个可用性参数在外部与内部定位主题之间选一个,timed.main() 创建一次订阅,不在主循环中动态切换。每轮先把当前墙钟写入时钟消息,并用上述范围判断设置外层有效位。只有所选主题本轮更新、消息单调时间距当前不超过两秒、定位有效且 GNSS 时间落在下界到上界之间,才调用校时函数;此路径没有检查所选定位消息的顶层有效位。偏差不足十秒直接跳过,更大的偏差通过系统命令设置,失败只记录异常。

六项假消息与假命令探针补充了执行顺序证据:时钟发布发生在 GNSS 门控之前,即使本地墙钟无效也可用新鲜定位尝试校时;所选定位消息的外层无效不阻断调用。定位时间戳在检查「本轮更新、新鲜度、定位有效」之前即被转成日期时间,因此假消息即使标为未更新,超出可表示范围的时间戳仍会先抛异常,使本轮不进入其余门控。此外主循环在校时函数正常返回后无条件睡十秒,未根据实际校时成功与否区分退避。

环节 实现事实 边界
订阅选择 按启动时可用性参数在两条定位主题中选一条 主循环不动态切换
新鲜度门 消息距当前单调时间不超过两秒 需定位有效且时间在范围内
校时调用 偏差超过十秒才设置系统时间 不检查定位消息顶层有效位
异常处理 设置失败只记录异常 主循环仍无条件睡十秒

启动自举与下游行为

时间门被多个网络与硬件路径复用:GNSS 相关服务仅在时间「有效」时给模组发送辅助时间,并在网络可用时才取辅助数据。另一方面 timed 又依赖 GNSS 首次有效定位来校准系统时间,所以自制硬件必须设计 RTC、NTP 或独立定位的冷启动路径,不能假设辅助时间与 GNSS 校时会自动互相解锁。

下游同样依赖这个门:eSIM 的配置下载函数先检查系统时间范围,通知上传也有同一门;更新服务在时间无效时等待再重试;UI 配对与更新路径、以及取令牌的辅助函数也依赖它。部分初始设置在证书错误且本地时间无效时会尝试重启时间同步服务。这些调用说明「日期在范围内」是业务前置条件,却不能替代 HTTPS 自身的证书验证和服务端认证。

还有两个容易混淆的语义:GNSS 时间戳被转为 UTC 后移除时区信息,再与本地时间下界比较,设备为 UTC 时一致、非 UTC 时边界会偏移;而外层有效位为真只表示当前墙钟通过了范围门,不是刚从 GNSS 成功校时。该进程也不会证明相机帧起始、IMU 中断与诊断日志时间戳已与墙钟完成共时钟标定。

硬件与插件化要求

时间服务应分别声明墙钟来源与可信级别、UTC 与闰秒、单调时钟域、观测时间戳、最后同步时间、估计误差、时钟跳变和上游服务状态。只有受信任的平台层可设置系统时间;GNSS 与网络插件应提交带来源与精度的候选时间,不能直接把范围检查当成「可信时间」,也不能自行运行系统校时命令。UI、更新与 eSIM 的网络门应区分「尚无可信时间、可信时间可用、时间失步」三种状态,避免把范围检查误认为完整安全检查。

待验证边界

尚未验证的场景包括:无 RTC 冷启动、真实镜像中该文件修改时间异常、时区非 UTC、GNSS 定位延迟或失效、NTP 与 GNSS 冲突,以及系统时间前后跳变对证书、令牌、日志与相机时序的影响。本轮未执行这些动态或实板测试。

常见问题

system_time_valid() 为真就代表时间可信吗?

不代表。它只是一个纯日期范围检查,不读 NTP 同步状态、GNSS 精度、硬件 RTC 来源或 TLS 证书有效期。一台时钟在区间内但快慢数天的设备同样能通过,因此「日期合理」不等于可信 UTC。

Python 与 C++ 的时间有效判断一致吗?

不一致。Python 侧下界为 2025-02-21、上界为 2035-01-01;C++ 侧下界为 2024-08-26 且没有上界。两端的「加一天」算术也不同:Python 先转本地无时区时间再加一个日历日,C++ 直接对 epoch 秒加 86400,跨夏令时时可差一小时。

只要 GNSS 有定位就会校准系统时间吗?

不一定。只有所选主题本轮更新、消息距当前单调时间不超过两秒、定位有效且时间落在范围内才调用校时函数;偏差不足十秒会直接跳过。而且该路径不检查定位消息的顶层有效位。

本地墙钟无效会不会阻止 GNSS 校时?

不会。探针显示时钟发布发生在 GNSS 门控之前,即使本地墙钟范围检查不通过,也可用新鲜定位尝试校时;所选定位消息的外层无效同样不阻断调用。

延伸阅读

参考资料

  • 项目 02 —— openpilot-research/SYSTEM_TIME_BOOTSTRAP_TRUST_CONTRACT_DEEP_DIVE.md(取用了公共日期门、GNSS 校时链、下游消费者与硬件插件要求)。
  • 项目 02 —— openpilot-research/NATIVE_UTIL_IO_EXIT_CONTRACT_DEEP_DIVE.md(关联的原生工具专题,用于对照 C++ 与 Python 两套日期门差异,本文未展开其 I/O 实现)。

说明:本文为对固定源码快照的静态结构分析,未运行完整测试套件、未连接硬件、未验证目标车型的真实参数组合。文中所有阈值、行号索引与配置均出自源文档,标注为未验证的结论保留其原有边界。

更新记录

首次发布 2026-10-11 最近核对:2026-10-11

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注