Add time detector network behavior
Add methods to enable the latest network time signal to be retrieved and cleared. Also add shell command support for their use in tests. getLatestNetworkSuggestion() already existed for internal use and has now been exposed. clearNetworkTime() / clearLatestNetworkSuggestion() have been added for use in a future commit. Bug: 222295093 Test: build / boot / treehugger Test: atest services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java Change-Id: I9ffc00b6f2f5a12cbe3e20fc5be544fd2aedee37
This commit is contained in:
@@ -121,7 +121,7 @@ public final class UnixEpochTime implements Parcelable {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnixEpochTime{"
|
||||
+ "mElapsedRealtimeTimeMillis=" + mElapsedRealtimeMillis
|
||||
+ "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
|
||||
+ ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@@ -72,6 +72,18 @@ public interface TimeDetector {
|
||||
*/
|
||||
String SHELL_COMMAND_SUGGEST_NETWORK_TIME = "suggest_network_time";
|
||||
|
||||
/**
|
||||
* A shell command that prints the current network time information.
|
||||
* @hide
|
||||
*/
|
||||
String SHELL_COMMAND_GET_NETWORK_TIME = "get_network_time";
|
||||
|
||||
/**
|
||||
* A shell command that clears the detector's network time information.
|
||||
* @hide
|
||||
*/
|
||||
String SHELL_COMMAND_CLEAR_NETWORK_TIME = "clear_network_time";
|
||||
|
||||
/**
|
||||
* A shell command that injects a GNSS time suggestion.
|
||||
* @hide
|
||||
|
||||
@@ -143,7 +143,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
return getTimeCapabilitiesAndConfig(userId);
|
||||
}
|
||||
|
||||
TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
|
||||
private TimeCapabilitiesAndConfig getTimeCapabilitiesAndConfig(@UserIdInt int userId) {
|
||||
enforceManageTimeDetectorPermission();
|
||||
|
||||
final long token = mCallerIdentityInjector.clearCallingIdentity();
|
||||
@@ -163,6 +163,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
return updateConfiguration(callingUserId, configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the user's configuration. Exposed for use by {@link TimeDetectorShellCommand}.
|
||||
*/
|
||||
boolean updateConfiguration(@UserIdInt int userId, @NonNull TimeConfiguration configuration) {
|
||||
// Resolve constants like USER_CURRENT to the true user ID as needed.
|
||||
int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
|
||||
@@ -256,7 +259,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
void handleConfigurationInternalChangedOnHandlerThread() {
|
||||
private void handleConfigurationInternalChangedOnHandlerThread() {
|
||||
// Configuration has changed, but each user may have a different view of the configuration.
|
||||
// It's possible that this will cause unnecessary notifications but that shouldn't be a
|
||||
// problem.
|
||||
@@ -287,6 +290,10 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the system time state. See {@link TimeState} for details. For use by {@link
|
||||
* TimeDetectorShellCommand}.
|
||||
*/
|
||||
void setTimeState(@NonNull TimeState timeState) {
|
||||
enforceManageTimeDetectorPermission();
|
||||
|
||||
@@ -353,6 +360,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests network time with permission checks. For use by {@link TimeDetectorShellCommand}.
|
||||
*/
|
||||
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSignal) {
|
||||
enforceSuggestNetworkTimePermission();
|
||||
Objects.requireNonNull(timeSignal);
|
||||
@@ -360,6 +370,23 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the cached network time information. For use during tests to simulate when no network
|
||||
* time has been made available. For use by {@link TimeDetectorShellCommand}.
|
||||
*
|
||||
* <p>This operation takes place in the calling thread.
|
||||
*/
|
||||
void clearNetworkTime() {
|
||||
enforceSuggestNetworkTimePermission();
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mTimeDetectorStrategy.clearLatestNetworkSuggestion();
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnixEpochTime latestNetworkTime() {
|
||||
NetworkTimeSuggestion suggestion = getLatestNetworkSuggestion();
|
||||
@@ -388,6 +415,9 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests GNSS time with permission checks. For use by {@link TimeDetectorShellCommand}.
|
||||
*/
|
||||
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
|
||||
enforceSuggestGnssTimePermission();
|
||||
Objects.requireNonNull(timeSignal);
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package com.android.server.timedetector;
|
||||
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CLEAR_NETWORK_TIME;
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_CONFIRM_TIME;
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_NETWORK_TIME;
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_GET_TIME_STATE;
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_IS_AUTO_DETECTION_ENABLED;
|
||||
import static android.app.timedetector.TimeDetector.SHELL_COMMAND_SERVICE_NAME;
|
||||
@@ -70,6 +72,10 @@ class TimeDetectorShellCommand extends ShellCommand {
|
||||
return runSuggestTelephonyTime();
|
||||
case SHELL_COMMAND_SUGGEST_NETWORK_TIME:
|
||||
return runSuggestNetworkTime();
|
||||
case SHELL_COMMAND_GET_NETWORK_TIME:
|
||||
return runGetNetworkTime();
|
||||
case SHELL_COMMAND_CLEAR_NETWORK_TIME:
|
||||
return runClearNetworkTime();
|
||||
case SHELL_COMMAND_SUGGEST_GNSS_TIME:
|
||||
return runSuggestGnssTime();
|
||||
case SHELL_COMMAND_SUGGEST_EXTERNAL_TIME:
|
||||
@@ -122,6 +128,18 @@ class TimeDetectorShellCommand extends ShellCommand {
|
||||
mInterface::suggestNetworkTime);
|
||||
}
|
||||
|
||||
private int runGetNetworkTime() {
|
||||
NetworkTimeSuggestion networkTimeSuggestion = mInterface.getLatestNetworkSuggestion();
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
pw.println(networkTimeSuggestion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runClearNetworkTime() {
|
||||
mInterface.clearNetworkTime();
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int runSuggestGnssTime() {
|
||||
return runSuggestTime(
|
||||
() -> GnssTimeSuggestion.parseCommandLineArg(this),
|
||||
@@ -196,6 +214,10 @@ class TimeDetectorShellCommand extends ShellCommand {
|
||||
pw.printf(" Sets the current time state for tests.\n");
|
||||
pw.printf(" %s <unix epoch time options>\n", SHELL_COMMAND_CONFIRM_TIME);
|
||||
pw.printf(" Tries to confirms the time, raising the confidence.\n");
|
||||
pw.printf(" %s\n", SHELL_COMMAND_GET_NETWORK_TIME);
|
||||
pw.printf(" Prints the network time information held by the detector.\n");
|
||||
pw.printf(" %s\n", SHELL_COMMAND_CLEAR_NETWORK_TIME);
|
||||
pw.printf(" Clears the network time information held by the detector.\n");
|
||||
pw.println();
|
||||
ManualTimeSuggestion.printCommandLineOpts(pw);
|
||||
pw.println();
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.server.timedetector;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.time.ExternalTimeSuggestion;
|
||||
import android.app.time.TimeState;
|
||||
@@ -103,6 +104,20 @@ public interface TimeDetectorStrategy extends Dumpable {
|
||||
/** Processes the suggested time from network sources. */
|
||||
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
|
||||
|
||||
/**
|
||||
* Returns the latest (accepted) network time suggestion. Returns {@code null} if there isn't
|
||||
* one.
|
||||
*/
|
||||
@Nullable
|
||||
NetworkTimeSuggestion getLatestNetworkSuggestion();
|
||||
|
||||
/**
|
||||
* Clears the latest network time suggestion, leaving none. The remaining time signals from
|
||||
* other sources will be reassessed causing the device's time to be updated if config and
|
||||
* settings allow.
|
||||
*/
|
||||
void clearLatestNetworkSuggestion();
|
||||
|
||||
/** Processes the suggested time from gnss sources. */
|
||||
void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion);
|
||||
|
||||
|
||||
@@ -315,6 +315,21 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
|
||||
doAutoTimeDetection(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
|
||||
return mLastNetworkSuggestion.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void clearLatestNetworkSuggestion() {
|
||||
mLastNetworkSuggestion.set(null);
|
||||
|
||||
// The loss of network time may change the time signal to use to set the system clock.
|
||||
String reason = "Network time cleared";
|
||||
doAutoTimeDetection(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull
|
||||
public synchronized TimeState getTimeState() {
|
||||
@@ -1063,15 +1078,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
|
||||
return mSuggestionBySlotIndex.get(slotIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* A method used to inspect state during tests. Not intended for general use.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public synchronized NetworkTimeSuggestion getLatestNetworkSuggestion() {
|
||||
return mLastNetworkSuggestion.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* A method used to inspect state during tests. Not intended for general use.
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,15 @@ public class FakeTimeDetectorStrategy implements TimeDetectorStrategy {
|
||||
public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public NetworkTimeSuggestion getLatestNetworkSuggestion() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearLatestNetworkSuggestion() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
|
||||
}
|
||||
|
||||
@@ -379,6 +379,28 @@ public class TimeDetectorServiceTest {
|
||||
verify(mFakeTimeDetectorStrategySpy).suggestExternalTime(externalTimeSuggestion);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearNetworkTime_withoutPermission() {
|
||||
doThrow(new SecurityException("Mock"))
|
||||
.when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
assertThrows(SecurityException.class,
|
||||
() -> mTimeDetectorService.clearNetworkTime());
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.SET_TIME), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearNetworkTime() throws Exception {
|
||||
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
|
||||
|
||||
mTimeDetectorService.clearNetworkTime();
|
||||
|
||||
verify(mMockContext).enforceCallingPermission(
|
||||
eq(android.Manifest.permission.SET_TIME), anyString());
|
||||
verify(mFakeTimeDetectorStrategySpy).clearLatestNetworkSuggestion();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLatestNetworkTime() {
|
||||
NtpTrustedTime.TimeResult latestNetworkTime = new NtpTrustedTime.TimeResult(
|
||||
|
||||
@@ -874,6 +874,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
long expectedSystemClockMillis =
|
||||
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
|
||||
}
|
||||
@@ -891,9 +892,54 @@ public class TimeDetectorStrategyImplTest {
|
||||
|
||||
script.simulateTimePassing()
|
||||
.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClearLatestNetworkSuggestion() {
|
||||
ConfigurationInternal configInternal =
|
||||
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
|
||||
.setOriginPriorities(ORIGIN_NETWORK, ORIGIN_EXTERNAL)
|
||||
.build();
|
||||
Script script = new Script().simulateConfigurationInternalChange(configInternal);
|
||||
|
||||
// Create two different time suggestions for the current elapsedRealtimeMillis.
|
||||
ExternalTimeSuggestion externalTimeSuggestion =
|
||||
script.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
|
||||
NetworkTimeSuggestion networkTimeSuggestion =
|
||||
script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME.plus(Duration.ofHours(5)));
|
||||
script.simulateTimePassing();
|
||||
|
||||
// Suggest an external time: This should cause the device to change time.
|
||||
{
|
||||
long expectedSystemClockMillis =
|
||||
script.calculateTimeInMillisForNow(externalTimeSuggestion.getUnixEpochTime());
|
||||
script.simulateExternalTimeSuggestion(externalTimeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
|
||||
}
|
||||
|
||||
// Suggest a network time: This should cause the device to change time because
|
||||
// network > external.
|
||||
{
|
||||
long expectedSystemClockMillis =
|
||||
script.calculateTimeInMillisForNow(networkTimeSuggestion.getUnixEpochTime());
|
||||
script.simulateNetworkTimeSuggestion(networkTimeSuggestion)
|
||||
.assertLatestNetworkSuggestion(networkTimeSuggestion)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
|
||||
}
|
||||
|
||||
// Clear the network time. This should cause the device to change back to the external time,
|
||||
// which is now the best time available.
|
||||
{
|
||||
long expectedSystemClockMillis =
|
||||
script.calculateTimeInMillisForNow(externalTimeSuggestion.getUnixEpochTime());
|
||||
script.simulateClearLatestNetworkSuggestion()
|
||||
.assertLatestNetworkSuggestion(null)
|
||||
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestNetworkTime_rejectedBelowLowerBound() {
|
||||
ConfigurationInternal configInternal =
|
||||
@@ -908,6 +954,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
NetworkTimeSuggestion timeSuggestion =
|
||||
script.generateNetworkTimeSuggestion(belowLowerBound);
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(null)
|
||||
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
@@ -926,6 +973,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
NetworkTimeSuggestion timeSuggestion =
|
||||
script.generateNetworkTimeSuggestion(aboveLowerBound);
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
|
||||
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
|
||||
}
|
||||
@@ -944,6 +992,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
NetworkTimeSuggestion timeSuggestion =
|
||||
script.generateNetworkTimeSuggestion(aboveUpperBound);
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(null)
|
||||
.verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
@@ -962,6 +1011,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
NetworkTimeSuggestion timeSuggestion =
|
||||
script.generateNetworkTimeSuggestion(belowUpperBound);
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
|
||||
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
|
||||
}
|
||||
@@ -1745,7 +1795,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestionsFromNetworkOriginNotInPriorityList_areIgnored() {
|
||||
public void suggestionsFromNetworkOriginNotInPriorityList_areNotUsed() {
|
||||
ConfigurationInternal configInternal =
|
||||
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
|
||||
.setOriginPriorities(ORIGIN_TELEPHONY)
|
||||
@@ -1756,12 +1806,13 @@ public class TimeDetectorStrategyImplTest {
|
||||
ARBITRARY_TEST_TIME);
|
||||
|
||||
script.simulateNetworkTimeSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.assertLatestNetworkSuggestion(timeSuggestion)
|
||||
.verifySystemClockWasNotSetAndResetCallTracking();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestionsFromGnssOriginNotInPriorityList_areIgnored() {
|
||||
public void suggestionsFromGnssOriginNotInPriorityList_areNotUsed() {
|
||||
ConfigurationInternal configInternal =
|
||||
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
|
||||
.setOriginPriorities(ORIGIN_TELEPHONY)
|
||||
@@ -1777,7 +1828,7 @@ public class TimeDetectorStrategyImplTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void suggestionsFromExternalOriginNotInPriorityList_areIgnored() {
|
||||
public void suggestionsFromExternalOriginNotInPriorityList_areNotUsed() {
|
||||
ConfigurationInternal configInternal =
|
||||
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
|
||||
.setOriginPriorities(ORIGIN_TELEPHONY)
|
||||
@@ -2015,6 +2066,11 @@ public class TimeDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
Script simulateClearLatestNetworkSuggestion() {
|
||||
mTimeDetectorStrategy.clearLatestNetworkSuggestion();
|
||||
return this;
|
||||
}
|
||||
|
||||
Script simulateGnssTimeSuggestion(GnssTimeSuggestion timeSuggestion) {
|
||||
mTimeDetectorStrategy.suggestGnssTime(timeSuggestion);
|
||||
return this;
|
||||
@@ -2056,6 +2112,12 @@ public class TimeDetectorStrategyImplTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Calls {@link TimeDetectorStrategy#confirmTime(UnixEpochTime)}. */
|
||||
Script simulateConfirmTime(UnixEpochTime confirmationTime, boolean expectedReturnValue) {
|
||||
assertEquals(expectedReturnValue, mTimeDetectorStrategy.confirmTime(confirmationTime));
|
||||
return this;
|
||||
}
|
||||
|
||||
Script verifySystemClockWasNotSetAndResetCallTracking() {
|
||||
mFakeEnvironment.verifySystemClockNotSet();
|
||||
mFakeEnvironment.resetCallTracking();
|
||||
@@ -2218,11 +2280,6 @@ public class TimeDetectorStrategyImplTest {
|
||||
long calculateTimeInMillisForNow(UnixEpochTime unixEpochTime) {
|
||||
return unixEpochTime.at(peekElapsedRealtimeMillis()).getUnixEpochTimeMillis();
|
||||
}
|
||||
|
||||
Script simulateConfirmTime(UnixEpochTime confirmationTime, boolean expectedReturnValue) {
|
||||
assertEquals(expectedReturnValue, mTimeDetectorStrategy.confirmTime(confirmationTime));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static TelephonyTimeSuggestion createTelephonyTimeSuggestion(int slotIndex,
|
||||
|
||||
Reference in New Issue
Block a user