Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android4.4 Telephony流程分析——SIM卡開機時的數據加載

Android4.4 Telephony流程分析——SIM卡開機時的數據加載

編輯:關於Android編程

本文代碼以MTK平台Android 4.4為分析對象,與Google原生AOSP有些許差異,請讀者知悉。

本文主要介紹sim卡數據的讀取過程,當射頻狀態處於准備狀態時,此時UiccCardApplication應處於AppState.APPSTATE_READY狀態,我們沿著這個信號跟蹤下去。閱讀本文時可先閱讀Android4.4 Telephony流程分析——SIM卡開機時的初始化一文,了解Radio和sim卡狀態更新過程。

先來看一下數據加載的序列圖:

\

step1~step3,走的是更新過程,創建過程參考Android4.4 Telephony流程分析——SIM卡開機時的初始化一文step21之後的步驟。

step4,通過Modem查褮喎?/kf/ware/vc/" target="_blank" class="keylink">vc2ltv6i1xEZETii5zLaosqa6xSnK/b7doaM8L3A+CjxwPnN0ZXA1o6zNqLn9TW9kZW2y6dGvc2ltv6i1xHBpbjHXtMysoaM8L3A+CjxwPnN0ZXA2fnN0ZXA3o6y9q3BpbjHXtMyszajWqrP2yKWjrEljY0NhcmRQcm94ebvh16Ky4W1QaW5Mb2NrZWRSZWdpc3RyYW50c6GjPC9wPgo8cD5zdGVwOH5zdGVwOaOsvatzaW2/qHJlYWR517TMrLeis/bIpaGjPC9wPgo8cD48L3A+CjxwcmUgY2xhc3M9"brush:java;"> private void notifyReadyRegistrantsIfNeeded(Registrant r) { if (mDestroyed) { return; } if (mAppState == AppState.APPSTATE_READY) { if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED || mPin1State == PinState.PINSTATE_ENABLED_BLOCKED || mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) { loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!"); // Don't notify if application is in insane state return; } if (r == null) { if (DBG) log("Notifying registrants: READY"); mReadyRegistrants.notifyRegistrants(); } else { if (DBG) log("Notifying 1 registrant: READY"); r.notifyRegistrant(new AsyncResult(null, null, null)); } } }
如果此時pin1是被激活的,也就是sim卡開啟了pin1鎖,sim卡ready狀態就不會發出去。

監聽mReadyRegistrants狀態變化的對象很多,主要有:SIMRecords(同類的還有RuimRecords、IsimUiccRecords),IccCardProxy(會將SIM卡狀態廣播出去),GsmServiceStateTracker(會根據SIM狀態去注冊網絡),這裡主要說一下SIMRecords,讀取SIM的數據。


step12,fetchSimRecords()方法:

