Android9.0 automatic update mechanism of local time zone and local time

Android9.0 automatic update mechanism of local time zone and local time

brief introduction

Now there are two ways for Android to synchronize time through the network: NITZ and NTP. They use different conditions and can obtain different information; After checking the automatic synchronization function, the phone will first try NITZ mode. If the time acquisition fails, NTP mode will be used
1.NITZ(network identity and time zone) synchronization time

NITZ is a GSM/WCDMA base station mode, and SIM card must be inserted; Time and time zone information can be provided

2.NTP(network time protocol) synchronization time

NTP is used when there is no SIM card or the operator does not support NITZ. It only obtains the time through the network (GPRS/WIFI), and only provides time information without time zone information (therefore, in areas that do not support NITZ, the function of automatically obtaining time zone is actually invalid)

NTP also has a caching mechanism: the current time successfully obtained will be saved. When the user turns on the automatic time update function next time, the time will be updated in combination with the mobile phone clock. This is also the reason why the mobile phone can automatically update the time when there is no network.

NITZ time update process:

The SIM card reports information, and the operator provides time zone information and time information to the terminal for updating

flow chart:

Requires com android. The phone process starts when Android intent. action. BOOT_ When the completed broadcast is sent out, com android. The phone process will start and call onCreate, com. Of Application android. The Application class of the phone process is phoneapp Java is as follows:

/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    }

You can see that onCreate initializes two global classes, PhoneGlobals and TelephonyGlobals, and calls their onCreate function. The automatic update of time is completed in onCreate of PhoneGlobals

/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 */
                   //Get the number of sim cards
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    }

The above function will create RIL instances according to the number of sim cards. The main function of RIL instances is to establish contact with haldevice and set some callbacks to halservice Android hardware. radio@1.2 -Radio service, which is implemented as ril_service.cpp. Then, gmcdmaphone is created with RIL instance as parameter, which is mainly used to bind the functions that process the time and time zone information transmitted from hal layer. Here are the details of these two steps:

1. Create RIL instance and set callback to hal service

/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            //Mobile network is not supported
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());
                   //Set the RadioResponse instance and RadioIndication instance when RIL is instantiated to 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    }

As mentioned before, the implementation of hal Service obtained by RIL is ril_service.cpp will call RIL_ setResponseFunctions of service:

/hardware/ril/libril/ril_service.cpp
790Return<void> RadioImpl::setResponseFunctions(
791        const ::android::sp<IRadioResponse>& radioResponseParam,
792        const ::android::sp<IRadioIndication>& 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    //Convert the RadioResponse instance and RadioIndication instance of java layer into the instance of c + + layer
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}

android. hardware. radio@1.2 -Radio service this halService will set some response functions when starting, and the corresponding relationship is in ril_unsol_commands.h, where the repose of the time and time zone sent by the operator is RIL_UNSOL_NITZ_TIME_RECEIVED, the corresponding function is radio::nitzTimeReceivedInd,

/hardware/ril/libril/ril_unsol_commands.h
{RIL_UNSOL_NITZ_TIME_RECEIVED, radio::nitzTimeReceivedInd, WAKE_PARTIAL},

When hal servce receives some responses, it will call the following function: 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;
       //Determine in RIL according to the response code_ unsol_ commands. H location
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);
           //Set the current running time
