Android4.4 Telephony流程分析——SIM卡開機時的資料載入

來源:互聯網
上載者:User

標籤:des   android   style   blog   http   io   color   ar   os   

本文代碼以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查詢sim卡的FDN(限制撥號號碼)資料。

step5,通過Modem查詢sim卡的pin1狀態。

step6~step7,將pin1狀態通知出去,IccCardProxy會註冊mPinLockedRegistrants。

step8~step9,將sim卡ready狀態發出去。

    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會去重新整理電訊廠商名稱,有需要的話,還會重新選擇註冊網路。


右鍵複製圖片地址,在瀏覽器中開啟即可查看大圖。

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


Android4.4 Telephony流程分析——SIM卡開機時的資料載入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.