文章目录
NTP介绍
NTP:网络时间协议,英文名称:Network Time Protocol(NTP)是用来使计算机时间同步化的一种协议,它可以使计算机对其服务器或时钟源(如石英钟,GPS等等)做同步化,它可以提供高精准度的时间校正(LAN上与标准间差小于1毫秒,WAN上几十毫秒),且可介由加密确认的方式来防止恶毒的协议攻击。NTP的目的是在无序的Internet环境中提供精确和健壮的时间服务。
Android系统使用NTP自动更新系统时间的触发机制有两种:
监听数据库字段AUTO_TIME,当这个字段发生变化的时候,会立即触发一次时间同步
网络连接发生变化,当网络接通,会触发一次时间检查和同步
定时更新机制,当预定的时间到了,会触发一次时间检查和同步
Android系统的使用NTP更新系统时间是在NetworkTimeUpdateService服务里面实现的,首先看一下服务的初始化过程。
NtpTrustedTime获取时间
mServer服务器名字,在初始化NtpTrustedTime时由config_ntpServer和NTP_SERVER共同制定
@frameworks/base/core/java/android/util/NtpTrustedTime.java
private NtpTrustedTime(String server, long timeout) {
if (LOGD) Log.d(TAG, "creating NtpTrustedTime using " + server);
mServer = server;
mTimeout = timeout;
}
public static synchronized NtpTrustedTime getInstance(Context context) {
if (sSingleton == null) {
final Resources res = context.getResources();
final ContentResolver resolver = context.getContentResolver();
final String defaultServer = res.getString(
com.android.internal.R.string.config_ntpServer);
final long defaultTimeout = res.getInteger(
com.android.internal.R.integer.config_ntpTimeout);
final String secureServer = Settings.Global.getString(
resolver, Settings.Global.NTP_SERVER);
final long timeout = Settings.Global.getLong(
resolver, Settings.Global.NTP_TIMEOUT, defaultTimeout);
final String server = secureServer != null ? secureServer : defaultServer;
sSingleton = new NtpTrustedTime(server, timeout);
sContext = context;
}
return sSingleton;
}
ntp服务地址: https://www.cnblogs.com/configure/p/13469039.html
<string translatable="false" name="config_ntpServer">time1.aliyun.com</string>
NtpService 调用forceRefresh获取时间,通过获取ConnectivityManager服务,SntpClient.requestTime来获取时间
@frameworks/base/core/java/android/util/NtpTrustedTime.java
@Override
public boolean forceRefresh() {
// We can't do this at initialization time: ConnectivityService might not be running yet.
synchronized (this) {
if (mCM == null) {
mCM = sContext.getSystemService(ConnectivityManager.class);
}
}
final Network network = mCM == null ? null : mCM.getActiveNetwork();
return forceRefresh(network);
}
public boolean forceRefresh(Network network) {
if (TextUtils.isEmpty(mServer)) {
// missing server, so no trusted time available
return false;
}
// We can't do this at initialization time: ConnectivityService might not be running yet.
synchronized (this) {
if (mCM == null) {
mCM = sContext.getSystemService(ConnectivityManager.class);
}
}
final NetworkInfo ni = mCM == null ? null : mCM.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();
if (client.requestTime(mServer, (int) mTimeout, network)) {
mHasCache = true;
mCachedNtpTime = client.getNtpTime();
mCachedNtpElapsedRealtime = client.getNtpTimeReference();
mCachedNtpCertainty = client.getRoundTripTime() / 2;
return true;
} else {
return false;
}
}
NTpService得到时间
@frameworks/base/core/java/android/util/NtpTrustedTime.java
@Override
public long currentTimeMillis() {
if (!mHasCache) {
throw new IllegalStateException("Missing authoritative time source");
}
if (LOGD) Log.d(TAG, "currentTimeMillis() cache hit");
// current time is age after the last ntp cache; callers who
// want fresh values will hit makeAuthoritative() first.
return mCachedNtpTime + getCacheAge();
}
SntpClient具体请求时间
大概就是mServer,通过socket访问,得到mNtpTime
@frameworks/base/core/java/android/net/SntpClient.java
public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
DatagramSocket socket = null;
final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NTP);
try {
socket = new DatagramSocket();
network.bindSocket(socket);
socket.setSoTimeout(timeout);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, port);
...
mNtpTime = responseTime + clockOffset;
mNtpTimeReference = responseTicks;
mRoundTripTime = roundTripTime;
} catch (Exception e) {
EventLogTags.writeNtpFailure(address.toString(), e.toString());
if (DBG) Log.d(TAG, "request time failed: " + e);
return false;
} finally {
if (socket != null) {
socket.close();
}
TrafficStats.setThreadStatsTag(oldTag);
}
return true;
}
NetworkTimeUpdateService启动和时间更新
NetworkTimeUpdateService启动
服务是在startOtherServices启动,并添加到ServiceManager里面,调用systemRunning运行
@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);
}
@frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
public NetworkTimeUpdateService(Context context) {
mContext = context;
// 创建NTP实例,这个就是使用NTP协议取得时间的类
mTime = NtpTrustedTime.getInstance(context);
// 取得AlarmManager实例
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);
// 从系统配置文件config.ini取得NTP时间参数
// 默认是86400000ms,即1天
mPollingIntervalMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingInterval);
// 由于网络原因,时间同步失败后,retry的时间间隔,默认是60000ms,即60s
mPollingIntervalShorterMs = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpPollingIntervalShorter);
// retry的次数,默认是3次
mTryAgainTimesMax = mContext.getResources().getInteger(
com.android.internal.R.integer.config_ntpRetry);
// 时间误差,默认是5000ms,当时间误差超过5s,会更新系统时间
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();
//注册MyHandler
HandlerThread thread = new HandlerThread(TAG);
thread.start();
mHandler = new MyHandler(thread.getLooper());
mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
//监听SettingProvider AUTO_TIME变化
mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
mSettingsObserver.observe(mContext);
}
1. 定时更新
private void registerForAlarms() {
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
}
}, new IntentFilter(ACTION_POLL));
}
2. AUTO_TIME变化发送Message
AUTO_TIME变化就会发送Message更新
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();
}
2. 网络变化
private class NetworkTimeUpdateCallback extends NetworkCallback {
@Override
public void onAvailable(Network network) {
Log.d(TAG, String.format("New default network %s; checking time.", network));
mDefaultNetwork = network;
// Running on mHandler so invoke directly.
onPollNetworkTime(EVENT_NETWORK_CHANGED);
}
@Override
public void onLost(Network network) {
if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
}
}
更新时间
变化msg受到都会触发onPollNetworkTime
/** 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 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(); //调用NtpTrustedTime获取时间,见上文
}
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);
}
}
}
最后调用setCurrentTimeMillis设置时间,时间从NtpTrustedTime获取(mTime.currentTimeMillis())
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());
}
SystemClock.setCurrentTimeMillis设置时间
调用ALARM_SERVICE的setTime
@frameworks/base/core/java/android/os/SystemClock.java
public static boolean setCurrentTimeMillis(long millis) {
final IAlarmManager mgr = IAlarmManager.Stub
.asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
if (mgr == null) {
return false;
}
try {
return mgr.setTime(millis);
} catch (RemoteException e) {
Slog.e(TAG, "Unable to set RTC", e);
} catch (SecurityException e) {
Slog.e(TAG, "Unable to set RTC", e);
}
return false;
}
AlarmManagerService添加ServiceManager ALARM_SERVICE
@frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
public void onStart() {
mNativeData = init();
mNextWakeup = mNextNonWakeup = 0;
...
try {
ActivityManager.getService().registerUidObserver(new UidObserver(),
ActivityManager.UID_OBSERVER_GONE | ActivityManager.UID_OBSERVER_IDLE
| ActivityManager.UID_OBSERVER_ACTIVE,
ActivityManager.PROCESS_STATE_UNKNOWN, null);
} catch (RemoteException e) {
// ignored; both services live in system_server
}
publishBinderService(Context.ALARM_SERVICE, mService);
}
注册AlarmManager
@frameworks/base/core/java/android/app/SystemServiceRegistry.java
registerService(Context.ALARM_SERVICE, AlarmManager.class,
new CachedServiceFetcher<AlarmManager>() {
@Override
public AlarmManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.ALARM_SERVICE);
IAlarmManager service = IAlarmManager.Stub.asInterface(b);
return new AlarmManager(service, ctx);
}});
IAlarmManager.aidl 提供设置时区时间等方法
@frameworks/base/core/java/android/app/IAlarmManager.aidl
interface IAlarmManager {
/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
void set(String callingPackage, int type, long triggerAtTime, long windowLength,
long interval, int flags, in PendingIntent operation, in IAlarmListener listener,
String listenerTag, in WorkSource workSource, in AlarmManager.AlarmClockInfo alarmClock);
boolean setTime(long millis);
void setTimeZone(String zone);
void remove(in PendingIntent operation, in IAlarmListener listener);
long getNextWakeFromIdleTime();
AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
long currentNetworkTimeMillis();
}
@@frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
@Override
public boolean setTime(long millis) {
getContext().enforceCallingOrSelfPermission(
"android.permission.SET_TIME",
"setTime");
return setTimeImpl(millis);
}
boolean setTimeImpl(long millis) {
if (mNativeData == 0) {
Slog.w(TAG, "Not setting time since no alarm driver is available.");
return false;
}
synchronized (mLock) {
return setKernelTime(mNativeData, millis) == 0;
}
}
private native int setKernelTime(long nativeData, long millis);
@frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp
static jint android_server_AlarmManagerService_setKernelTime(JNIEnv*, jobject, jlong nativeData, jlong millis)
{
AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
struct timeval tv;
...
ret = impl->setTime(&tv);
return ret;
}
打开dev/rtc节点,然后通过ioctl RTC_SET_TIME
int AlarmImpl::setTime(struct timeval *tv)
{
struct rtc_time rtc;
struct tm tm, *gmtime_res;
int fd;
int res;
res = settimeofday(tv, NULL);
...
android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
fd = open(rtc_dev.string(), O_RDWR);
gmtime_res = gmtime_r(&tv->tv_sec, &tm);
if (!gmtime_res) {
ALOGV("gmtime_r() failed: %s\n", strerror(errno));
res = -1;
goto done;
}
memset(&rtc, 0, sizeof(rtc));
rtc.tm_sec = tm.tm_sec;
rtc.tm_min = tm.tm_min;
rtc.tm_hour = tm.tm_hour;
rtc.tm_mday = tm.tm_mday;
rtc.tm_mon = tm.tm_mon;
rtc.tm_year = tm.tm_year;
rtc.tm_wday = tm.tm_wday;
rtc.tm_yday = tm.tm_yday;
rtc.tm_isdst = tm.tm_isdst;
res = ioctl(fd, RTC_SET_TIME, &rtc);
if (res < 0)
ALOGV("RTC_SET_TIME ioctl failed: %s\n", strerror(errno));
done:
close(fd);
return res;
}