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卡)。
接下來還有很多狀態變化,各種狀態變化太複雜了,先說到這吧。。。
右鍵複製圖片地址,在瀏覽器中開啟即可查看大圖。
未完待續,有不對的地方,請指正。