android自動更新時間時區機制

名詞解釋:

NITZ:NITZ(Network Identity and Time Zone)或網絡標識和時區,是一種用於自動配置本地的時間和日期的機制,同時也通過無線網向移動設備提供運營商信息。NITZ是自從PHASE 2+ RELEASE 96 的GSM中的可選功能,經常被用來自動更新移動電話的系統時鐘。

NTP:NTP(Network Time Protocol)提供準確時間,首先要有準確的時間來源,這一時間應該是國際標準時間UTC。 NTP獲得UTC的時間來源可以是原子鐘、天文臺、衛星,也可以從Internet上獲取。這樣就有了準確而可靠的時間源。時間按NTP服務器的等級傳 播。

基於Android5.0源碼:
勾選"自動確定日期和時間"
代碼路徑:packages/apps/Settings/src/com/android/settings/DateTimeSettings.Java
 @Override
 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
     if (key.equals(KEY_DATE_FORMAT)) {
         String format = preferences.getString(key,
                 getResources().getString(R.string.default_date_format));
         Settings.System.putString(getContentResolver(),
                 Settings.System.DATE_FORMAT, format);
        mChangeTime=true;
         updateTimeAndDateDisplay(getActivity());
     } else if (key.equals(KEY_AUTO_TIME)) {
         boolean autoEnabled = preferences.getBoolean(key, true);
         Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME,
                 autoEnabled ? 1 : 0);
         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);
     }
 }
當按鍵KEY_AUTO_TIME和KEY_AUTO_TIME_ZONE觸發時:
    1.設置Settings.Global.AUTO_TIME的值
    2.設置設置時間,日期的enable狀態
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
對Key值的改變進行了監聽
/** 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();
        resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
                false, this);
    }
    @Override
    public void onChange(boolean selfChange) {
        mHandler.obtainMessage(mMsg).sendToTarget();
    }
}
handler收到消息之後調用onPollNetworkTime,不管是移動數據和wifi環境下都會調該方法
@Override
public void handleMessage(Message msg) {
    switch (msg.what) {
        case EVENT_AUTO_TIME_CHANGED:
        case EVENT_POLL_NETWORK_TIME:
        case EVENT_NETWORK_CONNECTED:
            onPollNetworkTime(msg.what);
            break;
    }
}
首先,如果沒有勾選"自動更新.."直接return,其次,如果更新的NITZ時間不爲NOT_SET(-1),且更新間隔小於mPollingIntervalMs,mPollingIntervalMs=24小時,那麼就直接更新NITZ的時間,否則用NTP同步時間,如果服務器獲取的NTP時間小於Integer.MAX_VALUE,才設置當前獲取的NTP時間,否則需要更新時間.
private void onPollNetworkTime(int event) {
    // If Automatic time is not set, don't bother.
    if (!isAutomaticTimeRequested()) return;

    final long refTime = SystemClock.elapsedRealtime();
    // If NITZ time was received less than mPollingIntervalMs time ago,
    // no need to sync to NTP.
    if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
        resetAlarm(mPollingIntervalMs);
        return;
    }
    final long currentTime = System.currentTimeMillis();
    if (DBG) Log.d(TAG, "System time = " + currentTime);
    // Get the NTP time
    if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
            || event == EVENT_AUTO_TIME_CHANGED) {
        if (DBG) Log.d(TAG, "Before Ntp fetch");

        // force refresh NTP cache when outdated
        if (mTime.getCacheAge() >= mPollingIntervalMs) {
            mTime.forceRefresh();
        }
        // only update when NTP time is fresh
        if (mTime.getCacheAge() < mPollingIntervalMs) {
            final long ntp = mTime.currentTimeMillis();
            mTryAgainCounter = 0;
            // If the clock is more than N seconds off or this is the first time it's been
            // fetched since boot, set the current time.
            if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
                    || mLastNtpFetchTime == NOT_SET) {
                // Set the system time
                if (DBG && mLastNtpFetchTime == NOT_SET
                        && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
                    Log.d(TAG, "For initial setup, rtc = " + currentTime);
                }
                if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);
                // Make sure we don't overflow, since it's going to be converted to an int
                if (ntp / 1000 < Integer.MAX_VALUE) {
                    SystemClock.setCurrentTimeMillis(ntp);
                }
            } else {
                if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
            }
            mLastNtpFetchTime = SystemClock.elapsedRealtime();
        } else {
            // Try again shortly
            mTryAgainCounter++;
            if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
                resetAlarm(0);
                Log.d("ansen","2");
            } else {
                // Try much later
                mTryAgainCounter = 0;
                resetAlarm(0);
                Log.d("ansen","3");
            }
            return;
        }
    }
    Log.d("ansen","1");
    resetAlarm(0);
}
執行一個定時任務,定時 定時發送廣播更新時間 NetworkTimeUpdateService.ACTION_POLL
/**
 * Cancel old alarm and starts a new one for the specified interval.
 * @param interval when to trigger the alarm, starting from now.
 */
private void resetAlarm(long interval) {
    mAlarmManager.cancel(mPendingPollIntent);
    long now = SystemClock.elapsedRealtime();
    long next = now + interval;
    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
時間同步機制:
當自動更新選項沒有選中,直接返回,
當NITZ已同步,並且上次同步的時間不超過24小時,則設置定時器24小時之後同步
當NTP上次成功同步超過24小時或用戶勾選自動同步選項,則進行下面的NTP同步,否則同上設置定時器24小時後再觸發同步;
當上次NTP成功同步超過24小時,則發起同步mTime.forceRefresh();
當同步成功,獲取此刻NTP時間ntp=mTime.currentTimeMillis();
當同步時間與當前本機時間誤差超過指定值閥值,則把ntp設置爲本機時間SystemClock.setCurrentTimeMillis(ntp)






發佈了78 篇原創文章 · 獲贊 157 · 訪問量 46萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章