Android 时间同步服务NetworkTimeUpdateService

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值