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);    }


哪个代码更清晰,大家仁者见仁,智者见智,各取所好。

当然,我要声明一下,虽然我很有信心我改的代码没有问题,但是该代码我没有经过测试的,所以不要随便替换。

多年的写代码的经验告诉我,自信要有,但是不要自负,大脑是的优势在于创造,而机器的优势在于精确。

所以,在实际的工作中,写完代码之后,写测试用例测试下吧!


(完)


更多相关文章

  1. Android 源代码分享
  2. Android源代码目录组成介绍-android学习之旅(97)
  3. Android有用代码片段(四)
  4. [转]Android 源代码结构
  5. android代码库之textview跑马灯效果
  6. Android 垂直的Slidebar 代码
  7. Android Studio 系列(二)使用Android Studio 导入整个android 源码
  8. 【Android】Android 代码判断是否获取ROOT权限(一)
  9. Android月历控件(DatePicker)和时间控件(TimePicker)的使用

随机推荐

  1. Android中Telephony学习总结
  2. android 横竖屏切换,activity的生命周期
  3. Android开发所需的Android(安卓)SDK、开
  4. android.hardware.USB类介绍
  5. IdleHandler类在android中的使用
  6. Lifecycle-Aware Components生命周期组件
  7. API 25 (Android(安卓)7.1.1 API) widget
  8. ubuntu10 集成android创建工程出错解决
  9. Android(安卓)获取系统或SDCARD剩余空间
  10. Android打印日志管理