diff --git a/core/java/android/app/timedetector/TimeDetectorHelper.java b/core/java/android/app/timedetector/TimeDetectorHelper.java new file mode 100644 index 0000000000000..8752ee07067a6 --- /dev/null +++ b/core/java/android/app/timedetector/TimeDetectorHelper.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app.timedetector; + +import android.annotation.NonNull; +import android.os.Build; + +import java.time.Instant; + +/** + * A utility class for fundamental time detector-related logic that doesn't need to communicate with + * the time detector service, i.e. because it can use SDK APIs or hard-coded facts, and doesn't need + * permissions or singleton state. Putting logic here avoids the need to expose binder-based calls + * or to duplicate code to share related logic (since android.app.timedetector classes are visible + * to all processes). + * + * @hide + */ +// Not final for easy replacement / mocking during tests. +public class TimeDetectorHelper { + + /** + * See {@link #getManualDateSelectionYearMin()}. Chosen to produce Unix epoch times be greater + * than {@link #MANUAL_SUGGESTION_LOWER_BOUND}. + */ + private static final int MANUAL_SUGGESTION_YEAR_MIN = 2008; + + /** + * The maximum gregorian calendar year to allow for manual date selection on devices unlikely to + * have Y2038 issues. This serves as a sensible UI-enforced limit though the system server may + * support a larger upper bound. Users besides future archeologists are unlikely to need higher + * values, for a few years at least. + */ + private static final int MANUAL_SUGGESTION_YEAR_MAX_WITHOUT_Y2038_ISSUE = 2100; + + /** + * The maximum gregorian calendar year to allow for manual date selection on devices that may + * have Y2038 issues. This serves as a sensible UI-enforced limit though the system server may + * support a larger upper bound. That is, the signed 32-bit milliseconds value is + * 03:14:07 UTC on 19 January 2038, but this constant means users can only enter dates up to + * 2037-12-31. See {@link #MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE}. + * + *

Note: This UI limit also doesn't prevent devices reaching the Y2038 roll-over time through + * the natural passage of time, it just prevents users potentially causing issues in the years + * leading up to it accidentally via the UI. + */ + private static final int MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE = 2037; + + /** + * The upper bound for valid suggestions when the Y2038 issue is a risk. This is the instant + * when the Y2038 issue occurs. + */ + private static final Instant SUGGESTION_UPPER_BOUND_WITH_Y2038_ISSUE = + Instant.ofEpochMilli(1000L * Integer.MAX_VALUE); + + /** + * The upper bound for valid suggestions when the Y2038 issue is not a risk. This values means + * there is no practical upper bound. + * + *

