summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Neil Fuller <nfuller@google.com> 2019-11-23 11:33:57 +0000
committer Neil Fuller <nfuller@google.com> 2019-11-27 16:34:53 +0000
commit3aedd4923850b2c93bbc25d8a055af23e403f687 (patch)
tree4e51450e4f4f7981d2adad49aa614586038c1a60
parent9e5de85e21d9373bc8248827bc12e3e995b57c98 (diff)
Add a new method to set time
Before this change there are a various components that set the system clock by directly calling AlarmManager.setTime(). This change exposes a new method on TimeDetector to use when setting the device time manually (e.g. via settings) and modifies some callers to use it. The intent is to later restrict the number of distinct processes that can manipulate the device system clock directly so that all time changes go through the time detector service, which can enforce policy, log the reasons for changes, and so on. Bug: 140712361 Test: atest com.android.server.timedetector Change-Id: I9300dba868ed61249d0848b0dd4b953996161bda Merged-In: I9300dba868ed61249d0848b0dd4b953996161bda (cherry picked from commit e376756b0c0e3164300c3fd624f9221181e82553)
-rw-r--r--core/java/android/app/timedetector/ITimeDetectorService.aidl2
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.aidl19
-rw-r--r--core/java/android/app/timedetector/ManualTimeSuggestion.java127
-rw-r--r--core/java/android/app/timedetector/TimeDetector.java37
-rw-r--r--services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java131
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorService.java28
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java8
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java11
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java15
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java151
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java39
15 files changed, 504 insertions, 77 deletions
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index ddc4932d6fec..9877fc741b7b 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,6 +16,7 @@
package android.app.timedetector;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
/**
@@ -33,4 +34,5 @@ import android.app.timedetector.PhoneTimeSuggestion;
*/
interface ITimeDetectorService {
void suggestPhoneTime(in PhoneTimeSuggestion timeSuggestion);
+ void suggestManualTime(in ManualTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.aidl b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
new file mode 100644
index 000000000000..213940493114
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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;
+
+parcelable ManualTimeSuggestion;
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
new file mode 100644
index 000000000000..e7d619a27607
--- /dev/null
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 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.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a manual (user provided) source. The value consists of the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
+ * clock when that number was established. The elapsed realtime clock is considered accurate but
+ * volatile, so time signals must not be persisted across device resets.
+ *
+ * @hide
+ */
+public final class ManualTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Creator<ManualTimeSuggestion> CREATOR =
+ new Creator<ManualTimeSuggestion>() {
+ public ManualTimeSuggestion createFromParcel(Parcel in) {
+ return ManualTimeSuggestion.createFromParcel(in);
+ }
+
+ public ManualTimeSuggestion[] newArray(int size) {
+ return new ManualTimeSuggestion[size];
+ }
+ };
+
+ @NonNull
+ private final TimestampedValue<Long> mUtcTime;
+ @Nullable
+ private ArrayList<String> mDebugInfo;
+
+ public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
+ mUtcTime = Objects.requireNonNull(utcTime);
+ }
+
+ private static ManualTimeSuggestion createFromParcel(Parcel in) {
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ ManualTimeSuggestion suggestion = new ManualTimeSuggestion(utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ManualTimeSuggestion that = (ManualTimeSuggestion) o;
+ return Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "ManualTimeSuggestion{"
+ + "mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 334e9582a145..48d5cd2d65a5 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -17,19 +17,22 @@
package android.app.timedetector;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemClock;
import android.util.Log;
+import android.util.TimestampedValue;
/**
* The interface through which system components can send signals to the TimeDetectorService.
* @hide
*/
@SystemService(Context.TIME_DETECTOR_SERVICE)
-public final class TimeDetector {
+public class TimeDetector {
private static final String TAG = "timedetector.TimeDetector";
private static final boolean DEBUG = false;
@@ -41,10 +44,11 @@ public final class TimeDetector {
}
/**
- * Suggests the current time to the detector. The detector may ignore the signal if better
- * signals are available such as those that come from more reliable sources or were
- * determined more recently.
+ * Suggests the current phone-signal derived time to the detector. The detector may ignore the
+ * signal if better signals are available such as those that come from more reliable sources or
+ * were determined more recently.
*/
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
if (DEBUG) {
Log.d(TAG, "suggestPhoneTime called: " + timeSuggestion);
@@ -56,4 +60,29 @@ public final class TimeDetector {
}
}
+ /**
+ * Suggests the user's manually entered current time to the detector.
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestManualTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestManualTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * A shared utility method to create a {@link ManualTimeSuggestion}.
+ */
+ public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(SystemClock.elapsedRealtime(), when);
+ ManualTimeSuggestion manualTimeSuggestion = new ManualTimeSuggestion(utcTime);
+ manualTimeSuggestion.addDebugInfo(why);
+ return manualTimeSuggestion;
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index fd8cc24b658b..3c79b2399fa3 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -16,9 +16,11 @@
package com.android.server.timedetector;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.Slog;
@@ -27,6 +29,8 @@ import android.util.TimestampedValue;
import com.android.internal.telephony.TelephonyIntents;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
@@ -38,10 +42,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
+ @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Origin {}
+
+ /** Used when a time value originated from a telephony signal. */
+ @Origin
+ private static final int ORIGIN_PHONE = 1;
+
+ /** Used when a time value originated from a user / manual settings. */
+ @Origin
+ private static final int ORIGIN_MANUAL = 2;
+
/**
* CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
* actual system clock time before a warning is logged. Used to help identify situations where
- * there is something other than this class setting the system clock.
+ * there is something other than this class setting the system clock automatically.
*/
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
@@ -52,11 +68,11 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
@Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
// Information about the last time signal received: Used when toggling auto-time.
- @Nullable private TimestampedValue<Long> mLastSystemClockTime;
- private boolean mLastSystemClockTimeSendNetworkBroadcast;
+ @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
+ private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
// System clock state.
- @Nullable private TimestampedValue<Long> mLastSystemClockTimeSet;
+ @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
@Override
public void initialize(@NonNull Callback callback) {
@@ -78,17 +94,18 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
return;
}
// Always store the last NITZ value received, regardless of whether we go on to use it to
- // update the system clock. This is so that we can validate future NITZ signals.
+ // update the system clock. This is so that we can validate future phone suggestions.
mLastPhoneSuggestion = timeSuggestion;
// System clock update logic.
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
+ setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
+ }
- // Historically, Android has sent a telephony broadcast only when setting the time using
- // NITZ.
- final boolean sendNetworkBroadcast = true;
-
+ @Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
- setSystemClockIfRequired(newUtcTime, sendNetworkBroadcast);
+ setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
}
private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
@@ -110,16 +127,31 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
}
private void setSystemClockIfRequired(
- TimestampedValue<Long> time, boolean sendNetworkBroadcast) {
-
- // Store the last candidate we've seen in all cases so we can set the system clock
- // when/if time detection is enabled.
- mLastSystemClockTime = time;
- mLastSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
-
- if (!mCallback.isTimeDetectionEnabled()) {
- Slog.d(TAG, "setSystemClockIfRequired: Time detection is not enabled. time=" + time);
- return;
+ @Origin int origin, TimestampedValue<Long> time, Object cause) {
+ // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
+ // when setting the time using NITZ.
+ boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
+
+ boolean isOriginAutomatic = isOriginAutomatic(origin);
+ if (isOriginAutomatic) {
+ // Store the last auto time candidate we've seen in all cases so we can set the system
+ // clock when/if time detection is off but later enabled.
+ mLastAutoSystemClockTime = time;
+ mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
+
+ if (!mCallback.isAutoTimeDetectionEnabled()) {
+ Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is not enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ return;
+ }
+ } else {
+ if (mCallback.isAutoTimeDetectionEnabled()) {
+ Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ return;
+ }
}
mCallback.acquireWakeLock();
@@ -127,37 +159,44 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
long actualTimeMillis = mCallback.systemClockMillis();
- // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
- // may be setting the clock.
- if (mLastSystemClockTimeSet != null) {
- long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
- mLastSystemClockTimeSet, elapsedRealtimeMillis);
- long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
- if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
- Slog.w(TAG, "System clock has not tracked elapsed real time clock. A clock may"
- + " be inaccurate or something unexpectedly set the system clock."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " expectedTimeMillis=" + expectedTimeMillis
- + " actualTimeMillis=" + actualTimeMillis);
+ if (isOriginAutomatic) {
+ // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
+ // may be setting the clock.
+ if (mLastAutoSystemClockTimeSet != null) {
+ long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
+ mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
+ long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
+ if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
+ Slog.w(TAG,
+ "System clock has not tracked elapsed real time clock. A clock may"
+ + " be inaccurate or something unexpectedly set the system"
+ + " clock."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " expectedTimeMillis=" + expectedTimeMillis
+ + " actualTimeMillis=" + actualTimeMillis);
+ }
}
}
- final String reason = "New time signal";
adjustAndSetDeviceSystemClock(
- time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, reason);
+ time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
} finally {
mCallback.releaseWakeLock();
}
}
+ private static boolean isOriginAutomatic(@Origin int origin) {
+ return origin == ORIGIN_PHONE;
+ }
+
@Override
public void handleAutoTimeDetectionToggle(boolean enabled) {
// If automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, if automatic time detection is disabled we leave the clock as it is.
if (enabled) {
- if (mLastSystemClockTime != null) {
+ if (mLastAutoSystemClockTime != null) {
// Only send the network broadcast if the last candidate would have caused one.
- final boolean sendNetworkBroadcast = mLastSystemClockTimeSendNetworkBroadcast;
+ final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
mCallback.acquireWakeLock();
try {
@@ -165,7 +204,7 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
long actualTimeMillis = mCallback.systemClockMillis();
final String reason = "Automatic time detection enabled.";
- adjustAndSetDeviceSystemClock(mLastSystemClockTime, sendNetworkBroadcast,
+ adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
elapsedRealtimeMillis, actualTimeMillis, reason);
} finally {
mCallback.releaseWakeLock();
@@ -174,22 +213,22 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
} else {
// CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
// it should be in future.
- mLastSystemClockTimeSet = null;
+ mLastAutoSystemClockTimeSet = null;
}
}
@Override
public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
- pw.println("mLastSystemClockTimeSet=" + mLastSystemClockTimeSet);
- pw.println("mLastSystemClockTime=" + mLastSystemClockTime);
- pw.println("mLastSystemClockTimeSendNetworkBroadcast="
- + mLastSystemClockTimeSendNetworkBroadcast);
+ pw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
+ pw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
+ pw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
+ + mLastAutoSystemClockTimeSendNetworkBroadcast);
}
private void adjustAndSetDeviceSystemClock(
TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
- long elapsedRealtimeMillis, long actualSystemClockMillis, String reason) {
+ long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
@@ -203,20 +242,20 @@ public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
+ " system clock are close enough."
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " newTime=" + newTime
- + " reason=" + reason
+ + " cause=" + cause
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ " absTimeDifference=" + absTimeDifference);
return;
}
Slog.d(TAG, "Setting system clock using time=" + newTime
- + " reason=" + reason
+ + " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " newTimeMillis=" + newSystemClockMillis);
mCallback.setSystemClock(newSystemClockMillis);
// CLOCK_PARANOIA : Record the last time this class set the system clock.
- mLastSystemClockTimeSet = newTime;
+ mLastAutoSystemClockTimeSet = newTime;
if (sendNetworkBroadcast) {
// Send a broadcast that telephony code used to send after setting the clock.
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index ee42279f7d50..09309751d493 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -19,6 +19,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.timedetector.ITimeDetectorService;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.ContentResolver;
import android.content.Context;
@@ -97,7 +98,7 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
@Override
public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSignal) {
- enforceSetTimePermission();
+ enforceSuggestPhoneTimePermission();
Objects.requireNonNull(timeSignal);
long idToken = Binder.clearCallingIdentity();
@@ -110,10 +111,25 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
}
+ @Override
+ public void suggestManualTime(@NonNull ManualTimeSuggestion timeSignal) {
+ enforceSuggestManualTimePermission();
+ Objects.requireNonNull(timeSignal);
+
+ long idToken = Binder.clearCallingIdentity();
+ try {
+ synchronized (mStrategyLock) {
+ mTimeDetectorStrategy.suggestManualTime(timeSignal);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(idToken);
+ }
+ }
+
@VisibleForTesting
public void handleAutoTimeDetectionToggle() {
synchronized (mStrategyLock) {
- final boolean timeDetectionEnabled = mCallback.isTimeDetectionEnabled();
+ final boolean timeDetectionEnabled = mCallback.isAutoTimeDetectionEnabled();
mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
}
}
@@ -128,7 +144,11 @@ public final class TimeDetectorService extends ITimeDetectorService.Stub {
}
}
- private void enforceSetTimePermission() {
+ private void enforceSuggestPhoneTimePermission() {
+ mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
+ }
+
+ private void enforceSuggestManualTimePermission() {
mContext.enforceCallingPermission(android.Manifest.permission.SET_TIME, "set time");
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index 7c2a945854f5..b60cebf57b45 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -18,6 +18,7 @@ package com.android.server.timedetector;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.util.TimestampedValue;
@@ -47,7 +48,7 @@ public interface TimeDetectorStrategy {
int systemClockUpdateThresholdMillis();
/** Returns true if automatic time detection is enabled. */
- boolean isTimeDetectionEnabled();
+ boolean isAutoTimeDetectionEnabled();
/** Acquire a suitable wake lock. Must be followed by {@link #releaseWakeLock()} */
void acquireWakeLock();
@@ -71,9 +72,12 @@ public interface TimeDetectorStrategy {
/** Initialize the strategy. */
void initialize(@NonNull Callback callback);
- /** Process the suggested time. */
+ /** Process the suggested time from telephony sources. */
void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion);
+ /** Process the suggested manually entered time. */
+ void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
+
/** Handle the auto-time setting being toggled on or off. */
void handleAutoTimeDetectionToggle(boolean enabled);
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
index 77b9e6281086..42d59d51c6af 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyCallbackImpl.java
@@ -72,7 +72,7 @@ public final class TimeDetectorStrategyCallbackImpl implements TimeDetectorStrat
}
@Override
- public boolean isTimeDetectionEnabled() {
+ public boolean isAutoTimeDetectionEnabled() {
try {
return Settings.Global.getInt(mContentResolver, Settings.Global.AUTO_TIME) != 0;
} catch (Settings.SettingNotFoundException snfe) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 2e56fb096e3b..e8617bce920e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -133,6 +133,8 @@ import android.app.admin.StartInstallingUpdateCallback;
import android.app.admin.SystemUpdateInfo;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
+import android.app.timedetector.ManualTimeSuggestion;
+import android.app.timedetector.TimeDetector;
import android.app.trust.TrustManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
@@ -1950,6 +1952,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return mContext.getSystemService(AlarmManager.class);
}
+ TimeDetector getTimeDetector() {
+ return mContext.getSystemService(TimeDetector.class);
+ }
+
ConnectivityManager getConnectivityManager() {
return mContext.getSystemService(ConnectivityManager.class);
}
@@ -10859,7 +10865,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
if (mInjector.settingsGlobalGetInt(Global.AUTO_TIME, 0) == 1) {
return false;
}
- mInjector.binderWithCleanCallingIdentity(() -> mInjector.getAlarmManager().setTime(millis));
+ ManualTimeSuggestion manualTimeSuggestion = TimeDetector.createManualTimeSuggestion(
+ millis, "DevicePolicyManagerService: setTime");
+ mInjector.binderWithCleanCallingIdentity(
+ () -> mInjector.getTimeDetector().suggestManualTime(manualTimeSuggestion));
return true;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 2ce4c54a932b..0fde850d3021 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -22,6 +22,7 @@ import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
import android.content.Intent;
@@ -217,6 +218,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
AlarmManager getAlarmManager() {return services.alarmManager;}
@Override
+ TimeDetector getTimeDetector() {
+ return services.timeDetector;
+ }
+
+ @Override
LockPatternUtils newLockPatternUtils() {
return services.lockPatternUtils;
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 9ae9824da3e2..b93b47ad74bd 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -63,6 +63,7 @@ import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.PasswordMetrics;
+import android.app.timedetector.ManualTimeSuggestion;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
@@ -3473,7 +3474,19 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
dpm.setTime(admin1, 0);
- verify(getServices().alarmManager).setTime(0);
+
+ BaseMatcher<ManualTimeSuggestion> hasZeroTime = new BaseMatcher<ManualTimeSuggestion>() {
+ @Override
+ public boolean matches(Object item) {
+ final ManualTimeSuggestion suggestion = (ManualTimeSuggestion) item;
+ return suggestion.getUtcTime().getValue() == 0;
+ }
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("ManualTimeSuggestion{utcTime.value=0}");
+ }
+ };
+ verify(getServices().timeDetector).suggestManualTime(argThat(hasZeroTime));
}
public void testSetTimeFailWithPO() throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index bd513dc083be..1a67576c218f 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -207,6 +207,8 @@ public class DpmMockContext extends MockContext {
switch (name) {
case Context.ALARM_SERVICE:
return mMockSystemServices.alarmManager;
+ case Context.TIME_DETECTOR_SERVICE:
+ return mMockSystemServices.timeDetector;
case Context.USER_SERVICE:
return mMockSystemServices.userManager;
case Context.POWER_SERVICE:
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
index 8f0aeea3dbf8..b208f828ee85 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockSystemServices.java
@@ -31,6 +31,7 @@ import android.app.IActivityManager;
import android.app.IActivityTaskManager;
import android.app.NotificationManager;
import android.app.backup.IBackupManager;
+import android.app.timedetector.TimeDetector;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@@ -107,6 +108,7 @@ public class MockSystemServices {
public final TelephonyManager telephonyManager;
public final AccountManager accountManager;
public final AlarmManager alarmManager;
+ public final TimeDetector timeDetector;
public final KeyChain.KeyChainConnection keyChainConnection;
/** Note this is a partial mock, not a real mock. */
public final PackageManager packageManager;
@@ -146,6 +148,7 @@ public class MockSystemServices {
telephonyManager = mock(TelephonyManager.class);
accountManager = mock(AccountManager.class);
alarmManager = mock(AlarmManager.class);
+ timeDetector = mock(TimeDetector.class);
keyChainConnection = mock(KeyChain.KeyChainConnection.class, RETURNS_DEEP_STUBS);
// Package manager is huge, so we use a partial mock instead.
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
index b49845ae4006..317fd4d566ae 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
import android.icu.util.Calendar;
@@ -36,6 +37,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.time.Duration;
+
@RunWith(AndroidJUnit4.class)
public class SimpleTimeZoneDetectorStrategyTest {
@@ -47,6 +50,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
private static final int ARBITRARY_PHONE_ID = 123456;
+ private static final long ONE_DAY_MILLIS = Duration.ofDays(1).toMillis();
+
private Script mScript;
@Before
@@ -55,7 +60,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestPhoneTime_nitz_timeDetectionEnabled() {
+ public void testSuggestPhoneTime_autoTimeEnabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(true);
@@ -67,7 +72,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
mScript.simulateTimePassing(clockIncrement)
.simulatePhoneTimeSuggestion(timeSuggestion)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis, true /* expectNetworkBroadcast */);
}
@Test
@@ -103,7 +109,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Send the first time signal. It should be used.
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis1, true /* expectNetworkBroadcast */);
// Now send another time signal, but one that is too similar to the last one and should be
// ignored.
@@ -130,11 +137,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
TimeDetectorStrategy.getTimeAt(utcTime3, mScript.peekElapsedRealtimeMillis());
mScript.simulatePhoneTimeSuggestion(timeSuggestion3)
- .verifySystemClockWasSetAndResetCallTracking(expectSystemClockMillis3);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis3, true /* expectNetworkBroadcast */);
}
@Test
- public void testSuggestPhoneTime_nitz_timeDetectionDisabled() {
+ public void testSuggestPhoneTime_autoTimeDisabled() {
Scenario scenario = SCENARIO_1;
mScript.pokeFakeClocks(scenario)
.pokeTimeDetectionEnabled(false);
@@ -146,7 +154,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Test
- public void testSuggestPhoneTime_nitz_invalidNitzReferenceTimesIgnored() {
+ public void testSuggestPhoneTime_invalidNitzReferenceTimesIgnored() {
Scenario scenario = SCENARIO_1;
final int systemClockUpdateThreshold = 2000;
mScript.pokeFakeClocks(scenario)
@@ -161,7 +169,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
long expectedSystemClockMillis1 =
TimeDetectorStrategy.getTimeAt(utcTime1, mScript.peekElapsedRealtimeMillis());
mScript.simulatePhoneTimeSuggestion(timeSuggestion1)
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
// The UTC time increment should be larger than the system clock update threshold so we
// know it shouldn't be ignored for other reasons.
@@ -197,7 +206,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
PhoneTimeSuggestion timeSuggestion4 =
createPhoneTimeSuggestion(ARBITRARY_PHONE_ID, utcTime4);
mScript.simulatePhoneTimeSuggestion(timeSuggestion4)
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis4, true /* expectNetworkBroadcast */);
}
@Test
@@ -229,7 +239,8 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis1, true /* expectNetworkBroadcast */);
// Turn off auto time detection.
mScript.simulateAutoTimeDetectionToggle()
@@ -256,7 +267,99 @@ public class SimpleTimeZoneDetectorStrategyTest {
// Turn on auto time detection.
mScript.simulateAutoTimeDetectionToggle()
- .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2);
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedSystemClockMillis2, true /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestManualTime_autoTimeDisabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(false);
+
+ ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ final int clockIncrement = 1000;
+ long expectSystemClockMillis = scenario.getActualTimeMillis() + clockIncrement;
+
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateManualTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectSystemClockMillis, false /* expectNetworkBroadcast */);
+ }
+
+ @Test
+ public void testSuggestManualTime_retainsAutoSignal() {
+ Scenario scenario = SCENARIO_1;
+
+ // Configure the start state.
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
+
+ // Simulate a phone suggestion.
+ PhoneTimeSuggestion phoneTimeSuggestion =
+ scenario.createPhoneTimeSuggestionForActual(ARBITRARY_PHONE_ID);
+ long expectedAutoClockMillis = phoneTimeSuggestion.getUtcTime().getValue();
+ final int clockIncrement = 1000;
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ mScript.simulatePhoneTimeSuggestion(phoneTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ // Switch to manual.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+
+ // Simulate a manual suggestion 1 day different from the auto suggestion.
+ long manualTimeMillis = SCENARIO_1.getActualTimeMillis() + ONE_DAY_MILLIS;
+ long expectedManualClockMillis = manualTimeMillis;
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion(manualTimeMillis);
+ mScript.simulateManualTimeSuggestion(manualTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ expectedManualClockMillis, false /* expectNetworkBroadcast */);
+
+ // Simulate the passage of time.
+ mScript.simulateTimePassing(clockIncrement);
+ expectedAutoClockMillis += clockIncrement;
+
+ // Switch back to auto.
+ mScript.simulateAutoTimeDetectionToggle();
+
+ mScript.verifySystemClockWasSetAndResetCallTracking(
+ expectedAutoClockMillis, true /* expectNetworkBroadcast */);
+
+ // Switch back to manual - nothing should happen to the clock.
+ mScript.simulateAutoTimeDetectionToggle()
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ /**
+ * Manual suggestions should be ignored if auto time is enabled.
+ */
+ @Test
+ public void testSuggestManualTime_autoTimeEnabled() {
+ Scenario scenario = SCENARIO_1;
+ mScript.pokeFakeClocks(scenario)
+ .pokeTimeDetectionEnabled(true);
+
+ ManualTimeSuggestion timeSuggestion = scenario.createManualTimeSuggestionForActual();
+ final int clockIncrement = 1000;
+
+ mScript.simulateTimePassing(clockIncrement)
+ .simulateManualTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
}
/**
@@ -280,7 +383,7 @@ public class SimpleTimeZoneDetectorStrategyTest {
}
@Override
- public boolean isTimeDetectionEnabled() {
+ public boolean isAutoTimeDetectionEnabled() {
return mTimeDetectionEnabled;
}
@@ -426,8 +529,13 @@ public class SimpleTimeZoneDetectorStrategyTest {
return this;
}
+ Script simulateManualTimeSuggestion(ManualTimeSuggestion timeSuggestion) {
+ mSimpleTimeDetectorStrategy.suggestManualTime(timeSuggestion);
+ return this;
+ }
+
Script simulateAutoTimeDetectionToggle() {
- boolean enabled = !mFakeCallback.isTimeDetectionEnabled();
+ boolean enabled = !mFakeCallback.isAutoTimeDetectionEnabled();
mFakeCallback.pokeTimeDetectionEnabled(enabled);
mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
return this;
@@ -445,9 +553,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
return this;
}
- Script verifySystemClockWasSetAndResetCallTracking(long expectSystemClockMillis) {
+ Script verifySystemClockWasSetAndResetCallTracking(
+ long expectSystemClockMillis, boolean expectNetworkBroadcast) {
mFakeCallback.verifySystemClockWasSet(expectSystemClockMillis);
- mFakeCallback.verifyIntentWasBroadcast();
+ if (expectNetworkBroadcast) {
+ mFakeCallback.verifyIntentWasBroadcast();
+ }
mFakeCallback.resetCallTracking();
return this;
}
@@ -486,6 +597,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
return createPhoneTimeSuggestion(phoneId, time);
}
+ ManualTimeSuggestion createManualTimeSuggestionForActual() {
+ TimestampedValue<Long> time = new TimestampedValue<>(
+ mInitialDeviceRealtimeMillis, mActualTimeMillis);
+ return new ManualTimeSuggestion(time);
+ }
+
static class Builder {
private long mInitialDeviceSystemClockMillis;
@@ -525,6 +642,12 @@ public class SimpleTimeZoneDetectorStrategyTest {
return timeSuggestion;
}
+ private ManualTimeSuggestion createManualTimeSuggestion(long timeMillis) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(mScript.peekElapsedRealtimeMillis(), timeMillis);
+ return new ManualTimeSuggestion(utcTime);
+ }
+
private static long createUtcTime(int year, int monthInYear, int day, int hourOfDay, int minute,
int second) {
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/UTC"));
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 cfd8a457d2f0..4efe771a4e95 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -28,6 +28,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -90,6 +91,19 @@ public class TimeDetectorServiceTest {
}
@Test
+ public void testSuggestManualTime() {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
+ mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SET_TIME),
+ anyString());
+ mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
+ }
+
+ @Test
public void testDump() {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
.thenReturn(PackageManager.PERMISSION_GRANTED);
@@ -102,13 +116,13 @@ public class TimeDetectorServiceTest {
@Test
public void testAutoTimeDetectionToggle() {
- when(mMockCallback.isTimeDetectionEnabled()).thenReturn(true);
+ when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(true);
mTimeDetectorService.handleAutoTimeDetectionToggle();
mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
- when(mMockCallback.isTimeDetectionEnabled()).thenReturn(false);
+ when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(false);
mTimeDetectorService.handleAutoTimeDetectionToggle();
@@ -123,10 +137,16 @@ public class TimeDetectorServiceTest {
return suggestion;
}
+ private static ManualTimeSuggestion createManualTimeSuggestion() {
+ TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+ return new ManualTimeSuggestion(timeValue);
+ }
+
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
private PhoneTimeSuggestion mLastPhoneSuggestion;
+ private ManualTimeSuggestion mLastManualSuggestion;
private Boolean mLastAutoTimeDetectionToggle;
private boolean mDumpCalled;
@@ -141,6 +161,12 @@ public class TimeDetectorServiceTest {
}
@Override
+ public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+ resetCallTracking();
+ mLastManualSuggestion = timeSuggestion;
+ }
+
+ @Override
public void handleAutoTimeDetectionToggle(boolean enabled) {
resetCallTracking();
mLastAutoTimeDetectionToggle = enabled;
@@ -154,12 +180,17 @@ public class TimeDetectorServiceTest {
void resetCallTracking() {
mLastPhoneSuggestion = null;
+ mLastManualSuggestion = null;
mLastAutoTimeDetectionToggle = null;
mDumpCalled = false;
}
- void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSignal) {
- assertEquals(expectedSignal, mLastPhoneSuggestion);
+ void verifySuggestPhoneTimeCalled(PhoneTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastPhoneSuggestion);
+ }
+
+ public void verifySuggestManualTimeCalled(ManualTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastManualSuggestion);
}
void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {