天天看點

對UiccController 的認識

 UiccController 是對SIM卡管理的控制器,它通過 UiccCard 來更新SIM卡的資訊。

  1.UiccController 注冊了兩個監聽器,來監聽RIL的消息。分别監聽 UNSOL_RESPONSE_RADIO_STATE_CHANGED 和 RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED,當radio 和 sim卡狀态發生變化時,它會第一時間得到消息。

  2. 開機後,RIL 會上報 Radio off,然後上報 radio on,一旦 radio on ,mOnRegistrants.notifyRegistrants(),這個語句就會被調用,具體實作如下,

protected void setRadioState(RadioState newState) {

            .....

            mRadioStateChangedRegistrants.notifyRegistrants();

            if (mState.isAvailable() && !oldState.isAvailable()) {

                Log.d(LOG_TAG,"Notifying: radio available");

                mAvailRegistrants.notifyRegistrants();

                onRadioAvailable();

            }

            if (!mState.isAvailable() && oldState.isAvailable()) {

                Log.d(LOG_TAG,"Notifying: radio not available");

                mNotAvailRegistrants.notifyRegistrants();

            }

            if (mState.isOn() && !oldState.isOn()) {

                Log.d(LOG_TAG,"Notifying: Radio On");

                mOnRegistrants.notifyRegistrants();

            }

            if ((!mState.isOn() || !mState.isAvailable())

                && !((!oldState.isOn() || !oldState.isAvailable()))

            ) {

                Log.d(LOG_TAG,"Notifying: radio off or not available");

                mOffOrNotAvailRegistrants.notifyRegistrants();

            }

        }

    }

   notify 後,會通知相關對象,相關對象就會進行處理,UiccController 就是其中一個對象,處理事件 EVENT_ICC_STATUS_CHANGED.

因為 UiccController的構造方法中存在如下代碼。

    private UiccController(Context c, CommandsInterface[] ci) {

        if (DBG) log("Creating UiccController");

        mContext = c;

        mCi = ci;

        for (int i = 0; i < mCi.length; i++) {

            Integer index = new Integer(i);

            //意思是說 RIL 中收到 RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED 消息,notify 所有監聽器後,UiccController 就會處理 EVENT_ICC_STATUS_CHANGED 事件

            mCi[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);   

            mCi[i].registerForOff(this, EVENT_RADIO_OFF, index);

            // TODO remove this once modem correctly notifies the unsols

            // 意思是說 RIL 中收到 Radio ON 消息,notify 所有的監聽器後,UiccController 就會處理 EVENT_ICC_STATUS_CHANGED 事件。

            mCi[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);

        }

    }

    同樣 當SIM卡狀态發生變化後,上報RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED後,UiccController 也将處理事件 Event_ICC_STATUS_CHANGED,是以當手機信号不好或者SIM卡本身的狀态發生變化的時候,消息都會集中到UiccConroller這裡進行處理,然後傳播到所有對SIM卡資料感興趣的地方。UiccController 就是SIM卡管理的最為核心的類。

   <1> 通知 UiccController,UiccControl 處理EVENT_ICC_STATUS_CHANGED的消息

 case EVENT_ICC_STATUS_CHANGED:

                    if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");

                    mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));

                    break;

  <2> UiccControl 發出 RIL_REQUEST_GET_SIM_STATUS的請求,擷取SIM卡的狀态資訊。

  case EVENT_GET_ICC_STATUS_DONE:

                    if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");

                    AsyncResult ar = (AsyncResult)msg.obj;

                    onGetIccCardStatusDone(ar);

                    break;

 onGetIccCardStatusDone:

       IccCardStatus status = (IccCardStatus)ar.result;

        if (mUiccCard == null) {

            //Create new card

            mUiccCard = new UiccCard(mContext, mCi, status);

        } else {

            //Update already existing card

            mUiccCard.update(mContext, mCi , status);

        }

        if (DBG) log("Notifying IccChangedRegistrants");

        mIccChangedRegistrants.notifyRegistrants();

   <3> RIL 傳回SIM卡的狀态資訊,UiccControl 處理傳回的SIM卡的資訊,建立 UiccCard和 UiccCardApplication 對象。具體的實作過程如下

主要是在 UiccCard 的update 方法當中

