summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java113
-rw-r--r--apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp80
-rw-r--r--services/core/java/com/android/server/AlarmManagerInternal.java13
-rw-r--r--services/core/java/com/android/server/SystemClockTime.java174
-rw-r--r--services/core/java/com/android/server/timedetector/ConfigurationInternal.java58
-rw-r--r--services/core/java/com/android/server/timedetector/EnvironmentImpl.java40
-rw-r--r--services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java15
-rw-r--r--services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java215
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_SystemClockTime.cpp126
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java18
-rw-r--r--services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java313
13 files changed, 897 insertions, 271 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index 37fb746fa16f..232d3c9aaa53 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -39,6 +39,7 @@ import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROU
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED;
import static android.os.UserHandle.USER_SYSTEM;
+import static com.android.server.SystemClockTime.TIME_CONFIDENCE_HIGH;
import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
import static com.android.server.SystemTimeZone.getTimeZoneId;
import static com.android.server.alarm.Alarm.APP_STANDBY_POLICY_INDEX;
@@ -58,6 +59,8 @@ import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_R
import static com.android.server.alarm.AlarmManagerService.RemovedAlarm.REMOVE_REASON_UNDEFINED;
import android.Manifest;
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.app.Activity;
@@ -87,7 +90,6 @@ import android.os.BatteryManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -101,7 +103,6 @@ import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
-import android.os.SystemProperties;
import android.os.ThreadLocalWorkSource;
import android.os.Trace;
import android.os.UserHandle;
@@ -145,6 +146,8 @@ import com.android.server.DeviceIdleInternal;
import com.android.server.EventLogTags;
import com.android.server.JobSchedulerBackgroundThread;
import com.android.server.LocalServices;
+import com.android.server.SystemClockTime;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.SystemService;
import com.android.server.SystemServiceManager;
import com.android.server.SystemTimeZone;
@@ -1417,7 +1420,7 @@ public class AlarmManagerService extends SystemService {
private long convertToElapsed(long when, int type) {
if (isRtc(type)) {
- when -= mInjector.getCurrentTimeMillis() - mInjector.getElapsedRealtime();
+ when -= mInjector.getCurrentTimeMillis() - mInjector.getElapsedRealtimeMillis();
}
return when;
}
@@ -1577,7 +1580,7 @@ public class AlarmManagerService extends SystemService {
alarmsToDeliver = alarmsForUid;
mPendingBackgroundAlarms.remove(uid);
}
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, mInjector.getElapsedRealtime());
+ deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, mInjector.getElapsedRealtimeMillis());
}
/**
@@ -1594,7 +1597,8 @@ public class AlarmManagerService extends SystemService {
mPendingBackgroundAlarms, alarmsToDeliver, this::isBackgroundRestricted);
if (alarmsToDeliver.size() > 0) {
- deliverPendingBackgroundAlarmsLocked(alarmsToDeliver, mInjector.getElapsedRealtime());
+ deliverPendingBackgroundAlarmsLocked(
+ alarmsToDeliver, mInjector.getElapsedRealtimeMillis());
}
}
@@ -1908,17 +1912,8 @@ public class AlarmManagerService extends SystemService {
mInjector.syncKernelTimeZoneOffset();
}
- // Ensure that we're booting with a halfway sensible current time. Use the
- // most recent of Build.TIME, the root file system's timestamp, and the
- // value of the ro.build.date.utc system property (which is in seconds).
- final long systemBuildTime = Long.max(
- 1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
- Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
- if (mInjector.getCurrentTimeMillis() < systemBuildTime) {
- Slog.i(TAG, "Current time only " + mInjector.getCurrentTimeMillis()
- + ", advancing to build time " + systemBuildTime);
- mInjector.setKernelTime(systemBuildTime);
- }
+ // Ensure that we're booting with a halfway sensible current time.
+ mInjector.initializeTimeIfRequired();
mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
// Determine SysUI's uid
@@ -2133,21 +2128,18 @@ public class AlarmManagerService extends SystemService {
}
}
- boolean setTimeImpl(long millis) {
- if (!mInjector.isAlarmDriverPresent()) {
- Slog.w(TAG, "Not setting time since no alarm driver is available.");
- return false;
- }
-
+ boolean setTimeImpl(
+ @CurrentTimeMillisLong long newSystemClockTimeMillis, @TimeConfidence int confidence,
+ @NonNull String logMsg) {
synchronized (mLock) {
- final long currentTimeMillis = mInjector.getCurrentTimeMillis();
- mInjector.setKernelTime(millis);
+ final long oldSystemClockTimeMillis = mInjector.getCurrentTimeMillis();
+ mInjector.setCurrentTimeMillis(newSystemClockTimeMillis, confidence, logMsg);
if (KERNEL_TIME_ZONE_SYNC_ENABLED) {
// Changing the time may cross a DST transition; sync the kernel offset if needed.
final TimeZone timeZone = TimeZone.getTimeZone(SystemTimeZone.getTimeZoneId());
- final int currentTzOffset = timeZone.getOffset(currentTimeMillis);
- final int newTzOffset = timeZone.getOffset(millis);
+ final int currentTzOffset = timeZone.getOffset(oldSystemClockTimeMillis);
+ final int newTzOffset = timeZone.getOffset(newSystemClockTimeMillis);
if (currentTzOffset != newTzOffset) {
Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");
mInjector.setKernelTimeZoneOffset(newTzOffset);
@@ -2260,7 +2252,7 @@ public class AlarmManagerService extends SystemService {
triggerAtTime = 0;
}
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long nominalTrigger = convertToElapsed(triggerAtTime, type);
// Try to prevent spamming by making sure apps aren't firing alarms in the immediate future
final long minTrigger = nowElapsed
@@ -2383,7 +2375,7 @@ public class AlarmManagerService extends SystemService {
// No need to fuzz as this is already earlier than the coming wake-from-idle.
return changedBeforeFuzz;
}
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final long futurity = upcomingWakeFromIdle - nowElapsed;
if (futurity <= mConstants.MIN_DEVICE_IDLE_FUZZ) {
@@ -2405,7 +2397,7 @@ public class AlarmManagerService extends SystemService {
* @return {@code true} if the alarm delivery time was updated.
*/
private boolean adjustDeliveryTimeBasedOnBatterySaver(Alarm alarm) {
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
if (isExemptFromBatterySaver(alarm)) {
return false;
}
@@ -2472,7 +2464,7 @@ public class AlarmManagerService extends SystemService {
* @return {@code true} if the alarm delivery time was updated.
*/
private boolean adjustDeliveryTimeBasedOnDeviceIdle(Alarm alarm) {
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
if (mPendingIdleUntil == null || mPendingIdleUntil == alarm) {
return alarm.setPolicyElapsed(DEVICE_IDLE_POLICY_INDEX, nowElapsed);
}
@@ -2527,7 +2519,7 @@ public class AlarmManagerService extends SystemService {
* adjustments made in this call.
*/
private boolean adjustDeliveryTimeBasedOnBucketLocked(Alarm alarm) {
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
if (mConstants.USE_TARE_POLICY || isExemptFromAppStandby(alarm) || mAppStandbyParole) {
return alarm.setPolicyElapsed(APP_STANDBY_POLICY_INDEX, nowElapsed);
}
@@ -2587,7 +2579,7 @@ public class AlarmManagerService extends SystemService {
* adjustments made in this call.
*/
private boolean adjustDeliveryTimeBasedOnTareLocked(Alarm alarm) {
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
if (!mConstants.USE_TARE_POLICY
|| isExemptFromTare(alarm) || hasEnoughWealthLocked(alarm)) {
return alarm.setPolicyElapsed(TARE_POLICY_INDEX, nowElapsed);
@@ -2643,7 +2635,7 @@ public class AlarmManagerService extends SystemService {
ent.pkg = a.sourcePackage;
ent.tag = a.statsTag;
ent.op = "START IDLE";
- ent.elapsedRealtime = mInjector.getElapsedRealtime();
+ ent.elapsedRealtime = mInjector.getElapsedRealtimeMillis();
ent.argRealtime = a.getWhenElapsed();
mAllowWhileIdleDispatches.add(ent);
}
@@ -2719,6 +2711,13 @@ public class AlarmManagerService extends SystemService {
}
@Override
+ public void setTime(
+ @CurrentTimeMillisLong long unixEpochTimeMillis, int confidence,
+ String logMsg) {
+ setTimeImpl(unixEpochTimeMillis, confidence, logMsg);
+ }
+
+ @Override
public void registerInFlightListener(InFlightListener callback) {
synchronized (mLock) {
mInFlightListeners.add(callback);
@@ -2987,12 +2986,16 @@ public class AlarmManagerService extends SystemService {
}
@Override
- public boolean setTime(long millis) {
+ public boolean setTime(@CurrentTimeMillisLong long millis) {
getContext().enforceCallingOrSelfPermission(
"android.permission.SET_TIME",
"setTime");
- return setTimeImpl(millis);
+ // The public API (and the shell command that also uses this method) have no concept
+ // of confidence, but since the time should come either from apps working on behalf of
+ // the user or a developer, confidence is assumed "high".
+ final int timeConfidence = TIME_CONFIDENCE_HIGH;
+ return setTimeImpl(millis, timeConfidence, "AlarmManager.setTime() called");
}
@Override
@@ -3142,7 +3145,7 @@ public class AlarmManagerService extends SystemService {
pw.println();
}
- final long nowELAPSED = mInjector.getElapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtimeMillis();
final long nowUPTIME = SystemClock.uptimeMillis();
final long nowRTC = mInjector.getCurrentTimeMillis();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -3618,7 +3621,7 @@ public class AlarmManagerService extends SystemService {
synchronized (mLock) {
final long nowRTC = mInjector.getCurrentTimeMillis();
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
proto.write(AlarmManagerServiceDumpProto.CURRENT_TIME, nowRTC);
proto.write(AlarmManagerServiceDumpProto.ELAPSED_REALTIME, nowElapsed);
proto.write(AlarmManagerServiceDumpProto.LAST_TIME_CHANGE_CLOCK_TIME,
@@ -3956,7 +3959,7 @@ public class AlarmManagerService extends SystemService {
void rescheduleKernelAlarmsLocked() {
// Schedule the next upcoming wakeup alarm. If there is a deliverable batch
// prior to that which contains no wakeups, we schedule that as well.
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
long nextNonWakeup = 0;
if (mAlarmStore.size() > 0) {
final long firstWakeup = mAlarmStore.getNextWakeupDeliveryTime();
@@ -4069,7 +4072,7 @@ public class AlarmManagerService extends SystemService {
@GuardedBy("mLock")
private void removeAlarmsInternalLocked(Predicate<Alarm> whichAlarms, int reason) {
final long nowRtc = mInjector.getCurrentTimeMillis();
- final long nowElapsed = mInjector.getElapsedRealtime();
+ final long nowElapsed = mInjector.getElapsedRealtimeMillis();
final ArrayList<Alarm> removedAlarms = mAlarmStore.remove(whichAlarms);
final boolean removedFromStore = !removedAlarms.isEmpty();
@@ -4208,7 +4211,7 @@ public class AlarmManagerService extends SystemService {
void interactiveStateChangedLocked(boolean interactive) {
if (mInteractive != interactive) {
mInteractive = interactive;
- final long nowELAPSED = mInjector.getElapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtimeMillis();
if (interactive) {
if (mPendingNonWakeupAlarms.size() > 0) {
final long thisDelayTime = nowELAPSED - mStartCurrentDelayTime;
@@ -4310,7 +4313,6 @@ public class AlarmManagerService extends SystemService {
private static native void close(long nativeData);
private static native int set(long nativeData, int type, long seconds, long nanoseconds);
private static native int waitForAlarm(long nativeData);
- private static native int setKernelTime(long nativeData, long millis);
/*
* b/246256335: The @Keep ensures that the native definition is kept even when the optimizer can
@@ -4357,7 +4359,7 @@ public class AlarmManagerService extends SystemService {
ent.pkg = alarm.sourcePackage;
ent.tag = alarm.statsTag;
ent.op = "END IDLE";
- ent.elapsedRealtime = mInjector.getElapsedRealtime();
+ ent.elapsedRealtime = mInjector.getElapsedRealtimeMillis();
ent.argRealtime = alarm.getWhenElapsed();
mAllowWhileIdleDispatches.add(ent);
}
@@ -4602,20 +4604,27 @@ public class AlarmManagerService extends SystemService {
setKernelTimeZoneOffset(utcOffsetMillis);
}
- void setKernelTime(long millis) {
- if (mNativeData != 0) {
- AlarmManagerService.setKernelTime(mNativeData, millis);
- }
+ void initializeTimeIfRequired() {
+ SystemClockTime.initializeIfRequired();
+ }
+
+ void setCurrentTimeMillis(
+ @CurrentTimeMillisLong long unixEpochMillis,
+ @TimeConfidence int confidence,
+ @NonNull String logMsg) {
+ SystemClockTime.setTimeAndConfidence(unixEpochMillis, confidence, logMsg);
}
void close() {
AlarmManagerService.close(mNativeData);
}
- long getElapsedRealtime() {
+ @ElapsedRealtimeLong
+ long getElapsedRealtimeMillis() {
return SystemClock.elapsedRealtime();
}
+ @CurrentTimeMillisLong
long getCurrentTimeMillis() {
return System.currentTimeMillis();
}
@@ -4665,7 +4674,7 @@ public class AlarmManagerService extends SystemService {
while (true) {
int result = mInjector.waitForAlarm();
final long nowRTC = mInjector.getCurrentTimeMillis();
- final long nowELAPSED = mInjector.getElapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtimeMillis();
synchronized (mLock) {
mLastWakeup = nowELAPSED;
}
@@ -4913,7 +4922,7 @@ public class AlarmManagerService extends SystemService {
// this way, so WAKE_UP alarms will be delivered only when the device is awake.
ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
synchronized (mLock) {
- final long nowELAPSED = mInjector.getElapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtimeMillis();
triggerAlarmsLocked(triggerList, nowELAPSED);
updateNextAlarmClockLocked();
}
@@ -5090,7 +5099,7 @@ public class AlarmManagerService extends SystemService {
flags |= mConstants.TIME_TICK_ALLOWED_WHILE_IDLE ? FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED
: 0;
- setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtime() + tickEventDelay, 0,
+ setImpl(ELAPSED_REALTIME, mInjector.getElapsedRealtimeMillis() + tickEventDelay, 0,
0, null, mTimeTickTrigger, TIME_TICK_TAG, flags, workSource, null,
Process.myUid(), "android", null, EXACT_ALLOW_REASON_ALLOW_LIST);
@@ -5277,7 +5286,7 @@ public class AlarmManagerService extends SystemService {
}
synchronized (mLock) {
mTemporaryQuotaReserve.replenishQuota(packageName, userId, quotaBump,
- mInjector.getElapsedRealtime());
+ mInjector.getElapsedRealtimeMillis());
}
mHandler.obtainMessage(AlarmHandler.TEMPORARY_QUOTA_CHANGED, userId, -1,
packageName).sendToTarget();
@@ -5439,7 +5448,7 @@ public class AlarmManagerService extends SystemService {
}
private void updateStatsLocked(InFlight inflight) {
- final long nowELAPSED = mInjector.getElapsedRealtime();
+ final long nowELAPSED = mInjector.getElapsedRealtimeMillis();
BroadcastStats bs = inflight.mBroadcastStats;
bs.nesting--;
if (bs.nesting <= 0) {
diff --git a/apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp b/apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp
index 8f9e187a7a93..b2ed4d47adf4 100644
--- a/apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp
+++ b/apex/jobscheduler/service/jni/com_android_server_alarm_AlarmManagerService.cpp
@@ -76,19 +76,17 @@ typedef std::array<int, N_ANDROID_TIMERFDS> TimerFds;
class AlarmImpl
{
public:
- AlarmImpl(const TimerFds &fds, int epollfd, const std::string &rtc_dev)
- : fds{fds}, epollfd{epollfd}, rtc_dev{rtc_dev} {}
+ AlarmImpl(const TimerFds &fds, int epollfd)
+ : fds{fds}, epollfd{epollfd} {}
~AlarmImpl();
int set(int type, struct timespec *ts);
- int setTime(struct timeval *tv);
int waitForAlarm();
int getTime(int type, struct itimerspec *spec);
private:
const TimerFds fds;
const int epollfd;
- std::string rtc_dev;
};
AlarmImpl::~AlarmImpl()
@@ -131,43 +129,6 @@ int AlarmImpl::getTime(int type, struct itimerspec *spec)
return timerfd_gettime(fds[type], spec);
}
-int AlarmImpl::setTime(struct timeval *tv)
-{
- if (settimeofday(tv, NULL) == -1) {
- ALOGV("settimeofday() failed: %s", strerror(errno));
- return -1;
- }
-
- android::base::unique_fd fd{open(rtc_dev.c_str(), O_RDWR)};
- if (!fd.ok()) {
- ALOGE("Unable to open %s: %s", rtc_dev.c_str(), strerror(errno));
- return -1;
- }
-
- struct tm tm;
- if (!gmtime_r(&tv->tv_sec, &tm)) {
- ALOGV("gmtime_r() failed: %s", strerror(errno));
- return -1;
- }
-
- struct rtc_time rtc = {};
- rtc.tm_sec = tm.tm_sec;
- rtc.tm_min = tm.tm_min;
- rtc.tm_hour = tm.tm_hour;
- rtc.tm_mday = tm.tm_mday;
- rtc.tm_mon = tm.tm_mon;
- rtc.tm_year = tm.tm_year;
- rtc.tm_wday = tm.tm_wday;
- rtc.tm_yday = tm.tm_yday;
- rtc.tm_isdst = tm.tm_isdst;
- if (ioctl(fd, RTC_SET_TIME, &rtc) == -1) {
- ALOGV("RTC_SET_TIME ioctl failed: %s", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
int AlarmImpl::waitForAlarm()
{
epoll_event events[N_ANDROID_TIMERFDS];
@@ -198,28 +159,6 @@ int AlarmImpl::waitForAlarm()
return result;
}
-static jint android_server_alarm_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
-{
- AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
-
- if (millis <= 0 || millis / 1000LL >= std::numeric_limits<time_t>::max()) {
- return -1;
- }
-
- struct timeval tv;
- tv.tv_sec = (millis / 1000LL);
- tv.tv_usec = ((millis % 1000LL) * 1000LL);
-
- ALOGD("Setting time of day to sec=%ld", tv.tv_sec);
-
- int ret = impl->setTime(&tv);
- if (ret < 0) {
- ALOGW("Unable to set rtc to %ld: %s", tv.tv_sec, strerror(errno));
- ret = -1;
- }
- return ret;
-}
-
static jint android_server_alarm_AlarmManagerService_setKernelTimezone(JNIEnv*, jobject, jlong, jint minswest)
{
struct timezone tz;
@@ -287,19 +226,7 @@ static jlong android_server_alarm_AlarmManagerService_init(JNIEnv*, jobject)
}
}
- // Find the wall clock RTC. We expect this always to be /dev/rtc0, but
- // check the /dev/rtc symlink first so that legacy devices that don't use
- // rtc0 can add a symlink rather than need to carry a local patch to this
- // code.
- //
- // TODO: if you're reading this in a world where all devices are using the
- // GKI, you can remove the readlink and just assume /dev/rtc0.
- std::string dev_rtc;
- if (!android::base::Readlink("/dev/rtc", &dev_rtc)) {
- dev_rtc = "/dev/rtc0";
- }
-
- std::unique_ptr<AlarmImpl> alarm{new AlarmImpl(fds, epollfd, dev_rtc)};
+ std::unique_ptr<AlarmImpl> alarm{new AlarmImpl(fds, epollfd)};
for (size_t i = 0; i < fds.size(); i++) {
epoll_event event;
@@ -392,7 +319,6 @@ static const JNINativeMethod sMethods[] = {
{"close", "(J)V", (void*)android_server_alarm_AlarmManagerService_close},
{"set", "(JIJJ)I", (void*)android_server_alarm_AlarmManagerService_set},
{"waitForAlarm", "(J)I", (void*)android_server_alarm_AlarmManagerService_waitForAlarm},
- {"setKernelTime", "(JJ)I", (void*)android_server_alarm_AlarmManagerService_setKernelTime},
{"setKernelTimezone", "(JI)I", (void*)android_server_alarm_AlarmManagerService_setKernelTimezone},
{"getNextAlarm", "(JI)J", (void*)android_server_alarm_AlarmManagerService_getNextAlarm},
};
diff --git a/services/core/java/com/android/server/AlarmManagerInternal.java b/services/core/java/com/android/server/AlarmManagerInternal.java
index b2abdbd144b8..67aa2b9a89bb 100644
--- a/services/core/java/com/android/server/AlarmManagerInternal.java
+++ b/services/core/java/com/android/server/AlarmManagerInternal.java
@@ -16,8 +16,10 @@
package com.android.server;
+import android.annotation.CurrentTimeMillisLong;
import android.app.PendingIntent;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.SystemTimeZone.TimeZoneConfidence;
public interface AlarmManagerInternal {
@@ -59,4 +61,15 @@ public interface AlarmManagerInternal {
* for details
*/
void setTimeZone(String tzId, @TimeZoneConfidence int confidence);
+
+ /**
+ * Sets the device's current time and time confidence.
+ *
+ * @param unixEpochTimeMillis the time
+ * @param confidence the confidence that {@code unixEpochTimeMillis} is correct, see {@link
+ * TimeConfidence} for details
+ * @param logMsg the reason the time is being changed, for bug report logging
+ */
+ void setTime(@CurrentTimeMillisLong long unixEpochTimeMillis, @TimeConfidence int confidence,
+ String logMsg);
}
diff --git a/services/core/java/com/android/server/SystemClockTime.java b/services/core/java/com/android/server/SystemClockTime.java
new file mode 100644
index 000000000000..46fbbb290ed2
--- /dev/null
+++ b/services/core/java/com/android/server/SystemClockTime.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 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 com.android.server;
+
+import static java.lang.annotation.ElementType.TYPE_USE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.CurrentTimeMillisLong;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Build;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.util.LocalLog;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * A set of static methods that encapsulate knowledge of how the system clock time and associated
+ * metadata are stored on Android.
+ */
+public final class SystemClockTime {
+
+ private static final String TAG = "SystemClockTime";
+
+ /**
+ * 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 time.
+ */
+ @NonNull
+ private static final LocalLog sTimeDebugLog =
+ new LocalLog(30, false /* useLocalTimestamps */);
+
+
+ /**
+ * An annotation that indicates a "time confidence" value is expected.
+ *
+ * <p>The confidence indicates whether the time is expected to be correct. The confidence can be
+ * upgraded or downgraded over time. It can be used to decide whether a user could / should be
+ * asked to confirm the time. For example, during device set up low confidence would describe a
+ * time that has been initialized by default. The user may then be asked to confirm the time,
+ * moving it to a high confidence.
+ */
+ @Retention(SOURCE)
+ @Target(TYPE_USE)
+ @IntDef(prefix = "TIME_CONFIDENCE_",
+ value = { TIME_CONFIDENCE_LOW, TIME_CONFIDENCE_HIGH })
+ public @interface TimeConfidence {
+ }
+
+ /** Used when confidence is low and would (ideally) be confirmed by a user. */
+ public static final @TimeConfidence int TIME_CONFIDENCE_LOW = 0;
+
+ /**
+ * Used when confidence in the time is high and does not need to be confirmed by a user.
+ */
+ public static final @TimeConfidence int TIME_CONFIDENCE_HIGH = 100;
+
+ /**
+ * The confidence in the current time. Android's time confidence is held in memory because RTC
+ * hardware can forget / corrupt the time while the device is powered off. Therefore, on boot
+ * we can't assume the time is good, and so default it to "low" confidence until it is confirmed
+ * or explicitly set.
+ */
+ private static @TimeConfidence int sTimeConfidence = TIME_CONFIDENCE_LOW;
+
+ private static final long sNativeData = init();
+
+ private SystemClockTime() {
+ }
+
+ /**
+ * Sets the system clock time to a reasonable lower bound. Used during boot-up to ensure the
+ * device has a time that is better than a default like 1970-01-01.
+ */
+ public static void initializeIfRequired() {
+ // Use the most recent of Build.TIME, the root file system's timestamp, and the
+ // value of the ro.build.date.utc system property (which is in seconds).
+ final long systemBuildTime = Long.max(
+ 1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
+ Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
+ long currentTimeMillis = getCurrentTimeMillis();
+ if (currentTimeMillis < systemBuildTime) {
+ String logMsg = "Current time only " + currentTimeMillis
+ + ", advancing to build time " + systemBuildTime;
+ Slog.i(TAG, logMsg);
+ setTimeAndConfidence(systemBuildTime, TIME_CONFIDENCE_LOW, logMsg);
+ }
+ }
+
+ /**
+ * Sets the system clock time and confidence. See also {@link #setConfidence(int, String)} for
+ * an alternative that only sets the confidence.
+ *
+ * @param unixEpochMillis the time to set
+ * @param confidence the confidence in {@code unixEpochMillis}. See {@link TimeConfidence} for
+ * details.
+ * @param logMsg a log message that can be included in bug reports that explains the update
+ */
+ public static void setTimeAndConfidence(
+ @CurrentTimeMillisLong long unixEpochMillis, int confidence, @NonNull String logMsg) {
+ synchronized (SystemClockTime.class) {
+ setTime(sNativeData, unixEpochMillis);
+ sTimeConfidence = confidence;
+ sTimeDebugLog.log(logMsg);
+ }
+ }
+
+ /**
+ * Sets the system clock confidence. See also {@link #setTimeAndConfidence(long, int, String)}
+ * for an alternative that sets the time and confidence.
+ *
+ * @param confidence the confidence in the system clock time. See {@link TimeConfidence} for
+ * details.
+ * @param logMsg a log message that can be included in bug reports that explains the update
+ */
+ public static void setConfidence(@TimeConfidence int confidence, @NonNull String logMsg) {
+ synchronized (SystemClockTime.class) {
+ sTimeConfidence = confidence;
+ sTimeDebugLog.log(logMsg);
+ }
+ }
+
+ /**
+ * Returns the system clock time. The same as {@link System#currentTimeMillis()}.
+ */
+ private static @CurrentTimeMillisLong long getCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * Returns the system clock confidence. See {@link TimeConfidence} for details.
+ */
+ public static @TimeConfidence int getTimeConfidence() {
+ synchronized (SystemClockTime.class) {
+ return sTimeConfidence;
+ }
+ }
+
+ /**
+ * Adds an entry to the system time debug log that is included in bug reports. This method is
+ * intended to be used to record event that may lead to a time change, e.g. config or mode
+ * changes.
+ */
+ public static void addDebugLogEntry(@NonNull String logMsg) {
+ sTimeDebugLog.log(logMsg);
+ }
+
+ /**
+ * Dumps information about recent time / confidence changes to the supplied writer.
+ */
+ public static void dump(PrintWriter writer) {
+ sTimeDebugLog.dump(writer);
+ }
+
+ private static native long init();
+ private static native int setTime(long nativeData, @CurrentTimeMillisLong long millis);
+}
diff --git a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
index 372bcc6b07ca..46f335ef9fa2 100644
--- a/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timedetector/ConfigurationInternal.java
@@ -46,6 +46,7 @@ public final class ConfigurationInternal {
private final boolean mAutoDetectionSupported;
private final int mSystemClockUpdateThresholdMillis;
+ private final int mSystemClockConfidenceUpgradeThresholdMillis;
private final Instant mAutoSuggestionLowerBound;
private final Instant mManualSuggestionLowerBound;
private final Instant mSuggestionUpperBound;
@@ -57,6 +58,8 @@ public final class ConfigurationInternal {
private ConfigurationInternal(Builder builder) {
mAutoDetectionSupported = builder.mAutoDetectionSupported;
mSystemClockUpdateThresholdMillis = builder.mSystemClockUpdateThresholdMillis;
+ mSystemClockConfidenceUpgradeThresholdMillis =
+ builder.mSystemClockConfidenceUpgradeThresholdMillis;
mAutoSuggestionLowerBound = Objects.requireNonNull(builder.mAutoSuggestionLowerBound);
mManualSuggestionLowerBound = Objects.requireNonNull(builder.mManualSuggestionLowerBound);
mSuggestionUpperBound = Objects.requireNonNull(builder.mSuggestionUpperBound);
@@ -82,6 +85,17 @@ public final class ConfigurationInternal {
}
/**
+ * Return the absolute threshold at/below which the system clock confidence can be upgraded.
+ * i.e. if the detector receives a high-confidence time and the current system clock is +/- this
+ * value from that time and the confidence in the time is low, then the device's confidence in
+ * the current system clock time can be upgraded. This needs to be an amount users would
+ * consider "close enough".
+ */
+ public int getSystemClockConfidenceUpgradeThresholdMillis() {
+ return mSystemClockConfidenceUpgradeThresholdMillis;
+ }
+
+ /**
* 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,
@@ -242,6 +256,8 @@ public final class ConfigurationInternal {
return "ConfigurationInternal{"
+ "mAutoDetectionSupported=" + mAutoDetectionSupported
+ ", mSystemClockUpdateThresholdMillis=" + mSystemClockUpdateThresholdMillis
+ + ", mSystemClockConfidenceUpgradeThresholdMillis="
+ + mSystemClockConfidenceUpgradeThresholdMillis
+ ", mAutoSuggestionLowerBound=" + mAutoSuggestionLowerBound
+ "(" + mAutoSuggestionLowerBound.toEpochMilli() + ")"
+ ", mManualSuggestionLowerBound=" + mManualSuggestionLowerBound
@@ -258,6 +274,7 @@ public final class ConfigurationInternal {
static final class Builder {
private boolean mAutoDetectionSupported;
private int mSystemClockUpdateThresholdMillis;
+ private int mSystemClockConfidenceUpgradeThresholdMillis;
@NonNull private Instant mAutoSuggestionLowerBound;
@NonNull private Instant mManualSuggestionLowerBound;
@NonNull private Instant mSuggestionUpperBound;
@@ -286,68 +303,55 @@ public final class ConfigurationInternal {
this.mAutoDetectionEnabledSetting = toCopy.mAutoDetectionEnabledSetting;
}
- /**
- * Sets whether the user is allowed to configure time settings on this device.
- */
+ /** See {@link ConfigurationInternal#isUserConfigAllowed()}. */
Builder setUserConfigAllowed(boolean userConfigAllowed) {
mUserConfigAllowed = userConfigAllowed;
return this;
}
- /**
- * Sets whether automatic time detection is supported on this device.
- */
+ /** See {@link ConfigurationInternal#isAutoDetectionSupported()}. */
public Builder setAutoDetectionSupported(boolean supported) {
mAutoDetectionSupported = supported;
return this;
}
- /**
- * Sets the absolute threshold below which the system clock need not be updated. i.e. if
- * setting the system clock would adjust it by less than this (either backwards or forwards)
- * then it need not be set.
- */
+ /** See {@link ConfigurationInternal#getSystemClockUpdateThresholdMillis()}. */
public Builder setSystemClockUpdateThresholdMillis(int systemClockUpdateThresholdMillis) {
mSystemClockUpdateThresholdMillis = systemClockUpdateThresholdMillis;
return this;
}
- /**
- * Sets the lower bound for valid automatic time suggestions.
- */
+ /** See {@link ConfigurationInternal#getSystemClockConfidenceUpgradeThresholdMillis()}. */
+ public Builder setSystemClockConfidenceUpgradeThresholdMillis(int thresholdMillis) {
+ mSystemClockConfidenceUpgradeThresholdMillis = thresholdMillis;
+ return this;
+ }
+
+ /** See {@link ConfigurationInternal#getAutoSuggestionLowerBound()}. */
public Builder setAutoSuggestionLowerBound(@NonNull Instant autoSuggestionLowerBound) {
mAutoSuggestionLowerBound = Objects.requireNonNull(autoSuggestionLowerBound);
return this;
}
- /**
- * Sets the lower bound for valid manual time suggestions.
- */
+ /** See {@link ConfigurationInternal#getManualSuggestionLowerBound()}. */
public Builder setManualSuggestionLowerBound(@NonNull Instant manualSuggestionLowerBound) {
mManualSuggestionLowerBound = Objects.requireNonNull(manualSuggestionLowerBound);
return this;
}
- /**
- * Sets the upper bound for valid time suggestions (manual and automatic).
- */
+ /** See {@link ConfigurationInternal#getSuggestionUpperBound()}. */
public Builder setSuggestionUpperBound(@NonNull Instant suggestionUpperBound) {
mSuggestionUpperBound = Objects.requireNonNull(suggestionUpperBound);
return this;
}
- /**
- * Sets the order to look at time suggestions when automatically detecting time.
- * See {@code #ORIGIN_} constants
- */
+ /** See {@link ConfigurationInternal#getAutoOriginPriorities()}. */
public Builder setOriginPriorities(@NonNull @Origin int... originPriorities) {
mOriginPriorities = Objects.requireNonNull(originPriorities);
return this;
}
- /**
- * Sets the value of the automatic time detection enabled setting for this device.
- */
+ /** See {@link ConfigurationInternal#getAutoDetectionEnabledSetting()}. */
Builder setAutoDetectionEnabledSetting(boolean autoDetectionEnabledSetting) {
mAutoDetectionEnabledSetting = autoDetectionEnabledSetting;
return this;
diff --git a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
index 3e02b463284d..4972412472f1 100644
--- a/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
+++ b/services/core/java/com/android/server/timedetector/EnvironmentImpl.java
@@ -16,16 +16,21 @@
package com.android.server.timedetector;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.NonNull;
-import android.app.AlarmManager;
import android.content.Context;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Slog;
+import com.android.server.AlarmManagerInternal;
+import com.android.server.LocalServices;
+import com.android.server.SystemClockTime;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timezonedetector.ConfigurationChangeListener;
+import java.io.PrintWriter;
import java.util.Objects;
/**
@@ -38,7 +43,7 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
@NonNull private final Handler mHandler;
@NonNull private final ServiceConfigAccessor mServiceConfigAccessor;
@NonNull private final PowerManager.WakeLock mWakeLock;
- @NonNull private final AlarmManager mAlarmManager;
+ @NonNull private final AlarmManagerInternal mAlarmManagerInternal;
EnvironmentImpl(@NonNull Context context, @NonNull Handler handler,
@NonNull ServiceConfigAccessor serviceConfigAccessor) {
@@ -49,7 +54,8 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
mWakeLock = Objects.requireNonNull(
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG));
- mAlarmManager = Objects.requireNonNull(context.getSystemService(AlarmManager.class));
+ mAlarmManagerInternal = Objects.requireNonNull(
+ LocalServices.getService(AlarmManagerInternal.class));
}
@Override
@@ -84,9 +90,22 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
}
@Override
- public void setSystemClock(long newTimeMillis) {
+ public @TimeConfidence int systemClockConfidence() {
+ return SystemClockTime.getTimeConfidence();
+ }
+
+ @Override
+ public void setSystemClock(
+ @CurrentTimeMillisLong long newTimeMillis, @TimeConfidence int confidence,
+ @NonNull String logMsg) {
+ checkWakeLockHeld();
+ mAlarmManagerInternal.setTime(newTimeMillis, confidence, logMsg);
+ }
+
+ @Override
+ public void setSystemClockConfidence(@TimeConfidence int confidence, @NonNull String logMsg) {
checkWakeLockHeld();
- mAlarmManager.setTime(newTimeMillis);
+ SystemClockTime.setConfidence(confidence, logMsg);
}
@Override
@@ -100,4 +119,13 @@ final class EnvironmentImpl implements TimeDetectorStrategyImpl.Environment {
Slog.wtf(LOG_TAG, "WakeLock " + mWakeLock + " not held");
}
}
-}
+
+ @Override
+ public void addDebugLogEntry(@NonNull String logMsg) {
+ SystemClockTime.addDebugLogEntry(logMsg);
+ }
+
+ @Override
+ public void dumpDebugLog(@NonNull PrintWriter printWriter) {
+ SystemClockTime.dump(printWriter);
+ }}
diff --git a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
index 888304aa199b..0ea5f7a105d1 100644
--- a/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timedetector/ServiceConfigAccessorImpl.java
@@ -68,6 +68,15 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
private static final int SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS_DEFAULT = 2 * 1000;
/**
+ * An absolute threshold at/below which the system clock confidence can be upgraded. i.e. if the
+ * detector receives a high-confidence time and the current system clock is +/- this value from
+ * that time and the confidence in the time is low, then the device's confidence in the current
+ * system clock time can be upgraded. This needs to be an amount users would consider
+ * "close enough".
+ */
+ private static final int SYSTEM_CLOCK_CONFIRMATION_THRESHOLD_MILLIS = 1000;
+
+ /**
* By default telephony and network only suggestions are accepted and telephony takes
* precedence over network.
*/
@@ -236,6 +245,8 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
.setAutoDetectionSupported(isAutoDetectionSupported())
.setAutoDetectionEnabledSetting(getAutoDetectionEnabledSetting())
.setSystemClockUpdateThresholdMillis(getSystemClockUpdateThresholdMillis())
+ .setSystemClockConfidenceUpgradeThresholdMillis(
+ getSystemClockConfidenceUpgradeThresholdMillis())
.setAutoSuggestionLowerBound(getAutoSuggestionLowerBound())
.setManualSuggestionLowerBound(timeDetectorHelper.getManualSuggestionLowerBound())
.setSuggestionUpperBound(timeDetectorHelper.getSuggestionUpperBound())
@@ -285,6 +296,10 @@ final class ServiceConfigAccessorImpl implements ServiceConfigAccessor {
return mSystemClockUpdateThresholdMillis;
}
+ private int getSystemClockConfidenceUpgradeThresholdMillis() {
+ return SYSTEM_CLOCK_CONFIRMATION_THRESHOLD_MILLIS;
+ }
+
@NonNull
private Instant getAutoSuggestionLowerBound() {
return mServerFlags.getOptionalInstant(KEY_TIME_DETECTOR_LOWER_BOUND_MILLIS_OVERRIDE)
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index 547cf9d32aa1..fe2760e9ce10 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -16,6 +16,7 @@
package com.android.server.timedetector;
+import static com.android.server.SystemClockTime.TIME_CONFIDENCE_HIGH;
import static com.android.server.timedetector.TimeDetectorStrategy.originToString;
import android.annotation.CurrentTimeMillisLong;
@@ -23,7 +24,6 @@ import android.annotation.ElapsedRealtimeLong;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
-import android.app.AlarmManager;
import android.app.time.ExternalTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -31,24 +31,24 @@ import android.content.Context;
import android.os.Handler;
import android.os.TimestampedValue;
import android.util.IndentingPrintWriter;
-import android.util.LocalLog;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemClockTime;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timezonedetector.ArrayMapWithHistory;
import com.android.server.timezonedetector.ConfigurationChangeListener;
import com.android.server.timezonedetector.ReferenceWithHistory;
+import java.io.PrintWriter;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Objects;
/**
- * An implementation of {@link TimeDetectorStrategy} that passes telephony and manual suggestions to
- * {@link AlarmManager}. When there are multiple telephony sources, the one with the lowest ID is
- * used unless the data becomes too stale.
+ * The real implementation of {@link TimeDetectorStrategy}.
*
* <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
@@ -84,13 +84,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
*/
private static final int KEEP_SUGGESTION_HISTORY_SIZE = 10;
- /**
- * 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.
- */
- @NonNull
- private final LocalLog mTimeChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
-
@NonNull
private final Environment mEnvironment;
@@ -157,11 +150,30 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@CurrentTimeMillisLong
long systemClockMillis();
- /** Sets the device system clock. The WakeLock must be held. */
- void setSystemClock(@CurrentTimeMillisLong long newTimeMillis);
+ /** Returns the system clock confidence value. */
+ @TimeConfidence int systemClockConfidence();
+
+ /** Sets the device system clock and confidence. The WakeLock must be held. */
+ void setSystemClock(
+ @CurrentTimeMillisLong long newTimeMillis, @TimeConfidence int confidence,
+ @NonNull String logMsg);
+
+ /** Sets the device system clock confidence. The WakeLock must be held. */
+ void setSystemClockConfidence(@TimeConfidence int confidence, @NonNull String logMsg);
/** Release the wake lock acquired by a call to {@link #acquireWakeLock()}. */
void releaseWakeLock();
+
+
+ /**
+ * Adds a standalone entry to the time debug log.
+ */
+ void addDebugLogEntry(@NonNull String logMsg);
+
+ /**
+ * Dumps the time debug log to the supplied {@link PrintWriter}.
+ */
+ void dumpDebugLog(PrintWriter printWriter);
}
static TimeDetectorStrategy create(
@@ -250,7 +262,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
String cause = "Manual time suggestion received: suggestion=" + suggestion;
- return setSystemClockIfRequired(ORIGIN_MANUAL, newUnixEpochTime, cause);
+ return setSystemClockAndConfidenceIfRequired(ORIGIN_MANUAL, newUnixEpochTime, cause);
}
@Override
@@ -318,7 +330,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
String logMsg = "handleConfigurationInternalChanged:"
+ " oldConfiguration=" + mCurrentConfigurationInternal
+ ", newConfiguration=" + currentUserConfig;
- logTimeDetectorChange(logMsg);
+ addDebugLogEntry(logMsg);
mCurrentConfigurationInternal = currentUserConfig;
boolean autoDetectionEnabled =
@@ -335,11 +347,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
}
- private void logTimeDetectorChange(@NonNull String logMsg) {
+ private void addDebugLogEntry(@NonNull String logMsg) {
if (DBG) {
Slog.d(LOG_TAG, logMsg);
}
- mTimeChangesLog.log(logMsg);
+ mEnvironment.addDebugLogEntry(logMsg);
}
@Override
@@ -356,10 +368,11 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
long systemClockMillis = mEnvironment.systemClockMillis();
ipw.printf("mEnvironment.systemClockMillis()=%s (%s)\n",
Instant.ofEpochMilli(systemClockMillis), systemClockMillis);
+ ipw.println("mEnvironment.systemClockConfidence()=" + mEnvironment.systemClockConfidence());
ipw.println("Time change log:");
ipw.increaseIndent(); // level 2
- mTimeChangesLog.dump(ipw);
+ SystemClockTime.dump(ipw);
ipw.decreaseIndent(); // level 2
ipw.println("Telephony suggestion history:");
@@ -494,11 +507,6 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
@GuardedBy("this")
private void doAutoTimeDetection(@NonNull String detectionReason) {
- if (!mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
- // Avoid doing unnecessary work with this (race-prone) check.
- return;
- }
-
// Try the different origins one at a time.
int[] originPriorities = mCurrentConfigurationInternal.getAutoOriginPriorities();
for (int origin : originPriorities) {
@@ -544,7 +552,14 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
// Update the system clock if a good suggestion has been found.
if (newUnixEpochTime != null) {
- setSystemClockIfRequired(origin, newUnixEpochTime, cause);
+ if (mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
+ setSystemClockAndConfidenceIfRequired(origin, newUnixEpochTime, cause);
+ } else {
+ // An automatically detected time can be used to raise the confidence in the
+ // current time even if the device is set to only allow user input for the time
+ // itself.
+ upgradeSystemClockConfidenceIfRequired(newUnixEpochTime, cause);
+ }
return;
}
}
@@ -718,14 +733,18 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@GuardedBy("this")
- private boolean setSystemClockIfRequired(
+ private boolean setSystemClockAndConfidenceIfRequired(
@Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) {
+ // Any time set through this class is inherently high confidence. Either it came directly
+ // from a user, or it was detected automatically.
+ @TimeConfidence final int newTimeConfidence = TIME_CONFIDENCE_HIGH;
boolean isOriginAutomatic = isOriginAutomatic(origin);
if (isOriginAutomatic) {
if (!mCurrentConfigurationInternal.getAutoDetectionEnabledBehavior()) {
if (DBG) {
- Slog.d(LOG_TAG, "Auto time detection is not enabled."
+ Slog.d(LOG_TAG,
+ "Auto time detection is not enabled / no confidence update is needed."
+ " origin=" + originToString(origin)
+ ", time=" + time
+ ", cause=" + cause);
@@ -746,7 +765,57 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
mEnvironment.acquireWakeLock();
try {
- return setSystemClockUnderWakeLock(origin, time, cause);
+ return setSystemClockAndConfidenceUnderWakeLock(origin, time, newTimeConfidence, cause);
+ } finally {
+ mEnvironment.releaseWakeLock();
+ }
+ }
+
+ /**
+ * Upgrades the system clock confidence if the current time matches the supplied auto-detected
+ * time. The method never changes the system clock and it never lowers the confidence. It only
+ * raises the confidence if the supplied time is within the configured threshold of the current
+ * system clock time.
+ */
+ @GuardedBy("this")
+ private void upgradeSystemClockConfidenceIfRequired(
+ @NonNull TimestampedValue<Long> autoDetectedUnixEpochTime, @NonNull String cause) {
+ @TimeConfidence int newTimeConfidence = TIME_CONFIDENCE_HIGH;
+ @TimeConfidence int currentTimeConfidence = mEnvironment.systemClockConfidence();
+ boolean timeNeedsConfirmation = currentTimeConfidence < newTimeConfidence;
+ if (!timeNeedsConfirmation) {
+ return;
+ }
+
+ // All system clock calculation take place under a wake lock.
+ mEnvironment.acquireWakeLock();
+ try {
+ // Check if the specified time matches the current system clock time (closely
+ // enough) to raise the confidence.
+ long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
+ long actualSystemClockMillis = mEnvironment.systemClockMillis();
+ long adjustedAutoDetectedUnixEpochMillis = TimeDetectorStrategy.getTimeAt(
+ autoDetectedUnixEpochTime, elapsedRealtimeMillis);
+ long absTimeDifferenceMillis =
+ Math.abs(adjustedAutoDetectedUnixEpochMillis - actualSystemClockMillis);
+ int confidenceUpgradeThresholdMillis =
+ mCurrentConfigurationInternal.getSystemClockConfidenceUpgradeThresholdMillis();
+ boolean updateConfidenceRequired =
+ absTimeDifferenceMillis <= confidenceUpgradeThresholdMillis;
+ if (updateConfidenceRequired) {
+ String logMsg = "Upgrade system clock confidence."
+ + " autoDetectedUnixEpochTime=" + autoDetectedUnixEpochTime
+ + " newTimeConfidence=" + newTimeConfidence
+ + " cause=" + cause
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ + " currentTimeConfidence=" + currentTimeConfidence;
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
+ }
+
+ mEnvironment.setSystemClockConfidence(newTimeConfidence, logMsg);
+ }
} finally {
mEnvironment.releaseWakeLock();
}
@@ -757,8 +826,9 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
@GuardedBy("this")
- private boolean setSystemClockUnderWakeLock(
- @Origin int origin, @NonNull TimestampedValue<Long> newTime, @NonNull String cause) {
+ private boolean setSystemClockAndConfidenceUnderWakeLock(
+ @Origin int origin, @NonNull TimestampedValue<Long> newTime,
+ @TimeConfidence int newTimeConfidence, @NonNull String cause) {
long elapsedRealtimeMillis = mEnvironment.elapsedRealtimeMillis();
boolean isOriginAutomatic = isOriginAutomatic(origin);
@@ -776,6 +846,7 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
"System clock has not tracked elapsed real time clock. A clock may"
+ " be inaccurate or something unexpectedly set the system"
+ " clock."
+ + " origin=" + originToString(origin)
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " expectedTimeMillis=" + expectedTimeMillis
+ " actualTimeMillis=" + actualSystemClockMillis
@@ -784,44 +855,72 @@ public final class TimeDetectorStrategyImpl implements TimeDetectorStrategy {
}
}
+ // If the new signal would make sufficient difference to the system clock or mean a change
+ // in confidence then system state must be updated.
+
// Adjust for the time that has elapsed since the signal was received.
long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
-
- // Check if the new signal would make sufficient difference to the system clock. If it's
- // below the threshold then ignore it.
long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
long systemClockUpdateThreshold =
mCurrentConfigurationInternal.getSystemClockUpdateThresholdMillis();
- if (absTimeDifference < systemClockUpdateThreshold) {
+ boolean updateSystemClockRequired = absTimeDifference >= systemClockUpdateThreshold;
+
+ @TimeConfidence int currentTimeConfidence = mEnvironment.systemClockConfidence();
+ boolean updateConfidenceRequired = newTimeConfidence > currentTimeConfidence;
+
+ if (updateSystemClockRequired) {
+ String logMsg = "Set system clock & confidence."
+ + " origin=" + originToString(origin)
+ + " newTime=" + newTime
+ + " newTimeConfidence=" + newTimeConfidence
+ + " cause=" + cause
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ + " newSystemClockMillis=" + newSystemClockMillis
+ + " currentTimeConfidence=" + currentTimeConfidence;
+ mEnvironment.setSystemClock(newSystemClockMillis, newTimeConfidence, logMsg);
if (DBG) {
- Slog.d(LOG_TAG, "Not setting system clock. New time and"
- + " system clock are close enough."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ Slog.d(LOG_TAG, logMsg);
+ }
+
+ // CLOCK_PARANOIA : Record the last time this class set the system clock due to an
+ // auto-time signal, or clear the record it is being done manually.
+ if (isOriginAutomatic(origin)) {
+ mLastAutoSystemClockTimeSet = newTime;
+ } else {
+ mLastAutoSystemClockTimeSet = null;
+ }
+ } else if (updateConfidenceRequired) {
+ // Only the confidence needs updating. This path is separate from a system clock update
+ // to deliberately avoid touching the system clock's value when it's not needed. Doing
+ // so could introduce inaccuracies or cause unnecessary wear in RTC hardware or
+ // associated storage.
+ String logMsg = "Set system clock confidence."
+ + " origin=" + originToString(origin)
+ + " newTime=" + newTime
+ + " newTimeConfidence=" + newTimeConfidence
+ + " cause=" + cause
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " (old) actualSystemClockMillis=" + actualSystemClockMillis
+ + " newSystemClockMillis=" + newSystemClockMillis
+ + " currentTimeConfidence=" + currentTimeConfidence;
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
+ }
+ mEnvironment.setSystemClockConfidence(newTimeConfidence, logMsg);
+ } else {
+ // Neither clock nor confidence need updating.
+ if (DBG) {
+ Slog.d(LOG_TAG, "Not setting system clock or confidence."
+ + " origin=" + originToString(origin)
+ " newTime=" + newTime
+ + " newTimeConfidence=" + newTimeConfidence
+ " cause=" + cause
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
- + " absTimeDifference=" + absTimeDifference);
+ + " absTimeDifference=" + absTimeDifference
+ + " currentTimeConfidence=" + currentTimeConfidence);
}
- return true;
- }
-
- mEnvironment.setSystemClock(newSystemClockMillis);
- String logMsg = "Set system clock using time=" + newTime
- + " cause=" + cause
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " (old) actualSystemClockMillis=" + actualSystemClockMillis
- + " newSystemClockMillis=" + newSystemClockMillis;
- if (DBG) {
- Slog.d(LOG_TAG, logMsg);
- }
- mTimeChangesLog.log(logMsg);
-
- // CLOCK_PARANOIA : Record the last time this class set the system clock due to an auto-time
- // signal, or clear the record it is being done manually.
- if (isOriginAutomatic(origin)) {
- mLastAutoSystemClockTimeSet = newTime;
- } else {
- mLastAutoSystemClockTimeSet = null;
}
return true;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 5d6ffd8b8ead..7e93d623f3e0 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -53,6 +53,7 @@ cc_library_static {
"com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp",
"com_android_server_stats_pull_StatsPullAtomService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
+ "com_android_server_SystemClockTime.cpp",
"com_android_server_SystemServer.cpp",
"com_android_server_tv_TvUinputBridge.cpp",
"com_android_server_tv_TvInputHal.cpp",
diff --git a/services/core/jni/com_android_server_SystemClockTime.cpp b/services/core/jni/com_android_server_SystemClockTime.cpp
new file mode 100644
index 000000000000..9db4c429f0c7
--- /dev/null
+++ b/services/core/jni/com_android_server_SystemClockTime.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "SystemClockTime"
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <linux/rtc.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include "jni.h"
+
+namespace android {
+
+class SystemClockImpl {
+public:
+ SystemClockImpl(const std::string &rtc_dev) : rtc_dev{rtc_dev} {}
+
+ int setTime(struct timeval *tv);
+
+private:
+ std::string rtc_dev;
+};
+
+int SystemClockImpl::setTime(struct timeval *tv) {
+ if (settimeofday(tv, NULL) == -1) {
+ ALOGV("settimeofday() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ android::base::unique_fd fd{open(rtc_dev.c_str(), O_RDWR)};
+ if (!fd.ok()) {
+ ALOGE("Unable to open %s: %s", rtc_dev.c_str(), strerror(errno));
+ return -1;
+ }
+
+ struct tm tm;
+ if (!gmtime_r(&tv->tv_sec, &tm)) {
+ ALOGV("gmtime_r() failed: %s", strerror(errno));
+ return -1;
+ }
+
+ struct rtc_time rtc = {};
+ rtc.tm_sec = tm.tm_sec;
+ rtc.tm_min = tm.tm_min;
+ rtc.tm_hour = tm.tm_hour;
+ rtc.tm_mday = tm.tm_mday;
+ rtc.tm_mon = tm.tm_mon;
+ rtc.tm_year = tm.tm_year;
+ rtc.tm_wday = tm.tm_wday;
+ rtc.tm_yday = tm.tm_yday;
+ rtc.tm_isdst = tm.tm_isdst;
+ if (ioctl(fd, RTC_SET_TIME, &rtc) == -1) {
+ ALOGV("RTC_SET_TIME ioctl failed: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static jlong com_android_server_SystemClockTime_init(JNIEnv *, jobject) {
+ // Find the wall clock RTC. We expect this always to be /dev/rtc0, but
+ // check the /dev/rtc symlink first so that legacy devices that don't use
+ // rtc0 can add a symlink rather than need to carry a local patch to this
+ // code.
+ //
+ // TODO: if you're reading this in a world where all devices are using the
+ // GKI, you can remove the readlink and just assume /dev/rtc0.
+ std::string dev_rtc;
+ if (!android::base::Readlink("/dev/rtc", &dev_rtc)) {
+ dev_rtc = "/dev/rtc0";
+ }
+
+ std::unique_ptr<SystemClockImpl> system_clock{new SystemClockImpl(dev_rtc)};
+ return reinterpret_cast<jlong>(system_clock.release());
+}
+
+static jint com_android_server_SystemClockTime_setTime(JNIEnv *, jobject, jlong nativeData,
+ jlong millis) {
+ SystemClockImpl *impl = reinterpret_cast<SystemClockImpl *>(nativeData);
+
+ if (millis <= 0 || millis / 1000LL >= std::numeric_limits<time_t>::max()) {
+ return -1;
+ }
+
+ struct timeval tv;
+ tv.tv_sec = (millis / 1000LL);
+ tv.tv_usec = ((millis % 1000LL) * 1000LL);
+
+ ALOGD("Setting time of day to sec=%ld", tv.tv_sec);
+
+ int ret = impl->setTime(&tv);
+ if (ret < 0) {
+ ALOGW("Unable to set rtc to %ld: %s", tv.tv_sec, strerror(errno));
+ ret = -1;
+ }
+ return ret;
+}
+
+static const JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"init", "()J", (void *)com_android_server_SystemClockTime_init},
+ {"setTime", "(JJ)I", (void *)com_android_server_SystemClockTime_setTime},
+};
+
+int register_com_android_server_SystemClockTime(JNIEnv *env) {
+ return jniRegisterNativeMethods(env, "com/android/server/SystemClockTime", sMethods,
+ NELEM(sMethods));
+}
+
+} /* namespace android */
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 00bef0935308..00f851f9f4ff 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -65,6 +65,7 @@ int register_android_server_companion_virtual_InputController(JNIEnv* env);
int register_android_server_app_GameManagerService(JNIEnv* env);
int register_com_android_server_wm_TaskFpsCallbackController(JNIEnv* env);
int register_com_android_server_display_DisplayControl(JNIEnv* env);
+int register_com_android_server_SystemClockTime(JNIEnv* env);
};
using namespace android;
@@ -122,5 +123,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_app_GameManagerService(env);
register_com_android_server_wm_TaskFpsCallbackController(env);
register_com_android_server_display_DisplayControl(env);
+ register_com_android_server_SystemClockTime(env);
return JNI_VERSION_1_4;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
index 1b9282d426d0..830e2ac029c2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -168,6 +168,7 @@ import com.android.server.AppStateTracker;
import com.android.server.AppStateTrackerImpl;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.SystemService;
import com.android.server.pm.permission.PermissionManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
@@ -346,10 +347,6 @@ public class AlarmManagerServiceTest {
}
@Override
- void setKernelTime(long millis) {
- }
-
- @Override
int getSystemUiUid(PackageManagerInternal unused) {
return SYSTEM_UI_UID;
}
@@ -361,7 +358,18 @@ public class AlarmManagerServiceTest {
}
@Override
- long getElapsedRealtime() {
+ void initializeTimeIfRequired() {
+ // No-op
+ }
+
+ @Override
+ void setCurrentTimeMillis(long unixEpochMillis,
+ @TimeConfidence int confidence, String logMsg) {
+ mNowRtcTest = unixEpochMillis;
+ }
+
+ @Override
+ long getElapsedRealtimeMillis() {
return mNowElapsedTest;
}
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 1aea6727d3a1..060c31f2985e 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -16,6 +16,8 @@
package com.android.server.timedetector;
+import static com.android.server.SystemClockTime.TIME_CONFIDENCE_HIGH;
+import static com.android.server.SystemClockTime.TIME_CONFIDENCE_LOW;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_EXTERNAL;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_GNSS;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
@@ -35,6 +37,7 @@ import android.os.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.SystemClockTime.TimeConfidence;
import com.android.server.timedetector.TimeDetectorStrategy.Origin;
import com.android.server.timezonedetector.ConfigurationChangeListener;
@@ -42,6 +45,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.PrintWriter;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
@@ -86,6 +90,7 @@ public class TimeDetectorStrategyImplTest {
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(
ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setSystemClockUpdateThresholdMillis(TIME_CONFIDENCE_HIGH)
.setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND)
@@ -99,6 +104,7 @@ public class TimeDetectorStrategyImplTest {
.setAutoDetectionSupported(true)
.setSystemClockUpdateThresholdMillis(
ARBITRARY_SYSTEM_CLOCK_UPDATE_THRESHOLD_MILLIS)
+ .setSystemClockUpdateThresholdMillis(TIME_CONFIDENCE_HIGH)
.setAutoSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
.setManualSuggestionLowerBound(DEFAULT_SUGGESTION_LOWER_BOUND)
.setSuggestionUpperBound(DEFAULT_SUGGESTION_UPPER_BOUND)
@@ -112,12 +118,14 @@ public class TimeDetectorStrategyImplTest {
public void setUp() {
mFakeEnvironment = new FakeEnvironment();
mFakeEnvironment.initializeConfig(CONFIG_AUTO_DISABLED);
- mFakeEnvironment.initializeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO);
+ mFakeEnvironment.initializeFakeClocks(
+ ARBITRARY_CLOCK_INITIALIZATION_INFO, TIME_CONFIDENCE_LOW);
}
@Test
public void testSuggestTelephonyTime_autoTimeEnabled() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
@@ -129,18 +137,21 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
- script.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
+ script.verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
}
@Test
public void testSuggestTelephonyTime_emptySuggestionIgnored() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
int slotIndex = ARBITRARY_SLOT_INDEX;
TelephonyTimeSuggestion timeSuggestion =
script.generateTelephonyTimeSuggestion(slotIndex, null);
script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, null);
}
@@ -278,17 +289,115 @@ public class TimeDetectorStrategyImplTest {
}
}
+ /**
+ * If an auto suggested time matches the current system clock, the confidence in the current
+ * system clock is raised even when auto time is disabled. The system clock itself must not be
+ * changed.
+ */
@Test
- public void testSuggestTelephonyTime_autoTimeDisabled() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
+ public void testSuggestTelephonyTime_autoTimeDisabled_suggestionMatchesSystemClock() {
+ TimestampedValue<Instant> initialClockTime = ARBITRARY_CLOCK_INITIALIZATION_INFO;
+ final int confidenceUpgradeThresholdMillis = 1000;
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setSystemClockConfidenceUpgradeThresholdMillis(
+ confidenceUpgradeThresholdMillis)
+ .build();
+ Script script = new Script()
+ .pokeFakeClocks(initialClockTime, TIME_CONFIDENCE_LOW)
+ .simulateConfigurationInternalChange(configInternal);
int slotIndex = ARBITRARY_SLOT_INDEX;
- TelephonyTimeSuggestion timeSuggestion =
- script.generateTelephonyTimeSuggestion(slotIndex, ARBITRARY_TEST_TIME);
- script.simulateTimePassing()
- .simulateTelephonyTimeSuggestion(timeSuggestion)
- .verifySystemClockWasNotSetAndResetCallTracking()
- .assertLatestTelephonySuggestion(slotIndex, timeSuggestion);
+
+ script.simulateTimePassing();
+ long timeElapsedMillis =
+ script.peekElapsedRealtimeMillis() - initialClockTime.getReferenceTimeMillis();
+
+ // Create a suggestion time that approximately matches the current system clock.
+ Instant suggestionInstant = initialClockTime.getValue()
+ .plusMillis(timeElapsedMillis)
+ .plusMillis(confidenceUpgradeThresholdMillis);
+ TimestampedValue<Long> matchingClockTime = new TimestampedValue<>(
+ script.peekElapsedRealtimeMillis(),
+ suggestionInstant.toEpochMilli());
+ TelephonyTimeSuggestion timeSuggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
+ .setUnixEpochTime(matchingClockTime)
+ .build();
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ /**
+ * If an auto suggested time doesn't match the current system clock, the confidence in the
+ * current system clock will stay where it is. The system clock itself must not be changed.
+ */
+ @Test
+ public void testSuggestTelephonyTime_autoTimeDisabled_suggestionMismatchesSystemClock() {
+ TimestampedValue<Instant> initialClockTime = ARBITRARY_CLOCK_INITIALIZATION_INFO;
+ final int confidenceUpgradeThresholdMillis = 1000;
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setSystemClockConfidenceUpgradeThresholdMillis(
+ confidenceUpgradeThresholdMillis)
+ .build();
+ Script script = new Script().pokeFakeClocks(initialClockTime, TIME_CONFIDENCE_LOW)
+ .simulateConfigurationInternalChange(configInternal);
+
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+
+ script.simulateTimePassing();
+ long timeElapsedMillis =
+ script.peekElapsedRealtimeMillis() - initialClockTime.getReferenceTimeMillis();
+
+ // Create a suggestion time that doesn't match the current system clock closely enough.
+ Instant suggestionInstant = initialClockTime.getValue()
+ .plusMillis(timeElapsedMillis)
+ .plusMillis(confidenceUpgradeThresholdMillis + 1);
+ TimestampedValue<Long> mismatchingClockTime = new TimestampedValue<>(
+ script.peekElapsedRealtimeMillis(),
+ suggestionInstant.toEpochMilli());
+ TelephonyTimeSuggestion timeSuggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
+ .setUnixEpochTime(mismatchingClockTime)
+ .build();
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ /**
+ * If a suggested time doesn't match the current system clock, the confidence in the current
+ * system clock will not drop.
+ */
+ @Test
+ public void testSuggestTelephonyTime_autoTimeDisabled_suggestionMismatchesSystemClock2() {
+ TimestampedValue<Instant> initialClockTime = ARBITRARY_CLOCK_INITIALIZATION_INFO;
+ final int confidenceUpgradeThresholdMillis = 1000;
+ ConfigurationInternal configInternal =
+ new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
+ .setSystemClockConfidenceUpgradeThresholdMillis(
+ confidenceUpgradeThresholdMillis)
+ .build();
+ Script script = new Script().pokeFakeClocks(initialClockTime, TIME_CONFIDENCE_HIGH)
+ .simulateConfigurationInternalChange(configInternal);
+
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+
+ script.simulateTimePassing();
+ long timeElapsedMillis =
+ script.peekElapsedRealtimeMillis() - initialClockTime.getReferenceTimeMillis();
+
+ // Create a suggestion time that doesn't closely match the current system clock.
+ Instant initialClockInstant = initialClockTime.getValue();
+ TimestampedValue<Long> mismatchingClockTime = new TimestampedValue<>(
+ script.peekElapsedRealtimeMillis(),
+ initialClockInstant.plusMillis(timeElapsedMillis + 1_000_000).toEpochMilli());
+ TelephonyTimeSuggestion timeSuggestion = new TelephonyTimeSuggestion.Builder(slotIndex)
+ .setUnixEpochTime(mismatchingClockTime)
+ .build();
+ script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
+ .verifySystemClockWasNotSetAndResetCallTracking();
}
@Test
@@ -298,7 +407,8 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setSystemClockUpdateThresholdMillis(systemClockUpdateThresholdMillis)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant testTime = ARBITRARY_TEST_TIME;
int slotIndex = ARBITRARY_SLOT_INDEX;
@@ -311,6 +421,7 @@ public class TimeDetectorStrategyImplTest {
script.simulateTimePassing();
long expectedSystemClockMillis1 = script.calculateTimeInMillisForNow(unixEpochTime1);
script.simulateTelephonyTimeSuggestion(timeSuggestion1)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -327,6 +438,7 @@ public class TimeDetectorStrategyImplTest {
TelephonyTimeSuggestion timeSuggestion2 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime2);
script.simulateTelephonyTimeSuggestion(timeSuggestion2)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -339,6 +451,7 @@ public class TimeDetectorStrategyImplTest {
TelephonyTimeSuggestion timeSuggestion3 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime3);
script.simulateTelephonyTimeSuggestion(timeSuggestion3)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -350,6 +463,7 @@ public class TimeDetectorStrategyImplTest {
TelephonyTimeSuggestion timeSuggestion4 =
createTelephonyTimeSuggestion(slotIndex, unixEpochTime4);
script.simulateTelephonyTimeSuggestion(timeSuggestion4)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis4)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion4);
}
@@ -362,7 +476,8 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setSystemClockUpdateThresholdMillis(systemClockUpdateThresholdMillis)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
@@ -376,6 +491,7 @@ public class TimeDetectorStrategyImplTest {
// Simulate the time signal being received. It should not be used because auto time
// detection is off but it should be recorded.
script.simulateTelephonyTimeSuggestion(timeSuggestion1)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -386,11 +502,13 @@ public class TimeDetectorStrategyImplTest {
// Turn on auto time detection.
script.simulateAutoTimeDetectionToggle()
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis1)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
// Turn off auto time detection.
script.simulateAutoTimeDetectionToggle()
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion1);
@@ -408,18 +526,21 @@ public class TimeDetectorStrategyImplTest {
// The new time, though valid, should not be set in the system clock because auto time is
// disabled.
script.simulateTelephonyTimeSuggestion(timeSuggestion2)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
// Turn on auto time detection.
script.simulateAutoTimeDetectionToggle()
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis2)
.assertLatestTelephonySuggestion(slotIndex, timeSuggestion2);
}
@Test
public void testSuggestTelephonyTime_maxSuggestionAge() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
int slotIndex = ARBITRARY_SLOT_INDEX;
Instant testTime = ARBITRARY_TEST_TIME;
@@ -431,6 +552,7 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(telephonySuggestion.getUnixEpochTime());
script.simulateTelephonyTimeSuggestion(telephonySuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(
expectedSystemClockMillis /* expectedNetworkBroadcast */)
.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
@@ -442,7 +564,7 @@ public class TimeDetectorStrategyImplTest {
script.simulateTimePassing(TimeDetectorStrategyImpl.MAX_SUGGESTION_TIME_AGE_MILLIS);
// Look inside and check what the strategy considers the current best telephony suggestion.
- // It should still be the, it's just no longer used.
+ // It should still be there, it's just no longer used.
assertNull(script.peekBestTelephonySuggestion());
script.assertLatestTelephonySuggestion(slotIndex, telephonySuggestion);
}
@@ -454,12 +576,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_TELEPHONY)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
TelephonyTimeSuggestion timeSuggestion =
script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowLowerBound);
script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -470,12 +594,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_TELEPHONY)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
TelephonyTimeSuggestion timeSuggestion =
script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveLowerBound);
script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -486,12 +612,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_TELEPHONY)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
TelephonyTimeSuggestion timeSuggestion =
script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, aboveUpperBound);
script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -502,18 +630,21 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_TELEPHONY)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
TelephonyTimeSuggestion timeSuggestion =
script.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, belowUpperBound);
script.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@Test
public void testSuggestManualTime_autoTimeDisabled() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_DISABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
ManualTimeSuggestion timeSuggestion =
script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -524,12 +655,14 @@ public class TimeDetectorStrategyImplTest {
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@Test
public void testSuggestManualTime_retainsAutoSignal() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
int slotIndex = ARBITRARY_SLOT_INDEX;
@@ -544,6 +677,7 @@ public class TimeDetectorStrategyImplTest {
long expectedAutoClockMillis =
script.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
script.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -552,6 +686,7 @@ public class TimeDetectorStrategyImplTest {
// Switch to manual.
script.simulateAutoTimeDetectionToggle()
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -568,6 +703,7 @@ public class TimeDetectorStrategyImplTest {
script.calculateTimeInMillisForNow(manualTimeSuggestion.getUnixEpochTime());
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, manualTimeSuggestion, true /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedManualClockMillis)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
@@ -580,17 +716,20 @@ public class TimeDetectorStrategyImplTest {
expectedAutoClockMillis =
script.calculateTimeInMillisForNow(telephonyTimeSuggestion.getUnixEpochTime());
script.verifySystemClockWasSetAndResetCallTracking(expectedAutoClockMillis)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
// Switch back to manual - nothing should happen to the clock.
script.simulateAutoTimeDetectionToggle()
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasNotSetAndResetCallTracking()
.assertLatestTelephonySuggestion(slotIndex, telephonyTimeSuggestion);
}
@Test
public void testSuggestManualTime_isIgnored_whenAutoTimeEnabled() {
- Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED);
+ Script script = new Script().simulateConfigurationInternalChange(CONFIG_AUTO_ENABLED)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
ManualTimeSuggestion timeSuggestion =
script.generateManualTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -598,6 +737,7 @@ public class TimeDetectorStrategyImplTest {
script.simulateTimePassing()
.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -607,12 +747,14 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveUpperBound);
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -622,12 +764,14 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowUpperBound);
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -637,12 +781,14 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(belowLowerBound);
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, false /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -652,12 +798,14 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_DISABLED)
.setManualSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
ManualTimeSuggestion timeSuggestion = script.generateManualTimeSuggestion(aboveLowerBound);
script.simulateManualTimeSuggestion(
ARBITRARY_USER_ID, timeSuggestion, true /* expectedResult */)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -667,7 +815,8 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_NETWORK)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -677,6 +826,7 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -703,12 +853,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_NETWORK)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(belowLowerBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -719,12 +871,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_NETWORK)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(aboveLowerBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -735,12 +889,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_NETWORK)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(aboveUpperBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -751,12 +907,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_NETWORK)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
NetworkTimeSuggestion timeSuggestion =
script.generateNetworkTimeSuggestion(belowUpperBound);
script.simulateNetworkTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -766,7 +924,8 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_GNSS)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
GnssTimeSuggestion timeSuggestion =
script.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -776,6 +935,7 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
script.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -802,12 +962,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_GNSS)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
GnssTimeSuggestion timeSuggestion =
script.generateGnssTimeSuggestion(belowLowerBound);
script.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -818,12 +980,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_GNSS)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
GnssTimeSuggestion timeSuggestion =
script.generateGnssTimeSuggestion(aboveLowerBound);
script.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -834,12 +998,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_GNSS)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
GnssTimeSuggestion timeSuggestion =
script.generateGnssTimeSuggestion(aboveUpperBound);
script.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -850,12 +1016,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_GNSS)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
GnssTimeSuggestion timeSuggestion =
script.generateGnssTimeSuggestion(belowUpperBound);
script.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -865,7 +1033,8 @@ public class TimeDetectorStrategyImplTest {
new ConfigurationInternal.Builder(CONFIG_AUTO_ENABLED)
.setOriginPriorities(ORIGIN_EXTERNAL)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
ExternalTimeSuggestion timeSuggestion =
script.generateExternalTimeSuggestion(ARBITRARY_TEST_TIME);
@@ -875,6 +1044,7 @@ public class TimeDetectorStrategyImplTest {
long expectedSystemClockMillis =
script.calculateTimeInMillisForNow(timeSuggestion.getUnixEpochTime());
script.simulateExternalTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
}
@@ -901,12 +1071,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_EXTERNAL)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowLowerBound = TEST_SUGGESTION_LOWER_BOUND.minusSeconds(1);
ExternalTimeSuggestion timeSuggestion =
script.generateExternalTimeSuggestion(belowLowerBound);
script.simulateExternalTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -917,12 +1089,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_EXTERNAL)
.setAutoSuggestionLowerBound(TEST_SUGGESTION_LOWER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveLowerBound = TEST_SUGGESTION_LOWER_BOUND.plusSeconds(1);
ExternalTimeSuggestion timeSuggestion =
script.generateExternalTimeSuggestion(aboveLowerBound);
script.simulateExternalTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(aboveLowerBound.toEpochMilli());
}
@@ -933,12 +1107,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_EXTERNAL)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant aboveUpperBound = TEST_SUGGESTION_UPPER_BOUND.plusSeconds(1);
ExternalTimeSuggestion timeSuggestion =
script.generateExternalTimeSuggestion(aboveUpperBound);
script.simulateExternalTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW)
.verifySystemClockWasNotSetAndResetCallTracking();
}
@@ -949,12 +1125,14 @@ public class TimeDetectorStrategyImplTest {
.setOriginPriorities(ORIGIN_EXTERNAL)
.setSuggestionUpperBound(TEST_SUGGESTION_UPPER_BOUND)
.build();
- Script script = new Script().simulateConfigurationInternalChange(configInternal);
+ Script script = new Script().simulateConfigurationInternalChange(configInternal)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_LOW);
Instant belowUpperBound = TEST_SUGGESTION_UPPER_BOUND.minusSeconds(1);
ExternalTimeSuggestion timeSuggestion =
script.generateExternalTimeSuggestion(belowUpperBound);
script.simulateExternalTimeSuggestion(timeSuggestion)
+ .verifySystemClockConfidence(TIME_CONFIDENCE_HIGH)
.verifySystemClockWasSetAndResetCallTracking(belowUpperBound.toEpochMilli());
}
@@ -1472,6 +1650,7 @@ public class TimeDetectorStrategyImplTest {
private boolean mWakeLockAcquired;
private long mElapsedRealtimeMillis;
private long mSystemClockMillis;
+ private int mSystemClockConfidence = TIME_CONFIDENCE_LOW;
private ConfigurationChangeListener mConfigurationInternalChangeListener;
// Tracking operations.
@@ -1481,9 +1660,10 @@ public class TimeDetectorStrategyImplTest {
mConfigurationInternal = configurationInternal;
}
- public void initializeFakeClocks(TimestampedValue<Instant> timeInfo) {
+ public void initializeFakeClocks(
+ TimestampedValue<Instant> timeInfo, @TimeConfidence int timeConfidence) {
pokeElapsedRealtimeMillis(timeInfo.getReferenceTimeMillis());
- pokeSystemClockMillis(timeInfo.getValue().toEpochMilli());
+ pokeSystemClockMillis(timeInfo.getValue().toEpochMilli(), timeConfidence);
}
@Override
@@ -1515,10 +1695,23 @@ public class TimeDetectorStrategyImplTest {
}
@Override
- public void setSystemClock(long newTimeMillis) {
+ public @TimeConfidence int systemClockConfidence() {
+ return mSystemClockConfidence;
+ }
+
+ @Override
+ public void setSystemClock(
+ long newTimeMillis, @TimeConfidence int confidence, String logMsg) {
assertWakeLockAcquired();
mSystemClockWasSet = true;
mSystemClockMillis = newTimeMillis;
+ mSystemClockConfidence = confidence;
+ }
+
+ @Override
+ public void setSystemClockConfidence(@TimeConfidence int confidence, String logMsg) {
+ assertWakeLockAcquired();
+ mSystemClockConfidence = confidence;
}
@Override
@@ -1527,6 +1720,16 @@ public class TimeDetectorStrategyImplTest {
mWakeLockAcquired = false;
}
+ @Override
+ public void addDebugLogEntry(String logMsg) {
+ // No-op for tests
+ }
+
+ @Override
+ public void dumpDebugLog(PrintWriter printWriter) {
+ // No-op for tests
+ }
+
// Methods below are for managing the fake's behavior.
void simulateConfigurationInternalChange(ConfigurationInternal configurationInternal) {
@@ -1538,8 +1741,9 @@ public class TimeDetectorStrategyImplTest {
mElapsedRealtimeMillis = elapsedRealtimeMillis;
}
- void pokeSystemClockMillis(long systemClockMillis) {
+ void pokeSystemClockMillis(long systemClockMillis, @TimeConfidence int timeConfidence) {
mSystemClockMillis = systemClockMillis;
+ mSystemClockConfidence = timeConfidence;
}
long peekElapsedRealtimeMillis() {
@@ -1567,6 +1771,10 @@ public class TimeDetectorStrategyImplTest {
assertEquals(expectedSystemClockMillis, mSystemClockMillis);
}
+ public void verifySystemClockConfidence(@TimeConfidence int expectedConfidence) {
+ assertEquals(expectedConfidence, mSystemClockConfidence);
+ }
+
void resetCallTracking() {
mSystemClockWasSet = false;
}
@@ -1589,6 +1797,14 @@ public class TimeDetectorStrategyImplTest {
mTimeDetectorStrategy = new TimeDetectorStrategyImpl(mFakeEnvironment);
}
+ Script pokeFakeClocks(TimestampedValue<Instant> initialClockTime,
+ @TimeConfidence int timeConfidence) {
+ mFakeEnvironment.pokeElapsedRealtimeMillis(initialClockTime.getReferenceTimeMillis());
+ mFakeEnvironment.pokeSystemClockMillis(
+ initialClockTime.getValue().toEpochMilli(), timeConfidence);
+ return this;
+ }
+
long peekElapsedRealtimeMillis() {
return mFakeEnvironment.peekElapsedRealtimeMillis();
}
@@ -1675,6 +1891,11 @@ public class TimeDetectorStrategyImplTest {
return this;
}
+ Script verifySystemClockConfidence(@TimeConfidence int expectedConfidence) {
+ mFakeEnvironment.verifySystemClockConfidence(expectedConfidence);
+ return this;
+ }
+
/**
* White box test info: Asserts the latest suggestion for the slotIndex is as expected.
*/