1 相关文件:
frameworks\base\services\java\com\android\server\ SystemServer.java
frameworks\base\services\java\com\android\server\ NetworkTimeUpdateService.java
frameworks\base\core\java\android\util\NtpTrustedTime.java
frameworks\base\core\java\android\net\SntpClient.java
frameworks\base\core\res\res\values\config.xml
2 实现原理:
2.1 SystemServer的run中:
ActivityManagerService.self().systemReady(new Runnable() {
public void run() {
try {
if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();
} catch (Throwable e) {
reportWtf(“making Network Time Service ready”, e);
}
…
}
2.2 再来看看NetworkTimeUpdateService中的相关代码:
systemReady
public void systemReady() {
registerForTelephonyIntents();
//注册定时器广播
registerForAlarms();
//注册网络连接消息广播
registerForConnectivityIntents();
//创建用于接收NTP请求事件的HandlerThread
//用于处理:
// EVENT_AUTO_TIME_CHANGED:
// EVENT_POLL_NETWORK_TIME:
// EVENT_NETWORK_CONNECTED:
//三个消息
mThread = new HandlerThread(TAG);
mThread.start();
mHandler = new MyHandler(mThread.getLooper());
// Check the network time on the new thread
//发送请求NTP时间消息
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
//添加一个用于监听设置中时间改变消息通知
mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
mSettingsObserver.observe(mContext);
}
MyHandler
/** Handler to do the network accesses on */
private class MyHandler extends Handler {
public MyHandler(Looper l) {
super(l);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_AUTO_TIME_CHANGED:
case EVENT_POLL_NETWORK_TIME:
case EVENT_NETWORK_CONNECTED:
onPollNetworkTime(msg.what);
break;
}
}
}
重点来看看onPollNetworkTime这个函数:
在看这个函数之前先来理解几个相关变量,理解了这几个变量之后,该函数就比较好理解了。
在NetworkTimeUpdateService的构造函数中:
public NetworkTimeUpdateService(Context context) {
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
mPollingIntervalMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingInterval);
mPollingIntervalShorterMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingIntervalShorter);
mTryAgainTimesMax = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpRetry);
mTimeErrorThresholdMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpThreshold);
}
几个关键的变量:
mPollingIntervalMs
当NTP时间获取成功后,再次请求NTP时间的间隔
mPollingIntervalShorterMs
当NTP时间获取失败后,再次请求NTP时间的间隔
mTimeErrorThresholdMs
当NTP时间和系统时间不相同时,要更新系统时间的阀值
这几个变量的值是通过资源文件里读取的,配置的地址为config.xml,来看看相关的内容:
0.android.pool.ntp.org
864000000
5000
-1
5000
20000
其实只要看下注释这几个变量的功能就清楚了,可见注释是多么的重要,如果要自己看代码理解的话,可能要花比较多的时间。
好,最后来看下onPollNetworkTime的代码:
private void onPollNetworkTime(int event) {
// If Automatic time is not set, don't bother.
if (!isAutomaticTimeRequested()) return;
final long refTime = SystemClock.elapsedRealtime();
// If NITZ time was received less than mPollingIntervalMs time ago,
// no need to sync to NTP.
if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
resetAlarm(mPollingIntervalMs);
return;
}
final long currentTime = System.currentTimeMillis();
if (DBG) Log.d(TAG, "System time = " + currentTime);
// Get the NTP time
if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
|| event == EVENT_AUTO_TIME_CHANGED) {
if (DBG) Log.d(TAG, "Before Ntp fetch");
// force refresh NTP cache when outdated
//如果没有获取过NTP时间或者系统时间距离最后一次获取NTP时间超过了mPollingIntervalMs,就去请求NTP时间
if (mTime.getCacheAge() >= mPollingIntervalMs) {
mTime.forceRefresh();
}
// only update when NTP time is fresh
if (mTime.getCacheAge() < mPollingIntervalMs) {
final long ntp = mTime.currentTimeMillis();
mTryAgainCounter = 0;
// If the clock is more than N seconds off or this is the first time it's been
// fetched since boot, set the current time.
if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
|| mLastNtpFetchTime == NOT_SET) {
// Set the system time
if (DBG && mLastNtpFetchTime == NOT_SET
&& Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
Log.d(TAG, "For initial setup, rtc = " + currentTime);
}
if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
// Make sure we don't overflow, since it's going to be converted to an int
if (ntp / 1000 < Integer.MAX_VALUE) {
SystemClock.setCurrentTimeMillis(ntp);
}
} else {
if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
}
mLastNtpFetchTime = SystemClock.elapsedRealtime();
} else {
// Try again shortly
mTryAgainCounter++;
if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
resetAlarm(mPollingIntervalShorterMs);
} else {
// Try much later
mTryAgainCounter = 0;
resetAlarm(mPollingIntervalMs);
}
return;
}
}
resetAlarm(mPollingIntervalMs);
}
改了下,个人感觉比原来代码更容易理解了:
private void onPollNetworkTime(int event) {
// If Automatic time is not set, don't bother.
if (!isAutomaticTimeRequested()) return;
final long refTime = SystemClock.elapsedRealtime();
// If NITZ time was received less than mPollingIntervalMs time ago,
// no need to sync to NTP.
if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
resetAlarm(mPollingIntervalMs);
return;
}
final long currentTime = System.currentTimeMillis();
if (DBG) Log.d(TAG, "System time = " + currentTime);
// Get the NTP time
if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
|| event == EVENT_AUTO_TIME_CHANGED) {
if (DBG) Log.d(TAG, "Before Ntp fetch");
if (mTime.getCacheAge() >= mPollingIntervalMs && !mTime.forceRefresh()) {
mTryAgainCounter++;
if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
resetAlarm(mPollingIntervalShorterMs);
} else {
// Try much later
mTryAgainCounter = 0;
resetAlarm(mPollingIntervalMs);
}
return;
}
final long ntp = mTime.currentTimeMillis();
mTryAgainCounter = 0;
// If the clock is more than N seconds off or this is the first time it's been
// fetched since boot, set the current time.
if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
|| mLastNtpFetchTime == NOT_SET) {
// Set the system time
if (DBG && mLastNtpFetchTime == NOT_SET
&& Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
Log.d(TAG, "For initial setup, rtc = " + currentTime);
}
if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
// Make sure we don't overflow, since it's going to be converted to an int
if (ntp / 1000 < Integer.MAX_VALUE) {
SystemClock.setCurrentTimeMillis(ntp);
}
} else {
if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
}
mLastNtpFetchTime = SystemClock.elapsedRealtime();
resetAlarm(mPollingIntervalMs);
}
哪个代码更清晰,大家仁者见仁,智者见智,各取所好。
当然,我要声明一下,虽然我很有信心我改的代码没有问题,但是该代码我没有经过测试的,所以不要随便替换。
多年的写代码的经验告诉我,自信要有,但是不要自负,大脑是的优势在于创造,而机器的优势在于精确。
所以,在实际的工作中,写完代码之后,写测试用例测试下吧!
(完)