Android P系统时间更新分析

Android系统时间更新有两种方式:NITZ时间和NTP时间,NITZ由运营商提供,通过sim卡更新时间,NTP为通过网络,访问服务器获取时间,这里主要介绍NTP的方式

1、Android原生框架图

android 使用系统时间 安卓时间更新_android 使用系统时间

从上面框架图可以看出:其实网络时间更新最终是走到kernel驱动的,最终会调用到板子上的RTC芯片来更新时间。

2、代码位置

frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java
frameworks/base/services/core/java/com/android/server/AlarmManagerService.java
frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp
frameworks/base/core/java/android/os/SystemClock.java
frameworks/base/core/java/android/app/IAlarmManager.aidl
frameworks/base/core/jni/android_os_SystemClock.cpp
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

代码主要集中在framework层,framework层的services和jni

3、类图调用

android 使用系统时间 安卓时间更新_java_02

4、代码具体实现

4.1、 开机启动NetworkTimeUpdateService

开机就会启动NetworkTimeUpdateService和AlarmManagerService

NetworkTimeUpdateService作为Android系统服务,在SystemServer中启动

private void startOtherServices() {
	......
	NetworkTimeUpdateService networkTimeUpdater = null;
	  if (!disableNetwork && !disableNetworkTime) {
                traceBeginAndSlog("StartNetworkTimeUpdateService");
                try {
                    networkTimeUpdater = new NetworkTimeUpdateService(context);
                    ServiceManager.addService("network_time_update_service", networkTimeUpdater);
                } catch (Throwable e) {
                    reportWtf("starting NetworkTimeUpdate service", e);
                }
                traceEnd();
            }
            ......
            final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
			......
			try {
                if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
            } catch (Throwable e) {
                reportWtf("Notifying NetworkTimeService running", e);
            }
            ......
}

SystemServer中创建了NetworkTimeUpdateService,并注册到ServiceManager以供client端调用,接着调用NetworkTimeUpdateService的systemRunning方法

4.2、NetworkTimeUpdateService

先看看NetworkTimeUpdateService做了些什么?

NetworkTimeUpdateService构造函数中初始化了各种值:

public NetworkTimeUpdateService(Context context) {
        mContext = context;
        //获取NtpTrustedTime实例
        mTime = NtpTrustedTime.getInstance(context);
        //创建AlarmManager
        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
        //创建PendingPollIntent以供后面AlarmManager定时设置
        Intent pollIntent = new Intent(ACTION_POLL, null);
        mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
		//mPollingIntervalMs代表请求ntp服务器的频率
		//从config配置文件读取,86400000ms,就是一天
        mPollingIntervalMs = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_ntpPollingInterval);
        //mPollingIntervalShorterMs代表请求ntp服务器失败后再次
        //请求的时间间隔,为60000ms,就是1分钟
        mPollingIntervalShorterMs = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_ntpPollingIntervalShorter);
         //mTryAgainTimesMax 代表请求ntp服务器失败后再次尝试的
         //最大次数,为3次
        mTryAgainTimesMax = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_ntpRetry);
         //mTimeErrorThresholdMs代表请求ntp服务器得到的时间
         //和当前时间差大于此阈值,则更新时间。
        mTimeErrorThresholdMs = mContext.getResources().getInteger(
                com.android.internal.R.integer.config_ntpThreshold);
        mWakeLock = ((PowerManager) context.getSystemService(Context.POWER_SERVICE)).newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK, TAG);
    }

NtpTrustedTime

NtpTrustedTime通过单例获取,主要看下ntp服务器

public static synchronized NtpTrustedTime getInstance(Context context) {
        if (sSingleton == null) {
            final Resources res = context.getResources();
            final ContentResolver resolver = context.getContentResolver();
            //默认ntp服务器,从配置文件读取,time.android.com
            //这是google的服务器,国内用户如果请求这个服务器可能无法更新时间
            final String defaultServer = res.getString(
                    com.android.internal.R.string.config_ntpServer);
            //timeout为5s
            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);
            //默认都会使用配置文件中配置的ntp服务器
            final String server = secureServer != null ? secureServer : defaultServer;
            sSingleton = new NtpTrustedTime(server, timeout);
            sContext = context;
        }

        return sSingleton;
    }

4.3、systemRunning方法

接着看NetworkTimeUpdateService初始化完成后调用了systemRunning方法