Make sure this value remains in the value representable as a signed int64 Unix epoch + * millis value as in various places {@link Instant#toEpochMilli()} is called, and that throws + * an exception if the value is too large. + */ + private static final Instant SUGGESTION_UPPER_BOUND_WIITHOUT_Y2038_ISSUE = + Instant.ofEpochMilli(Long.MAX_VALUE); + + /** See {@link #getManualSuggestionLowerBound()}. */ + private static final Instant MANUAL_SUGGESTION_LOWER_BOUND = + Instant.ofEpochMilli(1194220800000L); // Nov 5, 2007, 0:00 UTC + + /** + * The lowest value in Unix epoch milliseconds that is considered a valid automatic suggestion. + * See also {@link #MANUAL_SUGGESTION_LOWER_BOUND}. + * + *

Note that this is a default value. The lower value enforced can be overridden to be + * lower in the system server with flags for testing. + */ + private static final Instant AUTO_SUGGESTION_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli( + Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME)); + + /** The singleton instance of this class. */ + public static final TimeDetectorHelper INSTANCE = new TimeDetectorHelper(); + + /** Constructor present for subclassing in tests. Use {@link #INSTANCE} in production code. */ + protected TimeDetectorHelper() {} + + /** + * Returns the minimum gregorian calendar year to offer for manual date selection. This serves + * as a sensible UI-enforced lower limit, the system server may support a smaller lower bound. + */ + public int getManualDateSelectionYearMin() { + return MANUAL_SUGGESTION_YEAR_MIN; + } + + /** + * Returns the maximum gregorian calendar year to offer for manual date selection. This serves + * as a sensible UI-enforced lower limit, the system server may support a larger upper bound. + */ + public int getManualDateSelectionYearMax() { + return getDeviceHasY2038Issue() + ? MANUAL_SUGGESTION_YEAR_MAX_WITH_Y2038_ISSUE + : MANUAL_SUGGESTION_YEAR_MAX_WITHOUT_Y2038_ISSUE; + } + + /** + * Returns the lowest value in Unix epoch milliseconds that is considered a valid manual + * suggestion. For historical reasons Android has a different lower limit for manual input than + * automatic. This may change in the future to align with automatic suggestions, but has been + * kept initially to avoid breaking manual tests that are hard-coded with old dates real users + * will never want to use. + */ + @NonNull + public Instant getManualSuggestionLowerBound() { + return MANUAL_SUGGESTION_LOWER_BOUND; + } + + /** + * Returns the lowest value in Unix epoch milliseconds that is considered a valid automatic + * suggestion. See also {@link #MANUAL_SUGGESTION_LOWER_BOUND}. + * + *

Note that this is a default value. The lower value enforced can be overridden to be + * different in the system server with server flags. + */ + @NonNull + public Instant getAutoSuggestionLowerBoundDefault() { + return AUTO_SUGGESTION_LOWER_BOUND_DEFAULT; + } + + /** Returns the upper bound to enforce for all time suggestions (manual and automatic). */ + @NonNull + public Instant getSuggestionUpperBound() { + return getDeviceHasY2038Issue() + ? SUGGESTION_UPPER_BOUND_WITH_Y2038_ISSUE + : SUGGESTION_UPPER_BOUND_WIITHOUT_Y2038_ISSUE; + } + + /** + * Returns {@code true} if the device may be at risk of time_t overflow (because bionic + * defines time_t as a 32-bit signed integer for 32-bit processes). + */ + private boolean getDeviceHasY2038Issue() { + return Build.SUPPORTED_32_BIT_ABIS.length > 0; + } +} diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java index 683eaeb961b04..372bcc6b07cae 100644 --- a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java +++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java @@ -46,9 +46,10 @@ public final class ConfigurationInternal { private final boolean mAutoDetectionSupported; private final int mSystemClockUpdateThresholdMillis; - private final Instant mAutoTimeLowerBound; + private final Instant mAutoSuggestionLowerBound; + private final Instant mManualSuggestionLowerBound; + private final Instant mSuggestionUpperBound; private final @Origin int[] mOriginPriorities; - private final boolean mDeviceHasY2038Issue; private final boolean mAutoDetectionEnabledSetting; private final @UserIdInt int mUserId; private final boolean mUserConfigAllowed; @@ -56,9 +57,10 @@ public final class ConfigurationInternal { private ConfigurationInternal(Builder builder) { mAutoDetectionSupported = builder.mAutoDetectionSupported; mSystemClockUpdateThresholdMillis = builder.mSystemClockUpdateThresholdMillis; - mAutoTimeLowerBound = Objects.requireNonNull(builder.mAutoTimeLowerBound); + mAutoSuggestionLowerBound = Objects.requireNonNull(builder.mAutoSuggestionLowerBound); + mManualSuggestionLowerBound = Objects.requireNonNull(builder.mManualSuggestionLowerBound); + mSuggestionUpperBound = Objects.requireNonNull(builder.mSuggestionUpperBound); mOriginPriorities = Objects.requireNonNull(builder.mOriginPriorities); - mDeviceHasY2038Issue = builder.mDeviceHasY2038Issue; mAutoDetectionEnabledSetting = builder.mAutoDetectionEnabledSetting; mUserId = builder.mUserId; @@ -80,14 +82,31 @@ public final class ConfigurationInternal { } /** - * Returns the lower bound for valid automatic times. It is guaranteed to be in the past, - * i.e. it is unrelated to the current system clock time. + * Returns the lower bound for valid automatic time suggestions. It is guaranteed to be in the + * past, i.e. it is unrelated to the current system clock time. * It holds no other meaning; it could be related to when the device system image was built, * or could be updated by a mainline module. */ @NonNull - public Instant getAutoTimeLowerBound() { - return mAutoTimeLowerBound; + public Instant getAutoSuggestionLowerBound() { + return mAutoSuggestionLowerBound; + } + + /** + * Returns the lower bound for valid manual time suggestions. It is guaranteed to be in the + * past, i.e. it is unrelated to the current system clock time. + */ + @NonNull + public Instant getManualSuggestionLowerBound() { + return mManualSuggestionLowerBound; + } + + /** + * Returns the upper bound for valid time suggestions (manual and automatic). + */ + @NonNull + public Instant getSuggestionUpperBound() { + return mSuggestionUpperBound; } /** @@ -98,14 +117,6 @@ public final class ConfigurationInternal { return mOriginPriorities; } - /** - * Returns {@code true} if the device may be at risk of time_t overflow (because bionic - * defines time_t as a 32-bit signed integer for 32-bit processes). - */ - public boolean getDeviceHasY2038Issue() { - return mDeviceHasY2038Issue; - } - /** Returns the value of the auto time detection enabled setting. */ public boolean getAutoDetectionEnabledSetting() { return mAutoDetectionEnabledSetting; @@ -207,16 +218,17 @@ public final class ConfigurationInternal { && mAutoDetectionEnabledSetting == that.mAutoDetectionEnabledSetting && mUserId == that.mUserId && mUserConfigAllowed == that.mUserConfigAllowed && mSystemClockUpdateThresholdMillis == that.mSystemClockUpdateThresholdMillis - && mAutoTimeLowerBound.equals(that.mAutoTimeLowerBound) - && mDeviceHasY2038Issue == that.mDeviceHasY2038Issue + && mAutoSuggestionLowerBound.equals(that.mAutoSuggestionLowerBound) + && mManualSuggestionLowerBound.equals(that.mManualSuggestionLowerBound) + && mSuggestionUpperBound.equals(that.mSuggestionUpperBound) && Arrays.equals(mOriginPriorities, that.mOriginPriorities); } @Override public int hashCode() { int result = Objects.hash(mAutoDetectionSupported, mAutoDetectionEnabledSetting, mUserId, - mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoTimeLowerBound, - mDeviceHasY2038Issue); + mUserConfigAllowed, mSystemClockUpdateThresholdMillis, mAutoSuggestionLowerBound, + mManualSuggestionLowerBound, mSuggestionUpperBound); result = 31 * result + Arrays.hashCode(mOriginPriorities); return result; } @@ -230,10 +242,13 @@ public final class ConfigurationInternal { return "ConfigurationInternal{" + "mAutoDetectionSupported=" + mAutoDetectionSupported + ", mSystemClockUpdateThresholdMillis=" + mSystemClockUpdateThresholdMillis - + ", mAutoTimeLowerBound=" + mAutoTimeLowerBound - + "(" + mAutoTimeLowerBound.toEpochMilli() + ")" + + ", mAutoSuggestionLowerBound=" + mAutoSuggestionLowerBound + + "(" + mAutoSuggestionLowerBound.toEpochMilli() + ")" + + ", mManualSuggestionLowerBound=" + mManualSuggestionLowerBound + + "(" + mManualSuggestionLowerBound.toEpochMilli() + ")" + + ", mSuggestionUpperBound=" + mSuggestionUpperBound + + "(" + mSuggestionUpperBound.toEpochMilli() + ")" + ", mOriginPriorities=" + originPrioritiesString - + ", mDeviceHasY2038Issue=" + mDeviceHasY2038Issue + ", mAutoDetectionEnabled=" + mAutoDetectionEnabledSetting + ", mUserId=" + mUserId + ", mUserConfigAllowed=" + mUserConfigAllowed @@ -243,9 +258,10 @@ public final class ConfigurationInternal { static final class Builder { private boolean mAutoDetectionSupported; private int mSystemClockUpdateThresholdMillis; - @NonNull private Instant mAutoTimeLowerBound; + @NonNull private Instant mAutoSuggestionLowerBound; + @NonNull private Instant mManualSuggestionLowerBound; + @NonNull private Instant mSuggestionUpperBound; @NonNull private @Origin int[] mOriginPriorities; - private boolean mDeviceHasY2038Issue; private boolean mAutoDetectionEnabledSetting; private final @UserIdInt int mUserId; @@ -263,9 +279,10 @@ public final class ConfigurationInternal { this.mUserConfigAllowed = toCopy.mUserConfigAllowed; this.mAutoDetectionSupported = toCopy.mAutoDetectionSupported; this.mSystemClockUpdateThresholdMillis = toCopy.mSystemClockUpdateThresholdMillis; - this.mAutoTimeLowerBound = toCopy.mAutoTimeLowerBound; + this.mAutoSuggestionLowerBound = toCopy.mAutoSuggestionLowerBound; + this.mManualSuggestionLowerBound = toCopy.mManualSuggestionLowerBound; + this.mSuggestionUpperBound = toCopy.mSuggestionUpperBound; this.mOriginPriorities = toCopy.mOriginPriorities; - this.mDeviceHasY2038Issue = toCopy.mDeviceHasY2038Issue; this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting; } @@ -296,10 +313,26 @@ public final class ConfigurationInternal { } /** - * Sets the lower bound for valid automatic times. + * Sets the lower bound for valid automatic time suggestions. */ - public Builder setAutoTimeLowerBound(@NonNull Instant autoTimeLowerBound) { - mAutoTimeLowerBound = Objects.requireNonNull(autoTimeLowerBound); + public Builder setAutoSuggestionLowerBound(@NonNull Instant autoSuggestionLowerBound) { + mAutoSuggestionLowerBound = Objects.requireNonNull(autoSuggestionLowerBound); + return this; + } + + /** + * Sets the lower bound for valid manual time suggestions. + */ + public Builder setManualSuggestionLowerBound(@NonNull Instant manualSuggestionLowerBound) { + mManualSuggestionLowerBound = Objects.requireNonNull(manualSuggestionLowerBound); + return this; + } + + /** + * Sets the upper bound for valid time suggestions (manual and automatic). + */ + public Builder setSuggestionUpperBound(@NonNull Instant suggestionUpperBound) { + mSuggestionUpperBound = Objects.requireNonNull(suggestionUpperBound); return this; } @@ -320,15 +353,6 @@ public final class ConfigurationInternal { return this; } - /** - * Returns {@code true} if the device may be at risk of time_t overflow (because bionic - * defines time_t as a 32-bit signed integer for 32-bit processes). - */ - Builder setDeviceHasY2038Issue(boolean deviceHasY2038Issue) { - mDeviceHasY2038Issue = deviceHasY2038Issue; - return this; - } - /** Returns a new {@link ConfigurationInternal}. */ @NonNull ConfigurationInternal build() { diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java index e4f3a80c03b5c..888304aa199b2 100644 --- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java +++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java @@ -31,6 +31,7 @@ import android.app.ActivityManagerInternal; import android.app.time.TimeCapabilities; import android.app.time.TimeCapabilitiesAndConfig; import android.app.time.TimeConfiguration; +import android.app.timedetector.TimeDetectorHelper; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -38,7 +39,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.database.ContentObserver; -import android.os.Build; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; @@ -74,13 +74,6 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { private static final @Origin int[] DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES = { ORIGIN_TELEPHONY, ORIGIN_NETWORK }; - /** - * Time in the past. If an automatic time suggestion is before this point, it is sure to be - * incorrect. - */ - private static final Instant TIME_LOWER_BOUND_DEFAULT = Instant.ofEpochMilli( - Long.max(android.os.Environment.getRootDirectory().lastModified(), Build.TIME)); - /** Device config keys that affect the {@link TimeDetectorService}. */ private static final Set SERVER_FLAGS_KEYS_TO_WATCH = Set.of( KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE, @@ -237,14 +230,16 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { @Override @NonNull public synchronized ConfigurationInternal getConfigurationInternal(@UserIdInt int userId) { + TimeDetectorHelper timeDetectorHelper = TimeDetectorHelper.INSTANCE; return new ConfigurationInternal.Builder(userId) .setUserConfigAllowed(isUserConfigAllowed(userId)) .setAutoDetectionSupported(isAutoDetectionSupported()) .setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting()) .setSystemClockUpdateThresholdMillis(getSystemClockUpdateThresholdMillis()) - .setAutoTimeLowerBound(getAutoTimeLowerBound()) + .setAutoSuggestionLowerBound(getAutoSuggestionLowerBound()) + .setManualSuggestionLowerBound(timeDetectorHelper.getManualSuggestionLowerBound()) + .setSuggestionUpperBound(timeDetectorHelper.getSuggestionUpperBound()) .setOriginPriorities(getOriginPriorities()) - .setDeviceHasY2038Issue(getDeviceHasY2038Issue()) .build(); } @@ -291,9 +286,9 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { } @NonNull - private Instant getAutoTimeLowerBound() { + private Instant getAutoSuggestionLowerBound() { return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE) - .orElse(TIME_LOWER_BOUND_DEFAULT); + .orElse(TimeDetectorHelper.INSTANCE.getAutoSuggestionLowerBoundDefault()); } @NonNull @@ -310,10 +305,6 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor { return DEFAULT_AUTOMATIC_TIME_ORIGIN_PRIORITIES; } - private boolean getDeviceHasY2038Issue() { - return Build.SUPPORTED_32_BIT_ABIS.length > 0; - } - /** * A base supplier of an array of time origin integers in priority order. * It handles memoization of the result to avoid repeated string parsing when nothing has diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java index 017306a5039dc..547cf9d32aa1d 100644 --- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java +++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java @@ -84,9 +84,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { */ private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10; - /** The value in Unix epoch milliseconds of the Y2038 issue. */ - private static final long Y2038_LIMIT_IN_MILLIS = 1000L * Integer.MAX_VALUE; - /** * A log that records the decisions / decision metadata that affected the device's system clock * time. This is logged in bug reports to assist with debugging issues with detection. @@ -248,7 +245,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { final TimestampedValue newUnixEpochTime = suggestion.getUnixEpochTime(); - if (!validateSuggestionTime(newUnixEpochTime, suggestion)) { + if (!validateManualSuggestionTime(newUnixEpochTime, suggestion)) { return false; } @@ -424,7 +421,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { } @GuardedBy("this") - private boolean validateSuggestionTime( + private boolean validateSuggestionCommon( @NonNull TimestampedValue newUnixEpochTime, @NonNull Object suggestion) { if (newUnixEpochTime.getValue() == null) { Slog.w(LOG_TAG, "Suggested time value is null. suggestion=" + suggestion); @@ -441,8 +438,8 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return false; } - if (newUnixEpochTime.getValue() > Y2038_LIMIT_IN_MILLIS - && mCurrentConfigurationInternal.getDeviceHasY2038Issue()) { + if (newUnixEpochTime.getValue() + > mCurrentConfigurationInternal.getSuggestionUpperBound().toEpochMilli()) { // This check won't prevent a device's system clock exceeding Integer.MAX_VALUE Unix // seconds through the normal passage of time, but it will stop it jumping above 2038 // because of a "bad" suggestion. b/204193177 @@ -453,20 +450,40 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy { return true; } + /** + * Returns {@code true} if an automatic time suggestion time is valid. + * See also {@link #validateManualSuggestionTime(TimestampedValue, Object)}. + */ @GuardedBy("this") private boolean validateAutoSuggestionTime( @NonNull TimestampedValue newUnixEpochTime, @NonNull Object suggestion) { - return validateSuggestionTime(newUnixEpochTime, suggestion) - && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion); + Instant lowerBound = mCurrentConfigurationInternal.getAutoSuggestionLowerBound(); + return validateSuggestionCommon(newUnixEpochTime, suggestion) + && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion, + lowerBound); + } + + /** + * Returns {@code true} if a manual time suggestion time is valid. + * See also {@link #validateAutoSuggestionTime(TimestampedValue, Object)}. + */ + @GuardedBy("this") + private boolean validateManualSuggestionTime( + @NonNull TimestampedValue newUnixEpochTime, @NonNull Object suggestion) { + Instant lowerBound = mCurrentConfigurationInternal.getManualSuggestionLowerBound(); + + // Suggestion is definitely wrong if it comes before lower time bound. + return validateSuggestionCommon(newUnixEpochTime, suggestion) + && validateSuggestionAgainstLowerBound(newUnixEpochTime, suggestion, lowerBound); } @GuardedBy("this") private boolean validateSuggestionAgainstLowerBound( - @NonNull TimestampedValue newUnixEpochTime, @NonNull Object suggestion) { - Instant lowerBound = mCurrentConfigurationInternal.getAutoTimeLowerBound(); + @NonNull TimestampedValue newUnixEpochTime, @NonNull Object suggestion, + @NonNull Instant lowerBound) { // Suggestion is definitely wrong if it comes before lower time bound. - if (lowerBound.isAfter(Instant.ofEpochMilli(newUnixEpochTime.getValue()))) { + if (lowerBound.toEpochMilli() > newUnixEpochTime.getValue()) { Slog.w(LOG_TAG, "Suggestion points to time before lower bound, skipping it. " + "suggestion=" + suggestion + ", lower bound=" + lowerBound); return false; diff --git a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java index c3d40daef412b..208f99ad63a91 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/ConfigurationInternalTest.java @@ -45,7 +45,9 @@ public class ConfigurationInternalTest { private static final int ARBITRARY_USER_ID = 99999; private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234; - private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0); + private static final Instant ARBITRARY_SUGGESTION_LOWER_BOUND = Instant.ofEpochMilli(0); + private static final Instant ARBITRARY_SUGGESTION_UPPER_BOUND = + Instant.ofEpochMilli(Long.MAX_VALUE); private static final @Origin int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK }; /** @@ -59,9 +61,10 @@ public class ConfigurationInternalTest { .setUserConfigAllowed(true) .setAutoDetectionSupported(true) .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(true) .build(); { @@ -110,9 +113,10 @@ public class ConfigurationInternalTest { .setUserConfigAllowed(false) .setAutoDetectionSupported(true) .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(true) .build(); { @@ -159,9 +163,10 @@ public class ConfigurationInternalTest { .setUserConfigAllowed(true) .setAutoDetectionSupported(false) .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(true) .build(); { diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java index b9c74baaf3d3a..67c8c4fc102fe 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java @@ -69,7 +69,9 @@ public class TimeDetectorServiceTest { private static final int ARBITRARY_USER_ID = 9999; private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234; - private static final Instant ARBITRARY_AUTO_TIME_LOWER_BOUND = Instant.ofEpochMilli(0); + private static final Instant ARBITRARY_SUGGESTION_LOWER_BOUND = Instant.ofEpochMilli(0); + private static final Instant ARBITRARY_SUGGESTION_UPPER_BOUND = + Instant.ofEpochMilli(Long.MAX_VALUE); private static final int[] ARBITRARY_ORIGIN_PRIORITIES = { ORIGIN_NETWORK }; private Context mMockContext; @@ -444,9 +446,10 @@ public class TimeDetectorServiceTest { .setUserConfigAllowed(true) .setAutoDetectionSupported(true) .setSystemClockUpdateThresholdMillis(ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(ARBITRARY_AUTO_TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(ARBITRARY_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(ARBITRARY_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ARBITRARY_ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(autoDetectionEnabled) .build(); } diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java index aeb5c65c8692f..1aea6727d3a17 100644 --- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java +++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java @@ -53,7 +53,16 @@ public class TimeDetectorStrategyImplTest { private static final @UserIdInt int ARBITRARY_USER_ID = 9876; private static final int ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS = 1234; - private static final Instant TIME_LOWER_BOUND = createUnixEpochTime(2009, 1, 1, 12, 0, 0); + private static final Instant DEFAULT_SUGGESTION_LOWER_BOUND = + createUnixEpochTime(2005, 1, 1, 1, 0, 0); + /** A value after {@link #DEFAULT_SUGGESTION_LOWER_BOUND} */ + private static final Instant TEST_SUGGESTION_LOWER_BOUND = + createUnixEpochTime(2006, 1, 1, 1, 0, 0); + private static final Instant DEFAULT_SUGGESTION_UPPER_BOUND = + createUnixEpochTime(2099, 12, 1, 1, 0, 0); + /** A value before {@link #DEFAULT_SUGGESTION_UPPER_BOUND} */ + private static final Instant TEST_SUGGESTION_UPPER_BOUND = + createUnixEpochTime(2037, 12, 1, 1, 0, 0); private static final TimestampedValue ARBITRARY_CLOCK_INITIALIZATION_INFO = new TimestampedValue<>( @@ -77,9 +86,10 @@ public class TimeDetectorStrategyImplTest { .setAutoDetectionSupported(true) .setSystemClockUpdateThresholdMillis( ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(false) .build(); @@ -89,9 +99,10 @@ public class TimeDetectorStrategyImplTest { .setAutoDetectionSupported(true) .setSystemClockUpdateThresholdMillis( ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS) - .setAutoTimeLowerBound(TIME_LOWER_BOUND) + .setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND) + .setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND) + .setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND) .setOriginPriorities(ORIGIN_PRIORITIES) - .setDeviceHasY2038Issue(true) .setAutoDetectionEnabledSetting(true) .build(); @@ -343,22 +354,6 @@ public class TimeDetectorStrategyImplTest { .assertLatestTelephonySuggestion(slotIndex, timeSuggestion4); } - @Test - public void telephonyTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() { - Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED); - - int slotIndex = ARBITRARY_SLOT_INDEX; - Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1)); - - TelephonyTimeSuggestion timeSuggestion = - script.generateTelephonyTimeSuggestion( - slotIndex, suggestedTime); - - script.simulateTelephonyTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking() - .assertLatestTelephonySuggestion(slotIndex, null); - } - @Test public void testSuggestTelephonyTime_timeDetectionToggled() { final int clockIncrementMillis = 100; @@ -452,6 +447,70 @@ public class TimeDetectorStrategyImplTest { script.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion); } + @Test + public void testSuggestTelephonyTime_rejectedBelowLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) + .setOriginPriorities(ORIGIN_TELEPHONY) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1); + TelephonyTimeSuggestion timeSuggestion = + script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowLowerBound); + script.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestTelephonyTime_notRejectedAboveLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_TELEPHONY) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1); + TelephonyTimeSuggestion timeSuggestion = + script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveLowerBound); + script.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli()); + } + + @Test + public void testSuggestTelephonyTime_rejectedAboveUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_TELEPHONY) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1); + TelephonyTimeSuggestion timeSuggestion = + script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveUpperBound); + script.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestTelephonyTime_notRejectedBelowUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_TELEPHONY) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1); + TelephonyTimeSuggestion timeSuggestion = + script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowUpperBound); + script.simulateTelephonyTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli()); + } + @Test public void testSuggestManualTime_autoTimeDisabled() { Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED); @@ -530,7 +589,7 @@ public class TimeDetectorStrategyImplTest { } @Test - public void manualTimeSuggestion_isIgnored_whenAutoTimeEnabled() { + public void testSuggestManualTime_isIgnored_whenAutoTimeEnabled() { Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED); ManualTimeSuggestion timeSuggestion = @@ -543,16 +602,63 @@ public class TimeDetectorStrategyImplTest { } @Test - public void manualTimeSuggestion_ignoresTimeLowerBound() { - Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED); - Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1)); - - ManualTimeSuggestion timeSuggestion = - script.generateManualTimeSuggestion(suggestedTime); + public void testSuggestManualTime_rejectedAboveUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1); + ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveUpperBound); script.simulateManualTimeSuggestion( - ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */) - .verifySystemClockWasSetAndResetCallTracking(suggestedTime.toEpochMilli()); + ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestManualTime_notRejectedBelowUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1); + ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowUpperBound); + script.simulateManualTimeSuggestion( + ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */) + .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli()); + } + + @Test + public void testSuggestManualTime_rejectedBelowLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) + .setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1); + ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowLowerBound); + script.simulateManualTimeSuggestion( + ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestManualTimes_notRejectedAboveLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) + .setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1); + ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveLowerBound); + script.simulateManualTimeSuggestion( + ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */) + .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli()); } @Test @@ -591,20 +697,67 @@ public class TimeDetectorStrategyImplTest { } @Test - public void networkTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() { + public void testSuggestNetworkTime_rejectedBelowLowerBound() { ConfigurationInternal configInternal = new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) .setOriginPriorities(ORIGIN_NETWORK) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) .build(); Script script = new Script().simulateConfigurationInternalChange(configInternal); - Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1)); + Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1); NetworkTimeSuggestion timeSuggestion = - script.generateNetworkTimeSuggestion(suggestedTime); - + script.generateNetworkTimeSuggestion(belowLowerBound); script.simulateNetworkTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking() - .assertLatestNetworkSuggestion(null); + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestNetworkTime_notRejectedAboveLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_NETWORK) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1); + NetworkTimeSuggestion timeSuggestion = + script.generateNetworkTimeSuggestion(aboveLowerBound); + script.simulateNetworkTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli()); + } + + @Test + public void testSuggestNetworkTime_rejectedAboveUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_NETWORK) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1); + NetworkTimeSuggestion timeSuggestion = + script.generateNetworkTimeSuggestion(aboveUpperBound); + script.simulateNetworkTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestNetworkTime_notRejectedBelowUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_NETWORK) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1); + NetworkTimeSuggestion timeSuggestion = + script.generateNetworkTimeSuggestion(belowUpperBound); + script.simulateNetworkTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli()); } @Test @@ -642,6 +795,70 @@ public class TimeDetectorStrategyImplTest { .verifySystemClockWasNotSetAndResetCallTracking(); } + @Test + public void testSuggestGnssTime_rejectedBelowLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_GNSS) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1); + GnssTimeSuggestion timeSuggestion = + script.generateGnssTimeSuggestion(belowLowerBound); + script.simulateGnssTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestGnssTime_notRejectedAboveLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_GNSS) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1); + GnssTimeSuggestion timeSuggestion = + script.generateGnssTimeSuggestion(aboveLowerBound); + script.simulateGnssTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli()); + } + + @Test + public void testSuggestGnssTime_rejectedAboveUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_GNSS) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1); + GnssTimeSuggestion timeSuggestion = + script.generateGnssTimeSuggestion(aboveUpperBound); + script.simulateGnssTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestGnssTime_notRejectedBelowUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_GNSS) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1); + GnssTimeSuggestion timeSuggestion = + script.generateGnssTimeSuggestion(belowUpperBound); + script.simulateGnssTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli()); + } + @Test public void testSuggestExternalTime_autoTimeEnabled() { ConfigurationInternal configInternal = @@ -678,20 +895,67 @@ public class TimeDetectorStrategyImplTest { } @Test - public void externalTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() { + public void testSuggestExternalTime_rejectedBelowLowerBound() { ConfigurationInternal configInternal = new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) .setOriginPriorities(ORIGIN_EXTERNAL) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) .build(); Script script = new Script().simulateConfigurationInternalChange(configInternal); - Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1)); + Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1); ExternalTimeSuggestion timeSuggestion = - script.generateExternalTimeSuggestion(suggestedTime); - + script.generateExternalTimeSuggestion(belowLowerBound); script.simulateExternalTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking() - .assertLatestExternalSuggestion(null); + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestExternalTime_notRejectedAboveLowerBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_EXTERNAL) + .setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1); + ExternalTimeSuggestion timeSuggestion = + script.generateExternalTimeSuggestion(aboveLowerBound); + script.simulateExternalTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli()); + } + + @Test + public void testSuggestExternalTime_rejectedAboveUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_EXTERNAL) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1); + ExternalTimeSuggestion timeSuggestion = + script.generateExternalTimeSuggestion(aboveUpperBound); + script.simulateExternalTimeSuggestion(timeSuggestion) + .verifySystemClockWasNotSetAndResetCallTracking(); + } + + @Test + public void testSuggestExternalTime_notRejectedBelowUpperBound() { + ConfigurationInternal configInternal = + new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) + .setOriginPriorities(ORIGIN_EXTERNAL) + .setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND) + .build(); + Script script = new Script().simulateConfigurationInternalChange(configInternal); + + Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1); + ExternalTimeSuggestion timeSuggestion = + script.generateExternalTimeSuggestion(belowUpperBound); + script.simulateExternalTimeSuggestion(timeSuggestion) + .verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli()); } @Test @@ -1198,56 +1462,6 @@ public class TimeDetectorStrategyImplTest { .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli()); } - @Test - public void manualY2038SuggestionsAreRejectedOnAffectedDevices() { - ConfigurationInternal configInternal = - new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED) - .setOriginPriorities(ORIGIN_TELEPHONY) - .setDeviceHasY2038Issue(true) - .build(); - Script script = new Script().simulateConfigurationInternalChange(configInternal); - - Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); - ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(y2038IssueTime); - script.simulateManualTimeSuggestion( - ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */) - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - @Test - public void telephonyY2038SuggestionsAreRejectedOnAffectedDevices() { - ConfigurationInternal configInternal = - new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) - .setOriginPriorities(ORIGIN_TELEPHONY) - .setDeviceHasY2038Issue(true) - .build(); - Script script = new Script().simulateConfigurationInternalChange(configInternal); - - final int slotIndex = 0; - Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); - TelephonyTimeSuggestion timeSuggestion = - script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime); - script.simulateTelephonyTimeSuggestion(timeSuggestion) - .verifySystemClockWasNotSetAndResetCallTracking(); - } - - @Test - public void telephonyY2038SuggestionsAreNotRejectedOnUnaffectedDevices() { - ConfigurationInternal configInternal = - new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED) - .setOriginPriorities(ORIGIN_TELEPHONY) - .setDeviceHasY2038Issue(false) - .build(); - Script script = new Script().simulateConfigurationInternalChange(configInternal); - - final int slotIndex = 0; - Instant y2038IssueTime = Instant.ofEpochMilli((1L + Integer.MAX_VALUE) * 1000L); - TelephonyTimeSuggestion timeSuggestion = - script.generateTelephonyTimeSuggestion(slotIndex, y2038IssueTime); - script.simulateTelephonyTimeSuggestion(timeSuggestion) - .verifySystemClockWasSetAndResetCallTracking(y2038IssueTime.toEpochMilli()); - } - /** * A fake implementation of {@link TimeDetectorStrategyImpl.Environment}. Besides tracking * changes and behaving like the real thing should, it also asserts preconditions.