在 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.javatelephony/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,但它们都没有去设置系统时间。

回复:

1.国内的运营商,网络不会下发数据,所以不支持,可以增加一段,如果NITZ获取不到数据的话,使用SNTP去处理。、

2.要看具体你的硬件3G模块是否支持获取时间等命令了,有些模块有CCLK的AT指令,就是用来获取时间的,如果模块支持,那么上层就可以通过这样的指令来获取时间,然后解析出来,广播给APP


更多相关文章

  1. Android网络编程之Http通信
  2. Android随笔之——Android时间、日期相关类和方法
  3. Android网络相关---上网流程
  4. android网络连接使用GET方式请求服务器时的setDoOutput(true)惹
  5. Android Studio--Android中的消息机制
  6. android 判断网络是否可用,并调用系统设置项

随机推荐

  1. Android专家/经理——北京招聘
  2. Mono for Android试用体验
  3. Android中Spinner的使用
  4. Android多媒体学习一:Android中Image的简
  5. Android中的通知—Notification
  6. Android工程源文件结构
  7. Android(安卓)- Handler 、AsyncTask(一)
  8. android控件的属性
  9. Android(安卓)Resource
  10. Android中执行java命令的方法及java代码