Android time synchronization mechanism and analysis of common problems

Recently, Android devices have encountered the problem of inaccurate time many times. Take this opportunity to analyze the Android time synchronization update mechanism.

This article will analyze the composition of the Android time synchronization update mechanism and common situations that cause time inaccuracy.

1. The composition of the Android time synchronization update mechanism:

1. According to the android startup process, the system service is started by SystemServer, and the time update service is found in SystemServer.

frameworks\base\services\java\com\android\server\SystemServer.java

SystemServer->startOtherServices->networkTimeUpdaterF.systemRunning();

 ​​​​

final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;

frameworks\base\services\core\java\com\android\server\NetworkTimeUpdateService.java 

 2. After the NetworkTimeUpdateService starts, it first issues EVENT_POLL_NETWORK_TIME to call onPollNetworkTime() to try to update the time.

 

    private void onPollNetworkTimeUnderWakeLock(int event) {
        // Force an NTP fix when outdated
        NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult();
        if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) {
            if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
            mTime.forceRefresh();
            cachedNtpResult = mTime.getCachedTimeResult();
        }

        if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) {
            // Obtained fresh fix; schedule next normal update
            resetAlarm(mPollingIntervalMs);

            // Suggest the time to the time detector. It may choose use it to set the system clock.
            TimestampedValue<Long> timeSignal = new TimestampedValue<>(
                    cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis());
            NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal);
            timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event);
            mTimeDetector.suggestNetworkTime(timeSuggestion);
        } else {
            // No fresh fix; schedule retry
            mTryAgainCounter++;
            if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
                resetAlarm(mPollingIntervalShorterMs);
            } else {
                // Try much later
                mTryAgainCounter = 0;
                resetAlarm(mPollingIntervalMs);
            }
        }
    }

It seems that onPollNetworkTimeUnderWakeLock() seems to be the core of the time update, see what it does.

private final NtpTrustedTime mTime;

frameworks\base\core\java\android\util\NtpTrustedTime.java

/**
     * Returns an object containing the latest NTP information available. Can return {@code null} if
     * no information is available.
     */
    @Nullable
    public TimeResult getCachedTimeResult() {
        return mTimeResult;
    }
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public boolean forceRefresh() {
        synchronized (this) {
            NtpConnectionInfo connectionInfo = getNtpConnectionInfo();
            if (connectionInfo == null) {
                // missing server config, so no trusted time available
                if (LOGD) Log.d(TAG, "forceRefresh: invalid server config");
                return false;
            }

            ConnectivityManager connectivityManager = mConnectivityManagerSupplier.get();
            if (connectivityManager == null) {
                if (LOGD) Log.d(TAG, "forceRefresh: no ConnectivityManager");
                return false;
            }
            final Network network = connectivityManager.getActiveNetwork();
            final NetworkInfo ni = connectivityManager.getNetworkInfo(network);
            if (ni == null || !ni.isConnected()) {
                if (LOGD) Log.d(TAG, "forceRefresh: no connectivity");
                return false;
            }

            if (LOGD) Log.d(TAG, "forceRefresh() from cache miss");
            final SntpClient client = new SntpClient();
            final String serverName = connectionInfo.getServer();
            final int timeoutMillis = connectionInfo.getTimeoutMillis();
            if (client.requestTime(serverName, timeoutMillis, network)) {
                long ntpCertainty = client.getRoundTripTime() / 2;
                mTimeResult = new TimeResult(
                        client.getNtpTime(), client.getNtpTimeReference(), ntpCertainty);
                return true;
            } else {
                return false;
            }
        }
    }

②There is a requirement for the time interval from the last time update, mPollingIntervalMs is obtained from the configuration file to the time interval of 24h, that is, the time will not be updated again if it is less than 24h from the last update

What is the function of mNitzTimeSetTime !=NOT_SET here, I will list it later, and look down first.

At ③, mTime.forceRefresh() updates the time after the update conditions are met, see forceRefresh() below

It seems that calling client.requestTime(mServer, (int)mTimeout) to access the server whose address is mServer sends a sntp request. How does sntp request? Read on:

Here we can know that sntp essentially sends UDP to the host whose host name is mServer to update the time, and the updated time is assigned to mNtpTime. In onPollNetworkTime(), set the system time through SystemClock.setCurrentTimeMillis(ntp) at ④, and the time here update completed.

Is that the end? of course not! Is there a retry mechanism if time synchronization fails? The synchronization update is successful, when will the next update be?

