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.app.timedetector.NetworkTimeSuggestion; 22 import android.app.timedetector.TimeDetector; 23 import android.content.BroadcastReceiver; 24 import android.content.ContentResolver; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.IntentFilter; 28 import android.database.ContentObserver; 29 import android.net.ConnectivityManager; 30 import android.net.ConnectivityManager.NetworkCallback; 31 import android.net.Network; 32 import android.os.Binder; 33 import android.os.Handler; 34 import android.os.HandlerThread; 35 import android.os.Looper; 36 import android.os.Message; 37 import android.os.PowerManager; 38 import android.os.SystemClock; 39 import android.os.TimestampedValue; 40 import android.provider.Settings; 41 import android.util.Log; 42 import android.util.NtpTrustedTime; 43 import android.util.TimeUtils; 44 45 import com.android.internal.util.DumpUtils; 46 47 import java.io.FileDescriptor; 48 import java.io.PrintWriter; 49 50 /** 51 * Monitors the network time. If looking up the network time fails for some reason, it tries a few 52 * times with a short interval and then resets to checking on longer intervals. 53 * 54 * <p>When available, the time is always suggested to the {@link 55 * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device 56 * system clock, depending on user settings and what other signals are available. 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_ENABLED = 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 Network mDefaultNetwork = null; 73 74 private final Context mContext; 75 private final NtpTrustedTime mTime; 76 private final AlarmManager mAlarmManager; 77 private final TimeDetector mTimeDetector; 78 private final ConnectivityManager mCM; 79 private final PendingIntent mPendingPollIntent; 80 private final PowerManager.WakeLock mWakeLock; 81 82 // NTP lookup is done on this thread and handler 83 private Handler mHandler; 84 private AutoTimeSettingObserver mAutoTimeSettingObserver; 85 private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; 86 87 // Normal polling frequency 88 private final long mPollingIntervalMs; 89 // Try-again polling interval, in case the network request failed 90 private final long mPollingIntervalShorterMs; 91 // Number of times to try again 92 private final int mTryAgainTimesMax; 93 // Keeps track of how many quick attempts were made to fetch NTP time. 94 // During bootup, the network may not have been up yet, or it's taking time for the 95 // connection to happen. 96 private int mTryAgainCounter; 97 NetworkTimeUpdateService(Context context)98 public NetworkTimeUpdateService(Context context) { 99 mContext = context; 100 mTime = NtpTrustedTime.getInstance(context); 101 mAlarmManager = mContext.getSystemService(AlarmManager.class); 102 mTimeDetector = mContext.getSystemService(TimeDetector.class); 103 mCM = mContext.getSystemService(ConnectivityManager.class); 104 105 Intent pollIntent = new Intent(ACTION_POLL, null); 106 // Broadcast alarms sent by system are immutable 107 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 108 PendingIntent.FLAG_IMMUTABLE); 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 117 mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( 118 PowerManager.PARTIAL_WAKE_LOCK, TAG); 119 } 120 121 /** Initialize the receivers and initiate the first NTP request */ systemRunning()122 public void systemRunning() { 123 registerForAlarms(); 124 125 HandlerThread thread = new HandlerThread(TAG); 126 thread.start(); 127 mHandler = new MyHandler(thread.getLooper()); 128 mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); 129 mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); 130 131 mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler, 132 EVENT_AUTO_TIME_ENABLED); 133 mAutoTimeSettingObserver.observe(); 134 } 135 registerForAlarms()136 private void registerForAlarms() { 137 mContext.registerReceiver( 138 new BroadcastReceiver() { 139 @Override 140 public void onReceive(Context context, Intent intent) { 141 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); 142 } 143 }, new IntentFilter(ACTION_POLL)); 144 } 145 onPollNetworkTime(int event)146 private void onPollNetworkTime(int event) { 147 // If we don't have any default network, don't bother. 148 if (mDefaultNetwork == null) return; 149 mWakeLock.acquire(); 150 try { 151 onPollNetworkTimeUnderWakeLock(event); 152 } finally { 153 mWakeLock.release(); 154 } 155 } 156 onPollNetworkTimeUnderWakeLock(int event)157 private void onPollNetworkTimeUnderWakeLock(int event) { 158 // Force an NTP fix when outdated 159 NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); 160 if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { 161 if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); 162 mTime.forceRefresh(); 163 cachedNtpResult = mTime.getCachedTimeResult(); 164 } 165 166 if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { 167 // Obtained fresh fix; schedule next normal update 168 resetAlarm(mPollingIntervalMs); 169 170 // Suggest the time to the time detector. It may choose use it to set the system clock. 171 TimestampedValue<Long> timeSignal = new TimestampedValue<>( 172 cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); 173 NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); 174 timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event); 175 mTimeDetector.suggestNetworkTime(timeSuggestion); 176 } else { 177 // No fresh fix; schedule retry 178 mTryAgainCounter++; 179 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { 180 resetAlarm(mPollingIntervalShorterMs); 181 } else { 182 // Try much later 183 mTryAgainCounter = 0; 184 resetAlarm(mPollingIntervalMs); 185 } 186 } 187 } 188 189 /** 190 * Cancel old alarm and starts a new one for the specified interval. 191 * 192 * @param interval when to trigger the alarm, starting from now. 193 */ resetAlarm(long interval)194 private void resetAlarm(long interval) { 195 mAlarmManager.cancel(mPendingPollIntent); 196 long now = SystemClock.elapsedRealtime(); 197 long next = now + interval; 198 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); 199 } 200 201 /** Handler to do the network accesses on */ 202 private class MyHandler extends Handler { 203 MyHandler(Looper l)204 MyHandler(Looper l) { 205 super(l); 206 } 207 208 @Override handleMessage(Message msg)209 public void handleMessage(Message msg) { 210 switch (msg.what) { 211 case EVENT_AUTO_TIME_ENABLED: 212 case EVENT_POLL_NETWORK_TIME: 213 case EVENT_NETWORK_CHANGED: 214 onPollNetworkTime(msg.what); 215 break; 216 } 217 } 218 } 219 220 private class NetworkTimeUpdateCallback extends NetworkCallback { 221 @Override onAvailable(Network network)222 public void onAvailable(Network network) { 223 Log.d(TAG, String.format("New default network %s; checking time.", network)); 224 mDefaultNetwork = network; 225 // Running on mHandler so invoke directly. 226 onPollNetworkTime(EVENT_NETWORK_CHANGED); 227 } 228 229 @Override onLost(Network network)230 public void onLost(Network network) { 231 if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; 232 } 233 } 234 235 /** 236 * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting 237 * is enabled. 238 */ 239 private static class AutoTimeSettingObserver extends ContentObserver { 240 241 private final Context mContext; 242 private final int mMsg; 243 private final Handler mHandler; 244 AutoTimeSettingObserver(Context context, Handler handler, int msg)245 AutoTimeSettingObserver(Context context, Handler handler, int msg) { 246 super(handler); 247 mContext = context; 248 mHandler = handler; 249 mMsg = msg; 250 } 251 observe()252 void observe() { 253 ContentResolver resolver = mContext.getContentResolver(); 254 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), 255 false, this); 256 } 257 258 @Override onChange(boolean selfChange)259 public void onChange(boolean selfChange) { 260 if (isAutomaticTimeEnabled()) { 261 mHandler.obtainMessage(mMsg).sendToTarget(); 262 } 263 } 264 265 /** 266 * Checks if the user prefers to automatically set the time. 267 */ isAutomaticTimeEnabled()268 private boolean isAutomaticTimeEnabled() { 269 ContentResolver resolver = mContext.getContentResolver(); 270 return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0; 271 } 272 } 273 274 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)275 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 276 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 277 pw.print("PollingIntervalMs: "); 278 TimeUtils.formatDuration(mPollingIntervalMs, pw); 279 pw.print("\nPollingIntervalShorterMs: "); 280 TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); 281 pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); 282 pw.println("\nTryAgainCounter: " + mTryAgainCounter); 283 NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); 284 pw.println("NTP cache result: " + ntpResult); 285 if (ntpResult != null) { 286 pw.println("NTP result age: " + ntpResult.getAgeMillis()); 287 } 288 pw.println(); 289 } 290 } 291