blob: b3a8fb61506b2cd9fca13c0d09b7a628ecae4775 [file] [log] [blame]
Amith Yamasani6734b9f2010-09-13 16:24:08 -07001/*
2 * Copyright (C) 2010 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;
18
Amith Yamasani6734b9f2010-09-13 16:24:08 -070019import android.app.AlarmManager;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.ContentResolver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.database.ContentObserver;
Amith Yamasani8d394fa2011-03-01 12:41:04 -080027import android.net.ConnectivityManager;
zhoulei45d1b262017-05-10 18:09:50 +080028import android.net.ConnectivityManager.NetworkCallback;
29import android.net.Network;
Fyodor Kupolov32af07a2016-02-26 16:54:25 -080030import android.os.Binder;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070031import android.os.Handler;
Amith Yamasani450a16b2013-09-18 16:28:50 -070032import android.os.HandlerThread;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070033import android.os.Looper;
34import android.os.Message;
Thierry Strudel8c842172015-10-29 14:40:29 -070035import android.os.PowerManager;
Jeff Sharkey9911a282018-02-14 22:29:11 -070036import android.os.SystemClock;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070037import android.provider.Settings;
38import android.util.Log;
Jeff Sharkey104344e2011-07-10 14:20:41 -070039import android.util.NtpTrustedTime;
Fyodor Kupolov32af07a2016-02-26 16:54:25 -080040import android.util.TimeUtils;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070041
Jeff Sharkey104344e2011-07-10 14:20:41 -070042import com.android.internal.telephony.TelephonyIntents;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060043import com.android.internal.util.DumpUtils;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070044
Fyodor Kupolov32af07a2016-02-26 16:54:25 -080045import java.io.FileDescriptor;
46import java.io.PrintWriter;
47
Amith Yamasani6734b9f2010-09-13 16:24:08 -070048/**
49 * Monitors the network time and updates the system time if it is out of sync
50 * and there hasn't been any NITZ update from the carrier recently.
51 * If looking up the network time fails for some reason, it tries a few times with a short
52 * interval and then resets to checking on longer intervals.
53 * <p>
54 * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
55 * available.
56 * </p>
57 */
Fyodor Kupolov32af07a2016-02-26 16:54:25 -080058public class NetworkTimeUpdateService extends Binder {
Amith Yamasani6734b9f2010-09-13 16:24:08 -070059
60 private static final String TAG = "NetworkTimeUpdateService";
61 private static final boolean DBG = false;
62
63 private static final int EVENT_AUTO_TIME_CHANGED = 1;
64 private static final int EVENT_POLL_NETWORK_TIME = 2;
Lorenzo Colittidf590532015-01-22 22:35:33 +090065 private static final int EVENT_NETWORK_CHANGED = 3;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070066
Amith Yamasani6734b9f2010-09-13 16:24:08 -070067 private static final String ACTION_POLL =
68 "com.android.server.NetworkTimeUpdateService.action.POLL";
Fyodor Kupolov32af07a2016-02-26 16:54:25 -080069
Neil Fullerc1211b52017-11-24 08:51:40 +000070 private static final int POLL_REQUEST = 0;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070071
72 private static final long NOT_SET = -1;
73 private long mNitzTimeSetTime = NOT_SET;
zhoulei45d1b262017-05-10 18:09:50 +080074 private Network mDefaultNetwork = null;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070075
Jeff Sharkey9911a282018-02-14 22:29:11 -070076 private final Context mContext;
77 private final NtpTrustedTime mTime;
78 private final AlarmManager mAlarmManager;
79 private final ConnectivityManager mCM;
80 private final PendingIntent mPendingPollIntent;
81 private final PowerManager.WakeLock mWakeLock;
Jeff Sharkey104344e2011-07-10 14:20:41 -070082
Amith Yamasani6734b9f2010-09-13 16:24:08 -070083 // NTP lookup is done on this thread and handler
84 private Handler mHandler;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070085 private SettingsObserver mSettingsObserver;
zhoulei45d1b262017-05-10 18:09:50 +080086 private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
Jaewan Kimc3560b82012-11-20 23:58:07 +090087
88 // Normal polling frequency
89 private final long mPollingIntervalMs;
90 // Try-again polling interval, in case the network request failed
91 private final long mPollingIntervalShorterMs;
92 // Number of times to try again
93 private final int mTryAgainTimesMax;
94 // If the time difference is greater than this threshold, then update the time.
95 private final int mTimeErrorThresholdMs;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070096 // Keeps track of how many quick attempts were made to fetch NTP time.
97 // During bootup, the network may not have been up yet, or it's taking time for the
98 // connection to happen.
99 private int mTryAgainCounter;
100
101 public NetworkTimeUpdateService(Context context) {
102 mContext = context;
Jeff Sharkey104344e2011-07-10 14:20:41 -0700103 mTime = NtpTrustedTime.getInstance(context);
Jeff Sharkey9911a282018-02-14 22:29:11 -0700104 mAlarmManager = mContext.getSystemService(AlarmManager.class);
105 mCM = mContext.getSystemService(ConnectivityManager.class);
106
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700107 Intent pollIntent = new Intent(ACTION_POLL, null);
108 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
Jaewan Kimc3560b82012-11-20 23:58:07 +0900109
110 mPollingIntervalMs = mContext.getResources().getInteger(
111 com.android.internal.R.integer.config_ntpPollingInterval);
112 mPollingIntervalShorterMs = mContext.getResources().getInteger(
113 com.android.internal.R.integer.config_ntpPollingIntervalShorter);
114 mTryAgainTimesMax = mContext.getResources().getInteger(
115 com.android.internal.R.integer.config_ntpRetry);
116 mTimeErrorThresholdMs = mContext.getResources().getInteger(
117 com.android.internal.R.integer.config_ntpThreshold);
Thierry Strudel8c842172015-10-29 14:40:29 -0700118
Jeff Sharkey9911a282018-02-14 22:29:11 -0700119 mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
Thierry Strudel8c842172015-10-29 14:40:29 -0700120 PowerManager.PARTIAL_WAKE_LOCK, TAG);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700121 }
122
123 /** Initialize the receivers and initiate the first NTP request */
Svetoslav Ganova0027152013-06-25 14:59:53 -0700124 public void systemRunning() {
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700125 registerForTelephonyIntents();
126 registerForAlarms();
127
Amith Yamasani450a16b2013-09-18 16:28:50 -0700128 HandlerThread thread = new HandlerThread(TAG);
129 thread.start();
130 mHandler = new MyHandler(thread.getLooper());
zhoulei45d1b262017-05-10 18:09:50 +0800131 mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
132 mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700133
134 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
135 mSettingsObserver.observe(mContext);
136 }
137
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700138 private void registerForTelephonyIntents() {
139 IntentFilter intentFilter = new IntentFilter();
140 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700141 mContext.registerReceiver(mNitzReceiver, intentFilter);
142 }
143
144 private void registerForAlarms() {
145 mContext.registerReceiver(
146 new BroadcastReceiver() {
147 @Override
148 public void onReceive(Context context, Intent intent) {
149 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
150 }
151 }, new IntentFilter(ACTION_POLL));
152 }
153
154 private void onPollNetworkTime(int event) {
zhoulei45d1b262017-05-10 18:09:50 +0800155 // If Automatic time is not set, don't bother. Similarly, if we don't
156 // have any default network, don't bother.
Jeff Sharkey9911a282018-02-14 22:29:11 -0700157 if (mDefaultNetwork == null) return;
Thierry Strudel8c842172015-10-29 14:40:29 -0700158 mWakeLock.acquire();
159 try {
160 onPollNetworkTimeUnderWakeLock(event);
161 } finally {
162 mWakeLock.release();
163 }
164 }
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700165
Thierry Strudel8c842172015-10-29 14:40:29 -0700166 private void onPollNetworkTimeUnderWakeLock(int event) {
Jeff Sharkey9911a282018-02-14 22:29:11 -0700167 // Force an NTP fix when outdated
168 if (mTime.getCacheAge() >= mPollingIntervalMs) {
169 if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
170 mTime.forceRefresh();
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700171 }
Jeff Sharkey104344e2011-07-10 14:20:41 -0700172
Jeff Sharkey9911a282018-02-14 22:29:11 -0700173 if (mTime.getCacheAge() < mPollingIntervalMs) {
174 // Obtained fresh fix; schedule next normal update
175 resetAlarm(mPollingIntervalMs);
176 if (isAutomaticTimeRequested()) {
177 updateSystemClock(event);
Jeff Sharkey104344e2011-07-10 14:20:41 -0700178 }
179
Jeff Sharkey9911a282018-02-14 22:29:11 -0700180 } else {
181 // No fresh fix; schedule retry
182 mTryAgainCounter++;
183 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
184 resetAlarm(mPollingIntervalShorterMs);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700185 } else {
Jeff Sharkey9911a282018-02-14 22:29:11 -0700186 // Try much later
187 mTryAgainCounter = 0;
188 resetAlarm(mPollingIntervalMs);
189 }
190 }
191 }
192
193 private long getNitzAge() {
194 if (mNitzTimeSetTime == NOT_SET) {
195 return Long.MAX_VALUE;
196 } else {
197 return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
198 }
199 }
200
201 /**
202 * Consider updating system clock based on current NTP fix, if requested by
203 * user, significant enough delta, and we don't have a recent NITZ.
204 */
205 private void updateSystemClock(int event) {
206 final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
207 if (!forceUpdate) {
208 if (getNitzAge() < mPollingIntervalMs) {
209 if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
210 return;
211 }
212
213 final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
214 if (skew < mTimeErrorThresholdMs) {
215 if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700216 return;
217 }
218 }
Jeff Sharkey9911a282018-02-14 22:29:11 -0700219
220 SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700221 }
222
223 /**
224 * Cancel old alarm and starts a new one for the specified interval.
225 *
226 * @param interval when to trigger the alarm, starting from now.
227 */
228 private void resetAlarm(long interval) {
229 mAlarmManager.cancel(mPendingPollIntent);
230 long now = SystemClock.elapsedRealtime();
231 long next = now + interval;
232 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
233 }
234
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700235 /**
236 * Checks if the user prefers to automatically set the time.
237 */
238 private boolean isAutomaticTimeRequested() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700239 return Settings.Global.getInt(
240 mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700241 }
242
243 /** Receiver for Nitz time events */
244 private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
245
246 @Override
247 public void onReceive(Context context, Intent intent) {
248 String action = intent.getAction();
Fyodor Kupolov32af07a2016-02-26 16:54:25 -0800249 if (DBG) Log.d(TAG, "Received " + action);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700250 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
251 mNitzTimeSetTime = SystemClock.elapsedRealtime();
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700252 }
253 }
254 };
255
256 /** Handler to do the network accesses on */
257 private class MyHandler extends Handler {
258
259 public MyHandler(Looper l) {
260 super(l);
261 }
262
263 @Override
264 public void handleMessage(Message msg) {
265 switch (msg.what) {
266 case EVENT_AUTO_TIME_CHANGED:
267 case EVENT_POLL_NETWORK_TIME:
Lorenzo Colittidf590532015-01-22 22:35:33 +0900268 case EVENT_NETWORK_CHANGED:
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700269 onPollNetworkTime(msg.what);
270 break;
271 }
272 }
273 }
274
zhoulei45d1b262017-05-10 18:09:50 +0800275 private class NetworkTimeUpdateCallback extends NetworkCallback {
276 @Override
277 public void onAvailable(Network network) {
278 Log.d(TAG, String.format("New default network %s; checking time.", network));
279 mDefaultNetwork = network;
280 // Running on mHandler so invoke directly.
281 onPollNetworkTime(EVENT_NETWORK_CHANGED);
282 }
283
284 @Override
285 public void onLost(Network network) {
286 if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
287 }
288 }
289
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700290 /** Observer to watch for changes to the AUTO_TIME setting */
291 private static class SettingsObserver extends ContentObserver {
292
293 private int mMsg;
294 private Handler mHandler;
295
296 SettingsObserver(Handler handler, int msg) {
297 super(handler);
298 mHandler = handler;
299 mMsg = msg;
300 }
301
302 void observe(Context context) {
303 ContentResolver resolver = context.getContentResolver();
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700304 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700305 false, this);
306 }
307
308 @Override
309 public void onChange(boolean selfChange) {
310 mHandler.obtainMessage(mMsg).sendToTarget();
311 }
312 }
Fyodor Kupolov32af07a2016-02-26 16:54:25 -0800313
314 @Override
315 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600316 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Fyodor Kupolov32af07a2016-02-26 16:54:25 -0800317 pw.print("PollingIntervalMs: ");
318 TimeUtils.formatDuration(mPollingIntervalMs, pw);
319 pw.print("\nPollingIntervalShorterMs: ");
320 TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
321 pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
322 pw.print("TimeErrorThresholdMs: ");
323 TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
324 pw.println("\nTryAgainCounter: " + mTryAgainCounter);
Jeff Sharkey9911a282018-02-14 22:29:11 -0700325 pw.println("NTP cache age: " + mTime.getCacheAge());
326 pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
Fyodor Kupolov32af07a2016-02-26 16:54:25 -0800327 pw.println();
328 }
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700329}