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.ConnectivityManager.NetworkCallback; 29 import android.net.Network; 30 import android.os.Binder; 31 import android.os.Handler; 32 import android.os.HandlerThread; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.PowerManager; 36 import android.os.SystemClock; 37 import android.provider.Settings; 38 import android.util.Log; 39 import android.util.NtpTrustedTime; 40 import android.util.TimeUtils; 41 42 import com.android.internal.telephony.TelephonyIntents; 43 import com.android.internal.util.DumpUtils; 44 45 import java.io.FileDescriptor; 46 import java.io.PrintWriter; 47 48 /** 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 */ 58 public class NetworkTimeUpdateService extends Binder { 59 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; 65 private static final int EVENT_NETWORK_CHANGED = 3; 66 67 private static final String ACTION_POLL = 68 "com.android.server.NetworkTimeUpdateService.action.POLL"; 69 70 private static final int POLL_REQUEST = 0; 71 72 private static final long NOT_SET = -1; 73 private long mNitzTimeSetTime = NOT_SET; 74 private Network mDefaultNetwork = null; 75 76 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; 82 83 // NTP lookup is done on this thread and handler 84 private Handler mHandler; 85 private SettingsObserver mSettingsObserver; 86 private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; 87 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; 96 // 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; 103 mTime = NtpTrustedTime.getInstance(context); 104 mAlarmManager = mContext.getSystemService(AlarmManager.class); 105 mCM = mContext.getSystemService(ConnectivityManager.class); 106 107 Intent pollIntent = new Intent(ACTION_POLL, null); 108 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); 109 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); 118 119 mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( 120 PowerManager.PARTIAL_WAKE_LOCK, TAG); 121 } 122 123 /** Initialize the receivers and initiate the first NTP request */ 124 public void systemRunning() { 125 registerForTelephonyIntents(); 126 registerForAlarms(); 127 128 HandlerThread thread = new HandlerThread(TAG); 129 thread.start(); 130 mHandler = new MyHandler(thread.getLooper()); 131 mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); 132 mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); 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 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) { 155 // If Automatic time is not set, don't bother. Similarly, if we don't 156 // have any default network, don't bother. 157 if (mDefaultNetwork == null) return; 158 mWakeLock.acquire(); 159 try { 160 onPollNetworkTimeUnderWakeLock(event); 161 } finally { 162 mWakeLock.release(); 163 } 164 } 165 166 private void onPollNetworkTimeUnderWakeLock(int event) { 167 // 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(); 171 } 172 173 if (mTime.getCacheAge() < mPollingIntervalMs) { 174 // Obtained fresh fix; schedule next normal update 175 resetAlarm(mPollingIntervalMs); 176 if (isAutomaticTimeRequested()) { 177 updateSystemClock(event); 178 } 179 180 } else { 181 // No fresh fix; schedule retry 182 mTryAgainCounter++; 183 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { 184 resetAlarm(mPollingIntervalShorterMs); 185 } else { 186 // 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"); 216 return; 217 } 218 } 219 220 SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis()); 221 } 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 235 /** 236 * Checks if the user prefers to automatically set the time. 237 */ 238 private boolean isAutomaticTimeRequested() { 239 return Settings.Global.getInt( 240 mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0; 241 } 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(); 249 if (DBG) Log.d(TAG, "Received " + action); 250 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) { 251 mNitzTimeSetTime = SystemClock.elapsedRealtime(); 252 } 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: 268 case EVENT_NETWORK_CHANGED: 269 onPollNetworkTime(msg.what); 270 break; 271 } 272 } 273 } 274 275 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 290 /** 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(); 304 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), 305 false, this); 306 } 307 308 @Override 309 public void onChange(boolean selfChange) { 310 mHandler.obtainMessage(mMsg).sendToTarget(); 311 } 312 } 313 314 @Override 315 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 316 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 317 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); 325 pw.println("NTP cache age: " + mTime.getCacheAge()); 326 pw.println("NTP cache certainty: " + mTime.getCacheCertainty()); 327 pw.println(); 328 } 329 } 330