public void update(Context c, CommandsInterface ci, IccCardStatus ics) {

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

                    }

                } else if (i >= ics.mApplications.length) {

                    //Delete removed applications

                    mUiccApplications[i].dispose();

                    mUiccApplications[i] = null;

                } else {

                    //Update the rest

                    mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);

                }

            }

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

            // No notifications while radio is off or we just powering up

            if (radioState == RadioState.RADIO_ON && mLastRadioState == RadioState.RADIO_ON) {

                if (oldState != CardState.CARDSTATE_ABSENT &&

                        mCardState == CardState.CARDSTATE_ABSENT) {

                    if (DBG) log("update: notify card removed");

                    mAbsentRegistrants.notifyRegistrants();

                    mHandler.sendMessage(mHandler.obtainMessage(EVENT_CARD_REMOVED, null));

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

        }

    }

  3.系統中其他對象對SIM卡的狀态,SIM卡的資料資訊很感興趣,他們通過UiccController來監聽SIM卡的狀态變化。是以當UiccCard更新完成後,它就通知 ServiceStateTracker(Gsm or Cdma),IccCardProxy,DataConnectionTracker,PhoneBase,SIM卡的狀态已經發生了變化。

DataConnectionTracker

GsmDataConnectionTracker

 protected void onUpdateIcc() {

        if (mUiccController == null ) {

            return;

        }

        IccRecords newIccRecords = mUiccController.getIccRecords(UiccController.APP_FAM_3GPP);

        IccRecords r = mIccRecords.get();

        if (r != newIccRecords) {

            if (r != null) {

                log("Removing stale icc objects.");

                r.unregisterForRecordsLoaded(this);

                mIccRecords.set(null);

            }

            if (newIccRecords != null) {

                log("New records found");

                mIccRecords.set(newIccRecords);

                newIccRecords.registerForRecordsLoaded(

                        this, DctConstants.EVENT_RECORDS_LOADED, null);

            }

        }

    }

  更新所持有的mIccRecords 對象的資料

IccCardProxy

  private void updateIccAvailability() {

        synchronized (mLock) {

            UiccCard newCard = mUiccController.getUiccCard();

            CardState state = CardState.CARDSTATE_ABSENT;

            UiccCardApplication newApp = null;

            IccRecords newRecords = null;

            if (newCard != null) {

                state = newCard.getCardState();

                newApp = newCard.getApplication(mCurrentAppType);

                if (newApp != null) {

                    newRecords = newApp.getIccRecords();

                }

            }

            if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {

                if (DBG) log("Icc changed. Reregestering.");

                unregisterUiccCardEvents();

                mUiccCard = newCard;

                mUiccApplication = newApp;

                mIccRecords = newRecords;

                registerUiccCardEvents();

            }

            updateExternalState();

        }

    }

   更新所持有的 mUiccCard,mUiccApplication,mIccRecords 對象。

    當sim卡狀态變化時,會發出廣播

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

            if (DBG) log("Broadcasting intent ACTION_SIM_STATE_CHANGED " +  value

                    + " reason " + reason);

            ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,

                    UserHandle.USER_ALL);

        }

    }

   如果應用程式或者系統服務對SIM卡的狀态有興趣,那麼可以監聽這個廣播

PhoneBase

GsmPhone

protected void onUpdateIccAvailability() {

        if (mUiccController == null ) {

            return;

        }

        UiccCardApplication newUiccApplication =

                mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);

        UiccCardApplication app = mUiccApplication.get();

        if (app != newUiccApplication) {

            if (app != null) {

                if (LOCAL_DEBUG) log("Removing stale icc objects.");

                if (mIccRecords.get() != null) {

                    unregisterForSimRecordEvents();

                    mSimPhoneBookIntManager.updateIccRecords(null);

                }

                mIccRecords.set(null);

                mUiccApplication.set(null);

            }

            if (newUiccApplication != null) {

                if (LOCAL_DEBUG) log("New Uicc application found");

                mUiccApplication.set(newUiccApplication);

                mIccRecords.set(newUiccApplication.getIccRecords());

                registerForSimRecordEvents();

                mSimPhoneBookIntManager.updateIccRecords(mIccRecords.get());

            }

        }

    }

更新所持有的mUiccApplication,mIccRecords,mSimPhoneBookIntManager 對象。

ServiceStateTracker

GsmServiceStateTracker

protected void onUpdateIccAvailability() {

        if (mUiccController == null ) {

            return;

        }

        UiccCardApplication newUiccApplication =

                mUiccController.getUiccCardApplication(UiccController.APP_FAM_3GPP);

        if (mUiccApplcation != newUiccApplication) {

            if (mUiccApplcation != null) {

                log("Removing stale icc objects.");

                mUiccApplcation.unregisterForReady(this);

                if (mIccRecords != null) {

                    mIccRecords.unregisterForRecordsLoaded(this);

                }

                mIccRecords = null;

                mUiccApplcation = null;

            }

            if (newUiccApplication != null) {

                log("New card found");

                mUiccApplcation = newUiccApplication;

                mIccRecords = mUiccApplcation.getIccRecords();

                mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);

                if (mIccRecords != null) {

                    mIccRecords.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);

                }

            }

        }

    }

更新 所持有的mIccRecords,mUiccApplication,等對象。

與UiccController 相關的資料流程如下圖所示

對UiccController 的認識