Android时区和时间同步

概念

NITZ(Network identifier Time Zone:网络标识和时区):用来配置本地日期和时间的机制,也通过无线网络向设备提供运营商信息。常用来更新设备的系统时钟,可校正时间和时区。需要运营商支持(如果不支持的话就需要采用SNTP更新时间了)
SNTP(Simple Network Time protocol:简单网络时间协议):用于使用Internet时间校正设备时间,只能校正时间,无法校正时区

系统启动和主动设置功能流程


时间同步之系统启动
时间同步之主动设置

系统开机时间设置原理

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

SystemServer包含init1和init2两个方法。init1用来加载JNI库,启动Native世界;init2启动了ServerThread,ServerThread中启动了framework世界;main方法中首先加载系统默认时间

 public static void main(String[] args) {...if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {// If a device's clock is before 1970 (before 0), a lot of// APIs crash dealing with negative numbers, notably// java.io.File#setLastModified, so instead we fake it and// hope that time from cell towers or NTP fixes it// shortly.Slog.w(TAG, "System clock is before 1970; setting to 1970.");SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);}System.loadLibrary("android_servers");init1(args);}/*** This method is called from Zygote to initialize the system. This will cause the native* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back* up into init2() to start the Android services.*/native public static void init1(String[] args);

init1通过System.loadLibrary(“android-servers”)加载一个类库文件,其对应的源码文件为com_android_server_SystemServer.cpp 其C++代码如下,在该类库中转调了system_init()方法

  // 类似java的抽象方法extern "C" int system_init();static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz){    // 转调system_init();}/** JNI registration.*/static JNINativeMethod gMethods[] = {/* name, signature, funcPtr */ // 函数指针 把init1方法映射到android_server_SystemServer_init1{ "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },};

System_init方法在System_init.cpp中实现,它首先启动系统的硬件服务,比如Audio、Camera等,启动完硬件服务后它又通过Android运行时环境调用了SystemServer中的init2()方法,init2()方法启动Framework世界,代码如下:

extern "C" status_t system_init(){...// 启动硬件的服务if (strcmp(propBuf, "1") == 0) {// Start the SurfaceFlingerSurfaceFlinger::instantiate();}AndroidRuntime* runtime = AndroidRuntime::getRuntime();LOGI("System server: starting Android services.\n");// 启动完硬件服务后,又回到Systemserver的init2方法runtime->callStatic("com/android/server/SystemServer", "init2");...}

SystemServer的init2方法中调用了ServerThread,启动了framework世界

public static final void init2() {Slog.i(TAG, "Entered the Android system server!");Thread thr = new ServerThread();thr.setName("android.server.ServerThread");thr.start();}

ServerThread中启动了NetworkTimeUpdateService,并调用了systemReady方法

  try {Slog.i(TAG, "NetworkTimeUpdateService");networkTimeUpdater = new NetworkTimeUpdateService(context);} catch (Throwable e) {reportWtf("starting NetworkTimeUpdate service", e);}....final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;...try {if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady();} catch (Throwable e) {reportWtf("making Network Time Service ready", e);}

systemReady()主要做了两件事:初始化了广播接受者和NTP请求:

/** Initialize the receivers and initiate the first NTP request */public void systemReady() {registerForTelephonyIntents();registerForAlarms();registerForConnectivityIntents();mThread = new HandlerThread(TAG);mThread.start();mHandler = new MyHandler(mThread.getLooper());// Check the network time on the new threadmHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);mSettingsObserver.observe(mContext);}

myHandler是用来做什么的呢?看代码:

 /** Handler to do the network accesses on */private class MyHandler extends Handler {public MyHandler(Looper l) {super(l);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case EVENT_AUTO_TIME_CHANGED:case EVENT_POLL_NETWORK_TIME:case EVENT_NETWORK_CONNECTED:onPollNetworkTime(msg.what);break;}}}

handler处理了三个事件:“选中了自动更新日期和时间”,“请求网络时间”,“网络已连接”,这三个事件如果被触发,都会调用onPollNetworkTime方法。onPollNetworkTime方法中都实现了什么功能呢?

 private void onPollNetworkTime(int event) {// If Automatic time is not set, don't bother.// 判断"自动确定日期和时间"是否选中,如果没有直接returnif (!isAutomaticTimeRequested()) return;final long refTime = SystemClock.elapsedRealtime();// If NITZ time was received less than POLLING_INTERVAL_MS time ago,// no need to sync to NTP.//判断NITZ时间已经上报,且上报时间距离现在小于POLLING_INTERVAL_MS(24h),不需要使用NTP同步时间if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < POLLING_INTERVAL_MS) {resetAlarm(POLLING_INTERVAL_MS);return;}final long currentTime = System.currentTimeMillis();if (DBG) Log.d(TAG, "System time = " + currentTime);// Get the NTP time//如果NTP第一次请求、自上次请求到现在大于POLLING_INTERVAL_MS(24h)、选中自动确定日期和时间则请求NTPif (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + POLLING_INTERVAL_MS|| event == EVENT_AUTO_TIME_CHANGED) {if (DBG) Log.d(TAG, "Before Ntp fetch");// force refresh NTP cache when outdated//如果ntp请求缓冲到现在大于POLLING_INTERVAL_MS(24h),刷新NTP时间if (mTime.getCacheAge() >= POLLING_INTERVAL_MS) {mTime.forceRefresh();}// only update when NTP time is fresh// 如果ntp时间刷新了,则更新本地时间if (mTime.getCacheAge() < POLLING_INTERVAL_MS) {final long ntp = mTime.currentTimeMillis();mTryAgainCounter = 0;// If the clock is more than N seconds off or this is the first time it's been// fetched since boot, set the current time.// 如果ntp请求到的时间和当前系统时间差大于5秒或第一次发起ntp请求,否则以本地时间为准if (Math.abs(ntp - currentTime) > TIME_ERROR_THRESHOLD_MS|| mLastNtpFetchTime == NOT_SET) {// Set the system timeif (DBG && mLastNtpFetchTime == NOT_SET&& Math.abs(ntp - currentTime) <= TIME_ERROR_THRESHOLD_MS) {Log.d(TAG, "For initial setup, rtc = " + currentTime);}if (DBG) Log.d(TAG, "Ntp time to be set = " + ntp);// Make sure we don't overflow, since it's going to be converted to an int// 设置ntp时间为系统本地时间if (ntp / 1000 < Integer.MAX_VALUE) {SystemClock.setCurrentTimeMillis(ntp);}} else {if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);}mLastNtpFetchTime = SystemClock.elapsedRealtime();} else {// Try again shortlymTryAgainCounter++;if (mTryAgainCounter <= TRY_AGAIN_TIMES_MAX) {resetAlarm(POLLING_INTERVAL_SHORTER_MS);} else {// Try much latermTryAgainCounter = 0;resetAlarm(POLLING_INTERVAL_MS);}return;}}resetAlarm(POLLING_INTERVAL_MS);}

整体流程就是:
1.判断是否选中“自动确定日期和时间”,如果没有,直接return
2.判断NITZ时间是否已经上报,且上报时间距离现在小于POLLING_INTERVAL_MS(24h),如果是的话采用NITZ世界,不需要使用NTP同步时间
3.如果NTP请求缓冲到现在大于POLLING_INTERVAL_MS(24h),刷新NTP时间
4.如果ntp时间刷新了,则更新本地时间
5.如果ntp请求到的时间和当前系统时间差大于5秒或第一次发起NTP请求,更新本地时间,否则以本地时间为准

主动设置“自动确定日期和时间”与“自动确定时区”原理

进入”设置“—”日期和时间“,界面如下:
这里写图片描述
我们先看看”自动确定日期和时间“的实现:
device\softwinner\common\packages\TvdSettings\src\com\android\settings\DateTimeSettings.java

        boolean autoTimeEnabled = getAutoState(Settings.Global.AUTO_TIME);boolean autoTimeZoneEnabled = getAutoState(Settings.Global.AUTO_TIME_ZONE);Intent intent = getActivity().getIntent();boolean isFirstRun = intent.getBooleanExtra(EXTRA_IS_FIRST_RUN, false);mDummyDate = Calendar.getInstance();mAutoTimePref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME);mAutoTimePref.setChecked(autoTimeEnabled);mAutoTimeZonePref = (CheckBoxPreference) findPreference(KEY_AUTO_TIME_ZONE);// Override auto-timezone if it's a wifi-only device or if we're still in setup wizard.// TODO: Remove the wifiOnly test when auto-timezone is implemented based on wifi-location.if (Utils.isWifiOnly(getActivity()) || isFirstRun) {getPreferenceScreen().removePreference(mAutoTimeZonePref);autoTimeZoneEnabled = false;}mAutoTimeZonePref.setChecked(autoTimeZoneEnabled);

“自动确定网络时间”和“自动确定时区”使用的都是CheckBoxPreference实现并保存状态的。当状态改变时,会触发:

 public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {if (key.equals(KEY_DATE_FORMAT)) {String format = preferences.getString(key,getResources().getString(R.string.default_date_format));Settings.System.putString(getContentResolver(),Settings.System.DATE_FORMAT, format);updateTimeAndDateDisplay(getActivity());} else if (key.equals(KEY_AUTO_TIME)) {boolean autoEnabled = preferences.getBoolean(key, true);Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME,autoEnabled ? 1 : 0);mTimePref.setEnabled(!autoEnabled);mDatePref.setEnabled(!autoEnabled);} else if (key.equals(KEY_AUTO_TIME_ZONE)) {boolean autoZoneEnabled = preferences.getBoolean(key, true);Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0);mTimeZone.setEnabled(!autoZoneEnabled);}}

结果只是实现了

Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME,autoEnabled ? 1 : 0);

 Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME_ZONE, autoZoneEnabled ? 1 : 0);

