Merge "Add time detector network behavior"

This commit is contained in:
Neil Fuller
2023-01-11 17:52:49 +00:00
committed by Android (Google) Code Review
9 changed files with 193 additions and 20 deletions

View File

@@ -124,7 +124,7 @@ public final class UnixEpochTime implements Parcelable {
@Override
public String toString() {
return "UnixEpochTime{"
+ "mElapsedRealtimeTimeMillis=" + mElapsedRealtimeMillis
+ "mElapsedRealtimeMillis=" + mElapsedRealtimeMillis
+ ", mUnixEpochTimeMillis=" + mUnixEpochTimeMillis
+ '}';
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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();

View File

@@ -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);

View File

@@ -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.
*/

View File

@@ -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) {
}

View File

@@ -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(

View File

@@ -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,