1. 程式人生 > >Android中的網路時間同步

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.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,但它們都沒有去設定系統時間。