789        radio::setNitzTimeReceived((int) soc_id, android::elapsedRealtime());
790    } else {
791        rwlockRet = pthread_rwlock_rdlock(radioServiceRwlockPtr);
792        assert(rwlockRet == 0);
793    }
794    //Call radio::nitzTimeReceivedInd to process RIL_UNSOL_NITZ_TIME_RECEIVED
795    ret = s_unsolResponses[unsolResponseIndex].responseFunction(
796            (int) soc_id, responseType, 0, RIL_E_SUCCESS, const_cast<void*>(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 
            //Call back to the nitzTimeReceived function of RadioIndication in the java layer, where nitzTime is the time and time zone information returned by the operator, and nitzTimeReceived is the running time of the system
6996        Return<void> 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}

Therefore, the key to the whole process is that the RIL instance will set a callback to the hal service during initialization, so that when the hal service receives the operator's time and time zone information, it can be returned to the Java layer for processing and setting the system time and time zone. The callback function for processing time and time zone information is the nitzTimeReceived function of RadioIndication.

/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        //Put the time zone information obtained from the native layer and the running time of the system when obtaining the time zone information in an Object array
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) {
                   //Call MRIL mNITZTimeRegistrant. Notifyregistry process and set
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 here is an instance of RIL. Where is mnitztimeregister initialized? We need to go back to the operator. Before sending the time and time zone information, when the RIL instance obtains the remote interface of halservice and sets the RadioResponse instance and RadioIndication instance, the RIL instantiation ends. At this time, we will take the following second step:

2. Create the processing function of binding time zone information of GsmCdmaPhone instance with RIL instance as parameter

 /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 will create a thread handler to process the time and time zone information returned by the operator
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 will create a new NitzStateMachine, then initialize TimeServiceHelper and call setListener to register the database to listen to Part 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.
           //Start a thread
519        mHandlerThread = new HandlerThread(LocaleTracker.class.getSimpleName());
520        mHandlerThread.start();
           ...
           //Binding processing functions for processing time and time zone information
526        mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);
527
           ...
569    }

From the above code, we know that mCi is an instance of RIL, so it will call RIL setOnNITZTime function of Java:

/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        //If it is the first time to start 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    }

You can see that setOnNITZTime and RIL are called to the parent class The parent class of Java is 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 is EVENT_NITZ_TIME h refers to 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    }

At this point, we return to the nitzTimeReceived function of RadioIndication, and finally call mRil.. mNITZTimeRegistrant. notifyRegistrant(new AsyncResult (null, result, null));

Mnitztimeregistry is what is event_ NITZ_ The time registry and notifyregistry are as follows:

/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    }

Therefore, the time and time zone information sent by the operator will be handed over to the ServiceStateTracker handler for processing

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                //Get the time and time zone information from the message
1179                String nitzString = (String)((Object[])ar.result)[0];
1180                long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
1181                //Set time and time zone information
1182                setTimeFromNITZString(nitzString, nitzReceiveTime);
1183                break;

3. Processing time zone information

The processing of time and time zone information sent by operators is mainly carried out by calling setTimeFromNITZString function as follows:

/frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
3537    private void setTimeFromNITZString(String nitzString, long nitzReceiveTime) {
            //start the running time of the current system
3538        long start = SystemClock.elapsedRealtime();
3539        if (DBG) {
3540            Rlog.d(LOG_TAG, "NITZ: " + nitzString + "," + nitzReceiveTime
3541                    + " start=" + start + " delay=" + (start - nitzReceiveTime));
3542        }
            //Convert the time zone and time information sent by the operator into NitzData entity class
3543        NitzData newNitzData = NitzData.parse(nitzString);
3544        if (newNitzData != null) {
3545            try {
                    //Then the NitzData and the information received by the operator will be combined into TimeStampedValue and the handleNitzReceived will be set up.
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    }

Then, handleTimeZoneFromNitz and handleTimeFromNitz are called to process the time and time zone information respectively.

3.1 time zone information processing handleTimeZoneFromNitz

/frameworks/opt/telephony/src/java/com/android/internal/telephony/NitzStateMachine.java
389    private void handleTimeZoneFromNitz(TimeStampedValue<NitzData> nitzSignal) {
390            //A series of processing
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) {
                   //Whether the time zone is automatically obtained in setting
439                if (mTimeServiceHelper.isTimeZoneDetectionEnabled()) {
                       //Set time and send broadcast
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    }

You can see that the last time zone information is set in the alarmManager, and the broadcast sent is Android intent. action. NETWORK_ SET_ TIMEZONE

3.2 processing of time information handleTimeFromNitz

/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. Calculate the elapsed time from the message received from the operator by the halservice to the current system 
473                long millisSinceNitzReceived = elapsedRealtime - nitzSignal.mElapsedRealtime;
474                if (millisSinceNitzReceived < 0 || millisSinceNitzReceived > Integer.MAX_VALUE) {
475                    //Boundary treatment
480                    return;
481                }
482
483                // Adjust the NITZ time by the delay since it was received to get the time now.
                   //2. Calculate the current absolute time
484                long adjustedCurrentTimeMillis =
485                        nitzSignal.mValue.getCurrentTimeInMillis() + millisSinceNitzReceived;
                   //3. Calculate the difference between network time and system time
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                    //If it is the first update time
495                    if (mSavedNitzTime == null) {
496                        logMsg += ": First update received.";
                           //Set the time and send the broadcast
497                        setAndBroadcastNetworkSetTime(logMsg, adjustedCurrentTimeMillis);
498                    } else {
                           //Calculate the running time of the system from the last save to the present
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                //Save the current time information and system operation time information
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    }

You can see that the time is finally set in SystemClock, which is actually set in AlarmManagerService.

4. Start the process of automatically updating time and time zone in setting

The Setting switch will change the settings in the Setting database Global. AUTO_ TIME_ Zone and settings Global. AUTO_ TIME_ The value of zone. When creating and processing handler ServiceStateTracker in the second stage, a database listener will be registered, as follows:

/frameworks/opt/telephony/src/java/com/android/internal/telephony/ServiceStateTracker.java
487    public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
           //makeNitzStateMachine will create a new NitzStateMachine, then initialize TimeServiceHelper and call setListener to register the database to listen to Part 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.
           //Start a thread
519        mHandlerThread = new HandlerThread(LocaleTracker.class.getSimpleName());
520        mHandlerThread.start();
           ...
           //Binding processing functions for processing time and time zone information
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;
           //Create TimeServiceHelper and set listening
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;
          //Register database listening
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    }

As you can see from the code, when the settings in the database Global. AUTO_ Time and settings Global. AUTO_ TIME_ When the zone changes, it will call onTimeDetectionChange and onTimeZoneDetectionChange, and then call back to handleAutoTimeEnabled and handleAutoTimeZoneEnabled to process automatic time acquisition and automatic time zone acquisition respectively,

/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    }

You can see that setAndBroadcastNetworkSetTime and setAndBroadcastNetworkSetTimeZone are still called to update the time, but they can only be updated when mSavedNitzTime and mSavedTimeZoneId are set. Where are mSavedNitzTime and mSavedTimeZoneId set? A global search of these two variables shows that they are set in the following places: they will be set when NITZ is updated

/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 time update mechanism

flow chart:

1. Startup process of networktimeupdateservice

NTP time update is initialized and set in NetworkTimeUpdateService. NetworkTimeUpdateService is started in SystemServer, as follows:

/frameworks/base/services/java/com/android/server/SystemServer.java
724    private void startOtherServices() {
       ...
736        NetworkTimeUpdateService networkTimeUpdater = null;
       ...
           //isWatch is a watch device and is 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();            
}

1.1 initialization of networktimeupdateservice:

/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
101    public NetworkTimeUpdateService(Context context) {
102        mContext = context;
           //Initialize 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        //Some parameters about 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            //The defaultServer is time android. com
64            final String defaultServer = res.getString(
65                    com.android.internal.R.string.config_ntpServer);
              //The defaultTimeout is 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 obtains a single instance of NtpTrustedTime during initialization. NtpTrustedTime is the implementation class of NTP.

1.2 startup of networktimeupdateservice:

/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. Register some broadcast recipients, such as "android.intent.action.NETWORK_SET_TIME" and "com.android.server.NetworkTimeUpdateService.action.POLL"
125        registerForTelephonyIntents();
126        registerForAlarms();
127        //2. Start the worker thread and set the handler
128        HandlerThread thread = new HandlerThread(TAG);
129        thread.start();
130        mHandler = new MyHandler(thread.getLooper());
           //3. Register a callback function to listen for changes in network status
131        mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
132        mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
133        //4. Register the function to monitor the change of Setting database
134        mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
135        mSettingsObserver.observe(mContext);
136    }

If NITZ updates the time successfully and sends ACTION_NETWORK_SET_TIME, then the mNitzReceiver of NetworkTimeUpdateService will receive this broadcast and set mNitzTimeSetTime as follows:

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    };

