zoukankan      html  css  js  c++  java
  • Android中的网络时间同步

    在 Android的系统设置中,有自动同步网络时间的选项。因为Broncho A1移植到froyo版本之后,我们发现时间同步选项无效了。所以我花了一点时间去研究 Android的网络时间同步的流程。研究的结果让我感到惊讶,Android的网络时间同步居然与SNTP协议无关,甚至与TCP/IP协议也毫无关系。

    从设置的应用程序中可以了解到,自动同步网络时间的选项只是修改了Settings.System.AUTO_TIME这个设置:

    private void setAutoState(boolean isEnabled, boolean autotimeStatus) {
           if (isEnabled == false) {
               mAutoPref.setChecked(autotimeStatus);
               mAutoPref.setEnabled(isEnabled);
           }
           else {
               Settings.System.putInt(getContentResolver(),
                  Settings.System.AUTO_TIME, autotimeStatus ? 1 : 0);
           }
           mTimePref.setEnabled(!autotimeStatus);
           mDatePref.setEnabled(!autotimeStatus);
           mTimeZone.setEnabled(!autotimeStatus);
        }
    

    谁会用这个设置呢?然后从代码中查找Settings.System.AUTO_TIME,主要有下面两处:

    telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
    telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
    

    GSM和CDMA的实现应该是类似的,这里只是看看GSM: 1. reference-ril/reference-ril.c处理主动上报消息。

        if (strStartsWith(s, "%CTZV:")) {
            /* TI specific -- NITZ time */
            char *response;
    
            line = p = strdup(s);
            at_tok_start(&p);
    
            err = at_tok_nextstr(&p, &response);
    
            free(line);
            if (err != 0) {
                LOGE("invalid NITZ line %s/n", s);
            } else {
                RIL_onUnsolicitedResponse (
                    RIL_UNSOL_NITZ_TIME_RECEIVED,
                    response, strlen(response));
            }
    }
    
    这里是处理模组主动上报的消息,如果是时间和时区消息,则调用RIL_onUnsolicitedResponse。
    
    2.	RIL_onUnsolicitedResponse会把消息发送给RIL的客户端。
    
    ret = sendResponse(p, client_id);
    
    时间和时区信息的格式在RIL_UNSOL_NITZ_TIME_RECEIVED消息的定义处有说明: "data" is const char * pointing to NITZ time string in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt" 3. RIL客户端处理RIL_UNSOL_NITZ_TIME_RECEIVED消息(telephony/java/com/android/internal/telephony/RIL.java: processUnsolicited)
                case RIL_UNSOL_NITZ_TIME_RECEIVED:
                    if (RILJ_LOGD) unsljLogRet(response, ret);
    
                    // has bonus long containing milliseconds since boot that the NITZ
                    // time was received
                    long nitzReceiveTime = p.readLong();
    
                    Object[] result = new Object[2];
    
                    result[0] = ret;
                    result[1] = Long.valueOf(nitzReceiveTime);
    
                    if (mNITZTimeRegistrant != null) {
    
                        mNITZTimeRegistrant
                            .notifyRegistrant(new AsyncResult (null, result, null));
                    } else {
                        // in case NITZ time registrant isnt registered yet
                        mLastNITZTimeInfo = result;
                    }
    
    是GsmServiceStateTracker向RIL注册的,所以事件会由GsmServiceStateTracker来处理。 4. GsmServiceStateTracker 处理EVENT_NITZ_TIME事件:
                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);
                    break;
    
    这里nitzString是时间字符串,由setTimeFromNITZString负责解析。
    private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
                String[] nitzSubs = nitz.split("[/:,+-]");
    
                int year = 2000 + Integer.parseInt(nitzSubs[0]);
                c.set(Calendar.YEAR, year);
    
                // month is 0 based!
                int month = Integer.parseInt(nitzSubs[1]) - 1;
                c.set(Calendar.MONTH, month);
    
                int date = Integer.parseInt(nitzSubs[2]);
                c.set(Calendar.DATE, date);
    
                int hour = Integer.parseInt(nitzSubs[3]);
                c.set(Calendar.HOUR, hour);
    
                int minute = Integer.parseInt(nitzSubs[4]);
                c.set(Calendar.MINUTE, minute);
    
    如果在系统设置中,用户选择了自动同步网络时间,才会去设置系统时间。
               if (getAutoTime()) {
                   setAndBroadcastNetworkSetTimeZone(zone.getID());
               }
               if (getAutoTime()) {
    setAndBroadcastNetworkSetTime(c.getTimeInMillis());
               }
    
    关于NITZ在WIKI上有说明: NITZ, or Network Identity and Time Zone[1], is a mechanism for provisioning local time and date, as well as network provider identity information to mobile devices via a wireless network[2]. NITZ has been part of the official GSM standard since phase 2+ release 96[3]. NITZ is often used to automatically update the system clock of mobile phones. 由于NITZ的实现是可选的,如果运营商不支持它,Android手机就无法使用此功能了。此时用最好用SNTP来代替,否则用户会感到迷惑。但Android目前好像并没有这样做,我只找到两处地方调用SntpClient,但它们都没有去设置系统时间。
  • 相关阅读:
    MyEclipse 中引用包的快捷键
    php中函数 isset(), empty(), is_null() 的区别
    Mysql sql_mode设置 timestamp default 00000000 00:00:00 创建表失败处理
    20190729 将博客搬至CSDN
    Python网络爬虫精要
    PhpStorm 头部注释、类注释和函数注释的设置
    asp.net 将内容导出EXCEL文件(转)
    C#中用GDI+生成饼状图和柱状图
    企业级架构、开发在软件中的定义
    C#中的装箱与拆箱的概念
  • 原文地址:https://www.cnblogs.com/zhangyunlin/p/6167385.html
Copyright © 2011-2022 走看看