• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package com.android.server;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.database.ContentObserver;
27 import android.net.ConnectivityManager;
28 import android.net.NetworkInfo;
29 import android.os.Handler;
30 import android.os.HandlerThread;
31 import android.os.Looper;
32 import android.os.Message;
33 import android.os.SystemClock;
34 import android.provider.Settings;
35 import android.util.Log;
36 import android.util.NtpTrustedTime;
37 import android.util.TrustedTime;
38 
39 import com.android.internal.telephony.TelephonyIntents;
40 
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  */
51 public 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;
58     private static final int EVENT_NETWORK_CONNECTED = 3;
59 
60     /** Normal polling frequency */
61     private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs
62     /** Try-again polling interval, in case the network request failed */
63     private static final long POLLING_INTERVAL_SHORTER_MS = 60 * 1000L; // 60 seconds
64     /** Number of times to try again */
65     private static final int TRY_AGAIN_TIMES_MAX = 3;
66     /** If the time difference is greater than this threshold, then update the time. */
67     private static final int TIME_ERROR_THRESHOLD_MS = 5 * 1000;
68 
69     private static final String ACTION_POLL =
70             "com.android.server.NetworkTimeUpdateService.action.POLL";
71     private static int POLL_REQUEST = 0;
72 
73     private static final long NOT_SET = -1;
74     private long mNitzTimeSetTime = NOT_SET;
75     // TODO: Have a way to look up the timezone we are in
76     private long mNitzZoneSetTime = NOT_SET;
77 
78     private Context mContext;
79     private TrustedTime mTime;
80 
81     // NTP lookup is done on this thread and handler
82     private Handler mHandler;
83     private HandlerThread mThread;
84     private AlarmManager mAlarmManager;
85     private PendingIntent mPendingPollIntent;
86     private SettingsObserver mSettingsObserver;
87     // The last time that we successfully fetched the NTP time.
88     private long mLastNtpFetchTime = NOT_SET;
89     // Keeps track of how many quick attempts were made to fetch NTP time.
90     // During bootup, the network may not have been up yet, or it's taking time for the
91     // connection to happen.
92     private int mTryAgainCounter;
93 
NetworkTimeUpdateService(Context context)94     public NetworkTimeUpdateService(Context context) {
95         mContext = context;
96         mTime = NtpTrustedTime.getInstance(context);
97         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
98         Intent pollIntent = new Intent(ACTION_POLL, null);
99         mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
100     }
101 
102     /** Initialize the receivers and initiate the first NTP request */
systemReady()103     public void systemReady() {
104         registerForTelephonyIntents();
105         registerForAlarms();
106         registerForConnectivityIntents();
107 
108         mThread = new HandlerThread(TAG);
109         mThread.start();
110         mHandler = new MyHandler(mThread.getLooper());
111         // Check the network time on the new thread
112         mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
113 
114         mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
115         mSettingsObserver.observe(mContext);
116     }
117 
registerForTelephonyIntents()118     private void registerForTelephonyIntents() {
119         IntentFilter intentFilter = new IntentFilter();
120         intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
121         intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
122         mContext.registerReceiver(mNitzReceiver, intentFilter);
123     }
124 
registerForAlarms()125     private void registerForAlarms() {
126         mContext.registerReceiver(
127             new BroadcastReceiver() {
128                 @Override
129                 public void onReceive(Context context, Intent intent) {
130                     mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
131                 }
132             }, new IntentFilter(ACTION_POLL));
133     }
134 
registerForConnectivityIntents()135     private void registerForConnectivityIntents() {
136         IntentFilter intentFilter = new IntentFilter();
137         intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
138         mContext.registerReceiver(mConnectivityReceiver, intentFilter);
139     }
140 
onPollNetworkTime(int event)141     private void onPollNetworkTime(int event) {
142         // If Automatic time is not set, don't bother.
143         if (!isAutomaticTimeRequested()) return;
144 
145         final long refTime = SystemClock.elapsedRealtime();
146         // If NITZ time was received less than POLLING_INTERVAL_MS time ago,
147         // no need to sync to NTP.
148         if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < POLLING_INTERVAL_MS) {
149             resetAlarm(POLLING_INTERVAL_MS);
150             return;
151         }
152         final long currentTime = System.currentTimeMillis();
153         if (DBG) Log.d(TAG, "System time = " + currentTime);
154         // Get the NTP time
155         if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + POLLING_INTERVAL_MS
156                 || event == EVENT_AUTO_TIME_CHANGED) {
157             if (DBG) Log.d(TAG, "Before Ntp fetch");
158 
159             // force refresh NTP cache when outdated
160             if (mTime.getCacheAge() >= POLLING_INTERVAL_MS) {
161                 mTime.forceRefresh();
162             }
163 
164             // only update when NTP time is fresh
165             if (mTime.getCacheAge() < POLLING_INTERVAL_MS) {
166                 final long ntp = mTime.currentTimeMillis();
167                 mTryAgainCounter = 0;
168                 // If the clock is more than N seconds off or this is the first time it's been
169                 // fetched since boot, set the current time.
170                 if (Math.abs(ntp - currentTime) > TIME_ERROR_THRESHOLD_MS
171                         || mLastNtpFetchTime == NOT_SET) {
172                     // Set the system time
173                     if (DBG && mLastNtpFetchTime == NOT_SET
174                             && Math.abs(ntp - currentTime) <= TIME_ERROR_THRESHOLD_MS) {
175                         Log.d(TAG, "For initial setup, rtc = " + currentTime);
176                     }
177                     if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
178                     // Make sure we don't overflow, since it's going to be converted to an int
179                     if (ntp / 1000 < Integer.MAX_VALUE) {
180                         SystemClock.setCurrentTimeMillis(ntp);
181                     }
182                 } else {
183                     if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
184                 }
185                 mLastNtpFetchTime = SystemClock.elapsedRealtime();
186             } else {
187                 // Try again shortly
188                 mTryAgainCounter++;
189                 if (mTryAgainCounter <= TRY_AGAIN_TIMES_MAX) {
190                     resetAlarm(POLLING_INTERVAL_SHORTER_MS);
191                 } else {
192                     // Try much later
193                     mTryAgainCounter = 0;
194                     resetAlarm(POLLING_INTERVAL_MS);
195                 }
196                 return;
197             }
198         }
199         resetAlarm(POLLING_INTERVAL_MS);
200     }
201 
202     /**
203      * Cancel old alarm and starts a new one for the specified interval.
204      *
205      * @param interval when to trigger the alarm, starting from now.
206      */
resetAlarm(long interval)207     private void resetAlarm(long interval) {
208         mAlarmManager.cancel(mPendingPollIntent);
209         long now = SystemClock.elapsedRealtime();
210         long next = now + interval;
211         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
212     }
213 
214     /**
215      * Checks if the user prefers to automatically set the time.
216      */
isAutomaticTimeRequested()217     private boolean isAutomaticTimeRequested() {
218         return Settings.System.getInt(mContext.getContentResolver(), Settings.System.AUTO_TIME, 0)
219                 != 0;
220     }
221 
222     /** Receiver for Nitz time events */
223     private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
224 
225         @Override
226         public void onReceive(Context context, Intent intent) {
227             String action = intent.getAction();
228             if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
229                 mNitzTimeSetTime = SystemClock.elapsedRealtime();
230             } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
231                 mNitzZoneSetTime = SystemClock.elapsedRealtime();
232             }
233         }
234     };
235 
236     /** Receiver for ConnectivityManager events */
237     private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
238 
239         @Override
240         public void onReceive(Context context, Intent intent) {
241             String action = intent.getAction();
242             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
243                 // There is connectivity
244                 final ConnectivityManager connManager = (ConnectivityManager) context
245                         .getSystemService(Context.CONNECTIVITY_SERVICE);
246                 final NetworkInfo netInfo = connManager.getActiveNetworkInfo();
247                 if (netInfo != null) {
248                     // Verify that it's a WIFI connection
249                     if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
250                             (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
251                                 netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
252                         mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
253                     }
254                 }
255             }
256         }
257     };
258 
259     /** Handler to do the network accesses on */
260     private class MyHandler extends Handler {
261 
MyHandler(Looper l)262         public MyHandler(Looper l) {
263             super(l);
264         }
265 
266         @Override
handleMessage(Message msg)267         public void handleMessage(Message msg) {
268             switch (msg.what) {
269                 case EVENT_AUTO_TIME_CHANGED:
270                 case EVENT_POLL_NETWORK_TIME:
271                 case EVENT_NETWORK_CONNECTED:
272                     onPollNetworkTime(msg.what);
273                     break;
274             }
275         }
276     }
277 
278     /** Observer to watch for changes to the AUTO_TIME setting */
279     private static class SettingsObserver extends ContentObserver {
280 
281         private int mMsg;
282         private Handler mHandler;
283 
SettingsObserver(Handler handler, int msg)284         SettingsObserver(Handler handler, int msg) {
285             super(handler);
286             mHandler = handler;
287             mMsg = msg;
288         }
289 
observe(Context context)290         void observe(Context context) {
291             ContentResolver resolver = context.getContentResolver();
292             resolver.registerContentObserver(Settings.System.getUriFor(Settings.System.AUTO_TIME),
293                     false, this);
294         }
295 
296         @Override
onChange(boolean selfChange)297         public void onChange(boolean selfChange) {
298             mHandler.obtainMessage(mMsg).sendToTarget();
299         }
300     }
301 }
302