Android4.4 Telephony流程分析——SIM卡開機時的初始化

來源:互聯網
上載者:User

Android4.4 Telephony流程分析——SIM卡開機時的初始化

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


本文主要介紹MTK Android開機時,SIM卡的Framework部分初始化過程。

先看一段注釋:

 /* Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed" * notifications. When such notification arrives UiccController will call * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS * request appropriate tree of uicc objects will be created. * * Following is class diagram for uicc classes: * *                       UiccController *                            # *                            | *                        UiccCard *                          #   # *                          |   ------------------ *                    UiccCardApplication    CatService *                      #            # *                      |            | *                 IccRecords    IccFileHandler *                 ^ ^ ^           ^ ^ ^ ^ ^ *    SIMRecords---- | |           | | | | ---SIMFileHandler *    RuimRecords----- |           | | | ----RuimFileHandler *    IsimUiccRecords---           | | -----UsimFileHandler *                                 | ------CsimFileHandler *                                 ----IsimFileHandler * * Legend: # stands for Composition *         ^ stands for Generalization */

這是UiccController.java檔案開頭對UiccController的注釋,意思很明顯UiccController是對Android SIM卡管理的控制器。

下面是SIM卡初始化順序圖表:



UiccController的初始化是在phone進程啟動的時候,PhoneFactory調用makeDefaultPhone()建立預設的Phone,然後走MTK雙卡流程中,調用MTKPhoneFactory.makeDefaultPhone()建立的,

{for (int l2 = 0; l2 < PhoneConstants.GEMINI_SIM_NUM; l2++)if (j1 == l2)ai[l2] = j;elseai[l2] = 1;I = new RIL(context, ai[0], l, 0);J = new RIL(context, ai[1], l, 1);}UiccController.make(context, I, 0);UiccController.make(context, J, 1);GSMPhone agsmphone[] = new GSMPhone[PhoneConstants.GEMINI_SIM_NUM];

上面是反編譯MTK的static_gemini_intermediates庫看到的,在RIL建立完成時,使用UiccController.make()初始化:

    public static UiccController make(Context c, CommandsInterface ci, int simId) {        synchronized (mLock) {            if (FeatureOption.MTK_GEMINI_SUPPORT) {                if(mInstance[simId] != null) {                    throw new RuntimeException("UiccController.make() should only be called once");                }                mInstance[simId] = new UiccController(c, ci, simId);                return mInstance[simId];            } else {                if (mInstance[0] != null) {                    throw new RuntimeException("UiccController.make() should only be called once");                }                mInstance[0] = new UiccController(c, ci);                return mInstance[0];            }        }    }

UiccController的建立使用了單例模式,使用時調用getInstance()擷取,

    public static UiccController getInstance(int simId) {        synchronized (mLock) {            if (FeatureOption.MTK_GEMINI_SUPPORT) {                if(mInstance[simId] == null) {                    throw new RuntimeException(                        "UiccController.getInstance can't be called before make()");                }                return mInstance[simId];            } else {                if (mInstance[0] == null) {                    throw new RuntimeException(                        "UiccController.getInstance can't be called before make()");                }                return mInstance[0];            }        }    }    private UiccController(Context c, CommandsInterface ci, int simId) {        if (DBG) log("Creating UiccController simId " + simId);        mContext = c;        mCi = ci;        mSimId = simId;        mCi.registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, null);        // TODO remove this once modem correctly notifies the unsols        mCi.registerForOn(this, EVENT_ICC_STATUS_CHANGED, null);        mCi.registerForVirtualSimOn(this, EVENT_VIRTUAL_SIM_ON, null);        mCi.registerForVirtualSimOff(this, EVENT_VIRTUAL_SIM_OFF, null);        mCi.registerForSimMissing(this, EVENT_SIM_MISSING, null);        mCi.registerForSimRecovery(this, EVENT_SIM_RECOVERY, null);        mCi.registerForSimPlugOut(this, EVENT_SIM_PLUG_OUT, null);        mCi.registerForSimPlugIn(this, EVENT_SIM_PLUG_IN, null);        mCi.registerForInvalidSimDetected(this, EVENT_INVALID_SIM_DETECTED, null);        IntentFilter filter = new IntentFilter();        filter.addAction("android.intent.action.ACTION_SHUTDOWN_IPO");        filter.addAction(GeminiPhone.EVENT_INITIALIZATION_FRAMEWORK_DONE);        filter.addAction(TelephonyIntents.ACTION_SIM_INFO_UPDATE);        filter.addAction(ACTION_RESET_MODEM);        mContext.registerReceiver(mIntentReceiver, filter);    }

