问题描述
不插sim卡,连接wifi启动,系统时间在2~3分钟之后才会同步到最新时间。
NITZ和NTP机制
在解决这个问题之前,让我们来学习一下NITZ和NTP的相关知识
NITZ:Network Identity and Time Zone(网络标识和时区),是一种用于自动配置本地的时间和日期的机制,需要运营商支持,可从运营商获取时间和时区具体信息。NITZ是自从PHASE 2+ RELEASE 96 的GSM中的可选功能,经常被用来自动更新移动电话的系统时钟。NITZ需要运营商网络支持(通过CS网络),目前国内电信、移动都支持NITZ方式更新时间日期,而联通目前不支持。
NTP:Network Time Protocol(网络时间协议),用来同步网络中各个计算机的时间的协议。在手机中,NTP更新时间的方式是通过GPRS或wifi向特定服务器获取时间信息(不包含时区信息)。
关于NITZ和NTP更新时间流程,建议参考博客:https://blog.youkuaiyun.com/yin1031468524/article/details/65447849
大佬的流程写的非常详细,建议大家去学习学习。
解决问题
遇事不决先抓Log,先来看看过滤ntp字段后的日志
Line 3819: 03-10 12:42:15.954 908 1079 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 3827: 03-10 12:42:15.958 908 1079 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 3829: 03-10 12:42:15.960 908 1073 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 3831: 03-10 12:42:15.967 908 1073 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 4857: 03-10 12:42:20.994 908 1224 D SntpClient: request time failed: java.net.SocketTimeoutException: Poll timed out
Line 4858: 03-10 12:42:20.995 908 1224 D NtpTrustedTime: setServer:[time.android.com]
Line 5510: 03-10 12:42:25.708 908 1072 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 5526: 03-10 12:42:25.729 908 1072 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 5527: 03-10 12:42:25.731 908 1073 W BestClock: java.time.DateTimeException: Missing NTP fix
Line 7007: 03-10 12:43:21.408 908 1224 D NetworkTimeUpdateService: Stale NTP fix; forcing refresh
Line 7008: 03-10 12:43:21.408 908 1224 D NetworkTimeUpdateService: mTryAgainCounter = 1;mNtpServers.size() = 2;index = 1;mNtpServers = asia.pool.ntp.org
Line 7009: 03-10 12:43:21.408 908 1224 D NtpTrustedTime: setServer:[asia.pool.ntp.org]
Line 7152: 03-10 12:43:21.636 908 1224 D SntpClient: round trip: 209ms, clock offset: 7919964ms
先来看看java.time.DateTimeException: Missing NTP fix这个异常,定位到代码位置
/frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
@Override
public long currentNetworkTimeMillis() {
final NtpTrustedTime time = NtpTrustedTime.getInstance(getContext());
if (time.hasCache()) {
return time.currentTimeMillis();
} else {
throw new ParcelableException(new DateTimeException("Missing NTP fix"));
}
}
接着看time.hasCache()方法
/frameworks/base/core/java/android/util/NtpTrustedTime.java
@Override
public boolean hasCache() {
return mHasCache;
}
public boolean forceRefresh(Network network) {
............
if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
final SntpClient client = new SntpClient();
if (client.requestTime(mServer, (int) mTimeout, network)) {
mHasCache = true;
mCachedNtpTime = client.getNtpTime();
mCachedNtpElapsedRealtime = client.getNtpTimeReference();
mCachedNtpCertainty = client.getRoundTripTime() / 2;
return true;
} else {
return false;
}
}
只有client.requestTime()获取时间成功,才会把mHasCache置为true,说明这些异常发生时,获取时间一直是失败的。
继续看日志:
NtpTrustedTime: setServer:[time.android.com],
设置ntp server为time.android.com之后,还是会出现Missing NTP fix的异常,获取时间失败。
再往下看日志:
NetworkTimeUpdateService: mTryAgainCounter = 1;mNtpServers.size() = 2;index = 1;mNtpServers = asia.pool.ntp.org
NtpTrustedTime: setServer:[asia.pool.ntp.org]
SntpClient: round trip: 209ms, clock offset: 7919964ms
对应到代码,在这个位置:
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
private void onPollNetworkTimeUnderWakeLock(int event) {
// Force an NTP fix when outdated
if (mTime.getCacheAge() >= mPollingIntervalMs) {
if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
//M: For multiple NTP server retry
//mTime.forceRefresh();
int index = mTryAgainCounter % mNtpServers.size();
if (DBG) Log.d(TAG, "mTryAgainCounter = " + mTryAgainCounter
+ ";mNtpServers.size() = " + mNtpServers.size()
+ ";index = " + index + ";mNtpServers = " + mNtpServers.get(index));
//轮询ntp server
if (mTime instanceof NtpTrustedTime){
((NtpTrustedTime) mTime).setServer(mNtpServers.get(index));
mTime.forceRefresh();
((NtpTrustedTime) mTime).setServer(mDefaultServer);
}
else{
mTime.forceRefresh();
}
}
if (mTime.getCacheAge() < mPollingIntervalMs) {
// Obtained fresh fix; schedule next normal update
resetAlarm(mPollingIntervalMs);
if (isAutomaticTimeRequested()) {
updateSystemClock(event);
}
} else {
// No fresh fix; schedule retry
mTryAgainCounter++;
if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
resetAlarm(mPollingIntervalShorterMs);
} else {
// Try much later
mTryAgainCounter = 0;
resetAlarm(mPollingIntervalMs);
}
}
}
onPollNetworkTimeUnderWakeLock()方法里面轮询访问ntp server获取时间。
adb shell进去设备,分别ping服务器time.android.com和asia.pool.ntp.org,前者Ping不同,后者可以ping通。
继续看代码resetAlarm()方法,发现轮训的时间间隔是60秒,和这个问题的现象对上了。
private void resetAlarm(long interval) {
mAlarmManager.cancel(mPendingPollIntent);
long now = SystemClock.elapsedRealtime();
long next = now + interval;
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
...........
mPollingIntervalShorterMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingIntervalShorter);
<!-- Remote server that can provide NTP responses. -->
<string translatable="false" name="config_ntpServer">time.android.com</string>
<!-- Try-again polling interval in milliseconds, in case the network request failed -->
<integer name="config_ntpPollingIntervalShorter">60000</integer>
修改config_ntpServer的值为2.android.pool.ntp.org,提前验证好,可以ping通。
编译framework-res.apk,push之后开机,时间更新及时,问题解决。