-
问题描述:
在日期和时间中开启自动设置,时间不变,并没有同步到网络时间。 -
问题查找:
开始以为是系统默认的ntp服务器有问题,查看后发现使用的是阿里云的NTP服务器ntp2.aliyun.com
,我在设备内pin了一下,也是通的。
然后,查看打印日志,发现报了request time failed: Unable to resolve host "ntp2.aliyun.com" No address associated with hostname
的错误,这个是因为通过域名获取地址时报的错。
通过查询源码,发现报错地方是在SntpClient.java
的requestTime
方法中,当address = network.getByName(host);
捕获到的异常。跟踪SntpClient.java的调用路径:
//java层
NetWork.getByName
InetAddress.getByNameOnNet
(Network.java)
Inet6AddressImpl.lookupAllHostAddr
lookupHostByName
//native层
Libcore.os.android_getaddrinfo
Linux_android_getaddrinfo
(libcore_io_Linux.cpp)
android_getaddrinfofornet
getaddrinfo
android_getaddrinfofornetcontext
(getaddrinfo.c)
android_getaddrinfo_proxy
getaddrinfo
后的流程,已有博客做了分析Android libc中dns部分源码分析。而且根据错误打印,可以知道对应的是EAI_NODATA
,所以可以顺藤摸瓜去发现主要是在android_getaddrinfo_proxy中,而android_getaddrinfo_proxy是跟netd调用有关。
- 解決方式:
因为network.getByName(host)
中调用的是InetAddress.getByNameOnNet
方法,该方法是基于给定的网络获取域名,第二个参数netid的值可以影响DNS请求包从哪个网卡出去。
所以,刚开始觉得可能是ip6导致的,因此关闭了ip6的网络,发现没啥效果。可能是其他网卡影响的(我们这里有vpn),不过没有再尝试了。
最后,就先通过代码优化一下,直接使用InetAddress.getByName
方法再次解析一遍。
try {
address = network.getByName(host);
} catch (Exception e) {
if (e.getMessage() != null
&& e.getMessage().endsWith("No address associated with hostname")) {
Log.d(TAG, "first request time failed: " + e);
address = InetAddress.getByName(host);
}
if (null == address || null == address.getHostAddress()) {
throw e;
}
}
- 总结
总的来说问题是解决了,基本原因也大概了解,通过netid对应的网卡发送请求去获取ip信息失败造成的,InetAddress.getByName中使用的netid和network.getByName使用的netid可能是不一样的(未检测)引起的
但是,因为没有很深入很深入的去研究,如果有机会,再完善吧。