下面開始解析上面順序圖表:

step1,rild主動上報射頻訊號狀態RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED。

step4,對訊號進行判斷,看看返回當前射頻狀態:

    private RadioState getRadioStateFromInt(int stateInt) {        RadioState state;        /* RIL_RadioState ril.h */        switch(stateInt) {            case 0: state = RadioState.RADIO_OFF; break;            case 1: state = RadioState.RADIO_UNAVAILABLE; break;            case 2: state = RadioState.SIM_NOT_READY; break;            case 3: state = RadioState.SIM_LOCKED_OR_ABSENT; break;            case 4: state = RadioState.SIM_READY; break;            case 5: state = RadioState.RUIM_NOT_READY; break;            case 6: state = RadioState.RUIM_READY; break;            case 7: state = RadioState.RUIM_LOCKED_OR_ABSENT; break;            case 8: state = RadioState.NV_NOT_READY; break;            case 9: state = RadioState.NV_READY; break;            case 10: state = RadioState.RADIO_ON; break;            case 15: state = RadioState.RADIO_OFF; break;            default:                throw new RuntimeException(                            "Unrecognized RIL_RadioState: " + stateInt);        }        return state;    }

一般剛開機射頻是RADIO_OFF的,之後轉為RADIO_ON。

step6,設定射頻的新狀態,比較新狀態和舊狀態對比,看看發生了什麼變化,step9~step13(還有其他的,沒有列出)對變化作出響應,具體看下面的源碼:

    /**     * Store new RadioState and send notification based on the changes     *     * This function is called only by RIL.java when receiving unsolicited     * RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED     *     * RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY,     * SIM_LOCKED_OR_ABSENT, and SIM_READY.     *     * @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED     */    protected void setRadioState(RadioState newState) {        RadioState oldState;        synchronized (mStateMonitor) {            Rlog.v(LOG_TAG, "setRadioState old: " + mState + " new " + newState);            oldState = mState;            mState = newState;            // For CTA feature, sim1 is radio on if no sim card inserted.             // In rild, it is in the state of SIM_LOCKED_OR_ABSENT.            // if the sim card is pin locked, then after turn on radio of sim, it still the state of SIM_LOCKED_OR_ABSENT            // special handle for this scenario, always notify radio changed if the state is SIM_LOCKED_OR_ABSENT            if (oldState == mState && mState != RadioState.SIM_LOCKED_OR_ABSENT) {                // no state transition                return;            }            // FIXME: Use Constants or Enums            if(mState.getType() == 0) {                mSimState = mState;                mRuimState = mState;                mNvState = mState;            }            else if (mState.getType() == 1) {                if(mSimState != mState) {                    mIccStatusChangedRegistrants.notifyRegistrants();                }                mSimState = mState;            }            else if (mState.getType() == 2) {                if(mRuimState != mState) {                    mIccStatusChangedRegistrants.notifyRegistrants();                }                mRuimState = mState;            }            else if (mState.getType() == 3) {                mNvState = mState;            }            mRadioStateChangedRegistrants.notifyRegistrants(new AsyncResult(null, mState, null));            if (mState.isAvailable() && !oldState.isAvailable()) {                Rlog.d(LOG_TAG,"Notifying: radio available");                mAvailRegistrants.notifyRegistrants();                onRadioAvailable();            }            if (!mState.isAvailable() && oldState.isAvailable()) {                Rlog.d(LOG_TAG,"Notifying: radio not available");                mNotAvailRegistrants.notifyRegistrants();            }            if (mState.isOn() && !oldState.isOn()) {                Rlog.d(LOG_TAG,"Notifying: Radio On");                mOnRegistrants.notifyRegistrants();            }            if ((!mState.isOn() || !mState.isAvailable())                && !((!oldState.isOn() || !oldState.isAvailable()))            ) {                Rlog.d(LOG_TAG,"Notifying: radio off or not available");                mOffOrNotAvailRegistrants.notifyRegistrants();            }            /* Radio Technology Change events             * NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the             *   current phone is determined by mPhoneType             * NOTE: at startup no phone have been created and the RIL determines the mPhoneType             *   looking based on the networkMode set by the PhoneFactory in the constructor             */            if (mState.isGsm() && oldState.isCdma()) {                Rlog.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM");                mVoiceRadioTechChangedRegistrants.notifyRegistrants();            }            if (mState.isGsm() && !oldState.isOn() && (mPhoneType == PhoneConstants.PHONE_TYPE_CDMA)) {                Rlog.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM");                mVoiceRadioTechChangedRegistrants.notifyRegistrants();            }            if (mState.isCdma() && oldState.isGsm()) {                Rlog.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA");                mVoiceRadioTechChangedRegistrants.notifyRegistrants();            }            if (mState.isCdma() && !oldState.isOn() && (mPhoneType == PhoneConstants.PHONE_TYPE_GSM)) {                Rlog.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA");                mVoiceRadioTechChangedRegistrants.notifyRegistrants();            }        }    }

step7,通知註冊了mIccStatusChangedRegistrants的觀察者,SIM卡(GSM卡和USIM卡)狀態改變了,SIM卡準備好了。UiccController註冊了它,看前面UiccController的建構函式,這裡EVENT_ICC_STATUS_CHANGED關聯了兩個RIL URC事件,除了這裡說的這個,還有RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED。所以,當Radio或者SIM卡狀態發生變化時,都會第一時間通知UiccController。

step8,對它感興趣的有,GsmServiceStateTracker(更新網路狀態)、SIMRecords(用IccFileHandler讀取SIM卡內建緊急號碼)和SIMRecordsEx(向RILD查詢20位的Iccid)。

step14,處理step7中mIccStatusChangedRegistrants發出的通知。

step15~step16,請求查詢現在SIM卡的狀態,請求id位RIL_REQUEST_GET_SIM_STATUS。

step17~step20,Rild反饋RIL_REQUEST_GET_SIM_STATUS請求。step19,responseIccCardStatus()方法中會對SIM卡狀態進行解析:

    private Object    responseIccCardStatus(Parcel p) {        IccCardApplicationStatus appStatus;        IccCardStatus cardStatus = new IccCardStatus();        cardStatus.setCardState(p.readInt());        cardStatus.setUniversalPinState(p.readInt());        cardStatus.mGsmUmtsSubscriptionAppIndex = p.readInt();        cardStatus.mCdmaSubscriptionAppIndex = p.readInt();        cardStatus.mImsSubscriptionAppIndex = p.readInt();        int numApplications = p.readInt();        // limit to maximum allowed applications        if (numApplications > IccCardStatus.CARD_MAX_APPS) {            numApplications = IccCardStatus.CARD_MAX_APPS;        }        cardStatus.mApplications = new IccCardApplicationStatus[numApplications];        for (int i = 0 ; i < numApplications ; i++) {            appStatus = new IccCardApplicationStatus();            appStatus.app_type       = appStatus.AppTypeFromRILInt(p.readInt());            appStatus.app_state      = appStatus.AppStateFromRILInt(p.readInt());            appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(p.readInt());            appStatus.aid            = p.readString();            appStatus.app_label      = p.readString();            appStatus.pin1_replaced  = p.readInt();            appStatus.pin1           = appStatus.PinStateFromRILInt(p.readInt());            appStatus.pin2           = appStatus.PinStateFromRILInt(p.readInt());            cardStatus.mApplications[i] = appStatus;        }        return cardStatus;    }

step21,onGetIccCardStatusDone()中更新SIM卡狀態mUiccCard.update(),如果第一次運行,mUiccCard對象還沒有建立,則先建立,再更新。

    private synchronized void onGetIccCardStatusDone(AsyncResult ar, boolean isUpdateSiminfo) {        if (ar.exception != null) {            Rlog.e(LOG_TAG,"[SIM " + mSimId + "] Error getting ICC status. "                    + "RIL_REQUEST_GET_ICC_STATUS should "                    + "never return an error", ar.exception);            return;        }        IccCardStatus status = (IccCardStatus)ar.result;        if (status.mCardState == IccCardStatus.CardState.CARDSTATE_PRESENT) {            if (DBG) log("onGetIccCardStatusDone, disableSimMissingNotification because card is present");            disableSimMissingNotification();        }        if (mUiccCard == null) {            //Create new card            //ALPS01311133: We also need to update SIM Info when SIM hot plug.            mUiccCard = new UiccCard(mContext, mCi, status, mSimId, isUpdateSiminfo);        } else {            //Update already existing card            mUiccCard.update(mContext, mCi , status, isUpdateSiminfo);        }        if (DBG) log("Notifying IccChangedRegistrants, isUpdateSiminfo:" + isUpdateSiminfo);        mIccChangedRegistrants.notifyRegistrants();    }

step23,更新時,如果UiccCardApplication還沒有建立,則先建立,同時需要根據SIM類型建立IccFileHandler具體子類對象(用來讀取SIM資料)和IccRecords具體子類對象(記錄SIM資料),否則直接更新。

    public void update(Context c, CommandsInterface ci, IccCardStatus ics, boolean isUpdateSimInfo) {        synchronized (mLock) {            if (mDestroyed) {                loge("Updated after destroyed! Fix me!");                return;            }            CardState oldState = mCardState;            mCardState = ics.mCardState;            mUniversalPinState = ics.mUniversalPinState;            mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;            mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex;            mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex;            mContext = c;            mCi = ci;            //update applications            if (DBG) log(ics.mApplications.length + " applications");            for ( int i = 0; i < mUiccApplications.length; i++) {                if (mUiccApplications[i] == null) {                    //Create newly added Applications                    if (i < ics.mApplications.length) {                        mUiccApplications[i] = new UiccCardApplication(this,                                ics.mApplications[i], mContext, mCi);                        mIccRecords = mUiccApplications[i].getIccRecords();                        mIccFileHandler = mUiccApplications[i].getIccFileHandler();                    }                } else if (i >= ics.mApplications.length) {                    //Delete removed applications                    if (DBG) log("update mUiccApplications[" + i + "] dispose");                    mUiccApplications[i].dispose();                    mUiccApplications[i] = null;                } else {                    //Update the rest                    if (DBG) log("update mUiccApplications[" + i + "] update");                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);                }            }            //if (!mIccRecordsList.isEmpty()){           //    for (IccRecords mIccRecords: mIccRecordsList)           if (mIccRecords != null)               mIccRecords.registerForImsiReady(mHandler, EVENT_IMSI_READY, null);            if (DBG) log("update mUiccApplications.length: " + mUiccApplications.length);            if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {                // Initialize or Reinitialize CatService                mCatService = CatService.getInstance(mCi,                                                     mContext,                                                     this);            } else {                if (mCatService != null) {                    mCatService.dispose();                }                mCatService = null;            }            sanitizeApplicationIndexes();            RadioState radioState = mCi.getRadioState();            if (DBG) log("update: radioState=" + radioState + " mLastRadioState="                    + mLastRadioState);            if(isUpdateSimInfo) { //SIM卡熱插拔會用到這裡                // No notifications while radio is off or we just powering up                //if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {                if (radioState != RadioState.RADIO_UNAVAILABLE) {                    if (mCardState == CardState.CARDSTATE_ABSENT) {                        if (DBG) log("update: notify card removed");                        mAbsentRegistrants.notifyRegistrants();                        mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));                        //Update SIM inserted state                        if (FeatureOption.MTK_GEMINI_SUPPORT) {                            Phone defaultPhone = PhoneFactory.getDefaultPhone();                            ((GeminiPhone)defaultPhone).setSimInsertedState(getMySimId(), false);                        }                    } else if (oldState == CardState.CARDSTATE_ABSENT &&                            mCardState != CardState.CARDSTATE_ABSENT) {                        if (DBG) log("update: notify card added");                        mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_ADDED, null));                    }                }            }            mLastRadioState = radioState;        }    }
UiccCardApplication執行update()操作時,如果此時SIM卡應用的狀態是APPSTATE_READY,這要進行如下操作:

            if (mAppState != oldAppState) {                if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);                // If the app state turns to APPSTATE_READY, then query FDN status,                //as it might have failed in earlier attempt.                if (mAppState == AppState.APPSTATE_READY) {                    queryFdn();//讀取FDN資料                    queryPin1State();//查詢pin狀態                }                notifyPinLockedRegistrantsIfNeeded(null);                notifyReadyRegistrantsIfNeeded(null);            }
如果SIM卡被鎖住了,則會通知彈出解鎖框。

step31,通知去讀取SIM卡的IMSI。

step32,建立SIM Toolkit Telephony Service。

step33,通知所有關注mIccChangedRegistrants變化的觀察者,如IccCardProxy(代理各種類型的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.