你的浏览器不支持canvas

松子的博客

当你有了责任感,就值得被托付

NITZ时间同步流程

Date: Author: Zarey C.Y. Chang

本文章采用 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议 进行许可。转载请注明来自Z2CARE的博客

NITZ time update similar from ntp, but it have time zone, so we start to learn it.

NITZ时间同步流程

sequenceDiagram
sprd_ril->>sprd_libril: RIL_onUnsolicitedResponse
sprd_libril->>sprd_libril: sendResponse
sprd_libril->>RILJ: RIL_UNSOL_NITZ_TIME_RECEIVED
RILJ->>RILJ: setOnNITZTime
RILJ->>GsmServiceStateTracker: EVENT_NITZ_TIME
GsmServiceStateTracker->>GsmServiceStateTracker: setTimeFromNITZString

RILC层

1. 接收到AT上报

++vendor/sprd/proprietories-source/ril/sprd_ril/sprd_ril.c +14034++

static void onUnsolicited (const char *s, const char *sms_pdu)
{
    ...
14034    if (strStartsWith(s, "+CTZV:")) {
14035        /*NITZ time */
14036        char *response;
14037        char *tmp;
14038        char *raw_str;
14039
14040        line = strdup(s);
14041        tmp = line;
14042        at_tok_start(&tmp);//获取:后的内容
14043
14044        err = at_tok_nextstr(&tmp, &response);//检查是否有多余内容
14045        if (err != 0) {
14046            RILLOGE("invalid NITZ line %s\n", s);
14047        } else {
14048#if defined (GLOBALCONFIG_RIL_SAMSUNG_LIBRIL_INTF_EXTENSION)
14049            raw_str = (char *)malloc(strlen(response) + 1);
14050            memcpy(raw_str, response, strlen(response) + 1)
14051            RIL_requestTimedCallback (onNitzReceived, raw_str, NULL);
14052#elif defined (RIL_SPRD_EXTENSION)
14053            **RIL_onUnsolicitedResponse** (//此函数是指针注册在RILD中
14054                    RIL_UNSOL_NITZ_TIME_RECEIVED,//上报给RILJ的ID
14055                    response, strlen(response)+1);//response是内容,长度加1是因为不含换行
14056#endif
14057        }

2. RIL_onUnsolicitedResponse处理

++vendor/sprd/proprietories-source/ril/sprd_libril/sprd_ril.c +6322++

6326    int unsolResponseIndex = -1;
6327    int ret;
6328    int64_t timeReceived = 0;
...
6431    // Mark the time this was received, doing this
6432    // after grabing the wakelock incase getting
6433    // the elapsedRealTime might cause us to goto
6434    // sleep.
6435    if (unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {
6436        timeReceived = elapsedRealtime();//记录此刻系统运行时间,用于校准NITZ时间
6437    }
...
6441    Parcel p;//打包数据给RILJ
6442
6443    p.writeInt32 (RESPONSE_UNSOLICITED);//data 0,上报类型是非主动请求
6444    p.writeInt32 (unsolResponse)//data 1,上报的信息ID
6445
6446    ret = s_unsolResponses[unsolResponseIndex]
6447                .responseFunction(p, data, datalen);//三个技巧用法
...
6468            p.writeInt64(timeReceived)//data 2,系统运行时间
...
6472    ret = **sendResponse(p, socket_type);**
6473    if (ret != 0 && unsolResponse == RIL_UNSOL_NITZ_TIME_RECEIVED) {//这里用于备份NITZ时间
6474
6475        // Unfortunately, NITZ time is not poll/update like everything
6476        // else in the system. So, if the upstream client isn't connected,
6477        // keep a copy of the last NITZ response (with receive time noted
6478        // above) around so we can deliver it when it is connected
...
6484
6485        s_lastNITZTimeData = malloc(p.dataSize());
6486        s_lastNITZTimeDataSize = p.dataSize();
6487        memcpy(s_lastNITZTimeData, p.data(), p.dataSize());
6488    }
...

3. 继续传递

++vendor/sprd/proprietories-source/ril/sprd_libril/sprd_ril.cpp++

2734static int
2735sendResponse (Parcel &p, RIL_SOCKET_TYPE socket_type) {
2736    printResponse;//打印log信息
2737    return sendResponseRaw(p.data(), p.dataSize(), socket_type);//传递打包后的信息
2738}
  1. 写入节点

    ++vendor/sprd/proprietories-source/ril/sprd_libril/sprd_ril.cpp++

    2687static int
    2688sendResponseRaw (const void *data, size_t dataSize, RIL_SOCKET_TYPE socket_type) {
    2689    int fd = s_rilSocketParam.fdCommand;//socket节
    2690    int ret;
    ...
    2709    pthread_mutex_lock(writeMutex);//加锁
    2710
    2711    header = htonl(dataSize);//序列话后顺序
    2712
    2713    ret = blockingWrite(fd, (void *)&header, sizeof(header));//写入size
    ...
    2721    ret = blockingWrite(fd, data, dataSize)//写入data
    2728
    2729    pthread_mutex_unlock(writeMutex);//解锁
    2730
    2731    return 0;
    2732}
    

RILJ层

1. 处理上报消息

++frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java++

2632    protected void
2633    processUnsolicited (Parcel p) {
...
2637        response = p.readInt();//读出消息ID
2638
...
2653            case RIL_UNSOL_NITZ_TIME_RECEIVED: ret =  responseString(p); break;//读出消息字串
...
2797                long nitzReceiveTime = p.readLong()//读出携带的系统运行时间
2798
2799                Object[] result = new Object[2];
2800
2801                result[0] = ret;
2802                result[1] = Long.valueOf(nitzReceiveTime);
2803
...
2807                if (ignoreNitz) {
2808                    if (RILJ_LOGD) riljLog("ignoring UNSOL_NITZ_TIME_RECEIVED");
2809                } else {
2810                    if (mNITZTimeRegistrant != null) {
2811
2812                        **mNITZTimeRegistrant**
2813                            .notifyRegistrant(new AsyncResult (null, result, null);//注意mNITZTimeRegistrant的初始化
2814                    } else {
2815                        // in case NITZ time registrant isnt registered yet
2816                        mLastNITZTimeInfo = result;
2817                    }
2818                }
2819            break;

2. 观察监听者是如何处理的

++frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java++

665    @Override public void
666    setOnNITZTime(Handler h, int what, Object obj) {
667        **super.setOnNITZTime(h, what, obj);**//在父类BaseCommands.java里实例化
668
669        // Send the last NITZ time if we have it
670        if (mLastNITZTimeInfo != null) {
671            mNITZTimeRegistrant
672                .notifyRegistrant(
673                    new AsyncResult (null, mLastNITZTimeInfo, null));
674            mLastNITZTimeInfo = null;
675        }
676    }

3. 注册监听的GsmServiceStateTracker

++frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java++

252    public GsmServiceStateTracker(GSMPhone phone) {
...
268        mCi.setOnNITZTime(this, EVENT_NITZ_TIME, null);//注册消息事件
...
333    @Override
334    public void handleMessage (Message msg) {
...
450            case EVENT_NITZ_TIME:
451                ar = (AsyncResult) msg.obj;
452
453                String nitzString = (String)((Object[])ar.result)[0];//读出携带的res
454                long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();//读出携带的系统运行时间
455
456                setTimeFromNITZString(nitzString, nitzReceiveTime);
457                break;

4. 关键的设置时间函

++

1747    /**
1748     * nitzReceiveTime is time_t that the NITZ time was posted
1749     */
1750    private void setTimeFromNITZString (String nitz, long nitzReceiveTime) {
1751        // "yy/mm/dd,hh:mm:ss(+/-)tz"
1752        // tz is in number of quarter-hours
1753
1754        long start = SystemClock.elapsedRealtime();//记录当前系统运行时间
1755        if (DBG) {log("NITZ: " + nitz + "," + nitzReceiveTime +
1756                        " start=" + start + " delay=" + (start - nitzReceiveTime));
1757        }
1758
1759        try {
1760            /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
1761             * offset as well (which we won't worry about until later) */
1762            Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
1763
1764            c.clear();
1765            c.set(Calendar.DST_OFFSET, 0);//夏令时偏移0
1766
1767            String[] nitzSubs = nitz.split("[/:,+-]");
1768
1769            try {
1770                int year = 2000 + Integer.parseInt(nitzSubs[0]);
1771                c.set(Calendar.YEAR, year);
1772
1773                // month is 0 based!
1774                int month = Integer.parseInt(nitzSubs[1]) - 1;
1775                c.set(Calendar.MONTH, month);
1776
1777                int date = Integer.parseInt(nitzSubs[2]);
1778                c.set(Calendar.DATE, date);
1779
1780                int hour = Integer.parseInt(nitzSubs[3]);
1781                c.set(Calendar.HOUR, hour);
1782
1783                int minute = Integer.parseInt(nitzSubs[4]);
1784                c.set(Calendar.MINUTE, minute);
1785
1786                int second = Integer.parseInt(nitzSubs[5]);
1787                c.set(Calendar.SECOND, second);
1788            } catch (NumberFormatException e) {
1789                log("NITZ: time format is incorrect");
1790                // set nitzReceiveTime to an invalid value to bypass the time update
1791                nitzReceiveTime = SystemClock.elapsedRealtime() + 60 * 1000;
1792            }//时间分割完毕
1793
1794            boolean sign = (nitz.indexOf('-') == -1);//时区偏移方向
1795
1796            int tzOffset = Integer.parseInt(nitzSubs[6]);//时区偏移值
1797
1798            int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
1799                                              : 0;//夏令时偏移
1800            if (DBG) log("sign = " + sign + "; tzOffset = " + tzOffset + "; dst = " + dst);
1801
1802            // The zone offset received from NITZ is for current local time,
1803            // so DST correction is already applied.  Don't add it again.
1804            //
1805            // tzOffset += dst * 4;
1806            //
1807            // We could unapply it if we wanted the raw offset.
1808
1809            tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;//时区偏移
1810
1811            TimeZone    zone = null;
1812
1813            // As a special extension, the Android emulator appends the name of
1814            // the host computer's timezone to the nitz string. this is zoneinfo
1815            // timezone name of the form Area!Location or Area!Location!SubLocation
1816            // so we need to convert the ! into /
1817            if (nitzSubs.length >= 9) {//转换时区信息
1818                String  tzname = nitzSubs[8].replace('!','/');
1819                if (DBG) log("tzname = " + tzname);
1820                zone = TimeZone.getTimeZone( tzname );
1821            }
1822
1823            String operatorIsoCountryProperty = TelephonyManager.getProperty(
1824                    TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, mPhone.getPhoneId());//以下是时区设置
1825            String iso = SystemProperties.get(operatorIsoCountryProperty);
1826
1827            if (DBG) log("iso = " + iso);
1828
1829            if (zone == null) {
1830
1831                if (mGotCountryCode) {
1832                    if (iso != null && iso.length() > 0) {
1833                        zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
1834                                c.getTimeInMillis(),
1835                                iso);
1836                    } else {
1837                        // We don't have a valid iso country code.  This is
1838                        // most likely because we're on a test network that's
1839                        // using a bogus MCC (eg, "001"), so get a TimeZone
1840                        // based only on the NITZ parameters.
1841                        zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
1842                    }
1843                }
1844            }
1845
1846            if ((zone == null) || (mZoneOffset != tzOffset) || (mZoneDst != (dst != 0))){
1847                // We got the time before the country or the zone has changed
1848                // so we don't know how to identify the DST rules yet.  Save
1849                // the information and hope to fix it up later.
1850
1851                mNeedFixZoneAfterNitz = true;
1852                mZoneOffset  = tzOffset;
1853                mZoneDst     = dst != 0;
1854                mZoneTime    = c.getTimeInMillis();
1855            }
1856
1857            if (zone != null) {
1858                if (getAutoTimeZone()) {
1859                    setAndBroadcastNetworkSetTimeZone(zone.getID());
1860                }
1861                saveNitzTimeZone(zone.getID());
1862            }
1863
1864            String ignore = SystemProperties.get("gsm.ignore-nitz");
1865            if (ignore != null && ignore.equals("yes")) {
1866                log("NITZ: Not setting clock because gsm.ignore-nitz is set");
1867                return;
1868            }
1869
1870            try {//处理时间设置
1871                mWakeLock.acquire();
1872
1873                if (getAutoTime()) {
1874                    long millisSinceNitzReceived
1875                            = SystemClock.elapsedRealtime() - nitzReceiveTime;
1876
1877                    if (millisSinceNitzReceived < 0) {
1878                        // Sanity check: something is wrong
1879                        if (DBG) {
1880                            log("NITZ: not setting time, clock has rolled "
1881                                            + "backwards since NITZ time was received, "
1882                                            + nitz);
1883                        }
1884                        return;
1885                    }
1886
1887                    if (millisSinceNitzReceived > Integer.MAX_VALUE) {
1888                        // If the time is this far off, something is wrong > 24 days!
1889                        if (DBG) {
1890                            log("NITZ: not setting time, processing has taken "
1891                                        + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
1892                                        + " days");
1893                        }
1894                        return;
1895                    }
1896
1897                    // Note: with range checks above, cast to int is safe
1898                    c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
1899
1900                    if (DBG) {
1901                        log("NITZ: Setting time of day to " + c.getTime()
1902                            + " NITZ receive delay(ms): " + millisSinceNitzReceived
1903                            + " gained(ms): "
1904                            + (c.getTimeInMillis() - System.currentTimeMillis())
1905                            + " from " + nitz);
1906                    }
1907
1908                    setAndBroadcastNetworkSetTime(c.getTimeInMillis());//此处设置时间
1909                    Rlog.i(LOG_TAG, "NITZ: after Setting time of day");
1910                }
1911                SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
1912                saveNitzTime(c.getTimeInMillis());
1913                if (VDBG) {
1914                    long end = SystemClock.elapsedRealtime();
1915                    log("NITZ: end=" + end + " dur=" + (end - start));
1916                }
1917                mNitzUpdatedTime = true;
1918            } finally {
1919                mWakeLock.release();
1920            }
1921        } catch (RuntimeException ex) {
1922            loge("NITZ: Parsing NITZ time " + nitz + " ex=" + ex);
1923        }
1924    }
...
1974    /**
1975     * Set the time and Send out a sticky broadcast so the system can determine
1976     * if the time was set by the carrier.
1977     *
1978     * @param time time set by network
1979     */
1980    private void setAndBroadcastNetworkSetTime(long time) {
1981        if (DBG) log("setAndBroadcastNetworkSetTime: time=" + time + "ms");
1982        SystemClock.setCurrentTimeMillis(time);//调用AlarmManagerService的setTime设置时间
1983        Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
1984        intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
1985        intent.putExtra("time", time);
1986        mPhone.getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);//用于NetworkTimeUpdateService.java记录本次设置的时间
1987    }

对于本文内容有问题或建议的小伙伴,欢迎在文章底部留言交流讨论。