android时间的更新方式,一般有moderm和网络更新两种,MTK在此基础上,添加了GPS的方式。现在分析的是网络更新时间的方式
从网络更新只能更新时间但是无法改变时区;从手机网络运营商处获取时间可以获得时间和分区(这种方式大陆的运营商支持率很低)
android系统中更新时间的操作 分为系统部分和应用部分
/frameworks/base/services/java/com/android/server/SystemServer.java
/frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
/frameworks/base/core/java/android/util/NtpTrustedTime.java
/packages/apps/Settings/src/com/android/settings/DateTimeSettings.java
android时间更新的系统部分是为应用程序提供”服务”。在SystemServer中启动网络更新的”service”。在网络更新的systemRunning方法中,会启动线程,当内容观察者observer发现数据库中AUTO_TIME的数据发生变化后,通过handler发送message给这个线程。在这个线程中进行 moderm 、网络、gps 等方式的更新时间。
在startOtherServices 中启动和网络更新时间相关的”service”
NetworkTimeUpdateService networkTimeUpdater = null;
if (!disableNetwork && !disableNetworkTime) {
try {
Slog.i(TAG, "NetworkTimeUpdateService");
networkTimeUpdater = new NetworkTimeUpdateService(context);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
}
}
获得了一个 NetworkTimeUpdateService的实例化对象 networkTimeUpdater;
这个networkTimeUpdater是被mActivityManagerService的run方法调用的。
//使用单例模式获得一个NtpTrustedTime的对象
mTime = NtpTrustedTime.getInstance(context);
//获得一个Server,其实质是Settings.Global.NTP_SERVER
mDefaultServer = ((NtpTrustedTime) mTime).getServer();
mNtpServers.add(mDefaultServer);
//时间服务器添加到ArrayList类型的mNtpServers中。(添加多个时间服务器是mtk在android源码的基础上添加的)
for (String str : SERVERLIST)
{
mNtpServers.add(str);
}
```
在NetworkTimeUpdateService的构造方法中 获得的服务器列表如下
- 默认的server
/frameworks/base/core/res/res/values/config.xml
asia.pool.ntp.org
- 服务器列表
private static final String[] SERVERLIST = new String[]{
"hshh.org",
"2.android.pool.ntp.org",
"time-a.nist.gov"
};
现在在原有的基础上,添加内部服务器,就能够通过内部服务器来更新时间。
## 启动NetworkUpdataService
当在startOtherService的最后,会调用 mActivityManagerService.systemReady()。此时会执行代码中的run方法。在这个run方法中,就会执行到NetworkUpdataService的systemRunning()方法。
final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
try {
if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying NetworkTimeService running", e);
}
## 执行systemRunning
registerForTelephonyIntents();
registerForAlarms();
registerForConnectivityIntents();
HandlerThread thread = new HandlerThread(TAG);
thread.start();
mHandler = new MyHandler(thread.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);
/// M: comment @{ add GPS Time Sync Service
Log.d(TAG, "add GPS time sync handler and looper");
mGpsThread = new HandlerThread(TAG);
mGpsThread.start();
mGpsHandler = new MyHandler(mGpsThread.getLooper());
mGpsTimeSyncObserver = new GpsTimeSyncObserver(mGpsHandler, EVENT_GPS_TIME_SYNC_CHANGED);
mGpsTimeSyncObserver.observe(mContext);
/// @}
- 首先会注册和moderm、alarms、网络的receiver
registerForTelephonyIntents(); //moderm的Receiver,会引起时间的变化
registerForAlarms(); //Alarm的Receiver 类型为EVENT_POLL_NETWORK_TIME
registerForConnectivityIntents();//网络变化引起的更新。类型为EVENT_NETWORK_CHANGED
- 利用消息处理机制,进行时间的更新操作
- 启动一个线程。用来处理消息。
- 在MyHandler中进行消息的处理
- 时间更新的类型为EVENT_POLL_NETWORK_TIME
```
mHandler = new MyHandler(thread.getLooper());
// Check the network time on the new thread
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
```
- 监听EVENT_AUTO_TIME_CHANGED的事件的发生,如果发生也将会执行到MyHandler的HandlMessage
```
mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
mSettingsObserver.observe(mContext);
```
- Mtk代码在网络更新的基础上,添加了GPS授时的方式,和网络跟新的思路相同
## MyHandler的HandeMessage处理
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_AUTO_TIME_CHANGED:
case EVENT_POLL_NETWORK_TIME:
case EVENT_NETWORK_CHANGED:
if (DBG) Log.d(TAG, "MyHandler::handleMessage what = " + msg.what);
onPollNetworkTime(msg.what);
break;
/// M: comment @{ add GPS Time Sync Service
case EVENT_GPS_TIME_SYNC_CHANGED:
boolean gpsTimeSyncStatus = getGpsTimeSyncState();;
Log.d(TAG, "GPS Time sync is changed to " + gpsTimeSyncStatus);
onGpsTimeChanged(gpsTimeSyncStatus);
break;
/// @}
}
}
- EVENT_AUTO_TIME_CHANGED EVENT_POLL_NETWORK_TIME EVENT_NETWORK_CHANGED 这三种类型的请求,都会交给 onPollNetworkTime来进行处理。
- EVENT_GPS_TIME_SYNC_CHANGED GPS的同步请求,会由onGpsTimeChanged 进行处理
- EVENT_POLL_NETWORK_TIME 这个请求和Alarms相关内容。用于系统定时的更新时间
## onPollNetworkTime 时间同步
- 用户是否勾选自动同步设置
if (!isAutomaticTimeRequested()) return;
- 从服务器获取时间。获取时间后,调用NtpTrustedTime中的forceRefresh 进行更新
// 满足一下三个添加条件的一个就会更新时间 系统刚启动 mLastNtpFetchTime == NOT_SET 运行时间refTime 大于了10天。或者AlermManager引起的EVENT_AUTO_TIME_CHANGED变化
if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
|| event == EVENT_AUTO_TIME_CHANGED) {
if (mTime instanceof NtpTrustedTime)
{
((NtpTrustedTime) mTime).setServer(mNtpServers.get(index));
mTime.forceRefresh();
((NtpTrustedTime) mTime).setServer(mDefaultServer);
}
“`
开机没联网 ,联网什么时候更新
系统在联网时,会自动更新更新时间。
如果此时从4个服务器中能正常更新时间,则进入10天一更新的周期
如果4个服务器都不能更新,则下次联网或开机或用户主动发起更新请求时,依然会从4个服务器获取时间 。
更新失败,什么时候继续更新
开机后,如果没有网络,不会进行更新
联网后,会进行更新。
遍历服务器。如果都失败。此时如果用户主动发起请求,也会进行ntp更新。如果用户没有主动的请求更新或重新开机或网络改变,则10天后,重发发起网络更新。如果以上三者条件有一个,则会发起网络同步请求
网络更新时间之后,(无关机重启条件下)
如果系统的运行时间大于10天,或者用户主动发起更新请求。则判断时间缓冲。
时间缓冲为 系统运行的时间 - 上一次同步的时间的时间差
如果时间缓冲超过10天,则会遍历服务器进行更新
如果更新成功。则判断目前系统的时间和要设定的时间差是否大于 设定值
如果大于设定值,则进行设定。否则不设定
如果更新失败,则更换服务器进行更新
如果所有的服务器都更新失败,则10天后,在进行更新
系统重启 会进行时间的同步更新
系统能进行网络更新的方式 (执行HandleMessage)
用户主动发起
网络变化
ALarm
更新时间 (执行onPollNetworkTime)
mLastNtpFetchTime == NOT_SET(关机重启)
运行时间大于10天
用户主动发起
registerForAlarms();
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
}
}, new IntentFilter(ACTION_POLL));
注册一个接受者,触发会回给Handler 发送EVENT_POLL_NETWORK_TIME
在内容观察者中,会监听AUTO_TIME 的变化。如果应用程序,改变了,就会执行相应的方法。
/** 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();
//此时监听AUTO_TIME的改变。 resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
false, this);
}
@Override
public void onChange(boolean selfChange) {
mHandler.obtainMessage(mMsg).sendToTarget();
}
}
应用部分的典型实例是Settings设置中 日期和时间的设定
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.date_time_prefs);
initUI();
在onSharedPreferenceChanged 中会判断选择的是网络还是gps类型。并设置Settings数据库。
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (key.equals(KEY_AUTO_TIME)) {
String value = mAutoTimePref.getValue();
int index = mAutoTimePref.findIndexOfValue(value);
mAutoTimePref.setSummary(value);
boolean autoEnabled = true;
if (index == AUTO_TIME_NETWORK_INDEX) {
Settings.Global.putInt(getContentResolver(),
Settings.Global.AUTO_TIME, 1);
Settings.Global.putInt(getContentResolver(),
Settings.System.AUTO_TIME_GPS, 0);
} else if (index == AUTO_TIME_GPS_INDEX) {
showDialog(DIALOG_GPS_CONFIRM);
setOnCancelListener(this);
} else {
Settings.Global.putInt(getContentResolver(), Settings.Global.AUTO_TIME, 0);
Settings.Global.putInt(getContentResolver(), Settings.System.AUTO_TIME_GPS, 0);
autoEnabled = false;
}
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通过选择不同的方式更新系统的时间的同时,会设置Settings.Global.AUTO_TIME的数值
系统中SettingsObserver如果监测到Settings.Global.AUTO_TIME 发生变化,会通过handler发送信息给处理时间的线程
处理时间的线程会从moderm、gps、网络中选择相应的方式进行更新时间。
网络更新时间的方式会从NetworkTimeUpdateService中SERVERLIST所示的服务器列表中获得时间。
触发时间更新操作的情况
moderm提供的时间,在网络更新中的优先级最高
AlarmManager 触发的更新。即设定每10天更新一次网络
ContentObserver auto_time引起的时间更新,和用户的操作有关
网络变化引起的更新。即开启网络引起的更新
MTK增加的GPS 更新方式
1.android手机和服务器之间的通信,是通过什么样的方式
4个服务器,为什么有时都无数据返回
Android 时间更新机制之网络更新时间
Android 时间更新机制之RIL更新时间
Android 时间同步原理分析
NITZ协议
telephony
The Radio Interface Layer (RIL)
Android 系统时间更新机制
SystemClock.elapsedRealtime() 开机运行的时间,包括深度睡眠的时间
final long currentTime = System.currentTimeMillis(); 当前系统的时间,