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.content.pm.PackageManager; 27import android.database.ContentObserver; 28import android.net.ConnectivityManager; 29import android.os.Binder; 30import android.os.Handler; 31import android.os.HandlerThread; 32import android.os.Looper; 33import android.os.Message; 34import android.os.SystemClock; 35import android.os.PowerManager; 36import android.provider.Settings; 37import android.util.Log; 38import android.util.NtpTrustedTime; 39import android.util.TimeUtils; 40import android.util.TrustedTime; 41 42import com.android.internal.telephony.TelephonyIntents; 43 44import java.io.FileDescriptor; 45import java.io.PrintWriter; 46 47/** 48 * Monitors the network time and updates the system time if it is out of sync 49 * and there hasn't been any NITZ update from the carrier recently. 50 * If looking up the network time fails for some reason, it tries a few times with a short 51 * interval and then resets to checking on longer intervals. 52 * <p> 53 * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't 54 * available. 55 * </p> 56 */ 57public class NetworkTimeUpdateService extends Binder { 58 59 private static final String TAG = "NetworkTimeUpdateService"; 60 private static final boolean DBG = false; 61 62 private static final int EVENT_AUTO_TIME_CHANGED = 1; 63 private static final int EVENT_POLL_NETWORK_TIME = 2; 64 private static final int EVENT_NETWORK_CHANGED = 3; 65 66 private static final String ACTION_POLL = 67 "com.android.server.NetworkTimeUpdateService.action.POLL"; 68 69 private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000; 70 private static int POLL_REQUEST = 0; 71 72 private static final long NOT_SET = -1; 73 private long mNitzTimeSetTime = NOT_SET; 74 // TODO: Have a way to look up the timezone we are in 75 private long mNitzZoneSetTime = NOT_SET; 76 77 private Context mContext; 78 private TrustedTime mTime; 79 80 // NTP lookup is done on this thread and handler 81 private Handler mHandler; 82 private AlarmManager mAlarmManager; 83 private PendingIntent mPendingPollIntent; 84 private SettingsObserver mSettingsObserver; 85 // The last time that we successfully fetched the NTP time. 86 private long mLastNtpFetchTime = NOT_SET; 87 private final PowerManager.WakeLock mWakeLock; 88 89 // Normal polling frequency 90 private final long mPollingIntervalMs; 91 // Try-again polling interval, in case the network request failed 92 private final long mPollingIntervalShorterMs; 93 // Number of times to try again 94 private final int mTryAgainTimesMax; 95 // If the time difference is greater than this threshold, then update the time. 96 private final int mTimeErrorThresholdMs; 97 // Keeps track of how many quick attempts were made to fetch NTP time. 98 // During bootup, the network may not have been up yet, or it's taking time for the 99 // connection to happen. 100 private int mTryAgainCounter; 101 102 public NetworkTimeUpdateService(Context context) { 103 mContext = context; 104 mTime = NtpTrustedTime.getInstance(context); 105 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 106 Intent pollIntent = new Intent(ACTION_POLL, null); 107 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); 108 109 mPollingIntervalMs = mContext.getResources().getInteger( 110 com.android.internal.R.integer.config_ntpPollingInterval); 111 mPollingIntervalShorterMs = mContext.getResources().getInteger( 112 com.android.internal.R.integer.config_ntpPollingIntervalShorter); 113 mTryAgainTimesMax = mContext.getResources().getInteger( 114 com.android.internal.R.integer.config_ntpRetry); 115 mTimeErrorThresholdMs = mContext.getResources().getInteger( 116 com.android.internal.R.integer.config_ntpThreshold); 117 118 mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock( 119 PowerManager.PARTIAL_WAKE_LOCK, TAG); 120 } 121 122 /** Initialize the receivers and initiate the first NTP request */ 123 public void systemRunning() { 124 registerForTelephonyIntents(); 125 registerForAlarms(); 126 registerForConnectivityIntents(); 127 128 HandlerThread thread = new HandlerThread(TAG); 129 thread.start(); 130 mHandler = new MyHandler(thread.getLooper()); 131 // Check the network time on the new thread 132 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); 133 134 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED); 135 mSettingsObserver.observe(mContext); 136 } 137 138 private void registerForTelephonyIntents() { 139 IntentFilter intentFilter = new IntentFilter(); 140 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME); 141 intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); 142 mContext.registerReceiver(mNitzReceiver, intentFilter); 143 } 144 145 private void registerForAlarms() { 146 mContext.registerReceiver( 147 new BroadcastReceiver() { 148 @Override 149 public void onReceive(Context context, Intent intent) { 150 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); 151 } 152 }, new IntentFilter(ACTION_POLL)); 153 } 154 155 private void registerForConnectivityIntents() { 156 IntentFilter intentFilter = new IntentFilter(); 157 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 158 mContext.registerReceiver(mConnectivityReceiver, intentFilter); 159 } 160 161 private void onPollNetworkTime(int event) { 162 // If Automatic time is not set, don't bother. 163 if (!isAutomaticTimeRequested()) return; 164 mWakeLock.acquire(); 165 try { 166 onPollNetworkTimeUnderWakeLock(event); 167 } finally { 168 mWakeLock.release(); 169 } 170 } 171 172 private void onPollNetworkTimeUnderWakeLock(int event) { 173 final long refTime = SystemClock.elapsedRealtime(); 174 // If NITZ time was received less than mPollingIntervalMs time ago, 175 // no need to sync to NTP. 176 if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) { 177 resetAlarm(mPollingIntervalMs); 178 return; 179 } 180 final long currentTime = System.currentTimeMillis(); 181 if (DBG) Log.d(TAG, "System time = " + currentTime); 182 // Get the NTP time 183 if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs 184 || event == EVENT_AUTO_TIME_CHANGED) { 185 if (DBG) Log.d(TAG, "Before Ntp fetch"); 186 187 // force refresh NTP cache when outdated 188 if (mTime.getCacheAge() >= mPollingIntervalMs) { 189 mTime.forceRefresh(); 190 } 191 192 // only update when NTP time is fresh 193 if (mTime.getCacheAge() < mPollingIntervalMs) { 194 final long ntp = mTime.currentTimeMillis(); 195 mTryAgainCounter = 0; 196 // If the clock is more than N seconds off or this is the first time it's been 197 // fetched since boot, set the current time. 198 if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs 199 || mLastNtpFetchTime == NOT_SET) { 200 // Set the system time 201 if (DBG && mLastNtpFetchTime == NOT_SET 202 && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) { 203 Log.d(TAG, "For initial setup, rtc = " + currentTime); 204 } 205 if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp); 206 // Make sure we don't overflow, since it's going to be converted to an int 207 if (ntp / 1000 < Integer.MAX_VALUE) { 208 SystemClock.setCurrentTimeMillis(ntp); 209 } 210 } else { 211 if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp); 212 } 213 mLastNtpFetchTime = SystemClock.elapsedRealtime(); 214 } else { 215 // Try again shortly 216 mTryAgainCounter++; 217 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { 218 resetAlarm(mPollingIntervalShorterMs); 219 } else { 220 // Try much later 221 mTryAgainCounter = 0; 222 resetAlarm(mPollingIntervalMs); 223 } 224 return; 225 } 226 } 227 resetAlarm(mPollingIntervalMs); 228 } 229 230 /** 231 * Cancel old alarm and starts a new one for the specified interval. 232 * 233 * @param interval when to trigger the alarm, starting from now. 234 */ 235 private void resetAlarm(long interval) { 236 mAlarmManager.cancel(mPendingPollIntent); 237 long now = SystemClock.elapsedRealtime(); 238 long next = now + interval; 239 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); 240 } 241 242 /** 243 * Checks if the user prefers to automatically set the time. 244 */ 245 private boolean isAutomaticTimeRequested() { 246 return Settings.Global.getInt( 247 mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0; 248 } 249 250 /** Receiver for Nitz time events */ 251 private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() { 252 253 @Override 254 public void onReceive(Context context, Intent intent) { 255 String action = intent.getAction(); 256 if (DBG) Log.d(TAG, "Received " + action); 257 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) { 258 mNitzTimeSetTime = SystemClock.elapsedRealtime(); 259 } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) { 260 mNitzZoneSetTime = SystemClock.elapsedRealtime(); 261 } 262 } 263 }; 264 265 /** Receiver for ConnectivityManager events */ 266 private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() { 267 268 @Override 269 public void onReceive(Context context, Intent intent) { 270 String action = intent.getAction(); 271 if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) { 272 if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION "); 273 // Don't bother checking if we have connectivity, NtpTrustedTime does that for us. 274 Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED); 275 // Send with a short delay to make sure the network is ready for use 276 mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS); 277 } 278 } 279 }; 280 281 /** Handler to do the network accesses on */ 282 private class MyHandler extends Handler { 283 284 public MyHandler(Looper l) { 285 super(l); 286 } 287 288 @Override 289 public void handleMessage(Message msg) { 290 switch (msg.what) { 291 case EVENT_AUTO_TIME_CHANGED: 292 case EVENT_POLL_NETWORK_TIME: 293 case EVENT_NETWORK_CHANGED: 294 onPollNetworkTime(msg.what); 295 break; 296 } 297 } 298 } 299 300 /** Observer to watch for changes to the AUTO_TIME setting */ 301 private static class SettingsObserver extends ContentObserver { 302 303 private int mMsg; 304 private Handler mHandler; 305 306 SettingsObserver(Handler handler, int msg) { 307 super(handler); 308 mHandler = handler; 309 mMsg = msg; 310 } 311 312 void observe(Context context) { 313 ContentResolver resolver = context.getContentResolver(); 314 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), 315 false, this); 316 } 317 318 @Override 319 public void onChange(boolean selfChange) { 320 mHandler.obtainMessage(mMsg).sendToTarget(); 321 } 322 } 323 324 @Override 325 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 326 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 327 != PackageManager.PERMISSION_GRANTED) { 328 pw.println("Permission Denial: can't dump NetworkTimeUpdateService from from pid=" 329 + Binder.getCallingPid() 330 + ", uid=" + Binder.getCallingUid() 331 + " without permission " 332 + android.Manifest.permission.DUMP); 333 return; 334 } 335 pw.print("PollingIntervalMs: "); 336 TimeUtils.formatDuration(mPollingIntervalMs, pw); 337 pw.print("\nPollingIntervalShorterMs: "); 338 TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); 339 pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); 340 pw.print("TimeErrorThresholdMs: "); 341 TimeUtils.formatDuration(mTimeErrorThresholdMs, pw); 342 pw.println("\nTryAgainCounter: " + mTryAgainCounter); 343 pw.print("LastNtpFetchTime: "); 344 TimeUtils.formatDuration(mLastNtpFetchTime, pw); 345 pw.println(); 346 } 347} 348