blob: cbddf6797797e54b293f645e9e9e590900ca60bc [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;
28import android.net.NetworkInfo;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070029import android.os.Handler;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070030import android.os.Looper;
31import android.os.Message;
32import android.os.SystemClock;
33import android.provider.Settings;
34import android.util.Log;
Jeff Sharkey104344e2011-07-10 14:20:41 -070035import android.util.NtpTrustedTime;
36import android.util.TrustedTime;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070037
Dianne Hackborn8d044e82013-04-30 17:24:15 -070038import com.android.internal.os.BackgroundThread;
Jeff Sharkey104344e2011-07-10 14:20:41 -070039import com.android.internal.telephony.TelephonyIntents;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070040
41/**
42 * Monitors the network time and updates the system time if it is out of sync
43 * and there hasn't been any NITZ update from the carrier recently.
44 * If looking up the network time fails for some reason, it tries a few times with a short
45 * interval and then resets to checking on longer intervals.
46 * <p>
47 * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
48 * available.
49 * </p>
50 */
51public class NetworkTimeUpdateService {
52
53 private static final String TAG = "NetworkTimeUpdateService";
54 private static final boolean DBG = false;
55
56 private static final int EVENT_AUTO_TIME_CHANGED = 1;
57 private static final int EVENT_POLL_NETWORK_TIME = 2;
Mike Lockwooda5abdb92011-11-09 10:49:29 -080058 private static final int EVENT_NETWORK_CONNECTED = 3;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070059
Amith Yamasani6734b9f2010-09-13 16:24:08 -070060 private static final String ACTION_POLL =
61 "com.android.server.NetworkTimeUpdateService.action.POLL";
Amith Yamasani6734b9f2010-09-13 16:24:08 -070062 private static int POLL_REQUEST = 0;
63
64 private static final long NOT_SET = -1;
65 private long mNitzTimeSetTime = NOT_SET;
66 // TODO: Have a way to look up the timezone we are in
67 private long mNitzZoneSetTime = NOT_SET;
68
69 private Context mContext;
Jeff Sharkey104344e2011-07-10 14:20:41 -070070 private TrustedTime mTime;
71
Amith Yamasani6734b9f2010-09-13 16:24:08 -070072 // NTP lookup is done on this thread and handler
73 private Handler mHandler;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070074 private AlarmManager mAlarmManager;
75 private PendingIntent mPendingPollIntent;
76 private SettingsObserver mSettingsObserver;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070077 // The last time that we successfully fetched the NTP time.
78 private long mLastNtpFetchTime = NOT_SET;
Jaewan Kimc3560b82012-11-20 23:58:07 +090079
80 // Normal polling frequency
81 private final long mPollingIntervalMs;
82 // Try-again polling interval, in case the network request failed
83 private final long mPollingIntervalShorterMs;
84 // Number of times to try again
85 private final int mTryAgainTimesMax;
86 // If the time difference is greater than this threshold, then update the time.
87 private final int mTimeErrorThresholdMs;
Amith Yamasani6734b9f2010-09-13 16:24:08 -070088 // Keeps track of how many quick attempts were made to fetch NTP time.
89 // During bootup, the network may not have been up yet, or it's taking time for the
90 // connection to happen.
91 private int mTryAgainCounter;
92
93 public NetworkTimeUpdateService(Context context) {
94 mContext = context;
Jeff Sharkey104344e2011-07-10 14:20:41 -070095 mTime = NtpTrustedTime.getInstance(context);
Amith Yamasani6734b9f2010-09-13 16:24:08 -070096 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
97 Intent pollIntent = new Intent(ACTION_POLL, null);
98 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
Jaewan Kimc3560b82012-11-20 23:58:07 +090099
100 mPollingIntervalMs = mContext.getResources().getInteger(
101 com.android.internal.R.integer.config_ntpPollingInterval);
102 mPollingIntervalShorterMs = mContext.getResources().getInteger(
103 com.android.internal.R.integer.config_ntpPollingIntervalShorter);
104 mTryAgainTimesMax = mContext.getResources().getInteger(
105 com.android.internal.R.integer.config_ntpRetry);
106 mTimeErrorThresholdMs = mContext.getResources().getInteger(
107 com.android.internal.R.integer.config_ntpThreshold);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700108 }
109
110 /** Initialize the receivers and initiate the first NTP request */
Svetoslav Ganova0027152013-06-25 14:59:53 -0700111 public void systemRunning() {
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700112 registerForTelephonyIntents();
113 registerForAlarms();
Amith Yamasani8d394fa2011-03-01 12:41:04 -0800114 registerForConnectivityIntents();
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700115
Dianne Hackborn8d044e82013-04-30 17:24:15 -0700116 mHandler = new MyHandler(BackgroundThread.get().getLooper());
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700117 // Check the network time on the new thread
118 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
119
120 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
121 mSettingsObserver.observe(mContext);
122 }
123
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700124 private void registerForTelephonyIntents() {
125 IntentFilter intentFilter = new IntentFilter();
126 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
127 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
128 mContext.registerReceiver(mNitzReceiver, intentFilter);
129 }
130
131 private void registerForAlarms() {
132 mContext.registerReceiver(
133 new BroadcastReceiver() {
134 @Override
135 public void onReceive(Context context, Intent intent) {
136 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
137 }
138 }, new IntentFilter(ACTION_POLL));
139 }
140
Amith Yamasani8d394fa2011-03-01 12:41:04 -0800141 private void registerForConnectivityIntents() {
142 IntentFilter intentFilter = new IntentFilter();
143 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
144 mContext.registerReceiver(mConnectivityReceiver, intentFilter);
145 }
146
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700147 private void onPollNetworkTime(int event) {
148 // If Automatic time is not set, don't bother.
149 if (!isAutomaticTimeRequested()) return;
150
151 final long refTime = SystemClock.elapsedRealtime();
Jaewan Kimc3560b82012-11-20 23:58:07 +0900152 // If NITZ time was received less than mPollingIntervalMs time ago,
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700153 // no need to sync to NTP.
Jaewan Kimc3560b82012-11-20 23:58:07 +0900154 if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
155 resetAlarm(mPollingIntervalMs);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700156 return;
157 }
158 final long currentTime = System.currentTimeMillis();
159 if (DBG) Log.d(TAG, "System time = " + currentTime);
160 // Get the NTP time
Jaewan Kimc3560b82012-11-20 23:58:07 +0900161 if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700162 || event == EVENT_AUTO_TIME_CHANGED) {
163 if (DBG) Log.d(TAG, "Before Ntp fetch");
Jeff Sharkey104344e2011-07-10 14:20:41 -0700164
165 // force refresh NTP cache when outdated
Jaewan Kimc3560b82012-11-20 23:58:07 +0900166 if (mTime.getCacheAge() >= mPollingIntervalMs) {
Jeff Sharkey104344e2011-07-10 14:20:41 -0700167 mTime.forceRefresh();
168 }
169
170 // only update when NTP time is fresh
Jaewan Kimc3560b82012-11-20 23:58:07 +0900171 if (mTime.getCacheAge() < mPollingIntervalMs) {
Jeff Sharkey104344e2011-07-10 14:20:41 -0700172 final long ntp = mTime.currentTimeMillis();
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700173 mTryAgainCounter = 0;
Amith Yamasani708d5d42012-05-02 11:50:31 -0700174 // If the clock is more than N seconds off or this is the first time it's been
175 // fetched since boot, set the current time.
Jaewan Kimc3560b82012-11-20 23:58:07 +0900176 if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
Amith Yamasani708d5d42012-05-02 11:50:31 -0700177 || mLastNtpFetchTime == NOT_SET) {
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700178 // Set the system time
Amith Yamasani708d5d42012-05-02 11:50:31 -0700179 if (DBG && mLastNtpFetchTime == NOT_SET
Jaewan Kimc3560b82012-11-20 23:58:07 +0900180 && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
Amith Yamasani708d5d42012-05-02 11:50:31 -0700181 Log.d(TAG, "For initial setup, rtc = " + currentTime);
182 }
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700183 if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
184 // Make sure we don't overflow, since it's going to be converted to an int
185 if (ntp / 1000 < Integer.MAX_VALUE) {
186 SystemClock.setCurrentTimeMillis(ntp);
187 }
188 } else {
189 if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
190 }
Amith Yamasani708d5d42012-05-02 11:50:31 -0700191 mLastNtpFetchTime = SystemClock.elapsedRealtime();
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700192 } else {
193 // Try again shortly
194 mTryAgainCounter++;
Jaewan Kimc3560b82012-11-20 23:58:07 +0900195 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
196 resetAlarm(mPollingIntervalShorterMs);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700197 } else {
198 // Try much later
199 mTryAgainCounter = 0;
Jaewan Kimc3560b82012-11-20 23:58:07 +0900200 resetAlarm(mPollingIntervalMs);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700201 }
202 return;
203 }
204 }
Jaewan Kimc3560b82012-11-20 23:58:07 +0900205 resetAlarm(mPollingIntervalMs);
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700206 }
207
208 /**
209 * Cancel old alarm and starts a new one for the specified interval.
210 *
211 * @param interval when to trigger the alarm, starting from now.
212 */
213 private void resetAlarm(long interval) {
214 mAlarmManager.cancel(mPendingPollIntent);
215 long now = SystemClock.elapsedRealtime();
216 long next = now + interval;
217 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
218 }
219
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700220 /**
221 * Checks if the user prefers to automatically set the time.
222 */
223 private boolean isAutomaticTimeRequested() {
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700224 return Settings.Global.getInt(
225 mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700226 }
227
228 /** Receiver for Nitz time events */
229 private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
230
231 @Override
232 public void onReceive(Context context, Intent intent) {
233 String action = intent.getAction();
234 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
235 mNitzTimeSetTime = SystemClock.elapsedRealtime();
236 } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
237 mNitzZoneSetTime = SystemClock.elapsedRealtime();
238 }
239 }
240 };
241
Amith Yamasani8d394fa2011-03-01 12:41:04 -0800242 /** Receiver for ConnectivityManager events */
243 private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
244
245 @Override
246 public void onReceive(Context context, Intent intent) {
247 String action = intent.getAction();
248 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
249 // There is connectivity
Jeff Sharkey5e613312012-01-30 11:16:20 -0800250 final ConnectivityManager connManager = (ConnectivityManager) context
251 .getSystemService(Context.CONNECTIVITY_SERVICE);
252 final NetworkInfo netInfo = connManager.getActiveNetworkInfo();
Amith Yamasani8d394fa2011-03-01 12:41:04 -0800253 if (netInfo != null) {
254 // Verify that it's a WIFI connection
255 if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
Mike Lockwooda5abdb92011-11-09 10:49:29 -0800256 (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
257 netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
258 mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
Amith Yamasani8d394fa2011-03-01 12:41:04 -0800259 }
260 }
261 }
262 }
263 };
264
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700265 /** Handler to do the network accesses on */
266 private class MyHandler extends Handler {
267
268 public MyHandler(Looper l) {
269 super(l);
270 }
271
272 @Override
273 public void handleMessage(Message msg) {
274 switch (msg.what) {
275 case EVENT_AUTO_TIME_CHANGED:
276 case EVENT_POLL_NETWORK_TIME:
Mike Lockwooda5abdb92011-11-09 10:49:29 -0800277 case EVENT_NETWORK_CONNECTED:
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700278 onPollNetworkTime(msg.what);
279 break;
280 }
281 }
282 }
283
284 /** Observer to watch for changes to the AUTO_TIME setting */
285 private static class SettingsObserver extends ContentObserver {
286
287 private int mMsg;
288 private Handler mHandler;
289
290 SettingsObserver(Handler handler, int msg) {
291 super(handler);
292 mHandler = handler;
293 mMsg = msg;
294 }
295
296 void observe(Context context) {
297 ContentResolver resolver = context.getContentResolver();
Jeff Brownbf6f6f92012-09-25 15:03:20 -0700298 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
Amith Yamasani6734b9f2010-09-13 16:24:08 -0700299 false, this);
300 }
301
302 @Override
303 public void onChange(boolean selfChange) {
304 mHandler.obtainMessage(mMsg).sendToTarget();
305 }
306 }
307}