Android中的网络时间同步 续

在通过android平台通过api Settings相关的接口设置时间的自动同步处理后,device上的时间并没有与网络上的某个服务器进行时间的同步处理。这个使用已插入有效sim卡 wcdma网络可以用的samsung i9000就可以验证出来。但是对于htc saga device,如果是自定的程序通过Settings去设置,时间同步是失效的,而通过device中的setting功能设置,时间同步有效。仔细查看 系统的log信息可以发现,device的setting在设置时间的自动同步标志值后会发送一个action为 com.htc.app.autosetting.location的broadcast,通过component com.htc.htclocationservice/.AutoSettingReceiver进行处理。处理的流程未进行跟踪:(

 

查询了相关资料,发现后续文章的内容帮助解答了一些疑惑。(此文仅用于备忘)

 

后续文章内容是基于http://blog.csdn.net/absurd/archive/2011/01/09/6125588.aspx的一个整理

Android的网络时间同步与SNTP协议无关,甚至与TCP/IP协议也毫无关系。

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

Java代码  收藏代码
  1. private void setAutoState(boolean isEnabled, boolean autotimeStatus) {  
  2.        if (isEnabled == false) {  
  3.            mAutoPref.setChecked(autotimeStatus);  
  4.            mAutoPref.setEnabled(isEnabled);  
  5.        }  
  6.        else {  
  7.            Settings.System.putInt(getContentResolver(),  
  8.               Settings.System.AUTO_TIME, autotimeStatus ? 1 : 0);  
  9.        }  
  10.        mTimePref.setEnabled(!autotimeStatus);  
  11.        mDatePref.setEnabled(!autotimeStatus);  
  12.        mTimeZone.setEnabled(!autotimeStatus);  
  13.     }  

 

       从代码中查找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处理主动上报消息。 
    

Java代码  收藏代码
  1. if (strStartsWith(s, "%CTZV:")) {  
  2.         /* TI specific -- NITZ time */  
  3.         char *response;  
  4.   
  5.         line = p = strdup(s);  
  6.         at_tok_start(&p);  
  7.   
  8.         err = at_tok_nextstr(&p, &response);  
  9.   
  10.         free(line);  
  11.         if (err != 0) {  
  12.             LOGE("invalid NITZ line %s\n", s);  
  13.         } else {  
  14.             RIL_onUnsolicitedResponse (  
  15.                 RIL_UNSOL_NITZ_TIME_RECEIVED,  
  16.                 response, strlen(response));  
  17.         }  
  18. }  

 
       这里是处理模组主动上报的消息,如果是时间和时区消息,则调用RIL_onUnsolicitedResponse。

       2. RIL_onUnsolicitedResponse会把消息发送给RIL的客户端。
       

Java代码  收藏代码
  1. 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)
            

Java代码  收藏代码
  1. case RIL_UNSOL_NITZ_TIME_RECEIVED:  
  2.                 if (RILJ_LOGD) unsljLogRet(response, ret);  
  3.   
  4.                 // has bonus long containing milliseconds since boot that the NITZ  
  5.                 // time was received  
  6.                 long nitzReceiveTime = p.readLong();  
  7.   
  8.                 Object[] result = new Object[2];  
  9.   
  10.                 result[0] = ret;  
  11.                 result[1] = Long.valueOf(nitzReceiveTime);  
  12.   
  13.                 if (mNITZTimeRegistrant != null) {  
  14.   
  15.                     mNITZTimeRegistrant  
  16.                         .notifyRegistrant(new AsyncResult (null, result, null));  
  17.                 } else {  
  18.                     // in case NITZ time registrant isnt registered yet  
  19.                     mLastNITZTimeInfo = result;  
  20.                 }  

 
       是GsmServiceStateTracker向RIL注册的,所以事件会由GsmServiceStateTracker来处理。

       4. GsmServiceStateTracker 处理EVENT_NITZ_TIME事件:
            

Java代码  收藏代码
  1. case EVENT_NITZ_TIME:  
  2.                 ar = (AsyncResult) msg.obj;  
  3.                 String nitzString = (String)((Object[])ar.result)[0];  
  4.                 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();  
  5.                 setTimeFromNITZString(nitzString, nitzReceiveTime);  
  6.                 break;  

 
       这里nitzString是时间字符串,由setTimeFromNITZString负责解析。

Java代码  收藏代码
  1. private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {  
  2.             String[] nitzSubs = nitz.split("[/:,+-]");  
  3.   
  4.             int year = 2000 + Integer.parseInt(nitzSubs[0]);  
  5.             c.set(Calendar.YEAR, year);  
  6.   
  7.             // month is 0 based!  
  8.             int month = Integer.parseInt(nitzSubs[1]) - 1;  
  9.             c.set(Calendar.MONTH, month);  
  10.   
  11.             int date = Integer.parseInt(nitzSubs[2]);  
  12.             c.set(Calendar.DATE, date);  
  13.   
  14.             int hour = Integer.parseInt(nitzSubs[3]);  
  15.             c.set(Calendar.HOUR, hour);  
  16.   
  17.             int minute = Integer.parseInt(nitzSubs[4]);  
  18.             c.set(Calendar.MINUTE, minute);  

 
       如果在系统设置中,用户选择了自动同步网络时间,才会去设置系统时间。
          

Java代码  收藏代码
  1. if (getAutoTime()) {  
  2.                setAndBroadcastNetworkSetTimeZone(zone.getID());  
  3.            }  
  4.            if (getAutoTime()) {  
  5. setAndBroadcastNetworkSetTime(c.getTimeInMillis());  
  6.            }  

 

关于NITZ在WIKI上有说明,可以参见:http://en.wikipedia.org/wiki/NITZ
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,但它们都没有去设置系统时间。

posted @ 2011-11-12 11:20  一根骨头棒子*熬的汤  阅读(5996)  评论(0)    收藏  举报