Android-NTP时间同步机制
最近收到一个需求,要求屏蔽原生时间同步设置系统时间的地方,换成广播把时间发送给中间件(这个也是捣鼓了很久)。在完成这个需求之后,后面测试反馈有个bug说是时间回溯了,看了下log发现是连接网络后,重启设备,从开机到回连设备花了大概一分多钟的才同步时间。先是叫负责网络同事帮忙看了下,发现网络是正常连接而且也是有网的。刚好通过这个bug再加深下ntp时间同步机制(因为是Android14,跟之前的版本改动也是比较大)
老规矩我们就按代码的调用顺序来说,直接就从监听到有网络开始吧(梦开始的地方),有网络之后就会调用onPollNetworkTime
\android14\frameworks\base\services\core\java\com\android\server\timedetector\NetworkTimeUpdateService.java
onPollNetworkTime
// All callbacks will be invoked using mHandler because of how the callback is registered.
private class NetworkConnectivityCallback extends ConnectivityManager.NetworkCallback {
@Override
public void onAvailable(@NonNull Network network) {
Log.d(TAG, String.format("New default network %s; checking time.", network));
synchronized (mLock) {
mDefaultNetwork = network;
}
// Running on mHandler so invoke directly.
Log.i(TAG, "wukexiang--network available");
onPollNetworkTime("network available");
}
@Override
public void onLost(@NonNull Network network) {
synchronized (mLock) {
if (network.equals(mDefaultNetwork)) {
mDefaultNetwork = null;
}
}
}
}
private void onPollNetworkTime(@NonNull String reason) {
Network network;
synchronized (mLock) {
network = mDefaultNetwork;
}
mWakeLock.acquire();
try {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired");
mEngine.refreshAndRescheduleIfRequired(network, reason, mRefreshCallbacks);
} finally {
mWakeLock.release();
}
}
refreshAndRescheduleIfRequired
然后就到了最关键的refreshAndRescheduleIfRequired,这个函数也是很复杂,我们一步一步来看
@Override
public void refreshAndRescheduleIfRequired(
@Nullable Network network, @NonNull String reason,
@NonNull RefreshCallbacks refreshCallbacks) {
//Log.i("wukexiang", Log.getStackTraceString(new Throwable()));
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired in ");
//没有网络,对时就是无米之谈。如果 network 为空,直接退出,等待下一次网络可用信号触发
if (network == null) {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired network == null ");
// If we don't have any default network, don't do anything: When a new network
// is available then this method will be called again.
logToDebugAndDumpsys("refreshIfRequiredAndReschedule:"
+ " reason=" + reason
+ ": No default network available. No refresh attempted and no next"
+ " attempt scheduled.");
return;
}
// Step 1: Work out if the latest time result, if any, needs to be refreshed and handle
// the refresh.
// A refresh should be attempted if there is no latest time result, or if the latest
// time result is considered too old.
//查缓存:看看本地有没有之前存好的时间(initialTimeResult)。
//2. 算年龄:当前时间减去上次对时时间,得到 timeResultAgeMillis。
//3. 做决定:如果时间太老了(超过了 24 小时的 mNormalPollingIntervalMillis),并且允许刷新(没被频繁请求限制),那么 shouldAttemptRefresh 就为 true。
NtpTrustedTime.TimeResult initialTimeResult = mNtpTrustedTime.getCachedTimeResult();
boolean shouldAttemptRefresh;
synchronized (this) {
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
// calculateTimeResultAgeMillis() safely handles a null initialTimeResult.
long timeResultAgeMillis = calculateTimeResultAgeMillis(
initialTimeResult, currentElapsedRealtimeMillis);
shouldAttemptRefresh =
timeResultAgeMillis >= mNormalPollingIntervalMillis
&& isRefreshAllowed(currentElapsedRealtimeMillis);
}
boolean refreshSuccessful = false;
if (shouldAttemptRefresh) {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired shouldAttemptRefresh " + shouldAttemptRefresh);
// This is a blocking call. Deliberately invoked without holding the "this" monitor
// to avoid blocking other logic that wants to use the "this" monitor, e.g. dump().
//这是一个阻塞操作,它会真正去请求 ntp 时间,这里先按下不表
refreshSuccessful = tryRefresh(network);
}
synchronized (this) {
// This section of code deliberately doesn't assume it is the only component using
// the NtpTrustedTime singleton to obtain NTP times: another component in the same
// process could be gathering NTP signals (which then won't have been suggested to
// the time detector).
// TODO(b/222295093): Make this class the sole user of the NtpTrustedTime singleton
// and simplify / reduce duplicate suggestions and other logic.
NtpTrustedTime.TimeResult latestTimeResult = mNtpTrustedTime.getCachedTimeResult();
// currentElapsedRealtimeMillis is used to evaluate ages and refresh scheduling
// below. Capturing this after obtaining the cached time result ensures that latest
// time result ages will be >= 0.
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
long latestTimeResultAgeMillis = calculateTimeResultAgeMillis(
latestTimeResult, currentElapsedRealtimeMillis);
// Step 2: Set mTryAgainCounter.
// + == 0: The last attempt was successful OR the latest time result is acceptable
// OR the mTryAgainCounter exceeded mTryAgainTimesMax and has been reset
// to 0. In all these cases the normal refresh interval should be used.
// + > 0: The last refresh attempt was unsuccessful. Some number of retries are
// allowed using the short interval depending on mTryAgainTimesMax.
//mTryAgainCounter(重试计数器) 是关键。
//• 如果对时失败(比如 DNS 解析不到),计数器变成 1。
//• 只要计数器大于 0,后面就会选择“短间隔模式”
if (shouldAttemptRefresh) {
if (refreshSuccessful) {
mTryAgainCounter = 0;
} else {
if (mTryAgainTimesMax < 0) {
// When mTryAgainTimesMax is negative there's no enforced maximum and
// short intervals should be used until a successful refresh. Setting
// mTryAgainCounter to 1 is sufficient for the interval calculations
// below, i.e. there's no need to increment.
mTryAgainCounter = 1;
} else {
mTryAgainCounter++;
if (mTryAgainCounter > mTryAgainTimesMax) {
mTryAgainCounter = 0;
}
}
}
}
if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
// The latest time result may indicate a successful refresh has been achieved by
// another user of the NtpTrustedTime singleton. This could be an "else if", but
// this is deliberately done defensively in all cases to maintain the invariant
// that mTryAgainCounter will be 0 if the latest time result is currently ok.
mTryAgainCounter = 0;
}
// Step 3: Suggest the latest time result to the time detector if it is fresh
// regardless of whether a refresh happened / succeeded above. The time detector
// service can detect duplicate suggestions and not do more work than it has to, so
// there is no need to avoid making duplicate suggestions.
//即使刚才 tryRefresh 失败了(比如 DNS 报错),但如果 mNtpTrustedTime 缓存里还有一个 1 小时前成功的旧时间,系统认为这个旧时间也比本地那个乱跳的硬件时钟准。• 于是它会调用 makeNetworkTimeSuggestion,把这个“次优解”推给 TimeDetectorService。
if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired makeNetworkTimeSuggestion ");
makeNetworkTimeSuggestion(latestTimeResult, reason, refreshCallbacks);
}
// Step 4: (Re)schedule the next refresh attempt based on the latest state.
// Determine which refresh attempt delay to use by using the current value of
// mTryAgainCounter.
// 如果前面判断计数器大于 0,这里就会选择“短间隔模式”,然后用两个分支来决定下次更新时间的具体时间戳(nextRefreshElapsedRealtimeMillis)
long refreshAttemptDelayMillis = mTryAgainCounter > 0
? mShortPollingIntervalMillis : mNormalPollingIntervalMillis;
// The refresh attempt delay is applied to a different point in time depending on
// whether a refresh attempt is overdue to ensure the refresh attempt scheduling
// acts correctly / safely, i.e. won't schedule actions for immediate execution or
// in the past.
long nextRefreshElapsedRealtimeMillis;
//当前时间依然有效,比如你刚对时成功,或者别人刚更新了缓存。系统会基于那个成功的时间点加上间隔。
if (latestTimeResultAgeMillis < refreshAttemptDelayMillis) {
// The latestTimeResultAgeMillis and refreshAttemptDelayMillis indicate a
// refresh attempt is not yet due. This branch uses the elapsed realtime of the
// latest time result to calculate when the latest time result will become too
// old and the next refresh attempt will be due.
//
// Possibilities:
// + A refresh was attempted and successful, mTryAgainCounter will be set
// to 0, refreshAttemptDelayMillis == mNormalPollingIntervalMillis, and this
// branch will execute.
// + No refresh was attempted, but something else refreshed the latest time
// result held by the NtpTrustedTime.
//
// If a refresh was attempted but was unsuccessful, latestTimeResultAgeMillis >=
// mNormalPollingIntervalMillis (because otherwise it wouldn't be attempted),
// this branch won't be executed, and the one below will be instead.
nextRefreshElapsedRealtimeMillis =
latestTimeResult.getElapsedRealtimeMillis() + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network latestTimeResultAgeMillis < " + latestTimeResult.getElapsedRealtimeMillis()+ "---" + refreshAttemptDelayMillis);
} else if (mLastRefreshAttemptElapsedRealtimeMillis != null) {
//当前时间无效或已过期,当你第一次失败时,mTryAgainCounter 变为了 1,refreshAttemptDelayMillis 变为了 60 秒。
//• 系统会计算:上次尝试的时间 + 60秒。这个60s就是在config配置文件中的<integer name="config_ntpPollingIntervalShorter">60000</integer>,默认为60s
//• 拦截逻辑:即使你在第 10 秒又调用了这个函数(因为网络又可用了),这个函数依然会计算出相同的 nextRefreshElapsedRealtimeMillis。它发现“下一次排班”还没到,所以就不会再次触发 tryRefresh。
// This branch is executed when the latest time result is missing, or it's older
// than refreshAttemptDelayMillis. There may already have been attempts to
// refresh the network time that have failed, so the important point for this
// branch is not how old the latest time result is, but when the last refresh
// attempt took place:
// + If a refresh was just attempted (and failed), then
// mLastRefreshAttemptElapsedRealtimeMillis will be close to
// currentElapsedRealtimeMillis.
// + If a refresh was not just attempted, for a refresh not to have been
// attempted EITHER:
// + The latest time result must be < mNormalPollingIntervalMillis ago
// (would be handled by the branch above)
// + A refresh wasn't allowed because {time since last refresh attempt}
// < mShortPollingIntervalMillis, so
// (mLastRefreshAttemptElapsedRealtimeMillis + refreshAttemptDelayMillis)
// would have to be in the future regardless of the
// refreshAttemptDelayMillis value. This ignores the execution time
// between the "current time" used to work out whether a refresh needed to
// happen, and "current time" used to compute the last time result age,
// but a single short interval shouldn't matter.
nextRefreshElapsedRealtimeMillis =
mLastRefreshAttemptElapsedRealtimeMillis + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null " + mLastRefreshAttemptElapsedRealtimeMillis + "---" + refreshAttemptDelayMillis);
} else {
// This branch should never execute: mLastRefreshAttemptElapsedRealtimeMillis
// should always be non-null because a refresh should always be attempted at
// least once above. Regardelss, the calculation below should result in safe
// scheduling behavior.
String logMsg = "mLastRefreshAttemptElapsedRealtimeMillis unexpectedly missing."
+ " Scheduling using currentElapsedRealtimeMillis";
Log.w(TAG, logMsg);
logToDebugAndDumpsys(logMsg);
nextRefreshElapsedRealtimeMillis =
currentElapsedRealtimeMillis + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis else " + currentElapsedRealtimeMillis + "---" + refreshAttemptDelayMillis);
}
// Defensive coding to guard against bad scheduling / logic errors above: Try to
// ensure that alarms aren't scheduled in the past.
if (nextRefreshElapsedRealtimeMillis <= currentElapsedRealtimeMillis) {
String logMsg = "nextRefreshElapsedRealtimeMillis is a time in the past."
+ " Scheduling using currentElapsedRealtimeMillis instead";
Log.w(TAG, logMsg);
logToDebugAndDumpsys(logMsg);
nextRefreshElapsedRealtimeMillis =
currentElapsedRealtimeMillis + refreshAttemptDelayMillis;
}
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh " + reason + network + nextRefreshElapsedRealtimeMillis);
//最后在这里是再次刷新的回调
refreshCallbacks.scheduleNextRefresh(nextRefreshElapsedRealtimeMillis);
logToDebugAndDumpsys("refreshIfRequiredAndReschedule:"
+ " network=" + network
+ ", reason=" + reason
+ ", initialTimeResult=" + initialTimeResult
+ ", shouldAttemptRefresh=" + shouldAttemptRefresh
+ ", refreshSuccessful=" + refreshSuccessful
+ ", currentElapsedRealtimeMillis="
+ formatElapsedRealtimeMillis(currentElapsedRealtimeMillis)
+ ", latestTimeResult=" + latestTimeResult
+ ", mTryAgainCounter=" + mTryAgainCounter
+ ", refreshAttemptDelayMillis=" + refreshAttemptDelayMillis
+ ", nextRefreshElapsedRealtimeMillis="
+ formatElapsedRealtimeMillis(nextRefreshElapsedRealtimeMillis));
}
}
makeNetworkTimeSuggestion
上面我们讲到,如果请求ntp时间成功,获取到最新的数据,就会调用makeNetworkTimeSuggestion这个函数来上报
/**
* Suggests the network time to the time detector. It may choose use it to set the system
* clock.
*/
private void makeNetworkTimeSuggestion(@NonNull TimeResult timeResult,
@NonNull String debugInfo, @NonNull RefreshCallbacks refreshCallbacks) {
UnixEpochTime timeSignal = new UnixEpochTime(
timeResult.getElapsedRealtimeMillis(), timeResult.getTimeMillis());
NetworkTimeSuggestion timeSuggestion =
new NetworkTimeSuggestion(timeSignal, timeResult.getUncertaintyMillis());
timeSuggestion.addDebugInfo(debugInfo);
timeSuggestion.addDebugInfo(timeResult.toString());
refreshCallbacks.submitSuggestion(timeSuggestion);
}
submitSuggestion
这里就也调用refreshCallbacks的回调来进行上报,跟上面的下次刷新回调是一个对象
mRefreshCallbacks = new Engine.RefreshCallbacks() {
@Override
public void scheduleNextRefresh(@ElapsedRealtimeLong long elapsedRealtimeMillis) {
alarmManager.cancel(pendingPollIntent);
alarmManager.set(
AlarmManager.ELAPSED_REALTIME, elapsedRealtimeMillis, pendingPollIntent);
}
@Override
public void submitSuggestion(NetworkTimeSuggestion suggestion) {
Log.i(TAG, "wukexiang--submitSuggestion suggestNetworkTime");
timeDetectorInternal.suggestNetworkTime(suggestion);
}
};
suggestNetworkTime
再到\android14\frameworks\base\services\core\java\com\android\server\timedetector\TimeDetectorInternalImpl.java
@Override
public void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
Objects.requireNonNull(suggestion);
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(suggestion));
}
suggestNetworkTime
再到\android14\frameworks\base\services\core\java\com\android\server\timedetector\TimeDetectorStrategyImpl.java
@Override
public synchronized void suggestNetworkTime(@NonNull NetworkTimeSuggestion suggestion) {
Log.i(LOG_TAG, "wukexiang--TimeDetectorStrategyImpl suggestNetworkTime");
ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
if (DBG) {
Slog.d(LOG_TAG, "Network suggestion received."
+ " currentUserConfig=" + currentUserConfig
+ " suggestion=" + suggestion);
}
Objects.requireNonNull(suggestion);
if (!validateAutoSuggestionTime(suggestion.getUnixEpochTime(), suggestion)) {
return;
}
// The caller submits suggestions with the best available information when there are network
// changes. The best available information may have been cached and if they were all stored
// this would lead to duplicates showing up in the suggestion history. The suggestions may
// be made for different reasons but there is not a significant benefit to storing the same
// suggestion information again. doAutoTimeDetection() should still be called: this ensures
// the suggestion and device state are always re-evaluated, which might produce a different
// detected time if, for example, the age of all suggestions are considered.
NetworkTimeSuggestion lastNetworkSuggestion = mLastNetworkSuggestion.get();
if (lastNetworkSuggestion == null || !lastNetworkSuggestion.equals(suggestion)) {
mLastNetworkSuggestion.set(suggestion);
notifyNetworkTimeUpdateListenersAsynchronously();
}
// Now perform auto time detection. The new suggestion may be used to modify the system
// clock.
String reason = "New network time suggested. suggestion=" + suggestion;
Log.i(LOG_TAG, "wukexiang--TimeDetectorStrategyImpl doAutoTimeDetection" + reason);
doAutoTimeDetection(reason);
}
doAutoTimeDetection
最后就走到这个doAutoTimeDetection这里,他会根据不同的reason来执行对应的逻辑
@GuardedBy("this")
private void doAutoTimeDetection(@NonNull String detectionReason) {
Log.i("wukexiang", Log.getStackTraceString(new Throwable()));
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection");
// Try the different origins one at a time.
int[] originPriorities = mCurrentConfigurationInternal.getAutoOriginPriorities();
for (int origin : originPriorities) {
UnixEpochTime newUnixEpochTime = null;
String cause = null;
if (origin == ORIGIN_TELEPHONY) {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection origin == ORIGIN_TELEPHONY");
TelephonyTimeSuggestion bestTelephonySuggestion = findBestTelephonySuggestion();
if (bestTelephonySuggestion != null) {
newUnixEpochTime = bestTelephonySuggestion.getUnixEpochTime();
cause = "Found good telephony suggestion."
+ ", bestTelephonySuggestion=" + bestTelephonySuggestion
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_NETWORK) {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection origin == ORIGIN_NETWORK");
NetworkTimeSuggestion networkSuggestion = findLatestValidNetworkSuggestion();
if (networkSuggestion != null) {
newUnixEpochTime = networkSuggestion.getUnixEpochTime();
cause = "Found good network suggestion."
+ ", networkSuggestion=" + networkSuggestion
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_GNSS) {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection origin == ORIGIN_GNSS");
GnssTimeSuggestion gnssSuggestion = findLatestValidGnssSuggestion();
if (gnssSuggestion != null) {
newUnixEpochTime = gnssSuggestion.getUnixEpochTime();
cause = "Found good gnss suggestion."
+ ", gnssSuggestion=" + gnssSuggestion
+ ", detectionReason=" + detectionReason;
}
} else if (origin == ORIGIN_EXTERNAL) {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection origin == ORIGIN_EXTERNAL");
ExternalTimeSuggestion externalSuggestion = findLatestValidExternalSuggestion();
if (externalSuggestion != null) {
newUnixEpochTime = externalSuggestion.getUnixEpochTime();
cause = "Found good external suggestion."
+ ", externalSuggestion=" + externalSuggestion
+ ", detectionReason=" + detectionReason;
}
} else {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection Unknown or unsupported origin=" + origin);
Slog.w(LOG_TAG, "Unknown or unsupported origin=" + origin
+ " in " + Arrays.toString(originPriorities)
+ ": Skipping");
}
// Update the system clock if a good suggestion has been found.
if (newUnixEpochTime != null) {
if (mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection setSystemClockAndConfidenceIfRequired");
setSystemClockAndConfidenceIfRequired(origin, newUnixEpochTime, cause);
} else {
// An automatically detected time can be used to raise the confidence in the
// current time even if the device is set to only allow user input for the time
// itself.
Log.i(LOG_TAG, "wukexiang--doAutoTimeDetection upgradeSystemClockConfidenceIfRequired");
upgradeSystemClockConfidenceIfRequired(newUnixEpochTime, cause);
}
return;
}
}
if (DBG) {
Slog.d(LOG_TAG, "Could not determine time: No suggestion found in"
+ " originPriorities=" + Arrays.toString(originPriorities)
+ ", detectionReason=" + detectionReason);
}
}
setSystemClockAndConfidenceIfRequired
再到setSystemClockAndConfidenceIfRequired
@GuardedBy("this")
private boolean setSystemClockAndConfidenceIfRequired(
@Origin int origin, @NonNull UnixEpochTime time, @NonNull String cause) {
// Any time set through this class is inherently high confidence. Either it came directly
// from a user, or it was detected automatically.
@TimeConfidence final int newTimeConfidence = TIME_CONFIDENCE_HIGH;
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
if (!mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
if (DBG) {
Slog.d(LOG_TAG,
"Auto time detection is not enabled / no confidence update is needed."
+ " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
return false;
}
} else {
if (mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
if (DBG) {
Slog.d(LOG_TAG, "Auto time detection is enabled."
+ " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
}
return false;
}
}
mEnvironment.acquireWakeLock();
try {
return setSystemClockAndConfidenceUnderWakeLock(origin, time, newTimeConfidence, cause);
} finally {
mEnvironment.releaseWakeLock();
}
}
setSystemClockAndConfidenceUnderWakeLock
再到setSystemClockAndConfidenceUnderWakeLock,到这里就是真正的设置系统时间了setSystemClock,感兴趣的话也可以看看他每个步骤都做了什么操作,我们这里就不展开讲了
@GuardedBy("this")
private boolean setSystemClockAndConfidenceUnderWakeLock(
@Origin int origin, @NonNull UnixEpochTime newTime,
@TimeConfidence int newTimeConfidence, @NonNull String cause) {
long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
boolean isOriginAutomatic = isOriginAutomatic(origin);
long actualSystemClockMillis = mEnvironment.systemClockMillis();
if (isOriginAutomatic) {
// CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
// may be setting the clock.
if (mLastAutoSystemClockTimeSet != null) {
long expectedTimeMillis = mLastAutoSystemClockTimeSet.at(elapsedRealtimeMillis)
.getUnixEpochTimeMillis();
long absSystemClockDifference =
Math.abs(expectedTimeMillis - actualSystemClockMillis);
if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
Slog.w(LOG_TAG,
"System clock has not tracked elapsed real time clock. A clock may"
+ " be inaccurate or something unexpectedly set the system"
+ " clock."
+ " origin=" + originToString(origin)
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " expectedTimeMillis=" + expectedTimeMillis
+ " actualTimeMillis=" + actualSystemClockMillis
+ " cause=" + cause);
}
}
}
// If the new signal would make sufficient difference to the system clock or mean a change
// in confidence then system state must be updated.
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = newTime.at(elapsedRealtimeMillis).getUnixEpochTimeMillis();
long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
long systemClockUpdateThreshold =
mCurrentConfigurationInternal.getSystemClockUpdateThresholdMillis();
boolean updateSystemClockRequired = absTimeDifference >= systemClockUpdateThreshold;
@TimeConfidence int currentTimeConfidence = mEnvironment.systemClockConfidence();
boolean updateConfidenceRequired = newTimeConfidence != currentTimeConfidence;
if (updateSystemClockRequired) {
String logMsg = "Set system clock & confidence."
+ " origin=" + originToString(origin)
+ " newTime=" + newTime
+ " newTimeConfidence=" + newTimeConfidence
+ " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ " newSystemClockMillis=" + newSystemClockMillis
+ " currentTimeConfidence=" + currentTimeConfidence;
// if (origin == ORIGIN_NETWORK) {
// sendNtpTimeBroadcast(newSystemClockMillis,"updateSystemClockRequired");
// }
//在这里来真正的设置系统时间,最后的最后就是调用底层的那个set来设置系统时间
mEnvironment.setSystemClock(newSystemClockMillis, newTimeConfidence, logMsg);
if (DBG) {
Slog.d(LOG_TAG, logMsg);
}
// CLOCK_PARANOIA : Record the last time this class set the system clock due to an
// auto-time signal, or clear the record it is being done manually.
if (isOriginAutomatic(origin)) {
mLastAutoSystemClockTimeSet = newTime;
} else {
mLastAutoSystemClockTimeSet = null;
}
} else if (updateConfidenceRequired) {
// Only the confidence needs updating. This path is separate from a system clock update
// to deliberately avoid touching the system clock's value when it's not needed. Doing
// so could introduce inaccuracies or cause unnecessary wear in RTC hardware or
// associated storage.
String logMsg = "Set system clock confidence."
+ " origin=" + originToString(origin)
+ " newTime=" + newTime
+ " newTimeConfidence=" + newTimeConfidence
+ " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ " newSystemClockMillis=" + newSystemClockMillis
+ " currentTimeConfidence=" + currentTimeConfidence;
if (DBG) {
Slog.d(LOG_TAG, logMsg);
}
mEnvironment.setSystemClockConfidence(newTimeConfidence, logMsg);
} else {
// Neither clock nor confidence need updating.
// if (origin == ORIGIN_NETWORK) {
// sendNtpTimeBroadcast(newSystemClockMillis,"clock no need updating");
// }
if (DBG) {
Slog.d(LOG_TAG, "Not setting system clock or confidence."
+ " origin=" + originToString(origin)
+ " newTime=" + newTime
+ " newTimeConfidence=" + newTimeConfidence
+ " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ " absTimeDifference=" + absTimeDifference
+ " currentTimeConfidence=" + currentTimeConfidence);
}
}
return true;
}
Ntp时间同步流程就差不多了,然后我们再回到bug,重启回连居然要一分多钟才完成校准时间,我先是看了ntp相关打印,发现是每隔5秒就请求一次ntp,前几次是失败的,初步判断是ntp时间请求失败导致。那就看看是不是请求ntp时间链路的问题,找到这个SntpClient然后加上调用栈看看
Line 128673: 03-14 11:33:11.739 940 1296 I ntp_failure: [ntp.ntsc.ac.cn/113.141.164.38,java.net.SocketTimeoutException: Poll timed out]
Line 149674: 03-14 11:33:16.818 940 1296 I ntp_failure: [ntp.ntsc.ac.cn/1.82.219.234,java.net.SocketTimeoutException: Poll timed out]
Line 169835: 03-14 11:33:21.831 940 1296 I ntp_failure: [ntp.ntsc.ac.cn/113.141.164.39,java.net.SocketTimeoutException: Poll timed out]
Line 188564: 03-14 11:33:26.877 940 2143 I ntp_failure: [ntp.ntsc.ac.cn/113.141.164.38,java.net.SocketTimeoutException: Poll timed out]
Line 188665: 03-14 11:33:27.002 940 2143 I ntp_success: [ntp.ntsc.ac.cn/1.82.219.234,121,278123347]
03-14 11:33:27.002 940 2143 D SntpClient: round trip: 121ms, clock offset: 278123347ms
从log分析,在01:55:23.280网络就已经就绪了,但是在ntp请求的时候就抛出了异常,Unknown host,那就再看看SntpClient逻辑
03-21 01:55:13.298 1140 1140 I time_detector: wukexiang--doAutoTimeDetection
03-21 01:55:13.298 1140 1140 I time_detector: wukexiang--doAutoTimeDetection origin == ORIGIN_TELEPHONY
03-21 01:55:13.298 1140 1140 I time_detector: wukexiang--doAutoTimeDetection origin == ORIGIN_NETWORK
03-21 01:55:13.298 1140 1140 I time_detector: wukexiang--doAutoTimeDetection origin == ORIGIN_GNSS
03-21 01:55:13.857 1140 1140 I NetworkTimeUpdateService: wukexiang--mShortPollingIntervalMillis 60000
03-21 01:55:23.280 1140 1388 I NetworkTimeUpdateService: wukexiang--network available
03-21 01:55:23.284 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired
03-21 01:55:23.284 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired in
03-21 01:55:23.284 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired shouldAttemptRefresh true
03-21 01:55:23.486 1140 1388 I wukexiang: java.lang.Throwable
03-21 01:55:23.486 1140 1388 I wukexiang: at android.net.SntpClient.requestTime(SntpClient.java:126)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.util.NtpTrustedTime$NtpTrustedTimeImpl.queryNtpServer(NtpTrustedTime.java:705)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.util.NtpTrustedTime.forceRefreshLocked(NtpTrustedTime.java:341)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.util.NtpTrustedTime.forceRefresh(NtpTrustedTime.java:273)
03-21 01:55:23.486 1140 1388 I wukexiang: at com.android.server.timedetector.NetworkTimeUpdateService$EngineImpl.tryRefresh(NetworkTimeUpdateService.java:674)
03-21 01:55:23.486 1140 1388 I wukexiang: at com.android.server.timedetector.NetworkTimeUpdateService$EngineImpl.refreshAndRescheduleIfRequired(NetworkTimeUpdateService.java:479)
03-21 01:55:23.486 1140 1388 I wukexiang: at com.android.server.timedetector.NetworkTimeUpdateService.onPollNetworkTime(NetworkTimeUpdateService.java:215)
03-21 01:55:23.486 1140 1388 I wukexiang: at com.android.server.timedetector.NetworkTimeUpdateService.-$$Nest$monPollNetworkTime(NetworkTimeUpdateService.java:0)
03-21 01:55:23.486 1140 1388 I wukexiang: at com.android.server.timedetector.NetworkTimeUpdateService$NetworkConnectivityCallback.onAvailable(NetworkTimeUpdateService.java:249)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.net.ConnectivityManager$NetworkCallback.onAvailable(ConnectivityManager.java:3954)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.net.ConnectivityManager$NetworkCallback.onAvailable(ConnectivityManager.java:3936)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.net.ConnectivityManager$CallbackHandler.handleMessage(ConnectivityManager.java:4263)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.os.Handler.dispatchMessage(Handler.java:106)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.os.Looper.loopOnce(Looper.java:205)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.os.Looper.loop(Looper.java:294)
03-21 01:55:23.486 1140 1388 I wukexiang: at android.os.HandlerThread.run(HandlerThread.java:67)
03-21 01:55:43.590 1140 1388 W wukexiang-SntpClient: wukexiang-Unknown host: ntp.aliyun.com5000
03-21 01:55:43.591 1140 1388 D wukexiang-SntpClient: wukexiang-request time failed
03-21 01:55:43.593 1140 1388 I NetworkTimeUpdateService: wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null 35356---60000
03-21 01:55:43.593 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh network available10395356
03-21 01:55:43.597 1140 1388 I NetworkTimeUpdateService: wukexiang--network available
03-21 01:55:43.600 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired
03-21 01:55:43.600 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired in
03-21 01:55:43.600 1140 1388 I NetworkTimeUpdateService: wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null 35356---60000
03-21 01:55:43.601 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh network available10695356
03-21 01:55:43.623 1140 1388 I NetworkTimeUpdateService: wukexiang--network available
03-21 01:55:43.625 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired
03-21 01:55:43.625 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired in
03-21 01:55:43.626 1140 1388 I NetworkTimeUpdateService: wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null 35356---60000
03-21 01:55:43.627 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh network available10395356
03-21 01:55:50.725 1140 1388 I NetworkTimeUpdateService: wukexiang--network available
03-21 01:55:50.726 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired
03-21 01:55:50.726 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired in
03-21 01:55:50.727 1140 1388 I NetworkTimeUpdateService: wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null 35356---60000
03-21 01:55:50.727 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh network available10795356
03-21 01:55:51.541 1140 5570 I wukexiang: java.lang.Throwable
03-21 01:55:51.541 1140 5570 I wukexiang: at android.net.SntpClient.requestTime(SntpClient.java:126)
03-21 01:55:51.541 1140 5570 I wukexiang: at android.util.NtpTrustedTime$NtpTrustedTimeImpl.queryNtpServer(NtpTrustedTime.java:705)
03-21 01:55:51.541 1140 5570 I wukexiang: at android.util.NtpTrustedTime.forceRefreshLocked(NtpTrustedTime.java:341)
03-21 01:55:51.541 1140 5570 I wukexiang: at android.util.NtpTrustedTime.forceRefresh(NtpTrustedTime.java:264)
03-21 01:55:51.541 1140 5570 I wukexiang: at com.android.server.location.gnss.NtpNetworkTimeHelper.blockingGetNtpTimeAndInject(NtpNetworkTimeHelper.java:185)
03-21 01:55:51.541 1140 5570 I wukexiang: at com.android.server.location.gnss.NtpNetworkTimeHelper.$r8$lambda$Prd1O8ovcWG64n9K2U2sS7gDDm0(NtpNetworkTimeHelper.java:0)
03-21 01:55:51.541 1140 5570 I wukexiang: at com.android.server.location.gnss.NtpNetworkTimeHelper$$ExternalSyntheticLambda0.run(R8$$SyntheticClass:0)
03-21 01:55:51.541 1140 5570 I wukexiang: at java.lang.Thread.run(Thread.java:1012)
03-21 01:55:51.732 1140 5570 D wukexiang-SntpClient: round trip: 70ms, clock offset: 927343513ms
03-21 01:56:31.714 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired
03-21 01:56:31.714 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired in
03-21 01:56:31.714 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired makeNetworkTimeSuggestion
03-21 01:56:31.714 1140 1388 I NetworkTimeUpdateService: wukexiang--submitSuggestion suggestNetworkTime
03-21 01:56:31.715 1140 1388 I NetworkTimeUpdateService: wukexiang--network latestTimeResultAgeMillis < 63752---64800000
03-21 01:56:31.715 1140 1182 I time_detector: wukexiang--TimeDetectorStrategyImpl suggestNetworkTime
03-21 01:56:31.715 1140 1388 I NetworkTimeUpdateService: wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh scheduled refresh10764863752
03-21 01:56:31.715 1140 1182 I time_detector: wukexiang--TimeDetectorStrategyImpl doAutoTimeDetectionNew network time suggested. suggestion=NetworkTimeSuggestion{mUnixEpochTime=UnixEpochTime{mElapsedRealtimeMillis=63752, mUnixEpochTimeMillis=1774956695192}, mUncertaintyMillis=35, mDebugInfo=[scheduled refresh, TimeResult{unixEpochTime=2026-03-31T11:31:35.192Z, elapsedRealtime=PT1M3.752S, mUncertaintyMillis=35, mNtpServerSocketAddress=ntp.aliyun.com/203.107.6.88:123}]}
03-21 01:56:31.715 1140 1182 I wukexiang: java.lang.Throwable
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.timedetector.TimeDetectorStrategyImpl.doAutoTimeDetection(TimeDetectorStrategyImpl.java:712)
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.timedetector.TimeDetectorStrategyImpl.suggestNetworkTime(TimeDetectorStrategyImpl.java:330)
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.timedetector.TimeDetectorInternalImpl.lambda$suggestNetworkTime$0(TimeDetectorInternalImpl.java:87)
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.timedetector.TimeDetectorInternalImpl.$r8$lambda$i_bY-cYaOWr1U99VfGrEI33C7n4(TimeDetectorInternalImpl.java:0)
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.timedetector.TimeDetectorInternalImpl$$ExternalSyntheticLambda1.run(R8$$SyntheticClass:0)
03-21 01:56:31.715 1140 1182 I wukexiang: at android.os.Handler.handleCallback(Handler.java:958)
03-21 01:56:31.715 1140 1182 I wukexiang: at android.os.Handler.dispatchMessage(Handler.java:99)
03-21 01:56:31.715 1140 1182 I wukexiang: at android.os.Looper.loopOnce(Looper.java:205)
03-21 01:56:31.715 1140 1182 I wukexiang: at android.os.Looper.loop(Looper.java:294)
03-21 01:56:31.715 1140 1182 I wukexiang: at android.os.HandlerThread.run(HandlerThread.java:67)
03-21 01:56:31.715 1140 1182 I wukexiang: at com.android.server.ServiceThread.run(ServiceThread.java:46)
03-21 01:56:31.715 1140 1182 I time_detector: wukexiang--doAutoTimeDetection
03-21 01:56:31.716 1140 1182 I time_detector: wukexiang--doAutoTimeDetection origin == ORIGIN_TELEPHONY
03-21 01:56:31.716 1140 1182 I time_detector: wukexiang--doAutoTimeDetection origin == ORIGIN_NETWORK
03-21 01:56:31.716 1140 1182 I time_detector: wukexiang--doAutoTimeDetection setSystemClockAndConfidenceIfRequired
\android14\frameworks\base\core\java\android\net\SntpClient.java
那我们来看看这个请求时间是怎么请求的,他是在需要解析DNS可能没有就绪导致解析不了地址,抛出异常。我也通过更换服务器,把原生的ntp.ntsc.ac.cn国家官方服务器改成阿里云的ntp.aliyun.com,结果也是一样会失败,排除服务器原因。我们再把这个timeout打出来确实也是5000ms,也就是5s来请求和log日志上一致,再经过几次的请求之后,后面也是成功获取到ntp时间。排除这里的原因,根本原因应该在后面流程
/**
* Sends an SNTP request to the given host and processes the response.
*
* @param host host name of the server.
* @param port port of the server.
* @param timeout network timeout in milliseconds. the timeout doesn't include the DNS lookup
* time, and it applies to each individual query to the resolved addresses of
* the NTP server.
* @param network network over which to send the request.
* @return true if the transaction was successful.
*/
public boolean requestTime(String host, int port, int timeout, Network network) {
Log.i("wukexiang", Log.getStackTraceString(new Throwable()));
final Network networkForResolv = network.getPrivateDnsBypassingCopy();
try {
final InetAddress[] addresses = networkForResolv.getAllByName(host);
for (int i = 0; i < addresses.length; i++) {
if (requestTime(addresses[i], port, timeout, networkForResolv)) {
return true;
}
}
} catch (UnknownHostException e) {
Log.w(TAG, "wukexiang-Unknown host: " + host + timeout);
EventLogTags.writeNtpFailure(host, e.toString());
}
if (DBG) Log.d(TAG, "wukexiang-request time failed");
return false;
}
上面日志里显示01:55:51.732时候我们ntp时间已经获取成功,应该直接往上报才对,但是并没有继续走刷新时间流程。我们在日志中打印中看到,应该是卡在刷新流程那了,把之前的refreshAndRescheduleIfRequired流程精简化看下,就知道原因了。关键点在于如果refreshSuccessful失败了,他就会走mTryAgainCounter重试计数器的流程, mTryAgainCounter置为1,refreshAttemptDelayMillis这个就会从24小时和mShortPollingIntervalMillis中选择短的这个,这个mShortPollingIntervalMillis我已经在日志中打印出来,正是60000ms也就是一分钟,到这里情况就很明朗了,再继续往下看。后面的逻辑就是判断如果你过来几秒网络又可以了,执行到这的时候,依旧会拦截,下次刷新的时间依旧是你之前的时间延时60s之后,再次刷新。
//查缓存:看看本地有没有之前存好的时间(initialTimeResult)。
//2. 算年龄:当前时间减去上次对时时间,得到 timeResultAgeMillis。
//3. 做决定:如果时间太老了(超过了 24 小时的 mNormalPollingIntervalMillis),并且允许刷新(没被频繁请求限制),那么 shouldAttemptRefresh 就为 true。
NtpTrustedTime.TimeResult initialTimeResult = mNtpTrustedTime.getCachedTimeResult();
boolean shouldAttemptRefresh;
synchronized (this) {
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
// calculateTimeResultAgeMillis() safely handles a null initialTimeResult.
long timeResultAgeMillis = calculateTimeResultAgeMillis(
initialTimeResult, currentElapsedRealtimeMillis);
shouldAttemptRefresh =
timeResultAgeMillis >= mNormalPollingIntervalMillis
&& isRefreshAllowed(currentElapsedRealtimeMillis);
}
boolean refreshSuccessful = false;
if (shouldAttemptRefresh) {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired shouldAttemptRefresh " + shouldAttemptRefres
//这是一个阻塞操作,它会真正去请求 ntp 时间,这里先按下不表
refreshSuccessful = tryRefresh(network);
}
synchronized (this) {
NtpTrustedTime.TimeResult latestTimeResult = mNtpTrustedTime.getCachedTimeResult()
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
long latestTimeResultAgeMillis = calculateTimeResultAgeMillis(
latestTimeResult, currentElapsedRealtimeMillis);
//mTryAgainCounter(重试计数器) 是关键。
//• 如果对时失败(比如 DNS 解析不到),计数器变成 1。
//• 只要计数器大于 0,后面就会选择“短间隔模式”
if (shouldAttemptRefresh) {
if (refreshSuccessful) {
mTryAgainCounter = 0;
} else {
if (mTryAgainTimesMax < 0) {
mTryAgainCounter = 1;
} else {
mTryAgainCounter++;
if (mTryAgainCounter > mTryAgainTimesMax) {
mTryAgainCounter = 0;
}
}
}
}
if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
mTryAgainCounter = 0;
}
//即使刚才 tryRefresh 失败了(比如 DNS 报错),但如果 mNtpTrustedTime 缓存里还有一个 1 小时前成功的旧时间,系统认为这个旧时间也比本地那个乱跳的硬件时钟准。• 于是它会调用 makeNetworkTimeSuggestion,把这个“次优解”推给 TimeDetectorService。
if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired makeNetworkTimeSuggestion ");
makeNetworkTimeSuggestion(latestTimeResult, reason, refreshCallbacks);
}
// 如果前面判断计数器大于 0,这里就会选择“短间隔模式”,然后用两个分支来决定下次更新时间的具体时间戳(nextRefreshElapsedRealtimeMillis)
long refreshAttemptDelayMillis = mTryAgainCounter > 0
? mShortPollingIntervalMillis : mNormalPollingIntervalMillis;
long nextRefreshElapsedRealtimeMillis;
//当前时间依然有效,比如你刚对时成功,或者别人刚更新了缓存。系统会基于那个成功的时间点加上间隔。
if (latestTimeResultAgeMillis < refreshAttemptDelayMillis) {
nextRefreshElapsedRealtimeMillis =
latestTimeResult.getElapsedRealtimeMillis() + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network latestTimeResultAgeMillis < " + latestTimeResult.getElapsedRealtimeMillis()+ "---" + refreshAttemptDelayMillis);
} else if (mLastRefreshAttemptElapsedRealtimeMillis != null) {
//当前时间无效或已过期,当你第一次失败时,mTryAgainCounter 变为了 1,refreshAttemptDelayMillis 变为了 60 秒。
//• 系统会计算:上次尝试的时间 + 60秒。这个60s就是在config配置文件中的<integer name="config_ntpPollingIntervalShorter">60000</integer>,默认为60s
//• 拦截逻辑:即使你在第 10 秒又调用了这个函数(因为网络又可用了),这个函数依然会计算出相同的 nextRefreshElapsedRealtimeMillis。它发现“下一次排班”还没到,所以就不会再次触发 tryRefresh。
nextRefreshElapsedRealtimeMillis =
mLastRefreshAttemptElapsedRealtimeMillis + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis != null " + mLastRefreshAttemptElapsedRealtimeMillis + "---" + refreshAttemptDelayMillis);
} else {
String logMsg = "mLastRefreshAttemptElapsedRealtimeMillis unexpectedly missing."
+ " Scheduling using currentElapsedRealtimeMillis";
Log.w(TAG, logMsg);
logToDebugAndDumpsys(logMsg);
nextRefreshElapsedRealtimeMillis =
currentElapsedRealtimeMillis + refreshAttemptDelayMillis;
Log.i(TAG, "wukexiang--network mLastRefreshAttemptElapsedRealtimeMillis else " + currentElapsedRealtimeMillis + "---" + refreshAttemptDelayMillis);
}
if (nextRefreshElapsedRealtimeMillis <= currentElapsedRealtimeMillis) {
String logMsg = "nextRefreshElapsedRealtimeMillis is a time in the past."
+ " Scheduling using currentElapsedRealtimeMillis instead";
Log.w(TAG, logMsg);
logToDebugAndDumpsys(logMsg);
nextRefreshElapsedRealtimeMillis =
currentElapsedRealtimeMillis + refreshAttemptDelayMillis;
}
Log.i(TAG, "wukexiang--network refreshAndRescheduleIfRequired refreshCallbacks.scheduleNextRefresh " + reason + network + nextRefreshElapsedRealtimeMillis);
//最后在这里是再次刷新的回调
refreshCallbacks.scheduleNextRefresh(nextRefreshElapsedRealtimeMillis);
}
}
根据日志我们也可以看出。那么问题来了,这个60000ms是在哪设置的呢,我们全局搜索了下,可以得出是在配置文件里配置的,可以看到那个ntpTimeout也是在这设置的,那我们把60s改成10s就可以了,在网上搜索看到也有人改成8s
core/res/res/values/config.xml: <string-array translatable="false" name="config_ntpServers">
core/res/res/values/config.xml: <integer name="config_ntpTimeout">5000</integer>
core/res/res/values/config.xml: <integer name="config_ntpPollingInterval">64800000</integer>
core/res/res/values/config.xml: <integer name="config_ntpPollingIntervalShorter">60000</integer>
core/res/res/values/config.xml: <integer name="config_ntpRetry">3</integer>
core/res/res/values/symbols.xml: <java-symbol type="integer" name="config_ntpPollingInterval" />
core/res/res/values/symbols.xml: <java-symbol type="integer" name="config_ntpPollingIntervalShorter" />
core/res/res/values/symbols.xml: <java-symbol type="integer" name="config_ntpRetry" />
core/res/res/values/symbols.xml: <java-symbol type="integer" name="config_ntpTimeout" />
core/res/res/values/symbols.xml: <java-symbol type="array" name="config_ntpServers" />
core/java/android/util/NtpTrustedTime.java: res.getStringArray(com.android.internal.R.array.config_ntpServers);
core/java/android/util/NtpTrustedTime.java: res.getInteger(com.android.internal.R.integer.config_ntpTimeout);