zoukankan      html  css  js  c++  java
  • MTK NTP和NITZ更新时间的问题

    NITZ(Network Identity and Time Zone,网络标识和时区),是一种用于自动配置本地的时间和日期的机制,同时也通过无线网向移动设备提供运营商信息。NITZ是自从PHASE 2+ RELEASE 96 的GSM中的可选功能,经常被用来自动更新移动电话的系统时钟。NITZ需要运营商网络支持(通过CS网络),目前国内电信、移动都支持NITZ方式更新时间日期,而联通目前不支持。

    一。配置服务器端:

    那么比如在英国的话就可以选择下面两个服务器 

    0.uk.pool.ntp.org 
    1.uk.pool.ntp.org 

    它的一般格式都是number.country.pool.ntp.org

    中国的ntp服务器地址:

    server 133.100.11.8 prefer 
    server 210.72.145.44 
    server 203.117.180.36 
    server 131.107.1.10 
    server time.asia.apple.com 
    server 64.236.96.53 
    server 130.149.17.21 
    server 66.92.68.246 
    server www.freebsd.org 
    server 18.145.0.30 
    server clock.via.net 
    server 137.92.140.80 
    server 133.100.9.2 
    server 128.118.46.3 
    server ntp.nasa.gov 
    server 129.7.1.66 
    server ntp-sop.inria.fr
    
    server (国家授时中心服务器IP地址)

    二。修改默认NTP配置

    1.通过SntpClient.java来封装请求。

    frameworks/base/core/java/android/net/SntpClient.java

    public boolean requestTime(String host, int timeout) {
            DatagramSocket socket = null;
            try {
                socket = new DatagramSocket();
                socket.setSoTimeout(timeout);
                InetAddress address = InetAddress.getByName(host);
                byte[] buffer = new byte[NTP_PACKET_SIZE];
                DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
     
                // set mode = 3 (client) and version = 3
                // mode is in low 3 bits of first byte
                // version is in bits 3-5 of first byte
                buffer[0] = NTP_MODE_CLIENT | (NTP_VERSION << 3);
     
                // get current time and write it to the request packet
                long requestTime = System.currentTimeMillis();
                long requestTicks = SystemClock.elapsedRealtime();
                writeTimeStamp(buffer, TRANSMIT_TIME_OFFSET, requestTime);
     
                socket.send(request);
     
                // read the response
                DatagramPacket response = new DatagramPacket(buffer, buffer.length);
                socket.receive(response);
                long responseTicks = SystemClock.elapsedRealtime();
                long responseTime = requestTime + (responseTicks - requestTicks);
     
                // extract the results
                long originateTime = readTimeStamp(buffer, ORIGINATE_TIME_OFFSET);
                long receiveTime = readTimeStamp(buffer, RECEIVE_TIME_OFFSET);
                long transmitTime = readTimeStamp(buffer, TRANSMIT_TIME_OFFSET);
                long roundTripTime = responseTicks - requestTicks - (transmitTime - receiveTime);
                // receiveTime = originateTime + transit + skew
                // responseTime = transmitTime + transit - skew
                // clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2
                //             = ((originateTime + transit + skew - originateTime) +
                //                (transmitTime - (transmitTime + transit - skew)))/2
                //             = ((transit + skew) + (transmitTime - transmitTime - transit + skew))/2
                //             = (transit + skew - transit + skew)/2
                //             = (2 * skew)/2 = skew
                long clockOffset = ((receiveTime - originateTime) + (transmitTime - responseTime))/2;
                // if (false) Log.d(TAG, round trip:  + roundTripTime +  ms);
                // if (false) Log.d(TAG, clock offset:  + clockOffset +  ms);
     
                // save our results - use the times on this side of the network latency
                // (response rather than request time)
                mNtpTime = responseTime + clockOffset;
                mNtpTimeReference = responseTicks;
                mRoundTripTime = roundTripTime;
            } catch (Exception e) {
                if (false) Log.d(TAG, request time failed:  + e);
                return false;
            } finally {
                if (socket != null) {
                    socket.close();
                }
            }
     
            return true;
        }

    2.发起同步的,这个方法的主角为:NtpTrustedTime.java  在该类中通过forceRefresh方法来更新获取服务器时间。

    frameworks/base/core/java/android/util/NtpTrustedTime.java

    public boolean forceRefresh() {
            if (mServer == null) {
                // missing server, so no trusted time available
                return false;
            }
     
            if (LOGD) Log.d(TAG, forceRefresh() from cache miss);
            final SntpClient client = new SntpClient();
            if (client.requestTime(mServer, (int) mTimeout)) {
                mHasCache = true;
                mCachedNtpTime = client.getNtpTime();
                mCachedNtpElapsedRealtime = client.getNtpTimeReference();
                mCachedNtpCertainty = client.getRoundTripTime() / 2;
                return true;
            } else {
                return false;
            }
        }

    3.时间同步请求处理逻辑。在onPollNetworkTime方法中进行同步处理。

    /frameworks/base/services/core/java/com/android/server/NetworkTimeUpdateService.java

    private void onPollNetworkTime(int event) {
    //1、是否勾选自动同步时间配置
            // If Automatic time is not set, don't bother.
            if (!isAutomaticTimeRequested()) return;
    //2、mNitzTimeSetTime 来自Moderm,如果当前时间刚通过moderm更新不久,则不进行时间同步。
            final long refTime = SystemClock.elapsedRealtime();
            // If NITZ time was received less than mPollingIntervalMs time ago,
            // no need to sync to NTP.
            if (mNitzTimeSetTime != NOT_SET && refTime - mNitzTimeSetTime < mPollingIntervalMs) {
                resetAlarm(mPollingIntervalMs);
                return;
            }
            //3、如果机器刚启动,或者机器运行时间大于mPollingIntervalMs,即10天,或者设置等发起的主动更新时间请求,则发起网络时间同步请求。否则,10天后再进行时间同步。
            final long currentTime = System.currentTimeMillis();
            if (DBG) Log.d(TAG, System time =  + currentTime);
            // Get the NTP time
            if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + mPollingIntervalMs
                    || event == EVENT_AUTO_TIME_CHANGED) {
                if (DBG) Log.d(TAG, Before Ntp fetch);
    //3.1、是否含有时间缓冲,如无,发起时间同步,
                // force refresh NTP cache when outdated
                if (mTime.getCacheAge() >= mPollingIntervalMs) {
                    //LEUI-START [BUG][MOBILEP-6067] [System time sync added
                    //mTime.forceRefresh();
                    int index = mTryAgainCounter % mNtpServers.size();
                    if (DBG) Log.d(TAG, mTryAgainCounter =  + mTryAgainCounter + ;mNtpServers.size() =  + mNtpServers.size() + ;index =  + index + ;mNtpServers =  + mNtpServers.get(index));
                    //3.1.1、遍历时间服务器,发起时间同步
                    if (mTime instanceof NtpTrustedTime)
                    {
                        ((NtpTrustedTime) mTime).setServer(mNtpServers.get(index));
                        mTime.forceRefresh();
                        ((NtpTrustedTime) mTime).setServer(mDefaultServer);
                    }
                    else
                    {
                        mTime.forceRefresh();
                    }
                    //LEUI-END [BUG][MOBILEP-6067] [System time sync added
                }
    //3.2、获取最新同步的时间缓冲数据,如无,则再次发起时间同步,间隔时间为mPollingIntervalShorterMs,即30秒。
                // only update when NTP time is fresh
                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.
                    //3.2.1、如果开机第一次同步或者最新时间与当前时间差别超过mTimeErrorThresholdMs即25秒,则进行时间设定。否则认定新同步时间与当前时间差别不大,不覆盖当前时间。
                    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
                        //3.2.2、设定同步时间
                        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
                    //3.3 如果不大于最大同步次数,30秒后进行时间同步,否则,10天后更新。
                    mTryAgainCounter++;
                    if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
                        resetAlarm(mPollingIntervalShorterMs);
                    } else {
                        // Try much later
                        mTryAgainCounter = 0;
                        resetAlarm(mPollingIntervalMs);
                    }
                    return;
                }
            }
            //4、如果刚更新时间不久,则10天后再发起时间同步请求。
            resetAlarm(mPollingIntervalMs);
        }

    4.减小NTP请求的时间,确保开机联网立即同步时间

    /frameworks/base/core/res/res/values/config.xml

    <integer name="config_ntpPollingIntervalShorter">10000</integer>
  • 相关阅读:
    IBM MQ 学习
    spring中配置监听队列的MQ
    数据库优化(二)
    设计模式
    VBA学习笔记(2)--新建word文档并插入文字
    VBA代码分行
    excel保存时出现“请注意,您的文档的部分内容可能包含了文档检查器无法删除的个人信息”
    Excel VBA 操作 Word(入门篇)
    win10无法使用内置管理员账户打开应用
    五笔字根拆分规则_字根拆分方法
  • 原文地址:https://www.cnblogs.com/zxouxuewei/p/8431911.html
Copyright © 2011-2022 走看看