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多分辨率适配框架(1)— 核心基础
  3. Android(安卓)指纹启动流程
  4. Android(安卓)ListView 去除边缘阴影、选中色、拖动背景色等
  5. Android源代码目录组成介绍-android学习之旅(97)
  6. android手动拖动滚动条快速滑动
  7. 获取Android(安卓)SDK 源代码并在Eclipse中关联查看的方法
  8. Android(安卓)ListView 去除边缘阴影、选中色、拖动背景色等
  9. Android有用代码片段(四)

随机推荐

  1. 细谈Android应用架构
  2. Android网络请求心路历程
  3. Android(安卓)设置投影效果
  4. Android知识体系结构概览
  5. 用cmd 命令更改Android(安卓)的默认虚拟
  6. Android横竖屏切换总结
  7. 微信小程序性能分析Trace工具
  8. Android(安卓)- ReactNative Debug 技巧
  9. 访问Android内部RIL接口(一)
  10. 开源项目之Android(安卓)undergarment