Part ⑤ answered us, there is a retry mechanism, the maximum number of retries mTryAgainTimesMax=3, and the interval mPollingIntervalShorterMs is 1 minute; if the synchronization is successful, the interval mPollingIntervalMs is checked again for updates, which is 24h (of course, if retrying 3 times is still If it fails, it will try to update after 24h).

If the network of the device is disconnected and the maximum number of retries mTryAgainTimesMax is used up, do you have to update after 24 hours? ? ?

Not at that time, android thought it out for you, review systemRunning():

systemRunning() registers network status monitoring, and sends EVENT_NETWORK_CHANGED->onPollNetworkTime() to try to update the time when the network changes.

So far, we already know that Android can update the time from the network through sntp. Android time updates seem to be about that.

Wait, there is a question at ② that has not been solved yet, what is the use of mNitzTimeSetTime !=NOT_SET?

look back:

The initial value of mNitzTimeSetTime is NOT_SET, we can naturally update the time from the network through sntp, so why set this condition?

Unless there is another time update mechanism, if this mechanism synchronizes the time, naturally there is no need to synchronize the time through sntp!

Then look at where mNitzTimeSetTime is assigned! =NOT_SET

Who sent out this ACTION_NETWORK_SET_TIME broadcast to tell NetworkTimeUpdateService that there is no need to update the time through sntp? Look again:

It turns out that GsmServiceStateTracker received EVENT_NITZ_TIME->setTimeFromNITZString()->setAndBroadcastNetworkSetTime() to set the time and sent a broadcast to inform NetworkTimeUpdateService that there is no need to do it multiple times. My brother has updated the time for you, so there is no need for my brother to work in vain!

After a closer look, GsmServiceStateTracke is actually just a Handler, which only transmits information. Who sent the message? Follow the lead at EVENT_NITZ_TIME.

Find the CommandsInterface implementation class BaseCommands

GsmServiceStateTracke sets itself and the Message EVENT_NITZ_TIME into BaseCommands and wraps it into a Registrant object mNITZTimeRegistrant,

So easy to handle, find out where mNITZTimeRegistrant is called and know who sent the message.

It turns out that RIL processUnsolicited() received the RIL_UNSOL_NITZ_TIME_RECEIVED event, continue to look down:

Now it is very clear, the thread RILReceiver is started in RIL, RILReceiver communicates with rild through the socket, reads the time value -> processResponse() and distributes upwards, this time synchronization mechanism is called NITZ (time synchronization through base station ) .

What is RILD?

RILD: Radio Interface Layer Deamon, undertake the communication between Android upper layer (RILJ) and Modem . The sketch is as follows:

So far, we know that the Android time synchronization update mechanism has two methods: SNTP and NITZ.

2. Common situations that cause time inaccuracy and solutions:

A common problem is that the NITZ time is inaccurate, which leads to inaccurate system time.

According to the analysis of the Android time synchronization mechanism, if NITZ synchronizes the time, SNTP will not be triggered within 24 hours. If NITZ synchronizes the wrong time, the device will still have the wrong time for a short time until SNTP is triggered. How to confirm it?

Analysis of GsmServiceStateTracker setTimeFromNITZString() shows that after updating the NITZ time, it will write temporary variables through SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis())) and output the log "setAndBroadcastNetworkSetTime: time", Compare with the time when the device is turned on to know whether the NITZ time is wrong.

Solution: The NITZ time is inaccurate, usually caused by the base station, which can be solved by any of the following methods:

1. Solve by disabling the NITZ mechanism and only keeping SNTP:

Analysis of GsmServiceStateTracker setTimeFromNITZString() shows that setting gsm.ignore-nitz to true will not set the NITZ time as the system time, so that the time is synchronized from SNTP.

Doing so requires a prerequisite, that is, the system has opened administrator privileges, so that the configuration of gsm.ignore-nitz=true can be solidified (build.prop).

2. Write a system application:

Turn off the automatic time synchronization switch, so that the system time synchronization mechanism is turned off, and at the same time learn from the SNTP mechanism, write a set of sntp, and update the time on the application.


---------------------
Author: GuangZhi-
Source: CSDN
Original: https://blog.csdn.net/u011360996/article/details/127629774Copyright
statement: This article is the author's original article, please attach the blog post link for reprinting!
Content analysis By: CSDN, CNBLOG blog post one-click reprint plug-in

Guess you like

Origin blog.csdn.net/xiaowang_lj/article/details/130951006