Android NTP time synchronization source code analysis

Android NTP time synchronization source code analysis

  • After the Android system sets the automatic time, if an available network is connected. Network time will be synchronized. This processing is completed by NetworkTimeUpdateService.
  • Some customized systems need to disable network time synchronization. For example, just use GPS time. Based on Android9, analyze the Android NTP time synchronization process.

Timing diagram:
Insert image description here

  • Service startup: NetworkTimeUpdateService is started in startOtherServices of SystemServer (frameworks/base/services/java/com/android/server/SystemServer.java)
if (!isWatch) {
    
    
	traceBeginAndSlog("StartNetworkTimeUpdateService");
	try {
    
    
		networkTimeUpdater = new NetworkTimeUpdateService(context);
		ServiceManager.addService("network_time_update_service", networkTimeUpdater);
	} catch (Throwable e) {
    
    
		reportWtf("starting NetworkTimeUpdate service", e);
	}
	traceEnd();
}
// 省略
try {
    
    
	if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
} catch (Throwable e) {
    
    
	reportWtf("Notifying NetworkTimeService running", e);
}
  • During the startup process of NetworkTimeUpdateService, NTP and Conectivity services will be called, and the monitoring NITZ and automatic time setting items will be registered (frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java)
public NetworkTimeUpdateService(Context context) {
    
    
	mContext = context;
	mTime = NtpTrustedTime.getInstance(context);
	mAlarmManager = mContext.getSystemService(AlarmManager.class);
	mCM = mContext.getSystemService(ConnectivityManager.class);

	Intent pollIntent = new Intent(ACTION_POLL, null);
	mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);

	mPollingIntervalMs = mContext.getResources().getInteger(
			com.android.internal.R.integer.config_ntpPollingInterval);
	mPollingIntervalShorterMs = mContext.getResources().getInteger(
			com.android.internal.R.integer.config_ntpPollingIntervalShorter);
	mTryAgainTimesMax = mContext.getResources().getInteger(
			com.android.internal.R.integer.config_ntpRetry);
	mTimeErrorThresholdMs = mContext.getResources().getInteger(
			com.android.internal.R.integer.config_ntpThreshold);

	mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
			PowerManager.PARTIAL_WAKE_LOCK, TAG);
}

/** Initialize the receivers and initiate the first NTP request */
public void systemRunning() {
    
    
	registerForTelephonyIntents();
	registerForAlarms();

	HandlerThread thread = new HandlerThread(TAG);
	thread.start();
	mHandler = new MyHandler(thread.getLooper());
	mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
	mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);

	mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
	mSettingsObserver.observe(mContext);
}
  • When the automatic time setting changes, the network status changes, and the update cycle is reached, NetworkTimeUpdateService will be triggered to update the system time. By obtaining the NTP time and making various judgments (such as whether the NITZ time has been updated recently), it is finally judged whether to use the NTP time update (refer to the timing diagram above)
/** Handler to do the network accesses on */
private class MyHandler extends Handler {
    
    

	public MyHandler(Looper l) {
    
    
		super(l);
	}

	@Override
	public void handleMessage(Message msg) {
    
    
		switch (msg.what) {
    
    
			case EVENT_AUTO_TIME_CHANGED:
			case EVENT_POLL_NETWORK_TIME:
			case EVENT_NETWORK_CHANGED:
				onPollNetworkTime(msg.what);
				break;
		}
	}
}

private void onPollNetworkTime(int event) {
    
    
	// If Automatic time is not set, don't bother. Similarly, if we don't
	// have any default network, don't bother.
	if (mDefaultNetwork == null) return;
	mWakeLock.acquire();
	try {
    
    
		onPollNetworkTimeUnderWakeLock(event);
	} finally {
    
    
		mWakeLock.release();
	}
}

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

	if (mTime.getCacheAge() < mPollingIntervalMs) {
    
    
		// Obtained fresh fix; schedule next normal update
		resetAlarm(mPollingIntervalMs);
		if (isAutomaticTimeRequested()) {
    
    
			updateSystemClock(event);
		}

	} else {
    
    
		// No fresh fix; schedule retry
		mTryAgainCounter++;
		if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
    
    
			resetAlarm(mPollingIntervalShorterMs);
		} else {
    
    
			// Try much later
			mTryAgainCounter = 0;
			resetAlarm(mPollingIntervalMs);
		}
	}
}

private void updateSystemClock(int event) {
    
    
	final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
	if (!forceUpdate) {
    
    
		if (getNitzAge() < mPollingIntervalMs) {
    
    
			if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
			return;
		}

		final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
		if (skew < mTimeErrorThresholdMs) {
    
    
			if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
			return;
		}
	}

	SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
}
  • The above code is based on Android9. The TimeDetect service was introduced in Android 12. By configuring the "config_autoTimeSourcesPriority" setting item in frameworks/base/core/res/res/values/config.xml, you can specify the preferred time source. So in Android12, NetworkTimeUpdateService will send the time update request to the TimeDetect service instead of directly using SystemClock to update the time. Regarding the detailed process of Android12’s NetworkTimeUpdateService, we will not analyze it here.

Guess you like

Origin blog.csdn.net/zxc024000/article/details/131625729