public void systemRunning() {
		//注册telephony的广播
        registerForTelephonyIntents();
        //注册Alarm发送的广播
        registerForAlarms();
        //注册网络改变的广播
        registerForConnectivityIntents();

        HandlerThread thread = new HandlerThread(TAG);
        thread.start();
        mHandler = new MyHandler(thread.getLooper());
        //发送EVENT_POLL_NETWORK_TIME消息
        mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
        /*
        创建SettingsObserver,监听Settings中AUTO_TIME
        值的变化
        */
        mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
        mSettingsObserver.observe(mContext);
    }
    /*
    TelephonyIntents.ACTION_NETWORK_SET_TIME 和 
    TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE 广播来监听来自运营商
    的时间改变
    */
 private void registerForTelephonyIntents() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
        intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
        mContext.registerReceiver(mNitzReceiver, intentFilter);
    }
    /*
    注册自定义的广播,ACTION_POLL由Alarm定时器来发送,
    在NetworkTimeUpdateService构造方法中创建了mPendingPollIntent
    供Alarm发送
    */
 private static final String ACTION_POLL =
            "com.android.server.NetworkTimeUpdateService.action.POLL";
 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));
    }
    /*
    监听网络发生变化的广播
    */
private void registerForConnectivityIntents() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
        mContext.registerReceiver(mConnectivityReceiver, intentFilter);
    }

SettingsObserver

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的值,也就是Settings中自动更新网络时间的开关
            resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
                    false, this);
        }

        @Override
        public void onChange(boolean selfChange) {
            //当AUTO_TIME变化时发送EVENT_POLL_NETWORK_TIME消息????
            //不是发送的 EVENT_AUTO_TIME_CHANGED 吗?????
            mHandler.obtainMessage(mMsg).sendToTarget();
        }
    }

再看一下mHandler,其实下面三个消息都会触发请求ntp服务器的方法,下面来挨着看下这三个消息的发送条件

private static final int EVENT_AUTO_TIME_CHANGED = 1;
 private static final int EVENT_POLL_NETWORK_TIME = 2;
 private static final int EVENT_NETWORK_CHANGED = 3;
 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;
            }
        }
    }

EVENT_AUTO_TIME_CHANGED
这个就是在SettingsObserver的onChange方法里发送的,当我们更新Settings中的AUTO_TIME开关打开就会触发

EVENT_POLL_NETWORK_TIME
Alarms发送广播:“com.android.server.NetworkTimeUpdateService.action.POLL”;触发

EVENT_NETWORK_CHANGED
监听到网络发生变化之后发送的

4.4、onPollNetworkTime

private void onPollNetworkTime(int event) {
        // 如果没有开启自动更新时间直接return
        if (!isAutomaticTimeRequested()) return;
        mWakeLock.acquire();
        try {
            onPollNetworkTimeUnderWakeLock(event);
        } finally {
            mWakeLock.release();
        }
    }

onPollNetworkTimeUnderWakeLock

private void onPollNetworkTimeUnderWakeLock(int event) {
        //从开机到现在的时间
        final long refTime = SystemClock.elapsedRealtime();
        //如果已经通过运营商更新了时间并且上次更新的时间到当前为止
        //小于1天则设置一个Alarm定时器(定时器为1天后触发)并且return
        if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
            resetAlarm(mPollingIntervalMs);
            return;
        }
        final long currentTime = System.currentTimeMillis();
        // 如果没有设置过ntp时间或者开机但现在的时间大于等于最后一次请求ntp
        //服务器加上1天的时间或者时因为Settings的自动更新开关触发的更新时间
        if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
                || event == EVENT_AUTO_TIME_CHANGED) {
            if (DBG) Log.d(TAG, "Before Ntp fetch");

            // mTime.getCacheAge等于上次请求ntp服务器的时间
            //如果大于等于1天则强制更新时间
            if (mTime.getCacheAge() >= mPollingIntervalMs) {
                mTime.forceRefresh();
            }

            // 如果上次请求ntp服务器的时间小于1天
            if (mTime.getCacheAge() < mPollingIntervalMs) {
                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.
                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
                        || mLastNtpFetchTime == NOT_SET) {
                    // Set the system time
                    if (DBG && mLastNtpFetchTime == NOT_SET
                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
                        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
                    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 {
               //如果上次请求ntp服务器的时间已经大于1天了
                mTryAgainCounter++;
                //最多尝试次数为mTryAgainTimesMax,3次
                if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
                    //尝试请求ntp服务器的时间间隔为mPollingIntervalShorterMs,1分钟
                    resetAlarm(mPollingIntervalShorterMs);
                } else {
                    // 如果三次请求之后则需要在1天之后再请求ntp服务器
                    mTryAgainCounter = 0;
                    resetAlarm(mPollingIntervalMs);
                }
                return;
            }
        }
        //保证无论如何都可以设置一个1天后请求ntp服务器的定时器
        resetAlarm(mPollingIntervalMs);
    }
    private void resetAlarm(long interval) {
        mAlarmManager.cancel(mPendingPollIntent);
        long now = SystemClock.elapsedRealtime();
        long next = now + interval;
        //在next时间之后执行mPendingPollIntent,mPendingPollIntent在
        //NetworkTimeUpdateService构造方法中初始化,作用时发送
        //自定义的ACTION_POLL广播
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
    }

4.5、mTime.forceRefresh()

NtpTrustedTime中的forceRefresh方法强制刷新时间

@Override
    public boolean forceRefresh() {
       //如果ntp服务器为空则返回
        if (TextUtils.isEmpty(mServer)) {
            // missing server, so no trusted time available
            return false;
        }
        synchronized (this) {
            if (mCM == null) {
                mCM = (ConnectivityManager) sContext.getSystemService(Context.CONNECTIVITY_SERVICE);
            }
        }

        final NetworkInfo ni = mCM == null ? null : mCM.getActiveNetworkInfo();
        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();
        //请求mServer,也就是time.android.com,5s超时
        if (client.requestTime(mServer, (int) mTimeout)) {
            mHasCache = true;
            //请求成功之后获取的ntp时间
            mCachedNtpTime = client.getNtpTime();
            mCachedNtpElapsedRealtime = client.getNtpTimeReference();
            mCachedNtpCertainty = client.getRoundTripTime() / 2;
            return true;
        } else {
            return false;
        }
    }

请求完成之后获取的时间如何更新呢,回到NetworkTimeUpdateService,
mCachedNtpTime = client.getNtpTime();

private void onPollNetworkTimeUnderWakeLock(int event) {
		......
		 
		  if (mTime.getCacheAge() >= mPollingIntervalMs) {
                mTime.forceRefresh();
            }
            //强制刷新时间之后
            if (mTime.getCacheAge() < mPollingIntervalMs) {
               //ntp请求服务器之后获取的时间
                final long ntp = mTime.currentTimeMillis();
                mTryAgainCounter = 0;
               
                if (Math.abs(ntp - currentTime) > mTimeErrorThresholdMs
                        || mLastNtpFetchTime == NOT_SET) {
                    // Set the system time
                    if (DBG && mLastNtpFetchTime == NOT_SET
                            && Math.abs(ntp - currentTime) <= mTimeErrorThresholdMs) {
                    //保证获取的网络时间不会超过最大值
                    if (ntp / 1000 < Integer.MAX_VALUE) {
                       //设置ntp时间到系统中
                        SystemClock.setCurrentTimeMillis(ntp);
                    }
                } else {
                    if (DBG) Log.d(TAG, "Ntp time is close enough = " + ntp);
                }
                mLastNtpFetchTime = SystemClock.elapsedRealtime();
            }
		......
}

4.6、SystemClock.setCurrentTimeMillis(ntp)

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;
}

frameworks/base/core/java/android/app/IAlarmManager.aidl

/* //device/java/android/android/app/IAlarmManager.aidl
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
package android.app;

import android.app.AlarmManager;
import android.app.IAlarmListener;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.WorkSource;

/**
 * System private API for talking with the alarm manager service.
 *
 * {@hide}
 */
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();
}

framework/base/services/core/java/com/android/server/AlarmManagerService.java

final IAlarmManager mgr = IAlarmManager.Stub
                .asInterface(ServiceManager.getService(Context.ALARM_SERVICE));
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;
        }
    }

getSystemService()返回的不再是IAlarmManager接口,而是AlarmManager对象。

Framework/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;
    int ret;

    if (millis <= 0 || millis / 1000LL >= INT_MAX) {
        return -1;
    }

    tv.tv_sec = (time_t) (millis / 1000LL);
    tv.tv_usec = (suseconds_t) ((millis % 1000LL) * 1000LL);

    ALOGD("Setting time of day to sec=%d\n", (int) tv.tv_sec);

    ret = impl->setTime(&tv);

    if(ret < 0) {
        ALOGW("Unable to set rtc to %ld: %s\n", tv.tv_sec, strerror(errno));
        ret = -1;
    }
    return ret;
}

AlarmImpl::setTime函数实现

int AlarmImpl::setTime(struct timeval *tv)
{
    struct rtc_time rtc;
    struct tm tm, *gmtime_res;
    int fd;
    int res;

    res = settimeofday(tv, NULL);
    if (res < 0) {
        ALOGV("settimeofday() failed: %s\n", strerror(errno));
        return -1;
    }

    if (rtc_id < 0) {
        ALOGV("Not setting RTC because wall clock RTC was not found");
        errno = ENODEV;
        return -1;
    }

    android::String8 rtc_dev = String8::format("/dev/rtc%d", rtc_id);
    fd = open(rtc_dev.string(), O_RDWR);
    if (fd < 0) {
        ALOGV("Unable to open %s: %s\n", rtc_dev.string(), strerror(errno));
        return res;
    }

    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;
}

调用res = settimeofday(tv, NULL);函数来设置系统时间
调用res = ioctl(fd, RTC_SET_TIME, &rtc);将时钟设置到RTC设备节点
最终将时间写到/dev/rtc*文件。

5、参考

RTC是什么?请参考: https://tech.hqew.com/fangan_1991867