Chrome OS在国内时间同步问题分析

最近在使用我的三星 ARM Chromebook 的时候发现一个问题就是这款 Chromebook 在锁定或者待机后电还是会慢慢的跑,如果待机之前电池电量本来就不多了,那再开机时很可能出现电池电量耗尽导致需要插电源重新开机的现象。接着就发现每次开机之后系统时间却不对,这对于 Chrome OS 这款基本一切皆通过网络同步的操作系统还是很意外的,而且我在 Chrome OS 系统设置中确认过网络时间同步也是开启的。

Chromebook 重新开机之后进入时间设置可以看到这样的报错信息:

Chromebook无法设置系统时间错误

之前遇到这种情况我都是傻傻的再设置下系统时间,最近准备专门看下系统时间不能正确同步的原因。

目前用户最常用的时间同步方法一般是通过广域网上的 NTP 时间服务器进行(Linux 下对应 ntpdate 命令),另一种是直接通过连接 HTTPS(TLS)服务器获取时间戳来同步时间(Linux 下对应 tlsdate 命令),这种方式相比 NTP 协议的主要优势就是更加安全了(NTP 协议可是诞生于上个世纪八九十年代的,协议本身没有任何加密认证之类的处理),另外还有一种是通过 HTTP 协议连接 Web 服务器时间来同步时间(对应 htpdate 命令,这个也算是非常通用了,具体见我之前的一篇博文 [树莓派上使用htpdate同步时间])。

Chrome OS 默认使用的就是 TLS 方式进行时间同步,这个可以通过登录到 Chrome OS Linux Shell 中查看运行进程进行确认:

chronos@localhost / $ ps ax | grep tlsdate | grep -v grep
13799 ?        S      0:00 tlsdated -v -- /usr/bin/tlsdate -v -C /usr/share/chromeos-ca-certificates -l
13800 ?        S      0:00 logger -t tlsdate
13801 ?        S      0:00 tlsdated -v -- /usr/bin/tlsdate -v -C /usr/share/chromeos-ca-certificates -l

可以看到 Chrome OS 自带的 tlsdated 服务运行 tlsdate 程序进行时间同步,查看 tlsdate 的日志文件 /var/log/tlsdate.log 检查为什么会时间同步出错:

chronos@localhost / $ cat /var/log/tlsdate.log
2015-11-10T01:55:05.881307+08:00 NOTICE tlsdate[3050]: V: tlsdate version 0.0.5
2015-11-10T01:55:05.881395+08:00 NOTICE tlsdate[3050]: V: We were called with the following arguments:
2015-11-10T01:55:05.881445+08:00 NOTICE tlsdate[3050]: V: validate SSL certificates host = clients3.google.com:443
2015-11-10T01:55:05.888424+08:00 NOTICE tlsdate[3050]: V: time is currently 1447091705.888190273
2015-11-10T01:55:05.888485+08:00 NOTICE tlsdate[3050]: V: time is greater than RECENT_COMPILE_DATE
2015-11-10T01:55:05.895243+08:00 NOTICE tlsdate[3050]: V: using TLSv1_client_method()
2015-11-10T01:55:05.896043+08:00 NOTICE tlsdate[3050]: V: opening socket to clients3.google.com:443
2015-11-10T01:55:08.881106+08:00 INFO tlsdated[3049]: [event:action_tlsdate_timeout] tlsdate timed out
2015-11-10T01:55:08.881361+08:00 NOTICE tlsdate[3050]: [event:action_tlsdate_timeout] tlsdate timed out
2015-11-10T01:55:08.883912+08:00 INFO tlsdated[3049]: [event:handle_child_death] tlsdate reaped => pid:3841 uid:234 status:9 code:2
2015-11-10T01:55:08.884132+08:00 NOTICE tlsdate[3050]: [event:handle_child_death] tlsdate reaped => pid:3841 uid:234 status:9 code:2
2015-11-10T01:57:13.153015+08:00 NOTICE tlsdate[3050]: SSL connection failed

这下直接就明白了,tlsdate 连接 clients3.google.com HTTPS 端口进行同步,但由于众所周知的大陆 GFW 系统原罪,我们国内的 Chromebook 用户是无法同步成功的(除非已经通过 VPN 之类的进行全局翻墙了)。

解决起来也就很简单了,下面直接列出几种解决方法:

1、通过 VPN 进行全局翻墙:

这是比较方便的解决办法,直接所有流量都走 VPN 就不存在问题了,只是我不太喜欢全局翻墙的方式,会影响国内网站的访问速度;不过如果你有支持隧道分流的 Cisco AnyConnect 之类的 VPN 账户,那也完全可以用这种简单的方式;

2、修改 tlsdate 连接的服务器地址:

这种方法需要先开启 Chromebook 的开发者模式,将 tlsdate 连接的 HTTPS 服务器地址改为任何一个国内可访问的信任服务器地址,Chrome OS 下 tlsdated 服务的配置文件路径为:/etc/tlsdate/tlsdated.conf,默认内容如下:

base-path                          /var/cache/tlsdated
dry-run                            no
jitter                             0
max-tries                          10
min-steady-state-interval          86400
should-load-disk                   yes
should-netlink                     yes
should-save-disk                   yes
should-sync-hwclock                yes
steady-state-interval              86400
subprocess-tries                   10
subprocess-wait-between-tries      3
verbose                            yes
wait-between-tries                 10

# Host configuration.
source
	host clients3.google.com
	port 443
	proxy dynamic
end

# Try it without the proxy.
source
	host clients3.google.com
	port 443
	proxy none
end

修改此 tlsdated 服务配置文件需要 root 身份,切换到 root 用户后执行下面的命令可以将 Chrome OS 的根文件系统改为可写的状态(默认只读的配置文件无法修改),执行完成之后必须重启才能生效:

chronos@localhost ~ $ sudo su -
Password:
localhost ~ # cd /usr/share/vboot/bin/
localhost bin # ./make_dev_ssd.sh --remove_rootfs_verification --partitions 4
Kernel B: Disabled rootfs verification.
Backup of Kernel B is stored in: /mnt/stateful_partition/backups/kernel_B_20151110_020745.bin
Kernel B: Re-signed with developer keys successfully.
Successfully re-signed 1 of 1 kernel(s)  on device /dev/mmcblk0.

重启之后我们就可以很 happy 的将 tlsdated.conf 配置文件中默认的 clients3.google.com 改为其它服务器地址了,我是直接改为 www.net.cn 万网的主页地址,修改完成之后直接运行 restart tlsdated 命令重启 tlsdated 服务就可以马上看到效果了,Chromebook 系统时间已经正常同步过来了。

3、为 tlsdate 指定时间同步代理服务器:

相信你也看到上面的 tlsdated.conf 配置文件中的 proxy 参数了,没错 tlsdate 也直接支持通过代理服务器连接 HTTPS 服务器同步时间,如果你信不过其它的服务器,坚持要用 Google 的服务器进行时间同步,那也可以将配置文件中的 proxy 参数由 none 改为代理服务器地址,代理服务器地址的写法也比较简单,例如如果要用 Shadowsocks 的 SOCKS5 代理,则写法如下(假设 Shadowsocks 使用的本地代理端口是 8050):

socks5://127.0.0.1:8050

修改完成之后重启 tlsdated 服务不出意外也能看到起作用咯。