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 17package com.android.server; 18 19import 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; 27import android.net.ConnectivityManager; 28import android.os.Handler; 29import android.os.HandlerThread; 30import android.os.Looper; 31import android.os.Message; 32import android.os.SystemClock; 33import android.os.PowerManager; 34import android.provider.Settings; 35import android.util.Log; 36import android.util.NtpTrustedTime; 37import android.util.TrustedTime; 38 39import 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 */ 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; 58 private static final int EVENT_NETWORK_CHANGED = 3; 59 60 private static final String ACTION_POLL = 61 "com.android.server.NetworkTimeUpdateService.action.POLL"; 62 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; 70 private TrustedTime mTime; 71 72 // NTP lookup is done on this thread and handler 73 private Handler mHandler; 74 private AlarmManager mAlarmManager; 75 private PendingIntent mPendingPollIntent; 76 private SettingsObserver mSettingsObserver; 77 // The last time that we successfully fetched the NTP time. 78 private long mLastNtpFetchTime = NOT_SET; 79 private final PowerManager.WakeLock mWakeLock; 80 81 // Normal polling frequency 82 private final long mPollingIntervalMs; 83 // Try-again polling interval, in case the network request failed 84 private final long mPollingIntervalShorterMs; 85 // Number of times to try again 86 private final int mTryAgainTimesMax; 87 // If the time difference is greater than this threshold, then update the time. 88 private final int mTimeErrorThresholdMs; 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 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 mPollingIntervalMs = mContext.getResources().getInteger( 102 com.android.internal.R.integer.config_ntpPollingInterval); 103 mPollingIntervalShorterMs = mContext.getResources().getInteger( 104 com.android.internal.R.integer.config_ntpPollingIntervalShorter); 105 mTryAgainTimesMax = mContext.getResources().getInteger( 106 com.android.internal.R.integer.config_ntpRetry); 107 mTimeErrorThresholdMs = mContext.getResources().getInteger( 108 com.android.internal.R.integer.config_ntpThreshold); 109 110 mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( 111 PowerManager.PARTIAL_WAKE_LOCK, TAG); 112 } 113 114 /** Initialize the receivers and initiate the first NTP request */ 115 public void systemRunning() { 116 registerForTelephonyIntents(); 117 registerForAlarms(); 118 registerForConnectivityIntents(); 119 120 HandlerThread thread = new HandlerThread(TAG); 121 thread.start(); 122 mHandler = new MyHandler(thread.getLooper()); 123 // Check the network time on the new thread 124 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); 125 126 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED); 127 mSettingsObserver.observe(mContext); 128 } 129 130 private void registerForTelephonyIntents() { 131 IntentFilter intentFilter = new IntentFilter(); 132 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME); 133 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); 134 mContext.registerReceiver(mNitzReceiver, intentFilter); 135 } 136 137 private void registerForAlarms() { 138 mContext.registerReceiver( 139 new BroadcastReceiver() { 140 @Override 141 public void onReceive(Context context, Intent intent) { 142 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); 143 } 144 }, new IntentFilter(ACTION_POLL)); 145 } 146 147 private void registerForConnectivityIntents() { 148 IntentFilter intentFilter = new IntentFilter(); 149 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 150 mContext.registerReceiver(mConnectivityReceiver, intentFilter); 151 } 152 153 private void onPollNetworkTime(int event) { 154 // If Automatic time is not set, don't bother. 155 if (!isAutomaticTimeRequested()) return; 156 mWakeLock.acquire(); 157 try { 158 onPollNetworkTimeUnderWakeLock(event); 159 } finally { 160 mWakeLock.release(); 161 } 162 } 163 164 private void onPollNetworkTimeUnderWakeLock(int event) { 165 final long refTime = SystemClock.elapsedRealtime(); 166 // If NITZ time was received less than mPollingIntervalMs time ago, 167 // no need to sync to NTP. 168 if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) { 169 resetAlarm(mPollingIntervalMs); 170 return; 171 } 172 final long currentTime = System.currentTimeMillis(); 173 if (DBG) Log.d(TAG, "System time = " + currentTime); 174 // Get the NTP time 175 if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs 176 || event == EVENT_AUTO_TIME_CHANGED) { 177 if (DBG) Log.d(TAG, "Before Ntp fetch"); 178 179 // force refresh NTP cache when outdated 180 if (mTime.getCacheAge() >= mPollingIntervalMs) { 181 mTime.forceRefresh(); 182 } 183 184 // only update when NTP time is fresh 185 if (mTime.getCacheAge() < mPollingIntervalMs) { 186 final long ntp = mTime.currentTimeMillis(); 187 mTryAgainCounter = 0; 188 // If the clock is more than N seconds off or this is the first time it's been 189 // fetched since boot, set the current time. 190 if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs 191 || mLastNtpFetchTime == NOT_SET) { 192 // Set the system time 193 if (DBG && mLastNtpFetchTime == NOT_SET 194 && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) { 195 Log.d(TAG, "For initial setup, rtc = " + currentTime); 196 } 197 if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp); 198 // Make sure we don't overflow, since it's going to be converted to an int 199 if (ntp / 1000 < Integer.MAX_VALUE) { 200 SystemClock.setCurrentTimeMillis(ntp); 201 } 202 } else { 203 if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp); 204 } 205 mLastNtpFetchTime = SystemClock.elapsedRealtime(); 206 } else { 207 // Try again shortly 208 mTryAgainCounter++; 209 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { 210 resetAlarm(mPollingIntervalShorterMs); 211 } else { 212 // Try much later 213 mTryAgainCounter = 0; 214 resetAlarm(mPollingIntervalMs); 215 } 216 return; 217 } 218 } 219 resetAlarm(mPollingIntervalMs); 220 } 221 222 /** 223 * Cancel old alarm and starts a new one for the specified interval. 224 * 225 * @param interval when to trigger the alarm, starting from now. 226 */ 227 private void resetAlarm(long interval) { 228 mAlarmManager.cancel(mPendingPollIntent); 229 long now = SystemClock.elapsedRealtime(); 230 long next = now + interval; 231 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); 232 } 233 234 /** 235 * Checks if the user prefers to automatically set the time. 236 */ 237 private boolean isAutomaticTimeRequested() { 238 return Settings.Global.getInt( 239 mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0; 240 } 241 242 /** Receiver for Nitz time events */ 243 private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() { 244 245 @Override 246 public void onReceive(Context context, Intent intent) { 247 String action = intent.getAction(); 248 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) { 249 mNitzTimeSetTime = SystemClock.elapsedRealtime(); 250 } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) { 251 mNitzZoneSetTime = SystemClock.elapsedRealtime(); 252 } 253 } 254 }; 255 256 /** Receiver for ConnectivityManager events */ 257 private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() { 258 259 @Override 260 public void onReceive(Context context, Intent intent) { 261 String action = intent.getAction(); 262 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { 263 // Don't bother checking if we have connectivity, NtpTrustedTime does that for us. 264 mHandler.obtainMessage(EVENT_NETWORK_CHANGED).sendToTarget(); 265 } 266 } 267 }; 268 269 /** Handler to do the network accesses on */ 270 private class MyHandler extends Handler { 271 272 public MyHandler(Looper l) { 273 super(l); 274 } 275 276 @Override 277 public void handleMessage(Message msg) { 278 switch (msg.what) { 279 case EVENT_AUTO_TIME_CHANGED: 280 case EVENT_POLL_NETWORK_TIME: 281 case EVENT_NETWORK_CHANGED: 282 onPollNetworkTime(msg.what); 283 break; 284 } 285 } 286 } 287 288 /** Observer to watch for changes to the AUTO_TIME setting */ 289 private static class SettingsObserver extends ContentObserver { 290 291 private int mMsg; 292 private Handler mHandler; 293 294 SettingsObserver(Handler handler, int msg) { 295 super(handler); 296 mHandler = handler; 297 mMsg = msg; 298 } 299 300 void observe(Context context) { 301 ContentResolver resolver = context.getContentResolver(); 302 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), 303 false, this); 304 } 305 306 @Override 307 public void onChange(boolean selfChange) { 308 mHandler.obtainMessage(mMsg).sendToTarget(); 309 } 310 } 311} 312