您的位置:首页 > 移动开发 > Android开发

Android4.4 Telephony流程分析——SIM卡开机时的初始化

2014-11-11 17:32 519 查看
本文代码以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;
else
ai[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卡)、ServiceStateTracker。这里说一下ServiceStateTracker收到mIccChangedRegistrants变化通知后做的事件:

case EVENT_ICC_CHANGED:
onUpdateIccAvailability();
break;


onUpdateIccAvailability()方法是在ServiceStateTracker中定义,在其子类中实现的,我们看看GsmServiceStateTracker中的实现:

@Override
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 = mUiccApplcation.getIccRecords();//When the app state turns to APPSTATE_READY
mUiccApplcation.registerForReady(this, EVENT_SIM_READY, null);//sim卡联系人读取后发出


接下来还有很多状态变化,各种状态变化太复杂了,先说到这吧。。。

右键复制图片地址,在浏览器中打开即可查看大图。

未完待续,有不对的地方,请指正。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: