现在Android通过网络同步时间有两种方式:NITZ和NTP,它们使用的条件不同,可以获取的信息也不一样;勾选自动同步功能后,手机首先会尝试NITZ方式,若获取时间失败,则使用NTP方式
1.NITZ(network identity and time zone)同步时间
NITZ是一种GSM/WCDMA基地台方式,必须插入SIM卡;可以提供时间和时区信息
2.NTP(network time protocol)同步时间
NTP在无SIM卡或operator不支持NITZ时使用,单纯通过网络(GPRS/WIFI)获取时间,只提供时间信息,没有时区信息(因此在不支持NITZ的地区,自动获取时区功能实际上是无效的)
NTP还有一种缓存机制:当前成功获取的时间会保存下来,当用户下次开启自动更新时间功能时会结合手机clock来进行时间更新。这也是没有任何网络时手机却能自动更新时间的原因。
SIM卡上报信息,运营商提供时区信息和时间信息给终端更新
流程图:
需要com.android.phone进程启动当android.intent.action.BOOT_COMPLETED广播发出来时,com.android.phone进程就会启动,同时调用Application的onCreate,com.android.phone进程的Application类是PhoneApp.java如下:
/packages/services/Telephony/src/com/android/phone/PhoneApp.java
35 @Override
36 public void onCreate() {
37 if (UserHandle.myUserId() == 0) {
38 // We are running as the primary user, so should bring up the
39 // global phone state.
40 mPhoneGlobals = new PhoneGlobals(this);
41 mPhoneGlobals.onCreate();
42
43 mTelephonyGlobals = new TelephonyGlobals(this);
44 mTelephonyGlobals.onCreate();
45 }
46 }
可以看到onCreate初始化了两个全局类PhoneGlobals和TelephonyGlobals并调用其onCreate函数,时间的自动更新则是在PhoneGlobals的onCreate中完成的
/packages/services/Telephony/src/com/android/phone/PhoneGlobals.java
269 public void onCreate() {
270 if (VDBG) Log.v(LOG_TAG, "onCreate()...");
...
284 if (mCM == null) {
285 // Initialize the telephony framework
286 PhoneFactory.makeDefaultPhones(this);
...
}
/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java
102 /**
103 * FIXME replace this with some other way of making these
104 * instances
105 */
106 public static void makeDefaultPhone(Context context) {
107 synchronized (sLockProxyPhones) {
108
142
143 /* In case of multi SIM mode two instances of Phone, RIL are created,
144 where as in single SIM mode only instance. isMultiSimEnabled() function checks
145 whether it is single SIM or multi SIM mode */
//获取sim卡的个数
146 int numPhones = TelephonyManager.getDefault().getPhoneCount();
159 ....
160 int[] networkModes = new int[numPhones];
161 sPhones = new Phone[numPhones];
162 sCommandsInterfaces = new RIL[numPhones];
163 sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
164
165 for (int i = 0; i < numPhones; i++) {
166 // reads the system properties and makes commandsinterface
167 // Get preferred network type.
168 networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;
169
170 Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
171 sCommandsInterfaces[i] = new RIL(context, networkModes[i],
172 cdmaSubscription, i);
173 }
...
187 for (int i = 0; i < numPhones; i++) {
188 Phone phone = null;
189 int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
190 if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
191 phone = new GsmCdmaPhone(context,
192 sCommandsInterfaces[i], sPhoneNotifier, i,
193 PhoneConstants.PHONE_TYPE_GSM,
194 TelephonyComponentFactory.getInstance());
195 } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
196 phone = new GsmCdmaPhone(context,
197 sCommandsInterfaces[i], sPhoneNotifier, i,
198 PhoneConstants.PHONE_TYPE_CDMA_LTE,
199 TelephonyComponentFactory.getInstance());
200 }
201 Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);
202
203 sPhones[i] = phone;
204 }
205
206 ....
263 }
264 }
265 }
上面这个函数会根据sim卡的个数去创建RIL实例,RIL实例的主要作用是和halsevice 建立联系并设置一些回调给halservice [email protected] 其实现为ril_service.cpp。接着以RIL实例为参数创建了GsmCdmaPhone主要是为了绑定处理hal层传过来的时间和时区信息的函数。下面分别看这两步的具体细节:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
445 public RIL(Context context, int preferredNetworkType,
446 int cdmaSubscription, Integer instanceId) {
447 super(context);
462
463 mRadioResponse = new RadioResponse(this);
464 mRadioIndication = new RadioIndication(this);
485
486 // set radio callback; needed to set RadioIndication callback (should be done after
487 // wakelock stuff is initialized above as callbacks are received on separate binder threads)
488 getRadioProxy(null);
489 ...
490 }
351 /** Returns a {@link IRadio} instance or null if the service is not available. */
352 @VisibleForTesting
353 public IRadio getRadioProxy(Message result) {
354 if (!mIsMobileNetworkSupported) {
355 //不支持手机移动网络
362 }
363
364 if (mRadioProxy != null) {
365 return mRadioProxy;
366 }
367
368 try {
369 mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId],
370 true);
371 if (mRadioProxy != null) {
372 mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
373 mRadioProxyCookie.incrementAndGet());
//将RIL实例化时的RadioResponse实例和RadioIndication实例设置给hal service
374 mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
375 } else {
376 riljLoge("getRadioProxy: mRadioProxy == null");
377 }
378 } catch (RemoteException | RuntimeException e) {
379 mRadioProxy = null;
380 riljLoge("RadioProxy getService/setResponseFunctions: " + e);
381 }
...
393 return mRadioProxy;
394 }
之前说过RIL获取的hal Service的实现是ril_service.cpp所以会调用到ril_service的setResponseFunctions:
/hardware/ril/libril/ril_service.cpp
790Return RadioImpl::setResponseFunctions(
791 const ::android::sp& radioResponseParam,
792 const ::android::sp& radioIndicationParam) {
793 RLOGD("setResponseFunctions");
794
795 pthread_rwlock_t *radioServiceRwlockPtr = radio::getRadioServiceRwlock(mSlotId);
796 int ret = pthread_rwlock_wrlock(radioServiceRwlockPtr);
797 assert(ret == 0);
798 //将java层的RadioResponse实例和RadioIndication实例转换成c++层的实例
799 mRadioResponse = radioResponseParam;
800 mRadioIndication = radioIndicationParam;
801 mRadioResponseV1_1 = V1_1::IRadioResponse::castFrom(mRadioResponse).withDefault(nullptr);
802 mRadioIndicationV1_1 = V1_1::IRadioIndication::castFrom(mRadioIndication).withDefault(nullptr);
803 if (mRadioResponseV1_1 == nullptr || mRadioIndicationV1_1 == nullptr) {
804 mRadioResponseV1_1 = nullptr;
805 mRadioIndicationV1_1 = nullptr;
806 }
807 //mSlotId ++
808 mCounterRadio[mSlotId]++;
809
812
813 // client is connected. Send initial indications.
814 android::onNewCommandConnect((RIL_SOCKET_ID) mSlotId);
815
816 return Void();
817}
[email protected] 这个halService 在启动时会设置一些回应函数其对应关系在ril_unsol_commands.h中其中运营商发送的时间和时区的repose是RIL_UNSOL_NITZ_TIME_RECEIVED,对应的函数则是radio::nitzTimeReceivedInd,
/hardware/ril/libril/ril_unsol_commands.h
{RIL_UNSOL_NITZ_TIME_RECEIVED, radio::nitzTimeReceivedInd, WAKE_PARTIAL},
当hal servce接受到某些回应时会调用到下面这个函数: RIL_onUnsolicitedResponse:
/hardware/ril/libril/ril.cpp
722#if defined(ANDROID_MULTI_SIM)
723extern "C"
724void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
725 size_t datalen, RIL_SOCKET_ID socket_id)
726#else
727extern "C"
728void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
729 size_t datalen)
730#endif
731{
732 int unsolResponseIndex;
733 int ret;
//根据回应码确定在ril_unsol_commands.h的位置
748 unsolResponseIndex = unsolResponse - RIL_UNSOL_RESPONSE_BASE;
749
750 if ((unsolResponseIndex < 0)
751 || (unsolResponseIndex >= (int32_t)NUM_ELEMS(s_unsolResponses))) {
752 RLOGE("unsupported unsolicited response code %d", unsolResponse);
753 return;
754 }
755
756 // Grab a wake lock if needed for this reponse,
757 // as we exit we'll either release it immediately
758 // or set a timer to release it later.
759 switch (s_unsolResponses[unsolResponseIndex].wakeType) {
760 case WAKE_PARTIAL:
761 grabPartialWakeLock();
762 shouldScheduleTimeout = true;
763 break;
764
765 case DONT_WAKE:
766 default:
767 // No wake lock is grabed so don't set timeout
768 shouldScheduleTimeout = false;
769 break;
770 }
771
772 appendPrintBuf("[UNSL]< %s", requestToString(unsolResponse));
773
784
785 if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
786 // get a write lock in caes of NITZ since setNitzTimeReceived() is called
787 rwlockRet = pthread_rwlock_wrlock(radioServiceRwlockPtr);
788 assert(rwlockRet == 0);
//设置当前的运行时间
789 radio::setNitzTimeReceived((int) soc_id, android::elapsedRealtime());
790 } else {
791 rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
792 assert(rwlockRet == 0);
793 }
794 //调用radio::nitzTimeReceivedInd处理RIL_UNSOL_NITZ_TIME_RECEIVED
795 ret = s_unsolResponses[unsolResponseIndex].responseFunction(
796 (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast(data),
797 datalen);
....
817 }
/hardware/ril/libril/ril_service.cpp
8550void radio::setNitzTimeReceived(int slotId, long timeReceived) {
8551 nitzTimeReceived[slotId] = timeReceived;
8552}
6983int radio::nitzTimeReceivedInd(int slotId,
6984 int indicationType, int token, RIL_Errno e, void *response,
6985 size_t responseLen) {
6986 if (radioService[slotId] != NULL && radioService[slotId]->mRadioIndication != NULL) {
6987 if (response == NULL || responseLen == 0) {
6988 RLOGE("nitzTimeReceivedInd: invalid response");
6989 return 0;
6990 }
6991 hidl_string nitzTime = convertCharPtrToHidlString((char *) response);
6992#if VDBG
6993 RLOGD("nitzTimeReceivedInd: nitzTime %s receivedTime %" PRId64, nitzTime.c_str(),
6994 nitzTimeReceived[slotId]);
6995#endif
//回调到java层的RadioIndication的nitzTimeReceived函数中 其中nitzTime为运营商返回的时间和时区信息nitzTimeReceived则是系统运行的时长
6996 Return retStatus = radioService[slotId]->mRadioIndication->nitzTimeReceived(
6997 convertIntToRadioIndicationType(indicationType), nitzTime,
6998 nitzTimeReceived[slotId]);
6999 radioService[slotId]->checkReturnStatus(retStatus);
7000 } else {
7001 RLOGE("nitzTimeReceivedInd: radioService[%d]->mRadioIndication == NULL", slotId);
7002 return -1;
7003 }
7004
7005 return 0;
7006}
所以整个流程的关键就是RIL实例在初始化时会设置回调给hal Service以便于在hal service 接收到运营商的时间和时区信息时能回传到Java层用来处理并设置系统的时间和时区。而这个处理时间和时区信息的回调函数就是RadioIndication的 nitzTimeReceived函数。
/frameworks/opt/telephony/src/java/com/android/internal/telephony/RadioIndication.java
202 public void nitzTimeReceived(int indicationType, String nitzTime, long receivedTime) {
203 mRil.processIndication(indicationType);
204
205 if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NITZ_TIME_RECEIVED, nitzTime);
206 //将从native层得到的时间时区信息和得到时间时区信息时系统的运行时间放在一个Object数组
207 // todo: Clean this up with a parcelable class for better self-documentation
208 Object[] result = new Object[2];
209 result[0] = nitzTime;
210 result[1] = receivedTime;
211
212 boolean ignoreNitz = SystemProperties.getBoolean(
213 TelephonyProperties.PROPERTY_IGNORE_NITZ, false);
214
215 if (ignoreNitz) {
216 if (RIL.RILJ_LOGD) mRil.riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
217 } else {
218 if (mRil.mNITZTimeRegistrant != null) {
//调用mRil.mNITZTimeRegistrant.notifyRegistrant处理并设置
219 mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null));
220 }
221 // in case NITZ time registrant isn't registered yet, or a new registrant
222 // registers later
223 mRil.mLastNITZTimeInfo = result;
224 }
225 }
这里的mRil就是ril实例,那mNITZTimeRegistrant是在哪里初始化的呢?需要我们回到运营商在发送时间和时区信息之前,当RIL实例在获取到halservice的远程接口并设置完RadioResponse实例和RadioIndication实例后,RIL的实例化就结束了,这时会走下面的第二步:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java
211 public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
212 boolean unitTestMode, int phoneId, int precisePhoneType,
213 TelephonyComponentFactory telephonyComponentFactory) {
...
//makeServiceStateTracker会创建一个线程handler来处理运营商返回的时间和时区信息
225 mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
...
232 logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
233 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
64 public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
65 return new ServiceStateTracker(phone, ci);
66 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
487 public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
//makeNitzStateMachine会新建一个NitzStateMachine 接着初始化TimeServiceHelper并调用setListener注册数据库监听 第4部分
488 mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone);
489 mPhone = phone;
490 mCi = ci;
491
...
517 // Create a new handler thread dedicated for locale tracker because the blocking
518 // getAllCellInfo call requires clients calling from a different thread.
//开启一个线程
519 mHandlerThread = new HandlerThread(LocaleTracker.class.getSimpleName());
520 mHandlerThread.start();
...
//绑定处理时间和时区信息的处理函数
526 mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
527
...
569 }
从上面的代码我们知道mCi是RIL的实例所以会调用到RIL.java的setOnNITZTime函数:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java
492 @Override
493 public void setOnNITZTime(Handler h, int what, Object obj) {
494 super.setOnNITZTime(h, what, obj);
495 //如果是第一次启动mLastNITZTimeInfo == null
496 // Send the last NITZ time if we have it
497 if (mLastNITZTimeInfo != null) {
498 mNITZTimeRegistrant
499 .notifyRegistrant(
500 new AsyncResult (null, mLastNITZTimeInfo, null));
501 }
502 }
可以看到是调用到父类的setOnNITZTime,RIL.java的父类是BaseCommands.java
/frameworks/opt/telephony/src/java/com/android/internal/telephony/BaseCommands.java
376 @Override
377 public void setOnNITZTime(Handler h, int what, Object obj) {
//what是EVENT_NITZ_TIME h指的是ServiceStateTracker
378 mNITZTimeRegistrant = new Registrant (h, what, obj);
379 }
/frameworks/base/core/java/android/os/Registrant.java
public
28 Registrant(Handler h, int what, Object obj)
29 {
30 refH = new WeakReference(h);
31 this.what = what;
32 userObj = obj;
33 }
这时我们回到RadioIndication的 nitzTimeReceived函数,最后调用的是 mRil.mNITZTimeRegistrant.notifyRegistrant(new AsyncResult (null, result, null));
mNITZTimeRegistrant就是what为EVENT_NITZ_TIME的Registrant,notifyRegistrant如下:
/frameworks/base/core/java/android/os/Registrant.java
48 public void
49 notifyResult(Object result)
50 {
51 internalNotifyRegistrant (result, null);
52 }
69 /*package*/ void
70 internalNotifyRegistrant (Object result, Throwable exception)
71 {
72 Handler h = getHandler();
73
74 if (h == null) {
75 clear();
76 } else {
77 Message msg = Message.obtain();
78
79 msg.what = what;
80
81 msg.obj = new AsyncResult(userObj, result, exception);
82
83 h.sendMessage(msg);
84 }
85 }
所以最后运营商发送的时间和时区的信息会交给ServiceStateTracker这个handler去处理
994 @Override
995 public void handleMessage(Message msg) {
996 AsyncResult ar;
997 int[] ints;
998 Message message;
...
1176 case EVENT_NITZ_TIME:
1177 ar = (AsyncResult) msg.obj;
1178 //从message中取出时间和时区信息
1179 String nitzString = (String)((Object[])ar.result)[0];
1180 long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
1181 //设置时间和时区信息
1182 setTimeFromNITZString(nitzString, nitzReceiveTime);
1183 break;
对于运营商发送的时间和时区信息的处理主要是调用setTimeFromNITZString函数来进行的如下:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
3537 private void setTimeFromNITZString(String nitzString, long nitzReceiveTime) {
//start 当前系统运行的时间
3538 long start = SystemClock.elapsedRealtime();
3539 if (DBG) {
3540 Rlog.d(LOG_TAG, "NITZ: " + nitzString + "," + nitzReceiveTime
3541 + " start=" + start + " delay=" + (start - nitzReceiveTime));
3542 }
//将运营商发送的时区和时间信息转换成NitzData实体类
3543 NitzData newNitzData = NitzData.parse(nitzString);
3544 if (newNitzData != null) {
3545 try {
//再将NitzData和接收到运营商的信息时系统的运行时间组合成TimeStampedValue 最后调用handleNitzReceived进行设置
3546 TimeStampedValue<NitzData> nitzSignal =
3547 new TimeStampedValue<>(newNitzData, nitzReceiveTime);
3548 mNitzState.handleNitzReceived(nitzSignal);
3549 } finally {
3550 if (DBG) {
3551 long end = SystemClock.elapsedRealtime();
3552 Rlog.d(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
3553 }
3554 }
3555 }
3556 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
384 public void handleNitzReceived(TimeStampedValue<NitzData> nitzSignal) {
385 handleTimeZoneFromNitz(nitzSignal);
386 handleTimeFromNitz(nitzSignal);
387 }
接着调用handleTimeZoneFromNitz和handleTimeFromNitz分别处理时间和时区信息。
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
389 private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) {
390 //一系列处理
426 ...
427 String tmpLog = "handleTimeZoneFromNitz: nitzSignal=" + nitzSignal
428 + " zoneId=" + zoneId
429 + " iso=" + iso + " mGotCountryCode=" + mGotCountryCode
430 + " mNeedCountryCodeForNitz=" + mNeedCountryCodeForNitz
431 + " isTimeZoneDetectionEnabled()="
432 + mTimeServiceHelper.isTimeZoneDetectionEnabled();
433 if (DBG) {
434 Rlog.d(LOG_TAG, tmpLog);
435 }
436 mTimeZoneLog.log(tmpLog);
437
438 if (zoneId != null) {
//setting中是否是自动获取时区
439 if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
//设置时间并发送广播
440 setAndBroadcastNetworkSetTimeZone(zoneId);
441 }
442 mNitzTimeZoneDetectionSuccessful = true;
443 mSavedTimeZoneId = zoneId;
444 }
445 } catch (RuntimeException ex) {
446 Rlog.e(LOG_TAG, "handleTimeZoneFromNitz: Processing NITZ data"
447 + " nitzSignal=" + nitzSignal
448 + " ex=" + ex);
449 }
450 }
539 private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
540 if (DBG) {
541 Rlog.d(LOG_TAG, "setAndBroadcastNetworkSetTimeZone: zoneId=" + zoneId);
542 }
543 mTimeServiceHelper.setDeviceTimeZone(zoneId);
544 if (DBG) {
545 Rlog.d(LOG_TAG,
546 "setAndBroadcastNetworkSetTimeZone: called setDeviceTimeZone()"
547 + " zoneId=" + zoneId);
548 }
549 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java
129 public boolean isTimeZoneDetectionEnabled() {
130 try {
131 return Settings.Global.getInt(mCr, Settings.Global.AUTO_TIME_ZONE) > 0;
132 } catch (Settings.SettingNotFoundException snfe) {
133 return true;
134 }
135 }
143 public void setDeviceTimeZone(String zoneId) {
144 setDeviceTimeZoneStatic(mContext, zoneId);
145 }
185 static void setDeviceTimeZoneStatic(Context context, String zoneId) {
186 AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
187 alarmManager.setTimeZone(zoneId);
188 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
189 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
190 intent.putExtra("time-zone", zoneId);
191 context.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
192 }
可以看到最后时区信息被设置到了alarmManager中发送的广播是android.intent.action.NETWORK_SET_TIMEZONE
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
457 private void handleTimeFromNitz(TimeStampedValue<NitzData> nitzSignal) {
458 try {
459 boolean ignoreNitz = mDeviceState.getIgnoreNitz();
460 if (ignoreNitz) {
461 Rlog.d(LOG_TAG,
462 "handleTimeFromNitz: Not setting clock because gsm.ignore-nitz is set");
463 return;
464 }
465
466 try {
467 // Acquire the wake lock as we are reading the elapsed realtime clock and system
468 // clock.
469 mWakeLock.acquire();
470
471 // Validate the nitzTimeSignal to reject obviously bogus elapsedRealtime values.
472 long elapsedRealtime = mTimeServiceHelper.elapsedRealtime();
//1. 计算从halservice接收到运营商的消息到现在系统经过的时间
473 long millisSinceNitzReceived = elapsedRealtime - nitzSignal.mElapsedRealtime;
474 if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) {
475 //边界处理
480 return;
481 }
482
483 // Adjust the NITZ time by the delay since it was received to get the time now.
//2.计算当前的绝对时间
484 long adjustedCurrentTimeMillis =
485 nitzSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived;
//3.计算网络时间和系统时间的差值
486 long gained = adjustedCurrentTimeMillis - mTimeServiceHelper.currentTimeMillis();
487
488 if (mTimeServiceHelper.isTimeDetectionEnabled()) {
489 String logMsg = "handleTimeFromNitz:"
490 + " nitzSignal=" + nitzSignal
491 + " adjustedCurrentTimeMillis=" + adjustedCurrentTimeMillis
492 + " millisSinceNitzReceived= " + millisSinceNitzReceived
493 + " gained=" + gained;
494 //如果是第一次更新时间
495 if (mSavedNitzTime == null) {
496 logMsg += ": First update received.";
//设置时间并发送过广播
497 setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis);
498 } else {
//计算从上次保存到现在的系统的运行时间
499 long elapsedRealtimeSinceLastSaved = mTimeServiceHelper.elapsedRealtime()
500 - mSavedNitzTime.mElapsedRealtime;
501 int nitzUpdateSpacing = mDeviceState.getNitzUpdateSpacingMillis();
502 int nitzUpdateDiff = mDeviceState.getNitzUpdateDiffMillis();
503 if (elapsedRealtimeSinceLastSaved > nitzUpdateSpacing
504 || Math.abs(gained) > nitzUpdateDiff) {
505 // Either it has been a while since we received an update, or the gain
506 // is sufficiently large that we want to act on it.
507 logMsg += ": New update received.";
508 setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis);
509 } else {
510 if (DBG) {
511 Rlog.d(LOG_TAG, logMsg + ": Update throttled.");
512 }
513
514 // Return early. This means that we don't reset the
515 // mSavedNitzTime for next time and that we may act on more
516 // NITZ time signals overall but should end up with a system clock that
517 // tracks NITZ more closely than if we saved throttled values (which
518 // would reset mSavedNitzTime.elapsedRealtime used to calculate time
519 // since the last NITZ signal was received).
520 return;
521 }
522 }
523 }
524 //保存当前的时间信息和系统运行的时间信息
525 // Save the last NITZ time signal used so we can return to it later
526 // if auto-time detection is toggled.
527 mSavedNitzTime = new TimeStampedValue<>(
528 adjustedCurrentTimeMillis, nitzSignal.mElapsedRealtime);
529 } finally {
530 mWakeLock.release();
531 }
532 } catch (RuntimeException ex) {
533 Rlog.e(LOG_TAG, "handleTimeFromNitz: Processing NITZ data"
534 + " nitzSignal=" + nitzSignal
535 + " ex=" + ex);
536 }
537 }
551 private void setAndBroadcastNetworkSetTime(String msg, long time) {
552 if (!mWakeLock.isHeld()) {
553 Rlog.w(LOG_TAG, "setAndBroadcastNetworkSetTime: Wake lock not held while setting device"
554 + " time (msg=" + msg + ")");
555 }
556
557 msg = "setAndBroadcastNetworkSetTime: [Setting time to time=" + time + "]:" + msg;
558 if (DBG) {
559 Rlog.d(LOG_TAG, msg);
560 }
561 mTimeLog.log(msg);
562 mTimeServiceHelper.setDeviceTime(time);
563 TelephonyMetrics.getInstance().writeNITZEvent(mPhone.getPhoneId(), time);
564 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java
153 public void setDeviceTime(long time) {
154 SystemClock.setCurrentTimeMillis(time);
155 Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
156 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
157 intent.putExtra("time", time);
158 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
159 }
/frameworks/base/core/java/android/os/SystemClock.java
149 public static boolean setCurrentTimeMillis(long millis) {
150 final IAlarmManager mgr = IAlarmManager.Stub
151 .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
152 if (mgr == null) {
153 return false;
154 }
155
156 try {
157 return mgr.setTime(millis);
158 } catch (RemoteException e) {
159 Slog.e(TAG, "Unable to set RTC", e);
160 } catch (SecurityException e) {
161 Slog.e(TAG, "Unable to set RTC", e);
162 }
163
164 return false;
165 }
可以看到最终是将时间设置到了SystemClock中,最终其实也是设置给了AlarmManagerService中。
Setting中开关会改变Setting数据库中Settings.Global.AUTO_TIME_ZONE和Settings.Global.AUTO_TIME_ZONE的值,而在第二阶段中创建处理handler ServiceStateTracker时,会注册一个数据库监听,如下:
/frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
487 public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
//makeNitzStateMachine会新建一个NitzStateMachine 接着初始化TimeServiceHelper并调用setListener注册数据库监听 第4部分
488 mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone);
489 mPhone = phone;
490 mCi = ci;
491
...
517 // Create a new handler thread dedicated for locale tracker because the blocking
518 // getAllCellInfo call requires clients calling from a different thread.
//开启一个线程
519 mHandlerThread = new HandlerThread(LocaleTracker.class.getSimpleName());
520 mHandlerThread.start();
...
//绑定处理时间和时区信息的处理函数
526 mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
527
...
569 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
71 public NitzStateMachine makeNitzStateMachine(GsmCdmaPhone phone) {
72 return new NitzStateMachine(phone);
73 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
153 public NitzStateMachine(GsmCdmaPhone phone) {
154 this(phone,
155 new TimeServiceHelper(phone.getContext()),
156 new DeviceState(phone),
157 new TimeZoneLookupHelper());
158 }
159
160 @VisibleForTesting
161 public NitzStateMachine(GsmCdmaPhone phone, TimeServiceHelper timeServiceHelper,
162 DeviceState deviceState, TimeZoneLookupHelper timeZoneLookupHelper) {
163 mPhone = phone;
164
165 Context context = phone.getContext();
166 PowerManager powerManager =
167 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
168 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
169
170 mDeviceState = deviceState;
171 mTimeZoneLookupHelper = timeZoneLookupHelper;
//创建TimeServiceHelper并设置监听
172 mTimeServiceHelper = timeServiceHelper;
173 mTimeServiceHelper.setListener(new TimeServiceHelper.Listener() {
174 @Override
175 public void onTimeDetectionChange(boolean enabled) {
176 if (enabled) {
177 handleAutoTimeEnabled();
178 }
179 }
180
181 @Override
182 public void onTimeZoneDetectionChange(boolean enabled) {
183 if (enabled) {
184 handleAutoTimeZoneEnabled();
185 }
186 }
187 });
188 }
/frameworks/opt/telephony/src/java/com/android/internal/telephony/TimeServiceHelper.java
69 public void setListener(Listener listener) {
70 if (listener == null) {
71 throw new NullPointerException("listener==null");
72 }
73 if (mListener != null) {
74 throw new IllegalStateException("listener already set");
75 }
76 this.mListener = listener;
//注册数据库监听
77 mCr.registerContentObserver(
78 Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
79 new ContentObserver(new Handler()) {
80 public void onChange(boolean selfChange) {
81 listener.onTimeDetectionChange(isTimeDetectionEnabled());
82 }
83 });
84 mCr.registerContentObserver(
85 Settings.Global.getUriFor(Settings.Global.AUTO_TIME_ZONE), true,
86 new ContentObserver(new Handler()) {
87 public void onChange(boolean selfChange) {
88 listener.onTimeZoneDetectionChange(isTimeZoneDetectionEnabled());
89 }
90 });
91 }
从代码可以看到,当数据库里的Settings.Global.AUTO_TIME和Settings.Global.AUTO_TIME_ZONE发生变化时,会调用到onTimeDetectionChange和onTimeZoneDetectionChange,接着就会回调到handleAutoTimeEnabled和handleAutoTimeZoneEnabled,分别处理自动获取时间和自动获取时区,
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
566 private void handleAutoTimeEnabled() {
567 if (DBG) {
568 Rlog.d(LOG_TAG, "handleAutoTimeEnabled: Reverting to NITZ Time:"
569 + " mSavedNitzTime=" + mSavedNitzTime);
570 }
571 if (mSavedNitzTime != null) {
572 try {
573 // Acquire the wakelock as we're reading the elapsed realtime clock here.
574 mWakeLock.acquire();
575
576 long elapsedRealtime = mTimeServiceHelper.elapsedRealtime();
577 String msg = "mSavedNitzTime: Reverting to NITZ time"
578 + " elapsedRealtime=" + elapsedRealtime
579 + " mSavedNitzTime=" + mSavedNitzTime;
580 long adjustedCurrentTimeMillis =
581 mSavedNitzTime.mValue + (elapsedRealtime - mSavedNitzTime.mElapsedRealtime);
582 setAndBroadcastNetworkSetTime(msg, adjustedCurrentTimeMillis);
583 } finally {
584 mWakeLock.release();
585 }
586 }
587 }
588
589 private void handleAutoTimeZoneEnabled() {
590 String tmpLog = "handleAutoTimeZoneEnabled: Reverting to NITZ TimeZone:"
591 + " mSavedTimeZoneId=" + mSavedTimeZoneId;
592 if (DBG) {
593 Rlog.d(LOG_TAG, tmpLog);
594 }
595 mTimeZoneLog.log(tmpLog);
596 if (mSavedTimeZoneId != null) {
597 setAndBroadcastNetworkSetTimeZone(mSavedTimeZoneId);
598 } else {
599 String iso = mDeviceState.getNetworkCountryIsoForPhone();
600 if (!TextUtils.isEmpty(iso)) {
601 updateTimeZoneByNetworkCountryCode(iso);
602 }
603 }
604 }
可以看到最终仍然是调用setAndBroadcastNetworkSetTime和setAndBroadcastNetworkSetTimeZone去更新时间,但是只有在mSavedNitzTime和mSavedTimeZoneId被设置过的情况下才能进行更新。那么mSavedNitzTime和mSavedTimeZoneId是在那里设置的呢?全局搜索一下这两个变量可以发现是在如下地方设置的:是在NITZ更新时间的时候会进行设置
/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) {
438 if (zoneId != null) {
439 if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
440 setAndBroadcastNetworkSetTimeZone(zoneId);
441 }
442 mNitzTimeZoneDetectionSuccessful = true;
443 mSavedTimeZoneId = zoneId;
444 }
}
private void handleTimeFromNitz(TimeStampedValue<NitzData> nitzSignal) {
525 // Save the last NITZ time signal used so we can return to it later
526 // if auto-time detection is toggled.
527 mSavedNitzTime = new TimeStampedValue<>(
528 adjustedCurrentTimeMillis, nitzSignal.mElapsedRealtime);
529 } finally {
530 mWakeLock.release();
531 }
}
流程图:
NTP时间的更新是在NetworkTimeUpdateService进行初始化并设置更新的,NetworkTimeUpdateService是在SystemServer中启动的,如下:
/frameworks/base/services/java/com/android/server/SystemServer.java
724 private void startOtherServices() {
...
736 NetworkTimeUpdateService networkTimeUpdater = null;
...
//isWatch是手表类设备为true
1402 if (!isWatch) {
1403 traceBeginAndSlog("StartNetworkTimeUpdateService");
1404 try {
1405 networkTimeUpdater = new NetworkTimeUpdateService(context);
1406 ServiceManager.addService("network_time_update_service", networkTimeUpdater);
1407 } catch (Throwable e) {
1408 reportWtf("starting NetworkTimeUpdate service", e);
1409 }
1410 traceEnd();
...
1867 traceBeginAndSlog("MakeNetworkTimeUpdateReady");
1868 try {
1869 if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
1870 } catch (Throwable e) {
1871 reportWtf("Notifying NetworkTimeService running", e);
1872 }
1873 traceEnd();
}
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
101 public NetworkTimeUpdateService(Context context) {
102 mContext = context;
//初始化NtpTrustedTime
103 mTime = NtpTrustedTime.getInstance(context);
104 mAlarmManager = mContext.getSystemService(AlarmManager.class);
105 mCM = mContext.getSystemService(ConnectivityManager.class);
106
107 Intent pollIntent = new Intent(ACTION_POLL, null);
108 mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
109 //一些关于NTP的参数
110 mPollingIntervalMs = mContext.getResources().getInteger(
111 com.android.internal.R.integer.config_ntpPollingInterval);
112 mPollingIntervalShorterMs = mContext.getResources().getInteger(
113 com.android.internal.R.integer.config_ntpPollingIntervalShorter);
114 mTryAgainTimesMax = mContext.getResources().getInteger(
115 com.android.internal.R.integer.config_ntpRetry);
116 mTimeErrorThresholdMs = mContext.getResources().getInteger(
117 com.android.internal.R.integer.config_ntpThreshold);
118
119 mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
120 PowerManager.PARTIAL_WAKE_LOCK, TAG);
121 }
/frameworks/base/core/java/android/util/NtpTrustedTime.java
59 public static synchronized NtpTrustedTime getInstance(Context context) {
60 if (sSingleton == null) {
61 final Resources res = context.getResources();
62 final ContentResolver resolver = context.getContentResolver();
63 //defaultServer 为time.android.com
64 final String defaultServer = res.getString(
65 com.android.internal.R.string.config_ntpServer);
//defaultTimeout 为5000
66 final long defaultTimeout = res.getInteger(
67 com.android.internal.R.integer.config_ntpTimeout);
68
69 final String secureServer = Settings.Global.getString(
70 resolver, Settings.Global.NTP_SERVER);
71 final long timeout = Settings.Global.getLong(
72 resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);
73
74 final String server = secureServer != null ? secureServer : defaultServer;
75 sSingleton = new NtpTrustedTime(server, timeout);
76 sContext = context;
77 }
78
79 return sSingleton;
80 }
NetworkTimeUpdateService在初始化时获得了NtpTrustedTime的单例,NtpTrustedTime就是NTP的实现类。
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
123 /** Initialize the receivers and initiate the first NTP request */
124 public void systemRunning() {
//1.注册一些广播的接受者比如"android.intent.action.NETWORK_SET_TIME"和"com.android.server.NetworkTimeUpdateService.action.POLL"
125 registerForTelephonyIntents();
126 registerForAlarms();
127 //2.启动工作线程并设置handler
128 HandlerThread thread = new HandlerThread(TAG);
129 thread.start();
130 mHandler = new MyHandler(thread.getLooper());
//3.注册监听网络状态变化的回调函数
131 mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
132 mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
133 //4.注册监听Setting数据库变化的函数
134 mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
135 mSettingsObserver.observe(mContext);
136 }
如果NITZ更新时间成功,并发送了ACTION_NETWORK_SET_TIME,那么NetworkTimeUpdateService的mNitzReceiver将会接收到这条广播并设置mNitzTimeSetTime,如下:
243 /** Receiver for Nitz time events */
244 private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
245
246 @Override
247 public void onReceive(Context context, Intent intent) {
248 String action = intent.getAction();
249 if (DBG) Log.d(TAG, "Received " + action);
250 if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
251 mNitzTimeSetTime = SystemClock.elapsedRealtime();
252 }
253 }
254 };
mNitzTimeSetTime如果没有设置的话初始值为NOT_SET = -1;
NTP时间更新触发有三种
NITZ没有生效时,如果连接了互联网并开启了自动设置时间那么会走如下流程
在Setting中开启自动获取时间,会触发数据库监听的回调函数onChange:
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
291 private static class SettingsObserver extends ContentObserver {
292
293 private int mMsg;
294 private Handler mHandler;
295
296 SettingsObserver(Handler handler, int msg) {
297 super(handler);
298 mHandler = handler;
299 mMsg = msg;
300 }
301
302 void observe(Context context) {
303 ContentResolver resolver = context.getContentResolver();
304 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
305 false, this);
306 }
307
308 @Override
309 public void onChange(boolean selfChange) {
310 mHandler.obtainMessage(mMsg).sendToTarget();
311 }
312 }
之前在注册时传入的msg为EVENT_AUTO_TIME_CHANGED,handler是NetworkTimeUpdateService的工作线程处理handler Myhandler:
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
256 /** Handler to do the network accesses on */
257 private class MyHandler extends Handler {
258
259 public MyHandler(Looper l) {
260 super(l);
261 }
262
263 @Override
264 public void handleMessage(Message msg) {
265 switch (msg.what) {
266 case EVENT_AUTO_TIME_CHANGED:
267 case EVENT_POLL_NETWORK_TIME:
268 case EVENT_NETWORK_CHANGED:
269 onPollNetworkTime(msg.what);
270 break;
271 }
272 }
273 }
154 private void onPollNetworkTime(int event) {
155 // If Automatic time is not set, don't bother. Similarly, if we don't
156 // have any default network, don't bother.
//mDefaultNetwork 是否连接上网络,如果没有连接上网络,那么直接返回
157 if (mDefaultNetwork == null) return;
158 mWakeLock.acquire();
159 try {
160 onPollNetworkTimeUnderWakeLock(event);
161 } finally {
162 mWakeLock.release();
163 }
164 }
166 private void onPollNetworkTimeUnderWakeLock(int event) {
167 // Force an NTP fix when outdated
//这里的mTime指的是NtpTrustedTime getCacheAge返回的是上次保存NTP的时间到当前时间的差值,如果还未获取到NTP时间那么返回Integer的最大值
168 if (mTime.getCacheAge() >= mPollingIntervalMs) {
169 if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
//更新时间
170 mTime.forceRefresh();
171 }
172
173 if (mTime.getCacheAge() < mPollingIntervalMs) {
174 // Obtained fresh fix; schedule next normal update
//重置更新的定时器
175 resetAlarm(mPollingIntervalMs);
//isAutomaticTimeRequested返回的是Setting数据库是否开启自动更新时间 这里返回true
176 if (isAutomaticTimeRequested()) {
177 updateSystemClock(event);
178 }
179
180 } else {
181 // No fresh fix; schedule retry
182 mTryAgainCounter++;
183 if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
184 resetAlarm(mPollingIntervalShorterMs);
185 } else {
186 // Try much later
187 mTryAgainCounter = 0;
188 resetAlarm(mPollingIntervalMs);
189 }
190 }
191 }
205 private void updateSystemClock(int event) {
206 final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
207 if (!forceUpdate) {
//如果不是自动更新时间被开启触发的时间更新才会走到下面
//getNitzAge返回的是 SystemClock.elapsedRealtime() - mNitzTimeSetTime的值,如果NITZ无效,那么返回最大值
//如果NITZ 刚刚才更新过,那么NTP不需要更新直接返回
208 if (getNitzAge() < mPollingIntervalMs) {
209 if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
210 return;
211 }
212
213 final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
214 if (skew < mTimeErrorThresholdMs) {
215 if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
216 return;
217 }
218 }
219 //最终设置到系统中
220 SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
221 }
所以NTP时间函数的更新核心是 mTime.forceRefresh()
/frameworks/base/core/java/android/util/NtpTrustedTime.java
95 public boolean forceRefresh(Network network) {
//这里的Server是Setting数据库中的Settings.Global.NTP_SERVER或者time.android.com
96 if (TextUtils.isEmpty(mServer)) {
97 // missing server, so no trusted time available
98 return false;
99 }
100 //获取网络服务
101 // We can't do this at initialization time: ConnectivityService might not be running yet.
102 synchronized (this) {
103 if (mCM == null) {
104 mCM = sContext.getSystemService(ConnectivityManager.class);
105 }
106 }
107 //获取已连接的网络
108 final NetworkInfo ni = mCM == null ? null : mCM.getNetworkInfo(network);
109 if (ni == null || !ni.isConnected()) {
110 if (LOGD) Log.d(TAG, "forceRefresh: no connectivity");
111 return false;
112 }
113
114
115 if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
116 final SntpClient client = new SntpClient();
//调用SntpClient的requestTime通过socket想服务器请求时间
117 if (client.requestTime(mServer, (int) mTimeout, network)) {
118 mHasCache = true;
119 mCachedNtpTime = client.getNtpTime();
120 mCachedNtpElapsedRealtime = client.getNtpTimeReference();
121 mCachedNtpCertainty = client.getRoundTripTime() / 2;
122 return true;
123 } else {
124 return false;
125 }
126 }
如果是自动获取时间已经开启,当网络连接时,会回调到NetworkTimeUpdateCallback的onAvailable,可以看到也是走的onPollNetworkTime只不过传入的Event是EVENT_NETWORK_CHANGED
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
275 private class NetworkTimeUpdateCallback extends NetworkCallback {
276 @Override
277 public void onAvailable(Network network) {
278 Log.d(TAG, String.format("New default network %s; checking time.", network));
279 mDefaultNetwork = network;
280 // Running on mHandler so invoke directly.
281 onPollNetworkTime(EVENT_NETWORK_CHANGED);
282 }
283
284 @Override
285 public void onLost(Network network) {
//如果网络断开,那么mDefaultNetwork置为null
286 if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
287 }
288 }
NetworkTimeUpdateService在系统启动时,注册了一个广播接收者当接收到ACTION_POLL时,会回调到 如下函数:
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
144 private void registerForAlarms() {
145 mContext.registerReceiver(
146 new BroadcastReceiver() {
147 @Override
148 public void onReceive(Context context, Intent intent) {
//其中mHandler是Myhandler
149 mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
150 }
151 }, new IntentFilter(ACTION_POLL));
152 }
256 /** Handler to do the network accesses on */
257 private class MyHandler extends Handler {
258
259 public MyHandler(Looper l) {
260 super(l);
261 }
262
263 @Override
264 public void handleMessage(Message msg) {
265 switch (msg.what) {
266 case EVENT_AUTO_TIME_CHANGED:
267 case EVENT_POLL_NETWORK_TIME:
268 case EVENT_NETWORK_CHANGED:
269 onPollNetworkTime(msg.what);
270 break;
271 }
272 }
273 }
可以看到最终也走到了onPollNetworkTime;剩下的都是一样的。当设备开机后第一次通过NTP更新时间后会调用resetAlarm来重置定时器;
这时就会触发一个定时器,到时间后发送广播
228 private void resetAlarm(long interval) {
229 mAlarmManager.cancel(mPendingPollIntent);
230 long now = SystemClock.elapsedRealtime();
231 long next = now + interval;
232 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
233 }
现在Android通过网络同步时间有两种方式:NITZ和NTP,它们使用的条件不同,可以获取的信息也不一样;勾选自动同步功能后,手机首先会尝试NITZ方式,若获取时间失败,则使用NTP方式
1.NITZ(network identity and time zone)同步时间
NITZ是一种GSM/WCDMA基地台方式,必须插入SIM卡,且需要operator支持;可以提供时间和时区信息
中国大陆运营商基本是不支持的
2.NTP(network time protocol)同步时间
NTP在无SIM卡或operator不支持NITZ时使用,单纯通过网络(GPRS/WIFI)获取时间,只提供时间信息,没有时区信息(因此在不支持NITZ的地区,自动获取时区功能实际上是无效的)
NTP还有一种缓存机制:当前成功获取的时间会保存下来,当用户下次开启自动更新时间功能时会结合手机clock来进行时间更新。这也是没有任何网络时手机却能自动更新时间的原因。