Merge "Introduce system clock time confidence"

This commit is contained in:
Neil Fuller
2022-10-04 17:12:55 +00:00
committed by Android (Google) Code Review
13 changed files with 898 additions and 272 deletions

View File

@@ -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);
}
@@ -2718,6 +2710,13 @@ public class AlarmManagerService extends SystemService {
setTimeZoneImpl(tzId, confidence);
}
@Override
public void setTime(
@CurrentTimeMillisLong long unixEpochTimeMillis, int confidence,
String logMsg) {
setTimeImpl(unixEpochTimeMillis, confidence, logMsg);
}
@Override
public void registerInFlightListener(InFlightListener callback) {
synchronized (mLock) {
@@ -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) {

View File

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

View File

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

View File

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

View File

@@ -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);
@@ -81,6 +84,17 @@ public final class ConfigurationInternal {
return mSystemClockUpdateThresholdMillis;
}
/**
* 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.
@@ -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;

View File

@@ -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();
mAlarmManager.setTime(newTimeMillis);
mAlarmManagerInternal.setTime(newTimeMillis, confidence, logMsg);
}
@Override
public void setSystemClockConfidence(@TimeConfidence int confidence, @NonNull String logMsg) {
checkWakeLockHeld();
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);
}}

View File

@@ -67,6 +67,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)

View File

@@ -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
+ " newTime=" + newTime
+ " cause=" + cause
+ " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ " absTimeDifference=" + absTimeDifference);
Slog.d(LOG_TAG, logMsg);
}
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;
// 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 {
mLastAutoSystemClockTimeSet = null;
// 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
+ " currentTimeConfidence=" + currentTimeConfidence);
}
}
return true;
}

View File

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

View File

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

View File

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

View File

@@ -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;
@@ -345,10 +346,6 @@ public class AlarmManagerServiceTest {
mTestTimer.set(type, millis);
}
@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;
}

View File

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