//MTK-END [mtk80601][111215][ALPS00093395]
    protected void fetchSimRecords() {
        mRecordsRequested = true;

        if (DBG) log("fetchSimRecords " + mRecordsToLoad);

        mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));//讀IMSI
        mRecordsToLoad++;

        //iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
        //mRecordsToLoad++;

        // FIXME should examine EF[MSISDN]'s capability configuration
        // to determine which is the voice/data/fax line
        //new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
                    //obtainMessage(EVENT_GET_MSISDN_DONE));
        //recordsToLoad++;

        // Record number is subscriber profile
        mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
        mRecordsToLoad++;

        mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
        mRecordsToLoad++;

        // Record number is subscriber profile
        mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
        mRecordsToLoad++;


        // Also load CPHS-style voice mail indicator, which stores
        // the same info as EF[MWIS]. If both exist, both are updated
        // but the EF[MWIS] data is preferred
        // Please note this must be loaded after EF[MWIS]
        mFh.loadEFTransparent(
                EF_VOICE_MAIL_INDICATOR_CPHS,
                obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
        mRecordsToLoad++;

        // Same goes for Call Forward Status indicator: fetch both
        // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
        mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
        mRecordsToLoad++;
        mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
        mRecordsToLoad++;


        //getSpnFsm(true, null);

        mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
        mRecordsToLoad++;

        //mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
        //recordsToLoad++;

        mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
        mRecordsToLoad++;

        mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
        mRecordsToLoad++;

        mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
        mRecordsToLoad++;

        mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
        mRecordsToLoad++;

        /*
          Detail description:
          This feature provides a interface to get menu title string from EF_SUME
        */
        if (mTelephonyExt != null) {
            if (mTelephonyExt.isSetLanguageBySIM()) {
                mFh.loadEFTransparent(EF_SUME, obtainMessage(EVENT_QUERY_MENU_TITLE_DONE)); 
                mRecordsToLoad++;
            }
        } else {
            loge("fetchSimRecords(): mTelephonyExt is null!!!");
        }

        fetchCPHSOns();

        // XXX should seek instead of examining them all
        if (false) { // XXX
            mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
            mRecordsToLoad++;
        }

        if (CRASH_RIL) {
            String sms = "0107912160130310f20404d0110041007030208054832b0120"
                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                         + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
                         + "ffffffffffffffffffffffffffffff";
            byte[] ba = IccUtils.hexStringToBytes(sms);

            mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
                            obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
        }
        if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
        /*
        * Here, we assume that PHB is ready and try to read the entries.
        * If it is not, we will receive the event EVENT_PHB_READY later.
        * Then, we will ready the PHB entries again.
        */
        fetchPhbRecords();//讀adn聯系人

	fetchRatBalancing();
    }

讀SIM卡是要通過Modem的,上層讀Modem就得通過RIL,我們以讀ADN聯系人fetchPhbRecords()為例,來看看讀取過程step13~step22,主要是通過IccFileHandler實現,先請求adn的長度(step16~step19),然後再請求具體的adn聯系人數據step20~step22,這個過程就是與Modem交互的過程,讀者可以先了解一下SIM卡的文件結構,才能更好的理解為什麼這樣讀,我也不甚熟悉。

step23,獲取SIM卡內置的緊急號碼,這個是由運營商定制的。

step24~step26,當需要load的數據都load完成,才會執行,再在onAllRecordsLoaded中發布mRecordsLoadedRegistrants通知。

    protected void onRecordLoaded() {
        // One record loaded successfully or failed, In either case
        // we need to update the recordsToLoad count
        mRecordsToLoad -= 1;
        if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);

        if (mRecordsToLoad == 0 && mRecordsRequested == true) {
            onAllRecordsLoaded();
        } else if (mRecordsToLoad < 0) {
            loge("recordsToLoad <0, programmer error suspected");
            mRecordsToLoad = 0;
        }
    }

step27之後的步驟,都是對mRecordsLoadedRegistrants偵聽的響應,IccCardProxy偵聽到後,會發廣播給外界:

    private void broadcastIccStateChangedIntent(String value, String reason) {
        synchronized (mLock) {
            if (mQuietMode) {
                log("QuietMode: NOT Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
                        + " reason " + reason);
                return;
            }

            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
            //intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
            intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mSimId);
            if (DBG) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value
                    + " reason " + reason + " sim id " + mSimId);
            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
                    UserHandle.USER_ALL);
        }
    }

    public void broadcastIccStateChangedExtendIntent(String value, String reason) {
        synchronized (mLock) {
            if (mQuietMode) {
                log("QuietMode: NOT Broadcasting extend intent ACTION_SIM_STATE_CHANGED " +  value
                        + " reason " + reason);
                return;
            }

            Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED_EXTEND);
            //intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
            intent.putExtra(PhoneConstants.GEMINI_SIM_ID_KEY, mSimId);
            if (DBG) log("Broadcasting intent ACTION_SIM_STATE_CHANGED_EXTEND " +  value
                    + " reason " + reason + " sim id " + mSimId);
            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
                    UserHandle.USER_ALL);
        }
    }

GsmServiceStateTracker會去刷新運營商名稱,有需要的話,還會重新選擇注冊網絡。


右鍵復制圖片地址,在浏覽器中打開即可查看大圖。

未完待續,有不對的地方,請指正。


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved