android源码分析之网络更新时间

android网络更新时间

  • android时间的更新方式,一般有moderm和网络更新两种,MTK在此基础上,添加了GPS的方式。现在分析的是网络更新时间的方式

  • 从网络更新只能更新时间但是无法改变时区;从手机网络运营商处获取时间可以获得时间和分区(这种方式大陆的运营商支持率很低)

  • android系统中更新时间的操作 分为系统部分和应用部分


代码路径


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

/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java

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

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

系统部分

android时间更新的系统部分是为应用程序提供”服务”。在SystemServer中启动网络更新的”service”。在网络更新的systemRunning方法中,会启动线程,当内容观察者observer发现数据库中AUTO_TIME的数据发生变化后,通过handler发送message给这个线程。在这个线程中进行 moderm 、网络、gps 等方式的更新时间。

SystemSever

在startOtherServices 中启动和网络更新时间相关的”service”


  NetworkTimeUpdateService networkTimeUpdater = null;



if (!disableNetwork && !disableNetworkTime) {

                try {

                    Slog.i(TAG, "NetworkTimeUpdateService");

                    networkTimeUpdater = new NetworkTimeUpdateService(context);

                } catch (Throwable e) {

                    reportWtf("starting NetworkTimeUpdate service", e);

                }

            }

获得了一个 NetworkTimeUpdateService的实例化对象 networkTimeUpdater;

这个networkTimeUpdater是被mActivityManagerService的run方法调用的。

NetworkTimeUpdateService的构造方法


//使用单例模式获得一个NtpTrustedTime的对象

 mTime = NtpTrustedTime.getInstance(context);

 //获得一个Server,其实质是Settings.Global.NTP_SERVER

 mDefaultServer = ((NtpTrustedTime) mTime).getServer();

   mNtpServers.add(mDefaultServer);  

   //时间服务器添加到ArrayList类型的mNtpServers中。(添加多个时间服务器是mtk在android源码的基础上添加的)

   for (String str : SERVERLIST)

{

   mNtpServers.add(str);

}



 ```

 在NetworkTimeUpdateService的构造方法中 获得的服务器列表如下

- 默认的server

/frameworks/base/core/res/res/values/config.xml

  asia.pool.ntp.org

- 服务器列表

private static final String[] SERVERLIST = new String[]{

                                        "hshh.org",

                                         "2.android.pool.ntp.org",

                                         "time-a.nist.gov"

                                         };



现在在原有的基础上,添加内部服务器,就能够通过内部服务器来更新时间。



## 启动NetworkUpdataService



当在startOtherService的最后,会调用   mActivityManagerService.systemReady()。此时会执行代码中的run方法。在这个run方法中,就会执行到NetworkUpdataService的systemRunning()方法。

final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;

 mActivityManagerService.systemReady(new Runnable() {

        @Override

        public void run() {

         try {

                if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();

            } catch (Throwable e) {

                reportWtf("Notifying NetworkTimeService running", e);

            }



## 执行systemRunning


    registerForTelephonyIntents();

    registerForAlarms();

    registerForConnectivityIntents();



    HandlerThread thread = new HandlerThread(TAG);

    thread.start();

    mHandler = new MyHandler(thread.getLooper());

    // Check the network time on the new thread

    mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();



    mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);

    mSettingsObserver.observe(mContext);



    /// M: comment @{ add GPS Time Sync Service

    Log.d(TAG, "add GPS time sync handler and looper");

    mGpsThread = new HandlerThread(TAG);

    mGpsThread.start();

    mGpsHandler = new MyHandler(mGpsThread.getLooper());



    mGpsTimeSyncObserver = new GpsTimeSyncObserver(mGpsHandler, EVENT_GPS_TIME_SYNC_CHANGED);

    mGpsTimeSyncObserver.observe(mContext);

    /// @}

- 首先会注册和moderm、alarms、网络的receiver

registerForTelephonyIntents(); //moderm的Receiver,会引起时间的变化

registerForAlarms(); //Alarm的Receiver 类型为EVENT_POLL_NETWORK_TIME

registerForConnectivityIntents();//网络变化引起的更新。类型为EVENT_NETWORK_CHANGED


- 利用消息处理机制,进行时间的更新操作

    - 启动一个线程。用来处理消息。

    -MyHandler中进行消息的处理

    - 时间更新的类型为EVENT_POLL_NETWORK_TIME



 ```

    mHandler = new MyHandler(thread.getLooper());

        // Check the network time on the new thread

        mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();



 ```

- 监听EVENT_AUTO_TIME_CHANGED的事件的发生,如果发生也将会执行到MyHandlerHandlMessage

 ```

  mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);

        mSettingsObserver.observe(mContext);

 ```

- Mtk代码在网络更新的基础上,添加了GPS授时的方式,和网络跟新的思路相同



## MyHandler的HandeMessage处理


public void handleMessage(Message msg) {

        switch (msg.what) {

            case EVENT_AUTO_TIME_CHANGED:

            case EVENT_POLL_NETWORK_TIME: 

            case EVENT_NETWORK_CHANGED:

                if (DBG) Log.d(TAG, "MyHandler::handleMessage what = " + msg.what);

                onPollNetworkTime(msg.what);

                break;



            /// M: comment @{ add GPS Time Sync Service

            case EVENT_GPS_TIME_SYNC_CHANGED:

                boolean gpsTimeSyncStatus = getGpsTimeSyncState();;

                Log.d(TAG, "GPS Time sync is changed to " + gpsTimeSyncStatus);

                onGpsTimeChanged(gpsTimeSyncStatus);

                break;

            /// @}

        }

    }



- EVENT_AUTO_TIME_CHANGED EVENT_POLL_NETWORK_TIME EVENT_NETWORK_CHANGED 这三种类型的请求,都会交给 onPollNetworkTime来进行处理。

- EVENT_GPS_TIME_SYNC_CHANGED GPS的同步请求,会由onGpsTimeChanged 进行处理

- EVENT_POLL_NETWORK_TIME 这个请求和Alarms相关内容。用于系统定时的更新时间 



## onPollNetworkTime 时间同步



- 用户是否勾选自动同步设置

if (!isAutomaticTimeRequested()) return;


- 从服务器获取时间。获取时间后,调用NtpTrustedTime中的forceRefresh 进行更新

// 满足一下三个添加条件的一个就会更新时间 系统刚启动 mLastNtpFetchTime == NOT_SET 运行时间refTime 大于了10天。或者AlermManager引起的EVENT_AUTO_TIME_CHANGED变化

if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs

            || event == EVENT_AUTO_TIME_CHANGED) {

if (mTime instanceof NtpTrustedTime)

            {

                ((NtpTrustedTime) mTime).setServer(mNtpServers.get(index));

                mTime.forceRefresh();

                ((NtpTrustedTime) mTime).setServer(mDefaultServer);

            }

“`

同步过程详细分析

  • 开机没联网 ,联网什么时候更新

    系统在联网时,会自动更新更新时间。

    • 如果此时从4个服务器中能正常更新时间,则进入10天一更新的周期

    • 如果4个服务器都不能更新,则下次联网或开机或用户主动发起更新请求时,依然会从4个服务器获取时间 。


  • 更新失败,什么时候继续更新

    • 开机后,如果没有网络,不会进行更新

    • 联网后,会进行更新。

    • 遍历服务器。如果都失败。此时如果用户主动发起请求,也会进行ntp更新。如果用户没有主动的请求更新或重新开机或网络改变,则10天后,重发发起网络更新。如果以上三者条件有一个,则会发起网络同步请求

  • 网络更新时间之后,(无关机重启条件下)

    • 如果系统的运行时间大于10天,或者用户主动发起更新请求。则判断时间缓冲。

    • 时间缓冲为 系统运行的时间 - 上一次同步的时间的时间差

    • 如果时间缓冲超过10天,则会遍历服务器进行更新

    • 如果更新成功。则判断目前系统的时间和要设定的时间差是否大于 设定值

    • 如果大于设定值,则进行设定。否则不设定

    • 如果更新失败,则更换服务器进行更新

    • 如果所有的服务器都更新失败,则10天后,在进行更新

  • 系统重启 会进行时间的同步更新


  • 系统能进行网络更新的方式 (执行HandleMessage)

    • 用户主动发起

    • 网络变化

    • ALarm

  • 更新时间 (执行onPollNetworkTime)

    • mLastNtpFetchTime == NOT_SET(关机重启)

    • 运行时间大于10天

    • 用户主动发起


  • 更新失败,或者还没有从服务器更新。则 mLastNtpFetchTime == NOT_SET

AlarmManager定时更新时间

  • registerForAlarms();

    
    mContext.registerReceiver(
    
            new BroadcastReceiver() {
    
                @Override
    
                public void onReceive(Context context, Intent intent) {
    
                    mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
    
                }
    
            }, new IntentFilter(ACTION_POLL));
    

    注册一个接受者,触发会回给Handler 发送EVENT_POLL_NETWORK_TIME

连接系统和应用的纽带SettingsObeserver

在内容观察者中,会监听AUTO_TIME 的变化。如果应用程序,改变了,就会执行相应的方法。


/** Observer to watch for changes to the AUTO_TIME setting */
private static class SettingsObserver extends ContentObserver {



    private int mMsg;

    private Handler mHandler;



    SettingsObserver(Handler handler, int msg) {

        super(handler);

        mHandler = handler;

        mMsg = msg;

    }



    void observe(Context context) {

        ContentResolver resolver = context.getContentResolver();

       //此时监听AUTO_TIME的改变。 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),

                false, this);

    }



    @Override

    public void onChange(boolean selfChange) {

        mHandler.obtainMessage(mMsg).sendToTarget();

    }

}

应用部分

应用部分的典型实例是Settings设置中 日期和时间的设定

Setting中网络自动更新时间

  • DataTieSettings.java中 加载布局和初始化UI

 public void onCreate(Bundle icicle) {

  super.onCreate(icicle);

 addPreferencesFromResource(R.xml.date_time_prefs);

  initUI();
  • 在onSharedPreferenceChanged 中会判断选择的是网络还是gps类型。并设置Settings数据库。

  • -

 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {

        if (key.equals(KEY_AUTO_TIME)) {

            String value = mAutoTimePref.getValue();

            int index = mAutoTimePref.findIndexOfValue(value);

            mAutoTimePref.setSummary(value);

            boolean autoEnabled = true;

            if (index == AUTO_TIME_NETWORK_INDEX) {

                Settings.Global.putInt(getContentResolver(),

                        Settings.Global.AUTO_TIME, 1);

                Settings.Global.putInt(getContentResolver(),

                        Settings.System.AUTO_TIME_GPS, 0);

            } else if (index == AUTO_TIME_GPS_INDEX) {

                showDialog(DIALOG_GPS_CONFIRM);

                setOnCancelListener(this);

            } else {

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

                Settings.Global.putInt(getContentResolver(), Settings.System.AUTO_TIME_GPS, 0);

                autoEnabled = false;

            }

            mTimePref.setEnabled(!autoEnabled);

            mDatePref.setEnabled(!autoEnabled);

        } else if (key.equals(KEY_AUTO_TIME_ZONE)) {

            boolean autoZoneEnabled = preferences.getBoolean(key, true);

            Settings.Global.putInt(

                    getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0);

            mTimeZone.setEnabled(!autoZoneEnabled);

        }

    }

总结

  • 应用程序Settings通过选择不同的方式更新系统的时间的同时,会设置Settings.Global.AUTO_TIME的数值

  • 系统中SettingsObserver如果监测到Settings.Global.AUTO_TIME 发生变化,会通过handler发送信息给处理时间的线程

  • 处理时间的线程会从moderm、gps、网络中选择相应的方式进行更新时间。

  • 网络更新时间的方式会从NetworkTimeUpdateService中SERVERLIST所示的服务器列表中获得时间。

  • 触发时间更新操作的情况

    • moderm提供的时间,在网络更新中的优先级最高

    • AlarmManager 触发的更新。即设定每10天更新一次网络

    • ContentObserver auto_time引起的时间更新,和用户的操作有关

    • 网络变化引起的更新。即开启网络引起的更新

    • MTK增加的GPS 更新方式

系统调用时序图

android源码分析之网络更新时间_第1张图片

问题

  • 1.android手机和服务器之间的通信,是通过什么样的方式

    • 通过DatagramSocket的方式,进行通信的
    1. 4个服务器,为什么有时都无数据返回

      • DatagramSocket是一种UDP。是一种面向无连接的通信方式

参考文献

  • Android 时间更新机制之网络更新时间

  • Android 时间更新机制之RIL更新时间

  • Android 时间同步原理分析

  • NITZ协议

  • telephony

  • The Radio Interface Layer (RIL)

  • Android 系统时间更新机制

其他

  • SystemClock.elapsedRealtime() 开机运行的时间,包括深度睡眠的时间

  • final long currentTime = System.currentTimeMillis(); 当前系统的时间,


你可能感兴趣的:(android,framework,android源码分析与笔记)