继续搜索代码,发现在NetworkTimeUpdateService.java 和GsmServiceStateTracker.java中实现了监听:
frameworks\base\services\java\com\android\server\NetworkTimeUpdateService.java

 /** Observer to watch for changes to the AUTO_TIME setting */private static class SettingsObserver extends ContentObserver {private int mMsg;private Handler mHandler;SettingsObserver(Handler handler, int msg) {super(handler);mHandler = handler;mMsg = msg;}void observe(Context context) {ContentResolver resolver = context.getContentResolver();resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),false, this);}@Overridepublic void onChange(boolean selfChange) {mHandler.obtainMessage(mMsg).sendToTarget();}}

frameworks\opt\telephony\src\java\com\android\internal\telephony\gsm\GsmServiceStateTracker.java

        cr = phone.getContext().getContentResolver();cr.registerContentObserver(Settings.System.getUriFor(Settings.System.AUTO_TIME), true,mAutoTimeObserver);cr.registerContentObserver(Settings.System.getUriFor(Settings.System.AUTO_TIME_ZONE), true,mAutoTimeZoneObserver);

我们先看看GsmServiceStateTracker.java中的实现流程:

    private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {@Overridepublic void onChange(boolean selfChange) {Log.i("GsmServiceStateTracker", "Auto time state changed");revertToNitzTime();}};private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {@Overridepublic void onChange(boolean selfChange) {Log.i("GsmServiceStateTracker", "Auto time zone state changed");revertToNitzTimeZone();}};

