Merge "Logging and readability improvements"
This commit is contained in:
@@ -358,9 +358,30 @@ public class NetworkTimeUpdateService extends Binder {
|
||||
@NonNull
|
||||
private final LocalLog mLocalDebugLog = new LocalLog(30, false /* useLocalTimestamps */);
|
||||
|
||||
/**
|
||||
* The usual interval between refresh attempts. Always used after a successful request.
|
||||
*
|
||||
* <p>The value also determines whether a network time result is considered fresh.
|
||||
* Refreshes only take place from this class when the latest time result is considered too
|
||||
* old.
|
||||
*/
|
||||
private final int mNormalPollingIntervalMillis;
|
||||
|
||||
/**
|
||||
* A shortened interval between refresh attempts used after a failure to refresh.
|
||||
* Always shorter than {@link #mNormalPollingIntervalMillis} and only used when {@link
|
||||
* #mTryAgainTimesMax} != 0.
|
||||
*/
|
||||
private final int mShortPollingIntervalMillis;
|
||||
|
||||
/**
|
||||
* The number of times {@link #mShortPollingIntervalMillis} can be used after successive
|
||||
* failures before switching back to using {@link #mNormalPollingIntervalMillis} once before
|
||||
* repeating. When this value is negative, the refresh algorithm will continue to use {@link
|
||||
* #mShortPollingIntervalMillis} until a successful refresh.
|
||||
*/
|
||||
private final int mTryAgainTimesMax;
|
||||
|
||||
private final NtpTrustedTime mNtpTrustedTime;
|
||||
|
||||
/**
|
||||
@@ -378,6 +399,11 @@ public class NetworkTimeUpdateService extends Binder {
|
||||
int normalPollingIntervalMillis, int shortPollingIntervalMillis,
|
||||
int tryAgainTimesMax, @NonNull NtpTrustedTime ntpTrustedTime) {
|
||||
mElapsedRealtimeMillisSupplier = Objects.requireNonNull(elapsedRealtimeMillisSupplier);
|
||||
if (shortPollingIntervalMillis > normalPollingIntervalMillis) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"shortPollingIntervalMillis (%s) > normalPollingIntervalMillis (%s)",
|
||||
shortPollingIntervalMillis, normalPollingIntervalMillis));
|
||||
}
|
||||
mNormalPollingIntervalMillis = normalPollingIntervalMillis;
|
||||
mShortPollingIntervalMillis = shortPollingIntervalMillis;
|
||||
mTryAgainTimesMax = tryAgainTimesMax;
|
||||
@@ -387,81 +413,121 @@ public class NetworkTimeUpdateService extends Binder {
|
||||
@Override
|
||||
public boolean forceRefreshForTests(
|
||||
@NonNull Network network, @NonNull RefreshCallbacks refreshCallbacks) {
|
||||
boolean success = mNtpTrustedTime.forceRefresh(network);
|
||||
logToDebugAndDumpsys("forceRefreshForTests: success=" + success);
|
||||
boolean refreshSuccessful = mNtpTrustedTime.forceRefresh(network);
|
||||
logToDebugAndDumpsys("forceRefreshForTests: refreshSuccessful=" + refreshSuccessful);
|
||||
|
||||
if (success) {
|
||||
if (refreshSuccessful) {
|
||||
makeNetworkTimeSuggestion(mNtpTrustedTime.getCachedTimeResult(),
|
||||
"EngineImpl.forceRefreshForTests()", refreshCallbacks);
|
||||
}
|
||||
return success;
|
||||
return refreshSuccessful;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshIfRequiredAndReschedule(
|
||||
@NonNull Network network, @NonNull String reason,
|
||||
@NonNull RefreshCallbacks refreshCallbacks) {
|
||||
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
|
||||
|
||||
final int maxNetworkTimeAgeMillis = mNormalPollingIntervalMillis;
|
||||
// Force an NTP fix when outdated
|
||||
// Attempt to refresh the network time if there is no latest time result, or if the
|
||||
// latest time result is considered too old.
|
||||
NtpTrustedTime.TimeResult initialTimeResult = mNtpTrustedTime.getCachedTimeResult();
|
||||
if (calculateTimeResultAgeMillis(initialTimeResult, currentElapsedRealtimeMillis)
|
||||
>= maxNetworkTimeAgeMillis) {
|
||||
if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh using network=" + network);
|
||||
boolean successful = mNtpTrustedTime.forceRefresh(network);
|
||||
if (successful) {
|
||||
synchronized (this) {
|
||||
mTryAgainCounter = 0;
|
||||
}
|
||||
} else {
|
||||
String logMsg = "forceRefresh() returned false:"
|
||||
+ " initialTimeResult=" + initialTimeResult
|
||||
+ ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis;
|
||||
logToDebugAndDumpsys(logMsg);
|
||||
}
|
||||
boolean shouldAttemptRefresh;
|
||||
synchronized (this) {
|
||||
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
|
||||
|
||||
// calculateTimeResultAgeMillis() safely handles a null initialTimeResult.
|
||||
long timeResultAgeMillis = calculateTimeResultAgeMillis(
|
||||
initialTimeResult, currentElapsedRealtimeMillis);
|
||||
shouldAttemptRefresh = timeResultAgeMillis >= mNormalPollingIntervalMillis;
|
||||
}
|
||||
|
||||
boolean refreshSuccessful = false;
|
||||
if (shouldAttemptRefresh) {
|
||||
// This is a blocking call. Deliberately invoked without holding the "this" monitor
|
||||
// to avoid blocking logic that wants to use the "this" monitor.
|
||||
refreshSuccessful = mNtpTrustedTime.forceRefresh(network);
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
long nextPollDelayMillis;
|
||||
NtpTrustedTime.TimeResult latestTimeResult = mNtpTrustedTime.getCachedTimeResult();
|
||||
if (calculateTimeResultAgeMillis(latestTimeResult, currentElapsedRealtimeMillis)
|
||||
< maxNetworkTimeAgeMillis) {
|
||||
// Obtained fresh fix; schedule next normal update
|
||||
nextPollDelayMillis = mNormalPollingIntervalMillis
|
||||
- latestTimeResult.getAgeMillis(currentElapsedRealtimeMillis);
|
||||
|
||||
makeNetworkTimeSuggestion(latestTimeResult, reason, refreshCallbacks);
|
||||
} else {
|
||||
// No fresh fix; schedule retry
|
||||
mTryAgainCounter++;
|
||||
if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
|
||||
nextPollDelayMillis = mShortPollingIntervalMillis;
|
||||
} else {
|
||||
// Try much later
|
||||
// Manage mTryAgainCounter.
|
||||
if (shouldAttemptRefresh) {
|
||||
if (refreshSuccessful) {
|
||||
// Reset failure tracking.
|
||||
mTryAgainCounter = 0;
|
||||
|
||||
nextPollDelayMillis = mNormalPollingIntervalMillis;
|
||||
} 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. There's no need to increment.
|
||||
mTryAgainCounter = 1;
|
||||
} else {
|
||||
mTryAgainCounter++;
|
||||
if (mTryAgainCounter > mTryAgainTimesMax) {
|
||||
mTryAgainCounter = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// currentElapsedRealtimeMillis is used to evaluate ages and refresh scheduling
|
||||
// below. Capturing this after a possible successful refresh ensures that latest
|
||||
// time result ages will be >= 0.
|
||||
long currentElapsedRealtimeMillis = mElapsedRealtimeMillisSupplier.get();
|
||||
|
||||
// This section of code deliberately doesn't assume it is the only component using
|
||||
// mNtpTrustedTime 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 owner of mNtpTrustedTime and
|
||||
// simplify / reduce duplicate suggestions.
|
||||
NtpTrustedTime.TimeResult latestTimeResult = mNtpTrustedTime.getCachedTimeResult();
|
||||
long latestTimeResultAgeMillis = calculateTimeResultAgeMillis(
|
||||
latestTimeResult, currentElapsedRealtimeMillis);
|
||||
|
||||
// Suggest the latest time result to the time detector if it is fresh regardless of
|
||||
// whether refresh happened above.
|
||||
if (latestTimeResultAgeMillis < mNormalPollingIntervalMillis) {
|
||||
// We assume the time detector service will detect duplicate suggestions and not
|
||||
// do more work than it has to, so no need to avoid making duplicate
|
||||
// suggestions.
|
||||
makeNetworkTimeSuggestion(latestTimeResult, reason, refreshCallbacks);
|
||||
}
|
||||
|
||||
// (Re)schedule the next refresh based on the latest state.
|
||||
// Determine which refresh delay to use by using the current value of
|
||||
// mTryAgainCounter.
|
||||
long refreshDelayMillis = mTryAgainCounter > 0
|
||||
? mShortPollingIntervalMillis : mNormalPollingIntervalMillis;
|
||||
// Adjust the next refresh time for the age of the latest time result.
|
||||
if (latestTimeResultAgeMillis < refreshDelayMillis) {
|
||||
refreshDelayMillis -= latestTimeResultAgeMillis;
|
||||
}
|
||||
|
||||
long nextRefreshElapsedRealtimeMillis =
|
||||
currentElapsedRealtimeMillis + nextPollDelayMillis;
|
||||
currentElapsedRealtimeMillis + refreshDelayMillis;
|
||||
refreshCallbacks.scheduleNextRefresh(nextRefreshElapsedRealtimeMillis);
|
||||
|
||||
logToDebugAndDumpsys("refreshIfRequiredAndReschedule:"
|
||||
+ " network=" + network
|
||||
+ ", reason=" + reason
|
||||
+ ", currentElapsedRealtimeMillis=" + currentElapsedRealtimeMillis
|
||||
+ ", initialTimeResult=" + initialTimeResult
|
||||
+ ", shouldAttemptRefresh=" + shouldAttemptRefresh
|
||||
+ ", refreshSuccessful=" + refreshSuccessful
|
||||
+ ", currentElapsedRealtimeMillis="
|
||||
+ formatElapsedRealtimeMillis(currentElapsedRealtimeMillis)
|
||||
+ ", latestTimeResult=" + latestTimeResult
|
||||
+ ", mTryAgainCounter=" + mTryAgainCounter
|
||||
+ ", nextPollDelayMillis=" + nextPollDelayMillis
|
||||
+ ", refreshDelayMillis=" + refreshDelayMillis
|
||||
+ ", nextRefreshElapsedRealtimeMillis="
|
||||
+ Duration.ofMillis(nextRefreshElapsedRealtimeMillis)
|
||||
+ " (" + nextRefreshElapsedRealtimeMillis + ")");
|
||||
+ formatElapsedRealtimeMillis(nextRefreshElapsedRealtimeMillis));
|
||||
}
|
||||
}
|
||||
|
||||
private static String formatElapsedRealtimeMillis(
|
||||
@ElapsedRealtimeLong long elapsedRealtimeMillis) {
|
||||
return Duration.ofMillis(elapsedRealtimeMillis) + " (" + elapsedRealtimeMillis + ")";
|
||||
}
|
||||
|
||||
private static long calculateTimeResultAgeMillis(
|
||||
@Nullable TimeResult timeResult,
|
||||
@ElapsedRealtimeLong long currentElapsedRealtimeMillis) {
|
||||
|
||||
@@ -74,10 +74,13 @@ public class NetworkTimeUpdateServiceTest {
|
||||
// Simulated NTP client behavior: No cached time value available initially, then a
|
||||
// successful refresh.
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() - 1);
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
// Trigger the engine's logic.
|
||||
engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
|
||||
@@ -86,10 +89,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
// Check everything happened that was supposed to.
|
||||
long expectedDelayMillis = calculateRefreshDelayMillisForTimeResult(
|
||||
timeResult, normalPollingIntervalMillis);
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
|
||||
verify(mockCallback).submitSuggestion(expectedSuggestion);
|
||||
@@ -108,6 +110,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
for (int i = 0; i < tryAgainTimesMax + 1; i++) {
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
// Simulated NTP client behavior: No cached time value available and failure to refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
|
||||
@@ -140,7 +145,6 @@ public class NetworkTimeUpdateServiceTest {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int maxTimeResultAgeMillis = normalPollingIntervalMillis;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = 5;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
@@ -149,7 +153,7 @@ public class NetworkTimeUpdateServiceTest {
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() - 1);
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
|
||||
|
||||
{
|
||||
@@ -158,6 +162,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
@@ -167,17 +174,16 @@ public class NetworkTimeUpdateServiceTest {
|
||||
// initially.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
long expectedDelayMillis = calculateRefreshDelayMillisForTimeResult(
|
||||
timeResult, normalPollingIntervalMillis);
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
|
||||
reset(mMockNtpTrustedTime);
|
||||
}
|
||||
|
||||
// Increment the current time by enough so that an attempt to refresh the time should be
|
||||
// made every time refreshIfRequiredAndReschedule() is called.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(maxTimeResultAgeMillis);
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
|
||||
|
||||
// Test multiple follow-up calls.
|
||||
for (int i = 0; i < tryAgainTimesMax + 1; i++) {
|
||||
@@ -208,30 +214,37 @@ public class NetworkTimeUpdateServiceTest {
|
||||
verify(mockCallback, never()).submitSuggestion(any());
|
||||
|
||||
reset(mMockNtpTrustedTime);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_successFailSuccess() {
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesZero() {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int maxTimeResultAgeMillis = normalPollingIntervalMillis;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = 5;
|
||||
int tryAgainTimesMax = 0;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
mFakeElapsedRealtimeClock,
|
||||
normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
NtpTrustedTime.TimeResult timeResult1 = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() - 1);
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
|
||||
|
||||
{
|
||||
// Simulated NTP client behavior: No cached time value available initially, with a
|
||||
// successful refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult1);
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
@@ -241,10 +254,159 @@ public class NetworkTimeUpdateServiceTest {
|
||||
// initially.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
long expectedDelayMillis = calculateRefreshDelayMillisForTimeResult(
|
||||
timeResult1, normalPollingIntervalMillis);
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
|
||||
reset(mMockNtpTrustedTime);
|
||||
}
|
||||
|
||||
// Increment the current time by enough so that an attempt to refresh the time should be
|
||||
// made every time refreshIfRequiredAndReschedule() is called.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
|
||||
|
||||
// Test multiple follow-up calls.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Simulated NTP client behavior: (Too old) cached time value available, unsuccessful
|
||||
// refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
|
||||
|
||||
// Expect a refresh attempt each time as the cached network time is too old.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
// Check the scheduling. tryAgainTimesMax == 0, so the algorithm should start with
|
||||
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
|
||||
// No valid time, no suggestion.
|
||||
verify(mockCallback, never()).submitSuggestion(any());
|
||||
|
||||
reset(mMockNtpTrustedTime);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_successThenFail_tryAgainTimesNegative() {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = -1;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
mFakeElapsedRealtimeClock,
|
||||
normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult);
|
||||
|
||||
{
|
||||
// Simulated NTP client behavior: No cached time value available initially, with a
|
||||
// successful refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
|
||||
|
||||
// Expect the refresh attempt to have been made: there is no cached network time
|
||||
// initially.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
|
||||
reset(mMockNtpTrustedTime);
|
||||
}
|
||||
|
||||
// Increment the current time by enough so that an attempt to refresh the time should be
|
||||
// made every time refreshIfRequiredAndReschedule() is called.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
|
||||
|
||||
// Test multiple follow-up calls.
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// Simulated NTP client behavior: (Too old) cached time value available, unsuccessful
|
||||
// refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
|
||||
|
||||
// Expect a refresh attempt each time as the cached network time is too old.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
// Check the scheduling. tryAgainTimesMax == -1, so it should always be
|
||||
// shortPollingIntervalMillis.
|
||||
long expectedDelayMillis = shortPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
|
||||
// No valid time, no suggestion.
|
||||
verify(mockCallback, never()).submitSuggestion(any());
|
||||
|
||||
reset(mMockNtpTrustedTime);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_successFailSuccess() {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = 5;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
mFakeElapsedRealtimeClock,
|
||||
normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
NtpTrustedTime.TimeResult timeResult1 = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
{
|
||||
// Simulated NTP client behavior: No cached time value available initially, with a
|
||||
// successful refresh.
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(null, timeResult1);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
engine.refreshIfRequiredAndReschedule(mDummyNetwork, "Test", mockCallback);
|
||||
|
||||
// Expect the refresh attempt to have been made: there is no cached network time
|
||||
// initially.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
timeResult1.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult1);
|
||||
verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
|
||||
reset(mMockNtpTrustedTime);
|
||||
@@ -253,7 +415,7 @@ public class NetworkTimeUpdateServiceTest {
|
||||
// Increment the current time by enough so that the cached time result is too old and an
|
||||
// attempt to refresh the time should be made every time refreshIfRequiredAndReschedule() is
|
||||
// called.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(maxTimeResultAgeMillis);
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
|
||||
|
||||
{
|
||||
// Simulated NTP client behavior: (Old) cached time value available initially, with an
|
||||
@@ -278,8 +440,11 @@ public class NetworkTimeUpdateServiceTest {
|
||||
reset(mMockNtpTrustedTime);
|
||||
}
|
||||
|
||||
// Increment time enough to avoid the minimum refresh interval protection.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(shortPollingIntervalMillis);
|
||||
|
||||
NtpTrustedTime.TimeResult timeResult2 = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() - 1);
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
|
||||
{
|
||||
// Simulated NTP client behavior: (Old) cached time value available initially, with a
|
||||
@@ -287,6 +452,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult1, timeResult2);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(true);
|
||||
|
||||
// Simulate the passage of time for realism.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(5000);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
|
||||
// Trigger the engine's logic.
|
||||
@@ -295,10 +463,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
// Expect the refresh attempt to have been made: the timeResult is too old.
|
||||
verify(mMockNtpTrustedTime).forceRefresh(mDummyNetwork);
|
||||
|
||||
long expectedDelayMillis = calculateRefreshDelayMillisForTimeResult(
|
||||
timeResult2, normalPollingIntervalMillis);
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
timeResult2.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
NetworkTimeSuggestion expectedSuggestion = createExpectedSuggestion(timeResult2);
|
||||
verify(mockCallback, times(1)).submitSuggestion(expectedSuggestion);
|
||||
reset(mMockNtpTrustedTime);
|
||||
@@ -311,11 +478,10 @@ public class NetworkTimeUpdateServiceTest {
|
||||
* A suggestion will still be made.
|
||||
*/
|
||||
@Test
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_noRefreshIfLatestIsNotTooOld() {
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_noRefreshIfLatestIsFresh() {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int maxTimeResultAgeMillis = normalPollingIntervalMillis;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = 5;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
@@ -323,12 +489,12 @@ public class NetworkTimeUpdateServiceTest {
|
||||
normalPollingIntervalMillis, shortPollingIntervalMillis, tryAgainTimesMax,
|
||||
mMockNtpTrustedTime);
|
||||
|
||||
// Simulated NTP client behavior: A cached time value is available, increment the clock, but
|
||||
// not enough to consider the cached value too old.
|
||||
// Simulated NTP client behavior: A cached time value is available.
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
|
||||
mFakeElapsedRealtimeClock.incrementMillis(maxTimeResultAgeMillis - 1);
|
||||
// Increment the clock, but not enough to consider the cached value too old.
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis - 1);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
// Trigger the engine's logic.
|
||||
@@ -339,10 +505,9 @@ public class NetworkTimeUpdateServiceTest {
|
||||
|
||||
// The next wake-up should be rescheduled for when the cached time value will become too
|
||||
// old.
|
||||
long expectedDelayMillis = calculateRefreshDelayMillisForTimeResult(timeResult,
|
||||
normalPollingIntervalMillis);
|
||||
long expectedDelayMillis = normalPollingIntervalMillis;
|
||||
verify(mockCallback).scheduleNextRefresh(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
timeResult.getElapsedRealtimeMillis() + expectedDelayMillis);
|
||||
|
||||
// Suggestions must be made every time if the cached time value is not too old in case it
|
||||
// was refreshed by a different component.
|
||||
@@ -352,15 +517,13 @@ public class NetworkTimeUpdateServiceTest {
|
||||
|
||||
/**
|
||||
* Confirms that if a refreshIfRequiredAndReschedule() call is made, e.g. for reasons besides
|
||||
* scheduled alerts, and the latest time is not too old, then an NTP refresh won't be attempted.
|
||||
* A suggestion will still be made.
|
||||
* scheduled alerts, and the latest time is too old, then an NTP refresh will be attempted.
|
||||
*/
|
||||
@Test
|
||||
public void engineImpl_refreshIfRequiredAndReschedule_failureHandlingAfterLatestIsTooOld() {
|
||||
mFakeElapsedRealtimeClock.setElapsedRealtimeMillis(ARBITRARY_ELAPSED_REALTIME_MILLIS);
|
||||
|
||||
int normalPollingIntervalMillis = 7777777;
|
||||
int maxTimeResultAgeMillis = normalPollingIntervalMillis;
|
||||
int shortPollingIntervalMillis = 3333;
|
||||
int tryAgainTimesMax = 5;
|
||||
NetworkTimeUpdateService.Engine engine = new NetworkTimeUpdateService.EngineImpl(
|
||||
@@ -373,7 +536,7 @@ public class NetworkTimeUpdateServiceTest {
|
||||
NtpTrustedTime.TimeResult timeResult = createNtpTimeResult(
|
||||
mFakeElapsedRealtimeClock.getElapsedRealtimeMillis());
|
||||
when(mMockNtpTrustedTime.getCachedTimeResult()).thenReturn(timeResult);
|
||||
mFakeElapsedRealtimeClock.incrementMillis(maxTimeResultAgeMillis);
|
||||
mFakeElapsedRealtimeClock.incrementMillis(normalPollingIntervalMillis);
|
||||
when(mMockNtpTrustedTime.forceRefresh(mDummyNetwork)).thenReturn(false);
|
||||
|
||||
RefreshCallbacks mockCallback = mock(RefreshCallbacks.class);
|
||||
@@ -392,13 +555,6 @@ public class NetworkTimeUpdateServiceTest {
|
||||
verify(mockCallback, never()).submitSuggestion(any());
|
||||
}
|
||||
|
||||
private long calculateRefreshDelayMillisForTimeResult(NtpTrustedTime.TimeResult timeResult,
|
||||
int normalPollingIntervalMillis) {
|
||||
long currentElapsedRealtimeMillis = mFakeElapsedRealtimeClock.getElapsedRealtimeMillis();
|
||||
long timeResultAgeMillis = timeResult.getAgeMillis(currentElapsedRealtimeMillis);
|
||||
return normalPollingIntervalMillis - timeResultAgeMillis;
|
||||
}
|
||||
|
||||
private static NetworkTimeSuggestion createExpectedSuggestion(
|
||||
NtpTrustedTime.TimeResult timeResult) {
|
||||
UnixEpochTime unixEpochTime = new UnixEpochTime(
|
||||
|
||||
Reference in New Issue
Block a user