blob: 0b970bfc0076db9fad096b9c2ea6fb8c437825c5 [file] [log] [blame]
Neil Fuller4773b9d2018-06-08 18:44:49 +01001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.timedetector;
18
Neil Fuller3aedd492019-11-23 11:33:57 +000019import android.annotation.IntDef;
Neil Fuller4773b9d2018-06-08 18:44:49 +010020import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.app.AlarmManager;
Neil Fuller3aedd492019-11-23 11:33:57 +000023import android.app.timedetector.ManualTimeSuggestion;
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010024import android.app.timedetector.PhoneTimeSuggestion;
Neil Fuller4980bbc2018-06-12 21:06:20 +010025import android.content.Intent;
Neil Fuller40cf2952019-11-28 09:47:30 +000026import android.util.LocalLog;
Neil Fuller4773b9d2018-06-08 18:44:49 +010027import android.util.Slog;
Neil Fuller4980bbc2018-06-12 21:06:20 +010028import android.util.TimestampedValue;
Neil Fuller4773b9d2018-06-08 18:44:49 +010029
Neil Fuller40cf2952019-11-28 09:47:30 +000030import com.android.internal.annotations.GuardedBy;
Neil Fuller4980bbc2018-06-12 21:06:20 +010031import com.android.internal.telephony.TelephonyIntents;
Neil Fuller40cf2952019-11-28 09:47:30 +000032import com.android.internal.util.IndentingPrintWriter;
Neil Fuller4980bbc2018-06-12 21:06:20 +010033
Neil Fuller4773b9d2018-06-08 18:44:49 +010034import java.io.PrintWriter;
Neil Fuller3aedd492019-11-23 11:33:57 +000035import java.lang.annotation.Retention;
36import java.lang.annotation.RetentionPolicy;
Neil Fuller4773b9d2018-06-08 18:44:49 +010037
38/**
Neil Fuller4980bbc2018-06-12 21:06:20 +010039 * An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
Neil Fuller40cf2952019-11-28 09:47:30 +000040 * {@link AlarmManager}.
41 *
42 * <p>Most public methods are marked synchronized to ensure thread safety around internal state.
Neil Fuller4773b9d2018-06-08 18:44:49 +010043 */
44public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
45
Neil Fuller40cf2952019-11-28 09:47:30 +000046 private static final boolean DBG = false;
47 private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
Neil Fuller4773b9d2018-06-08 18:44:49 +010048
Neil Fuller3aedd492019-11-23 11:33:57 +000049 @IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
50 @Retention(RetentionPolicy.SOURCE)
51 public @interface Origin {}
52
53 /** Used when a time value originated from a telephony signal. */
54 @Origin
55 private static final int ORIGIN_PHONE = 1;
56
57 /** Used when a time value originated from a user / manual settings. */
58 @Origin
59 private static final int ORIGIN_MANUAL = 2;
60
Neil Fuller4980bbc2018-06-12 21:06:20 +010061 /**
62 * CLOCK_PARANOIA: The maximum difference allowed between the expected system clock time and the
63 * actual system clock time before a warning is logged. Used to help identify situations where
Neil Fuller3aedd492019-11-23 11:33:57 +000064 * there is something other than this class setting the system clock automatically.
Neil Fuller4980bbc2018-06-12 21:06:20 +010065 */
66 private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
67
Neil Fuller40cf2952019-11-28 09:47:30 +000068 // A log for changes made to the system clock and why.
69 @NonNull private final LocalLog mTimeChangesLog = new LocalLog(30);
70
Neil Fuller4980bbc2018-06-12 21:06:20 +010071 // @NonNull after initialize()
72 private Callback mCallback;
73
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010074 // Last phone suggestion.
75 @Nullable private PhoneTimeSuggestion mLastPhoneSuggestion;
Neil Fuller4980bbc2018-06-12 21:06:20 +010076
77 // Information about the last time signal received: Used when toggling auto-time.
Neil Fuller3aedd492019-11-23 11:33:57 +000078 @Nullable private TimestampedValue<Long> mLastAutoSystemClockTime;
79 private boolean mLastAutoSystemClockTimeSendNetworkBroadcast;
Neil Fuller4980bbc2018-06-12 21:06:20 +010080
81 // System clock state.
Neil Fuller3aedd492019-11-23 11:33:57 +000082 @Nullable private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
Neil Fuller4773b9d2018-06-08 18:44:49 +010083
84 @Override
85 public void initialize(@NonNull Callback callback) {
Neil Fuller4980bbc2018-06-12 21:06:20 +010086 mCallback = callback;
Neil Fuller4773b9d2018-06-08 18:44:49 +010087 }
88
89 @Override
Neil Fuller40cf2952019-11-28 09:47:30 +000090 public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
Neil Fuller4980bbc2018-06-12 21:06:20 +010091 // NITZ logic
92
Neil Fuller568fd892019-11-20 14:39:06 +000093 // Empty suggestions are just ignored as we don't currently keep track of suggestion origin.
94 if (timeSuggestion.getUtcTime() == null) {
95 return;
96 }
97
Neil Fulleraf3eeaf2019-10-15 14:37:37 +010098 boolean timeSuggestionIsValid =
99 validateNewPhoneSuggestion(timeSuggestion, mLastPhoneSuggestion);
100 if (!timeSuggestionIsValid) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100101 return;
102 }
103 // Always store the last NITZ value received, regardless of whether we go on to use it to
Neil Fuller3aedd492019-11-23 11:33:57 +0000104 // update the system clock. This is so that we can validate future phone suggestions.
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100105 mLastPhoneSuggestion = timeSuggestion;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100106
107 // System clock update logic.
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100108 final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
Neil Fuller3aedd492019-11-23 11:33:57 +0000109 setSystemClockIfRequired(ORIGIN_PHONE, newUtcTime, timeSuggestion);
110 }
111
112 @Override
Neil Fuller40cf2952019-11-28 09:47:30 +0000113 public synchronized void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
Neil Fuller3aedd492019-11-23 11:33:57 +0000114 final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
115 setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100116 }
117
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100118 private static boolean validateNewPhoneSuggestion(@NonNull PhoneTimeSuggestion newSuggestion,
119 @Nullable PhoneTimeSuggestion lastSuggestion) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100120
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100121 if (lastSuggestion != null) {
122 long referenceTimeDifference = TimestampedValue.referenceTimeDifference(
123 newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
Neil Fuller4980bbc2018-06-12 21:06:20 +0100124 if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
125 // Out of order or bogus.
Neil Fuller40cf2952019-11-28 09:47:30 +0000126 Slog.w(LOG_TAG, "Bad NITZ signal received."
Neil Fuller4980bbc2018-06-12 21:06:20 +0100127 + " referenceTimeDifference=" + referenceTimeDifference
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100128 + " lastSuggestion=" + lastSuggestion
129 + " newSuggestion=" + newSuggestion);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100130 return false;
131 }
132 }
133 return true;
134 }
135
Neil Fuller40cf2952019-11-28 09:47:30 +0000136 @GuardedBy("this")
Neil Fuller4980bbc2018-06-12 21:06:20 +0100137 private void setSystemClockIfRequired(
Neil Fuller3aedd492019-11-23 11:33:57 +0000138 @Origin int origin, TimestampedValue<Long> time, Object cause) {
139 // Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
140 // when setting the time using NITZ.
141 boolean sendNetworkBroadcast = origin == ORIGIN_PHONE;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100142
Neil Fuller3aedd492019-11-23 11:33:57 +0000143 boolean isOriginAutomatic = isOriginAutomatic(origin);
144 if (isOriginAutomatic) {
145 // Store the last auto time candidate we've seen in all cases so we can set the system
146 // clock when/if time detection is off but later enabled.
147 mLastAutoSystemClockTime = time;
148 mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100149
Neil Fuller3aedd492019-11-23 11:33:57 +0000150 if (!mCallback.isAutoTimeDetectionEnabled()) {
Neil Fuller40cf2952019-11-28 09:47:30 +0000151 if (DBG) {
152 Slog.d(LOG_TAG, "Auto time detection is not enabled."
153 + " time=" + time
154 + ", cause=" + cause);
155 }
Neil Fuller3aedd492019-11-23 11:33:57 +0000156 return;
157 }
158 } else {
159 if (mCallback.isAutoTimeDetectionEnabled()) {
Neil Fuller40cf2952019-11-28 09:47:30 +0000160 if (DBG) {
161 Slog.d(LOG_TAG, "Auto time detection is enabled."
162 + " time=" + time
163 + ", cause=" + cause);
164 }
Neil Fuller3aedd492019-11-23 11:33:57 +0000165 return;
166 }
Neil Fuller4980bbc2018-06-12 21:06:20 +0100167 }
168
169 mCallback.acquireWakeLock();
170 try {
171 long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
172 long actualTimeMillis = mCallback.systemClockMillis();
173
Neil Fuller3aedd492019-11-23 11:33:57 +0000174 if (isOriginAutomatic) {
175 // CLOCK_PARANOIA : Check to see if this class owns the clock or if something else
176 // may be setting the clock.
177 if (mLastAutoSystemClockTimeSet != null) {
178 long expectedTimeMillis = TimeDetectorStrategy.getTimeAt(
179 mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
180 long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
181 if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
Neil Fuller40cf2952019-11-28 09:47:30 +0000182 Slog.w(LOG_TAG,
Neil Fuller3aedd492019-11-23 11:33:57 +0000183 "System clock has not tracked elapsed real time clock. A clock may"
184 + " be inaccurate or something unexpectedly set the system"
185 + " clock."
186 + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
187 + " expectedTimeMillis=" + expectedTimeMillis
188 + " actualTimeMillis=" + actualTimeMillis);
189 }
Neil Fuller4980bbc2018-06-12 21:06:20 +0100190 }
191 }
192
Neil Fuller4980bbc2018-06-12 21:06:20 +0100193 adjustAndSetDeviceSystemClock(
Neil Fuller3aedd492019-11-23 11:33:57 +0000194 time, sendNetworkBroadcast, elapsedRealtimeMillis, actualTimeMillis, cause);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100195 } finally {
196 mCallback.releaseWakeLock();
197 }
Neil Fuller4773b9d2018-06-08 18:44:49 +0100198 }
199
Neil Fuller3aedd492019-11-23 11:33:57 +0000200 private static boolean isOriginAutomatic(@Origin int origin) {
201 return origin == ORIGIN_PHONE;
202 }
203
Neil Fuller4773b9d2018-06-08 18:44:49 +0100204 @Override
Neil Fuller40cf2952019-11-28 09:47:30 +0000205 public synchronized void handleAutoTimeDetectionChanged() {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100206 // If automatic time detection is enabled we update the system clock instantly if we can.
207 // Conversely, if automatic time detection is disabled we leave the clock as it is.
Neil Fuller40cf2952019-11-28 09:47:30 +0000208 boolean enabled = mCallback.isAutoTimeDetectionEnabled();
Neil Fuller4980bbc2018-06-12 21:06:20 +0100209 if (enabled) {
Neil Fuller3aedd492019-11-23 11:33:57 +0000210 if (mLastAutoSystemClockTime != null) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100211 // Only send the network broadcast if the last candidate would have caused one.
Neil Fuller3aedd492019-11-23 11:33:57 +0000212 final boolean sendNetworkBroadcast = mLastAutoSystemClockTimeSendNetworkBroadcast;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100213
214 mCallback.acquireWakeLock();
215 try {
216 long elapsedRealtimeMillis = mCallback.elapsedRealtimeMillis();
217 long actualTimeMillis = mCallback.systemClockMillis();
218
219 final String reason = "Automatic time detection enabled.";
Neil Fuller3aedd492019-11-23 11:33:57 +0000220 adjustAndSetDeviceSystemClock(mLastAutoSystemClockTime, sendNetworkBroadcast,
Neil Fuller4980bbc2018-06-12 21:06:20 +0100221 elapsedRealtimeMillis, actualTimeMillis, reason);
222 } finally {
223 mCallback.releaseWakeLock();
224 }
225 }
226 } else {
227 // CLOCK_PARANOIA: We are losing "control" of the system clock so we cannot predict what
228 // it should be in future.
Neil Fuller3aedd492019-11-23 11:33:57 +0000229 mLastAutoSystemClockTimeSet = null;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100230 }
231 }
232
233 @Override
Neil Fuller40cf2952019-11-28 09:47:30 +0000234 public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
Neil Fulleraf3eeaf2019-10-15 14:37:37 +0100235 pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
Neil Fuller3aedd492019-11-23 11:33:57 +0000236 pw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
237 pw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
238 pw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
239 + mLastAutoSystemClockTimeSendNetworkBroadcast);
Neil Fuller40cf2952019-11-28 09:47:30 +0000240
241 IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
242
243 ipw.println("TimeDetectorStrategyImpl logs:");
244 ipw.increaseIndent(); // level 1
245
246 ipw.println("Time change log:");
247 ipw.increaseIndent(); // level 2
248 mTimeChangesLog.dump(ipw);
249 ipw.decreaseIndent(); // level 2
250
251 ipw.decreaseIndent(); // level 1
Neil Fuller4980bbc2018-06-12 21:06:20 +0100252 }
253
Neil Fuller40cf2952019-11-28 09:47:30 +0000254 @GuardedBy("this")
Neil Fuller4980bbc2018-06-12 21:06:20 +0100255 private void adjustAndSetDeviceSystemClock(
256 TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
Neil Fuller3aedd492019-11-23 11:33:57 +0000257 long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
Neil Fuller4980bbc2018-06-12 21:06:20 +0100258
259 // Adjust for the time that has elapsed since the signal was received.
260 long newSystemClockMillis = TimeDetectorStrategy.getTimeAt(newTime, elapsedRealtimeMillis);
261
262 // Check if the new signal would make sufficient difference to the system clock. If it's
263 // below the threshold then ignore it.
264 long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
265 long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis();
266 if (absTimeDifference < systemClockUpdateThreshold) {
Neil Fuller40cf2952019-11-28 09:47:30 +0000267 if (DBG) {
268 Slog.d(LOG_TAG, "Not setting system clock. New time and"
269 + " system clock are close enough."
270 + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
271 + " newTime=" + newTime
272 + " cause=" + cause
273 + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
274 + " absTimeDifference=" + absTimeDifference);
275 }
Neil Fuller4980bbc2018-06-12 21:06:20 +0100276 return;
277 }
278
Neil Fuller40cf2952019-11-28 09:47:30 +0000279 mCallback.setSystemClock(newSystemClockMillis);
280 String logMsg = "Set system clock using time=" + newTime
Neil Fuller3aedd492019-11-23 11:33:57 +0000281 + " cause=" + cause
Neil Fuller4980bbc2018-06-12 21:06:20 +0100282 + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
Neil Fuller40cf2952019-11-28 09:47:30 +0000283 + " newSystemClockMillis=" + newSystemClockMillis;
284 if (DBG) {
285 Slog.d(LOG_TAG, logMsg);
286 }
287 mTimeChangesLog.log(logMsg);
Neil Fuller4980bbc2018-06-12 21:06:20 +0100288
289 // CLOCK_PARANOIA : Record the last time this class set the system clock.
Neil Fuller3aedd492019-11-23 11:33:57 +0000290 mLastAutoSystemClockTimeSet = newTime;
Neil Fuller4980bbc2018-06-12 21:06:20 +0100291
292 if (sendNetworkBroadcast) {
293 // Send a broadcast that telephony code used to send after setting the clock.
294 // TODO Remove this broadcast as soon as there are no remaining listeners.
295 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
296 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
297 intent.putExtra("time", newSystemClockMillis);
298 mCallback.sendStickyBroadcast(intent);
299 }
Neil Fuller4773b9d2018-06-08 18:44:49 +0100300 }
301}