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 SurfaceFlinger
SurfaceFlinger::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 thread
mHandler.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);
}
@Override
public 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.
// 判断"自动确定日期和时间"是否选中,如果没有直接return
if (!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)、选中自动确定日期和时间则请求NTP
if (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 time
if (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 shortly
mTryAgainCounter++;
if (mTryAgainCounter <= TRY_AGAIN_TIMES_MAX) {
resetAlarm(POLLING_INTERVAL_SHORTER_MS);
} else {
// Try much later
mTryAgainCounter = 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);
}
@Override
public 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()) {
@Override
public void onChange(boolean selfChange) {
Log.i("GsmServiceStateTracker", "Auto time state changed");
revertToNitzTime();
}
};
private ContentObserver mAutoTimeZoneObserver = new ContentObserver(new Handler()) {
@Override
public 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() {
@Override
public 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);
}
@Override
public 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
“`