跟踪revertToNitzTime()和revertToNitzeTimeZone()

 private void revertToNitzTime() {if (Settings.System.getInt(phone.getContext().getContentResolver(),Settings.System.AUTO_TIME, 0) == 0) {return;}if (DBG) {log("Reverting to NITZ Time: mSavedTime=" + mSavedTime+ " mSavedAtTime=" + mSavedAtTime);}if (mSavedTime != 0 && mSavedAtTime != 0) {setAndBroadcastNetworkSetTime(mSavedTime+ (SystemClock.elapsedRealtime() - mSavedAtTime));}}private void revertToNitzTimeZone() {if (Settings.System.getInt(phone.getContext().getContentResolver(),Settings.System.AUTO_TIME_ZONE, 0) == 0) {return;}if (DBG) log("Reverting to NITZ TimeZone: tz='" + mSavedTimeZone);if (mSavedTimeZone != null) {setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);}}


首先判断是否选中自动确定,如果否的话直接return。是的话我们看到最后如果符合if判断的话,会发出广播:

 private void setAndBroadcastNetworkSetTime(long time) {if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");SystemClock.setCurrentTimeMillis(time);Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);intent.putExtra("time", time);phone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);}

首先设置了系统时间,然后发出广播。跟踪TelephonyIntents.ACTION_NETWORK_SET_TIME发现在NetworkTimeUpdateService.java中进行了监听:

  /** Receiver for Nitz time events */private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {mNitzTimeSetTime = SystemClock.elapsedRealtime();} else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {mNitzZoneSetTime = SystemClock.elapsedRealtime();}}};

只是修改了mNitzTimeSetTime(NITZ上报的时间)。
接下来我们进入NetworkTimeUpdateService.java查看实现流程:

 /** Observer to watch for changes to the AUTO_TIME setting */private static class SettingsObserver extends ContentObserver {private int mMsg;private Handler mHandler;SettingsObserver(Handler handler, int msg) {super(handler);mHandler = handler;mMsg = msg;}void observe(Context context) {ContentResolver resolver = context.getContentResolver();resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),false, this);}@Overridepublic void onChange(boolean selfChange) {mHandler.obtainMessage(mMsg).sendToTarget();}}

当“自动确定日期和时间”状态发生改变时,mHandler又会触发,又跳转到了上面说的onPollNetworkTime(int event)方法;

参考资料:
同步时间:http://www.eoeandroid.com/thread-575174-1-1.html?_dsign=f33cbc51

Android 时间更新机制之网络更新时间:http://blog.csdn.net/droyon/article/details/45701257
源码级分析Android系统启动流程:http://www.cnblogs.com/rocomp/p/5001639.html
Android 时间同步原理分析:http://zhengken.me/2016/09/26/the-principle-of-date-time-sync/#more
Android中的时间时区自动更新:http://www.ithao123.cn/content-1560712.html
Android中时间和时区的自动更新(NITZ ZONE):http://www.itdadao.com/articles/c15a273865p0.html
“`


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部