本文分析基于AOSP 8.0源码:在线网址为: 8.0.0_r4
Android时间更新的服务为:NetworkTimeUpdateService,位于 frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
public class NetworkTimeUpdateService extends Binder
该类设计的比较简单,我们来看看其是如何工作的
首先要知道的是,该类运行在SystemServer进程中,我们可以在SystemServer中看到,以下代码:
NetworkTimeUpdateService networkTimeUpdater = null;
// 初始化NetworkTimeUpdateService,走其构造方法
networkTimeUpdater = new NetworkTimeUpdateService(context);
ServiceManager.addService("network_time_update_service", networkTimeUpdater);
//调用service的systemRunning方法
try {
if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying NetworkTimeService running", e);
}
可以看到,SystemServer对其进行了初始化,还调用了systemRunning方法。
继续去看看其构造方法,和systemRunning,先看下够造方法:
103 public NetworkTimeUpdateService(Context context) {
104 mContext = context;
105 mTime = NtpTrustedTime.getInstance(context);
106 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
107 Intent pollIntent = new Intent(ACTION_POLL, null);
//时间同步有可能超时,使用该PendingIntent进行(间隔再次发起)时间同步。
108 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
109 // poll间隔
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 = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
120 PowerManager.PARTIAL_WAKE_LOCK, TAG);
121 }
看上面的代码,我们可以看到:
- 调用了 NtpTrustedTime.getInstance(context); 等下去看干嘛的
- 初始化一个时间同步的pendingIntent
- 初始化一些可以OEM的时间同步相关参数
那么看下 NtpTrustedTime.getInstance(context); 看这个名字叫:可信时间 frameworks/base/core/java/android/util/NtpTrustedTime.java
52 private NtpTrustedTime(String server, long timeout) {
53 if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
54 mServer = server;
55 mTimeout = timeout;
56 }
57
58 public static synchronized NtpTrustedTime getInstance(Context context) {
59 if (sSingleton == null) {
60 final Resources res = context.getResources();
61 final ContentResolver resolver = context.getContentResolver();
62
63 final String defaultServer = res.getString(
64 com.android.internal.R.string.config_ntpServer);
65 final long defaultTimeout = res.getInteger(
66 com.android.internal.R.integer.config_ntpTimeout);
67
68 final String secureServer = Settings.Global.getString(
69 resolver, Settings.Global.NTP_SERVER);
70 final long timeout = Settings.Global.getLong(
71 resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);
72
73 final String server = secureServer != null ? secureServer : defaultServer;
74 sSingleton = new NtpTrustedTime(server, timeout);
75 sContext = context;
76 }
77
78 return sSingleton;
79 }
我们可以看到,这个类是用来管理增加时间同步服务器的。那我们继续回到NetworkTimeUpdateService的systemRunning。
122
123 /** Initialize the receivers and initiate the first NTP request */
124 public void systemRunning() {
// 注册来自Telephony Ril的广播,moderm时间会通过这个方法更新
125 registerForTelephonyIntents();
// 是配合第“一”中介绍的mPendingPollIntent 来工作的,主要作用是构造handler Message并再次发起时间同步请求。
126 registerForAlarms();
// 监听网络状态变化,以便于在连接网络后更新时间
127 registerForConnectivityIntents();
128
129 HandlerThread thread = new HandlerThread(TAG);
130 thread.start();
131 mHandler = new MyHandler(thread.getLooper());
132 // Check the network time on the new thread
133 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
134 // 注册SettingsObserver, 在设置里点击了自动时间的开关就会触发这儿
135 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
136 mSettingsObserver.observe(mContext);
137 }
我们可以看到,发了一个请求网络时间的请求给Handler,那么Handler 怎么处理的呢。
282 /** Handler to do the network accesses on */
283 private class MyHandler extends Handler {
284
285 public MyHandler(Looper l) {
286 super(l);
287 }
288
289 @Override
290 public void handleMessage(Message msg) {
291 switch (msg.what) {
292 case EVENT_AUTO_TIME_CHANGED:
293 case EVENT_POLL_NETWORK_TIME:
294 case EVENT_NETWORK_CHANGED:
295 onPollNetworkTime(msg.what);
296 break;
297 }
298 }
299 }
三个请求都会去走onPollNetworkTime
方法,这些请求由:数据库变换,网络状态变化等状态改变发出的。
162 private void onPollNetworkTime(int event) {
163 // If Automatic time is not set, don't bother.
164 if (!isAutomaticTimeRequested()) return;
165 mWakeLock.acquire();
166 try {
167 onPollNetworkTimeUnderWakeLock(event);
168 } finally {
169 mWakeLock.release();
170 }
171 }
172
173 private void onPollNetworkTimeUnderWakeLock(int event) {
174 final long refTime = SystemClock.elapsedRealtime();
175 // If NITZ time was received less than mPollingIntervalMs time ago,
176 // no need to sync to NTP.
// mNitzTimeSetTime 来自Moderm,如果当前时间刚通过moderm更新不久,小于我们设定的阈值时间,则不进行时间同步。
177 if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
178 resetAlarm(mPollingIntervalMs);
179 return;
180 }
181 final long currentTime = System.currentTimeMillis();
182 if (DBG) Log.d(TAG, "System time = " + currentTime);
183 // Get the NTP time
// 如果机器刚启动,或者机器运行时间大于mPollingIntervalMs,即10天
// 或者设置等发起的主动更新时间请求,则发起网络时间同步请求。否则,10天后再进行时间同步。
184 if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
185 || event == EVENT_AUTO_TIME_CHANGED) {
186 if (DBG) Log.d(TAG, "Before Ntp fetch");
187
188 // force refresh NTP cache when outdated
189 if (mTime.getCacheAge() >= mPollingIntervalMs) {
190 mTime.forceRefresh(); //遍历时间服务器,发起时间同步
191 }
192
//获取最新同步的时间缓冲数据,如无,则再次发起时间同步,间隔时间为mPollingIntervalShorterMs,即30秒。
193 // only update when NTP time is fresh
194 if (mTime.getCacheAge() < mPollingIntervalMs) {
195 final long ntp = mTime.currentTimeMillis();
196 mTryAgainCounter = 0;
197 // If the clock is more than N seconds off or this is the first time it's been
198 // fetched since boot, set the current time.
// 如果开机第一次同步或者最新时间与当前时间差别超过mTimeErrorThresholdMs即25
//则进行时间设定。否则认定新同步时间与当前时间差别不大,不覆盖当前时间。
199 if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
200 || mLastNtpFetchTime == NOT_SET) {
201 // Set the system time
202 if (DBG && mLastNtpFetchTime == NOT_SET
203 && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
204 Log.d(TAG, "For initial setup, rtc = " + currentTime);
205 }
206 if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
207 // Make sure we don't overflow, since it's going to be converted to an int
208 if (ntp / 1000 < Integer.MAX_VALUE) {
209 SystemClock.setCurrentTimeMillis(ntp);
210 }
211 } else {
212 if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
213 }
214 mLastNtpFetchTime = SystemClock.elapsedRealtime();
215 } else {
// 重新获取时间,30秒后进行时间同步,否则,10天后更新。
216 // Try again shortly
217 mTryAgainCounter++;
218 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
219 resetAlarm(mPollingIntervalShorterMs);
220 } else {
221 // Try much later
222 mTryAgainCounter = 0;
223 resetAlarm(mPollingIntervalMs);
224 }
225 return;
226 }
227 }
// 如果刚更新时间不久,则10天后再发起时间同步请求。
228 resetAlarm(mPollingIntervalMs);
229 }
190行刚刚循环获取时间的forceRefresh,NtpTrustedTime的代码,从代码中可以看到,是使用SNTP获取时间的,连上了我们的第二讲中的SNTP
81 @Override
82 public boolean forceRefresh() {
83 if (TextUtils.isEmpty(mServer)) {
84 // missing server, so no trusted time available
85 return false;
86 }
87
88 // We can't do this at initialization time: ConnectivityService might not be running yet.
89 synchronized (this) {
90 if (mCM == null) {
91 mCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
92 }
93 }
94
95 final NetworkInfo ni = mCM == null ? null : mCM.getActiveNetworkInfo();
96 if (ni == null || !ni.isConnected()) {
97 if (LOGD) Log.d(TAG, "forceRefresh: no connectivity");
98 return false;
99 }
100
101
102 if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
103 final SntpClient client = new SntpClient();
// SNTP协议更新时间
104 if (client.requestTime(mServer, (int) mTimeout)) {
105 mHasCache = true;
106 mCachedNtpTime = client.getNtpTime();
107 mCachedNtpElapsedRealtime = client.getNtpTimeReference();
108 mCachedNtpCertainty = client.getRoundTripTime() / 2;
109 return true;
110 } else {
111 return false;
112 }
113 }
关于SNTP协议里面的,暂时就不讲了。我们的分析到此基本就够了,有兴趣的可以继续追。
谢谢大家的阅读
作者:Anderson大码渣,欢迎关注我的简书: Anderson大码渣