If mNitzTimeSetTime is not set, the initial value is NOT_SET = -1;

2.NTP time update

There are three kinds of NTP time update triggers

2.1 enable automatic time acquisition in Settings

When NITZ does not take effect, if the Internet is connected and automatic time setting is enabled, the following process will be followed

Enabling automatic time acquisition in Setting will trigger the callback function onChange of database listening:

/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    }

The msg passed in during the previous registration is EVENT_AUTO_TIME_CHANGED, handler is the worker thread of 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 is connected to the network. If it is not connected to the network, it returns directly
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 here refers to ntptrustedtime. Getcacheage returns the difference between the time when NTP was last saved and the current time. If NTP time has not been obtained, the maximum value of Integer is returned
168        if (mTime.getCacheAge() >= mPollingIntervalMs) {
169            if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
               //Update time
170            mTime.forceRefresh();
171        }
172
173        if (mTime.getCacheAge() < mPollingIntervalMs) {
174            // Obtained fresh fix; schedule next normal update
               //Reset updated timer
175            resetAlarm(mPollingIntervalMs);
               //isAutomaticTimeRequested returns whether the Setting database is enabled to automatically update the time. Here, true is returned
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) {
               //If the time is not automatically updated, the triggered time update will go below
              //getNitzAge returns systemclock Elapseddrealtime() - the value of mnitztimesettime. If NITZ is invalid, the maximum value will be returned
              //If NITZ has just been updated, NTP does not need to be updated and returns directly
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        //Finally set into the system
220        SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
221    }

Therefore, the update core of NTP time function is mtime forceRefresh()

/frameworks/base/core/java/android/util/NtpTrustedTime.java
95    public boolean forceRefresh(Network network) {
          //The server here is settings in the Setting database Global. NTP_ Server or time android. com
96        if (TextUtils.isEmpty(mServer)) {
97            // missing server, so no trusted time available
98            return false;
99        }
100        //Get network services
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         //Get connected network
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();
           //Call the requestTime of SntpClient and request the time from the server through the 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    }

2.2 network connection

If automatic time acquisition has been enabled, when the network is connected, it will call back to onAvailable of NetworkTimeUpdateCallback. You can see that onPollNetworkTime also goes, but the incoming Event is 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) {
               //If the network is disconnected, mDefaultNetwork is set to null
286            if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
287        }
288    }

2.3 when it is time to update:

NetworkTimeUpdateService registers a broadcast receiver when the system starts. When receiving the action_ When poll, it will call back to the following functions:

/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) {
                       //Where mHandler is 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    }

You can see that you have finally reached onPollNetworkTime; The rest are the same. When the device is powered on, it will call resetAlarm to reset the timer after updating the time through NTP for the first time;

At this time, a timer will be triggered and the broadcast will be sent after the time

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    }

NITZ and NTP summary

Now there are two ways for Android to synchronize time through the network: NITZ and NTP. They use different conditions and can obtain different information; After checking the automatic synchronization function, the phone will first try NITZ mode. If the time acquisition fails, NTP mode will be used
1.NITZ(network identity and time zone) synchronization time

NITZ is a GSM/WCDMA base station mode. SIM card must be inserted and supported by the operator; Time and time zone information can be provided

Chinese mainland operators basically do not support it.

2.NTP(network time protocol) synchronization time

NTP is used when there is no SIM card or the operator does not support NITZ. It only obtains the time through the network (GPRS/WIFI), and only provides time information without time zone information (therefore, in areas that do not support NITZ, the function of automatically obtaining time zone is actually invalid)

NTP also has a caching mechanism: the current time successfully obtained will be saved. When the user turns on the automatic time update function next time, the time will be updated in combination with the mobile phone clock. This is also the reason why the mobile phone can automatically update the time when there is no network.

Keywords: Java Android

Added by gyash on Fri, 28 Jan 2022 20:14:02 +0200