Android4.4 Telephony Process Analysis-initialization of SIM card upon startup

Source: Internet
Author: User

Android4.4 Telephony Process Analysis-initialization of SIM card upon startup

The code in this article takes the MTK platform Android 4.4 as the analysis object, which is somewhat different from Google's native AOSP. Please be aware of it.


This article describes the initialization process of the SIM card Framework when the MTK Android is started.

First look at a comment:

 /* 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 */

This is a comment on UiccController at the beginning of the UiccController. java file, which means that UiccController is the Controller for managing the Android SIM card.

The following figure shows the SIM card initialization sequence:



UiccController is initialized when the phone process is started, PhoneFactory calls makeDefaultPhone () to create the default Phone, and then calls MTKPhoneFactory. makedefaphone phone () to create the Phone in the MTK dual-card process,

{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];

The above figure shows the static_gemini_intermediates library of the MTK. When the RIL is created, use UiccController. make () to initialize it:

    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 is created in singleton mode and is obtained by calling 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);    }

The above sequence diagram is parsed as follows:

Step 1, rild actively reports the RF Signal Status RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED.

Step 4: Determine the signal and check whether the current RF status is returned:

    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;    }

Generally, the first boot frequency is RADIO_OFF, which is then converted to RADIO_ON.

Step 6: set the new RF status, compare the new status and the old status to see what has changed. Step 9 ~ Step 13 (there are other ones not listed) to respond to changes. For details, refer to the following source code:

    /**     * 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();            }        }    }

Step 7: Notify the observer who has registered mIccStatusChangedRegistrants that the status of the SIM card (GSM card and USIM card) has changed and the SIM card is ready. UiccController registers it and looks at the UiccController constructor. EVENT_ICC_STATUS_CHANGED is associated with two ril urc events. In addition to this, there are also RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED. Therefore, when the Radio or SIM card status changes, UiccController will be notified immediately.

Step 8: you are interested in GsmServiceStateTracker (updating network status), SIMRecords (using IccFileHandler to read SIM card embedded emergency numbers), and SIMRecordsEx (querying RILD for 20-bit Iccid ).

Step 14: process the notifications sent by mIccStatusChangedRegistrants in Step 7.

Step 15 ~ Step 16: request to query the current SIM card status. The request id is RIL_REQUEST_GET_SIM_STATUS.

Step17 ~ Step 20, Rild feedback the RIL_REQUEST_GET_SIM_STATUS request. Step 19, the SIM card status will be resolved in the responseIccCardStatus () method:

    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;    }

Step 21: update the SIM card status mUiccCard. update () in onGetIccCardStatusDone (). If the mUiccCard object has not been created for the first time, it is created and then updated.

    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();    }

Step 23: If UiccCardApplication has not been created before the update, create it first. At the same time, create an IccFileHandler subclass object based on the SIM type (used to read SIM data) and IccRecords subclass object (record SIM data), otherwise directly update.

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 + "application S "); 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. mApplicati Ons. 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 card hot swapping will be used here // No restrictions while radio is off or we just powering up // if (radioState = RadioState. RADIO_ON & mLastRadioState = RadioState. RADIO_O N) {if (radioState! = RadioState. RADIO_UNAVAILABLE) {if (mCardState = CardState. CARDSTATE_ABSENT) {if (DBG) log ("update: Using Y card removed"); mAbsentRegistrants. notifyRegistrants (); mHandler. sendMessage (mHandler. obtainMessage (EVENT_CARD_REMOVED, null); // Update SIM inserted state if (FeatureOption. MTK_GEMINI_SUPPORT) {Phone defaultPhone = PhoneFactory. getdefaphone phone (); (GeminiPhone) defaultPhone ). setSimInserte DState (getMySimId (), false) ;}} else if (oldState = CardState. CARDSTATE_ABSENT & mCardState! = CardState. CARDSTATE_ABSENT) {if (DBG) log ("update: Using Y card added"); mHandler. sendMessage (mHandler. obtainMessage (EVENT_CARD_ADDED, null) ;}} mLastRadioState = radioState ;}}
When UiccCardApplication performs the update () operation, if the status of the SIM card application is APPSTATE_READY, perform the following operations:

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 (); // read the FDN data queryPin1State (); // query the pin status} yypinlockedregistrantsifneeded (null); policyreadyregistrantsifneeded (null );}
If the SIM card is locked, the unlock box is displayed.

Step 31: Notify you to read the IMSI of the SIM card.

Step 32: Create the SIM Toolkit Telephony Service.

Step 33: Notify all observers who follow changes in mIccChangedRegistrants, such as IccCardProxy (proxy for various SIM cards ).

There are still many status changes. The changes are too complicated. Let's talk about them first...


Right-click the image address and open it in the browser to view the large image.

Not yet resumed. please correct me if there is anything wrong.


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.