Android时间同步流程

对时概述

Android的自动对时有好几种,基本的是通过ntp网络服务器对时和通过手机sim卡运营商网络对时,国内如果是电信cdma手机的话,按照运营商需求是强制通过第二种方式对时的,手机设置中不可选择取消自动对时。不过目前手机基本都是全网通了,所以这个限制好像取消了。mtk的还有通过gps对时的选项。

ntp介绍见百度百科:

NTP服务器【Network Time Protocol(NTP)】是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。时间按NTP服务器的等级传播。按照离外部UTC源的远近把所有服务器归入不同的Stratum(层)中。

ntp对时服务器可见http://www.ntp.org.cn/,Android源码默认服务器不是中国区的,android是通过SettingProvider设置对时服务器值的,设置中的大多数值其实都是SettingsProvider数据库某个值。

Android系统服务器的值是在NtpTrustedTime类中初始化的。

frameworks/base/core/java/android/util/NtpTrustedTime.java

   public static synchronized NtpTrustedTime getInstance(Context context) {
        if (sSingleton == null) {
            final Resources res = context.getResources();
            final ContentResolver resolver = context.getContentResolver();

            final String defaultServer = res.getString(
                    com.android.internal.R.string.config_ntpServer);
            final long defaultTimeout = res.getInteger(
                    com.android.internal.R.integer.config_ntpTimeout);

            final String secureServer = Settings.Global.getString(
                    resolver, Settings.Global.NTP_SERVER);
            final long timeout = Settings.Global.getLong(
                    resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);

            final String server = secureServer != null ? secureServer : defaultServer;
            sSingleton = new NtpTrustedTime(server, timeout);
            sContext = context;
        }

        return sSingleton;
    }
可以修改Settings.Global.NTP_SERVER数据库值来设置ntp服务器地址。之前有过自动对时无效的问题,后来修改ntp服务器地址为中国区的就没有再出现过这个问题了。注意通过网络对时是需要连接网络的,数据连接或者wifi都是可以的,不联网肯定没用啊...


网络服务器对时流程

android系统在设置中可以选择自动对时,自动对时设置界面代码是DateTimeSettings,启用自动对时的起点就是控件的点击事件

packages/apps/Settings/src/com/android/settings/DateTimeSettings.java

                Settings.Global.putInt(getContentResolver(),
                        Settings.Global.AUTO_TIME, 1);

控件点击事件中写入了Settings.Global.AUTO_TIME值,使用自动同步的时候值为1


对时服务创建于SystemServer的run()函数,SystemServer的启动流程网上有不少分析了,不赘述

/frameworks/base/services/java/com/android/server/SystemServer.java

private void run() {
    ...
    startOtherServices();
    ...
}
调用startOtherServices

private void startOtherServices() {
    ...
    networkTimeUpdater = new NetworkTimeUpdateService(context);
    ...
    if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
    ...
}

创建了NetworkTimeUpdateService对象并调用了systemRunning

public void systemRunning() {
    ...
    mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
    mSettingsObserver.observe(mContext);
    ...
}
创建了一个数据库监控Observer监控Settings.Global.AUTO_TIME值的变化,值有变化就发送到内部的handler类对象中进行处理,处理函数是:

private void onPollNetworkTime(int event)
该方法稍长,不过基本逻辑就是先获取ntp时间,然后设置时间。

该方法最终调用SystemClock类中方法设置系统时间

SystemClock.setCurrentTimeMillis(ntp);

sim卡网络对时

手机不用通过数据网络照样可以对时的,例如电信手机开机后应该可以看到系统会发送自动对时的notification。

以Cdma网络为例,代码在CdmaServiceStateTracker.java,该类中有两条路径设置时间,路径1同样是监听Settings.Global.AUTO_TIME值

   private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
        @Override
        public void onChange(boolean selfChange) {
            if (DBG) log("Auto time state changed");
            revertToNitzTime();
        }
    };
监听到值有变化的时候调用revertToNitzTime

private void revertToNitzTime() {
            ...
            setAndBroadcastNetworkSetTime(mSavedTime
                    + (SystemClock.elapsedRealtime() - mSavedAtTime));
            ...
    }
revertToNitzTime调用setAndBroadcastNetworkSetTime

 private void setAndBroadcastNetworkSetTime(long time) {
        if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
        SystemClock.setCurrentTimeMillis(time);
        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        intent.putExtra("time", time);
        mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
    }
setAndBroadcastNetworkSetTime设置时间并发送了一个广播。路径1的流程到此完毕


路径2是ril上报时间,从而导致更新。在CdmaServiceStateTracker构造函数中

     mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
向ril注册了监听时间,ril有对时消息上报的时候会通知CdmaServiceStateTracker,telephony framework中的xxTracker基本都是继承Handler类的,目的就是为了方便发送和接收消息

        case EVENT_NITZ_TIME:
            ar = (AsyncResult) msg.obj;

            String nitzString = (String)((Object[])ar.result)[0];
            long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();

            setTimeFromNITZString(nitzString, nitzReceiveTime);
收到EVENT_NITZ_TIME消息后调用setTimeFromNITZString:

private void setTimeFromNITZString (String nitz, long nitzReceiveTime){
           ...
           Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
           ...
           if (getAutoTime()) {
               ...
               setAndBroadcastNetworkSetTime(c.getTimeInMillis());
               ...
           }
           ...
}
调用路径1末尾同样的方法设置时间。gsm的代码和cdma类似。不过依据我的个人经验,国内好像只有电信才有这个功能。

你可能感兴趣的:(android)