关于这部分的流程,UiccController.java中的注释写的很清楚,先把这部分注释拿出来,如下:
* 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---- | | | | | | ---SIMFileHandle
RuimRecords---- | | | | ----RuimFileHandler
IsimUiccRecords--- | | -----UsimFileHandler
| -------CsimFileHandler
-----IsimFileHandler
上面的注释是简单明了,按照代码流程看几遍,记住每个类的主要作用, 这部分也就算是掌握了。
UiccController是在PhoneApp启动的过程中创建的,算是这部分知识的一个起点;UiccController构造函数里面便注册了RIL监听, 后续根据这些监听反馈便逐层创建了各个对象。
比较重要的两个点:
1.调用Ril的getIccCardStatus方法向modem查询card的状态。
2.用onGetIccCardStatusDone方法处理modem的反馈结果,UiccCard对象就是在这个方法里面创建的。
UiccCard—每个对象对应一张卡。
1.创建UiccCardApplication—每张卡最多有8个应用。
2.创建Catservice。
3.通过这个对象提供的API可以获取Card state,application等信息。
UiccCard的update方法用来更新对象的内部信息,方法如下:
public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
synchronized (mLock) {
CardState oldState = mCardState;
mCardState = ics.mCardState;//更新card state
mUniversalPinState = ics.mUniversalPinState;//更新pin state
mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex;//更新application的index,下面两句也是这个作用.
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++) {
//下面这段代码用来创建/删除UiccCardApplication对象。
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);
}
}
createAndUpdateCatService();//catservice相关的操作。
// Reload the carrier privilege rules if necessary.
log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
} else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = null;
}
sanitizeApplicationIndexes();//通过判断Application是否有效来确定application index有效性.
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;
}
}
上面update方法根据卡的状态变化发出EVENT_CARD_REMOVED/EVENT_CARD_ADDED 消息,handler处理这两个消息时会调用onIccSwap(boolean isAdded) 方法。
private void onIccSwap(boolean isAdded) {
boolean isHotSwapSupported = mContext.getResources().getBoolean(//判断是否支持热插拔。
R.bool.config_hotswapCapable);
if (isHotSwapSupported) {//如果支持热插拔就不需要重启手机。
log("onIccSwap: isHotSwapSupported is true, don't prompt for rebooting");
return;
}
log("onIccSwap: isHotSwapSupported is false, prompt for rebooting");
promptForRestart(isAdded);//用于不支持热插拔时,提示用户重启手机,并调用PowerManager
}
1.内部存储了Pin1,Pin2, FDN等信息; 所以可以通过这个对象提供的API来查询这些信息。
2.内部有IccFileHandler,SIMRecords对象; 可以通过这个对象提供的API来获取这两个对象。
IccRecords有三个子类,分别对应了一种卡,主要看看SIMRecords。
1.fetchSimRecords是重要的一个方法, 这个方法获取了卡里的很多数据,像IMSI, Spn,PLMN,PNN, CPHS等;SIM refresh,ready时会调用该方法。
2.SIMRecords对象在RIL里注册了SIM refresh监听,在UiccCardApplication里面注册了app ready/lock事件,还注册了ACTION_CARRIER_CONFIG_CHANGED的广播(用于spn的override)。
另外IccCardProxy也要说下,根据这个名字也能猜到这个类的大致作用; 这个类实现了IccCard接口,根据注释,
这个接口是为了外部应用(主要是PhoneApp)可以方便的操作icc card相关的功能,这当然也是IccCardProxy的作用了。
这个类的对象是在phone对象初始化的过程中创建的,我们通过phone.getIccCard()获取的也是这个类的对象。
由于这个类的作用是方便外部应用操作icc card相关的功能, 所以这个类的方法很多, 而具体方法里的实现自然要用到UiccController,Uicard, UiccCardApplication, IccRecords和IccFileHandler。IccCardProxy 会通过ACTION_SIM_STATE_CHANGED 将SIM state发出去。当IccCardProxy收到IccCardConstants.INTENT_VALUE_ICC_LOCKED的状态,SIMRecords的records loaded以及UiccCard 的EVENT_CARRIER_PRIVILIGES_LOADED的通知后,还会发送ACTION_INTERNAL_SIM_STATE_CHANGED广播。
CARDSTATE_ABSENT,
CARDSTATE_PRESENT,
CARDSTATE_ERROR,
CARDSTATE_RESTRICTED;
UNKNOWN, /** ordinal(0) == {@See TelephonyManager#SIM_STATE_UNKNOWN} */
ABSENT, /** ordinal(1) == {@See TelephonyManager#SIM_STATE_ABSENT} */
PIN_REQUIRED, /** ordinal(2) == {@See TelephonyManager#SIM_STATE_PIN_REQUIRED} */
PUK_REQUIRED, /** ordinal(3) == {@See TelephonyManager#SIM_STATE_PUK_REQUIRED} */
NETWORK_LOCKED, /** ordinal(4) == {@See TelephonyManager#SIM_STATE_NETWORK_LOCKED} */
READY, /** ordinal(5) == {@See TelephonyManager#SIM_STATE_READY} */
NOT_READY, /** ordinal(6) == {@See TelephonyManager#SIM_STATE_NOT_READY} */
PERM_DISABLED, /** ordinal(7) == {@See TelephonyManager#SIM_STATE_PERM_DISABLED} */
CARD_IO_ERROR, /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */
CARD_RESTRICTED;/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */
icc card的状态比较好理解,通过UiccCard的getCardState方法可以获取。
我们比较常用的是SIM状态,可以通过TelephonyManger提供的getSimState(int slotIndex)/getSimState() 这两个API获取。getSimState(int slotIndex)/getSimState()内部进一步调用了SubscriptionController里面的方法getSimStateForSlotIndex(int index),而getSimStateForSlotIndex(int index)进一步调用了IccCardProxy的getState()方法,所以如果可以获取GsmCdmaPhone对象,可以通过getIccCard()方法获取IccCardProxy对象,进而调用getState()方法获取SIM状态。getState()方法只是返回了一个成员变量mExternalState,而这个变量值的更新是通过IccCardProxy在UiccController,UiccCard以及UiccApplication里面注册的监听驱动的(registerUiccCardEvents方法), 这个成员变量的赋值操作是通过setExternalState方法,下面几个情况会调用这个方法:
1.构造函数State.NOT_READY
2.updateQuietMode
3.handleMessage
4.updateExternalState
5.processLockedState
SIM state的定义是综合了IccCardStatus.CardState,IccCardStatus.PinState以及IccCardApplicationStatus.AppState。
下面的表格根据IccCardProxy里面的代码逻辑,总结了SIM state各个状态所依赖的条件。
SIM state | Depends on |
---|---|
State.UNKNOWN | UNKNOWN只是一个短暂的状态, 比如在一些状态转换的时候会处于该状态。除了APPSTATE_UNKNOWN时为UNKOWN外,UNKNOWN也被用于其他特殊情况。 |
State.ABSENT | CARDSTATE_ABSENT |
State.NOT_READY | Radio 不可用, 获取不到UiccCard或者UiccApplication对象的情况下设置为此状态。 |
State.READY | APPSTATE_READY CARDSTATE_PRESENT |
State.PIN_REQUIRED | APPSTATE_PIN |
State.PUK_REQUIRED | APPSTATE_PUK |
State.NETWORK_LOCKED | APPSTATE_SUBSCRIPTION_PERSO, SIMLock开启时 |
State.PERM_DISABLED | PinState.PINSTATE_ENABLED_PERM_BLOCKED |
State.CARD_IO_ERROR | CARDSTATE_ERROR |
State.CARD_RESTRICTED | CARDSTATE_RESTRICTED |
命令GET_SIM_STATUS, 首先返回CARDSTATE_ABSENT, 然后是CARDSTATE_PRESENT, 这些RIL消息里面会带有PIN lock等信息。
对于SIMRecords中的onRecordLoaded方法, 从定义和调用角度考虑,分成两部分: