1.RIL从modem收到主动上报的消息
RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED
2.UiccController监听了这条消息,mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
===========================UICC框架结构=================================
/**
* This class is responsible for keeping all knowledge about
* Universal Integrated Circuit Card (UICC), also know as SIM's,
* in the system. It is also used as API to get appropriate
* applications to pass them to phone and service trackers.
*
* UiccController is created with the call to make() function.
* UiccController is a singleton and make() must only be called once
* and throws an exception if called multiple times.
*
* 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
*
* See also {@link com.android.internal.telephony.IccCard}
* and {@link com.android.internal.telephony.uicc.IccCardProxy}
*/
===========================UICC框架结构=================================
看一下在UiccController中的处理过程
case EVENT_ICC_STATUS_CHANGED:
->mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
请求卡的状态,并回调EVENT_GET_ICC_STATUS_DONE
case EVENT_GET_ICC_STATUS_DONE:
->onGetIccCardStatusDone(ar, index);
卡的状态放在了ar里,开始处理ar。
在onGetIccCardStatusDone中,卡的处理分成两种,如果mUiccCards[index]已经被实例化,就会更新状态,否则创建新的mUiccCards[index]。
if (mUiccCards[index] == null) {
//Create new card
mUiccCards[index] = new UiccCard(mContext, mCis[index], status, index);
} else {
//Update already existing card
mUiccCards[index].update(mContext, mCis[index] , status);
}
最后要通知卡变化了mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
a.创建新的mUiccCard[index]的过程。
new UiccCard(mContext, mCis[index], status, index);
->update(c, ci, ics);
-->createAndUpdateCatService(); // CatService 应该是在这里建立的。
update方法里最复杂的逻辑应该是下面这段代码
//update applications
if (DBG) log(ics.mApplications.length + " applications");
for ( int i = 0; i < mUiccApplications.length; i++) {//根据卡应用的**最大**长度来遍历
if (mUiccApplications[i] == null) {//mUiccApplications需要通过ics来获得
//Create newly added Applications
if (i < ics.mApplications.length) {//ics来获得卡应用没有那么多就不会新建了
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);
}
}
到了UiccCardApplication这以后又会分成两路new & update,看代码其实构造方法和update方法没差的特别多。
new:
mUiccApplications[i] = new UiccCardApplication(this,
ics.mApplications[i], mContext, mCi);
->mIccFh = createIccFileHandler(as.app_type);//根据app type创建文件处理类
mIccRecords = createIccRecords(as.app_type, mContext, mCi);//创建IccRecord
if (mAppState == AppState.APPSTATE_READY) {
queryFdn();
queryPin1State();//这两个函数查完之后就把状态更新到本地
}
update:
mUiccApplications[i].update(ics.mApplications[i], mContext, mCi);//没多大区别,逻辑简单
->notifyReadyRegistrantsIfNeeded(null);//这句代码会引起识卡。
看一下识卡的具体过程。
假如实例化SIMRecord
SIMRecords
protected IccFileHandler mFh;
protected UiccCardApplication mParentApp;
protected int mRecordsToLoad; // number of pending load request
// recordsRequested is set to false indicating that the SIM
// read requests made so far are not valid. This is set to
// true only when fresh set of read requests are made.
protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
protected String mIccId;
SIMRecords 构造函数更新了成员变量
mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
// Start off by setting empty state
resetRecords(); // 重置属性 mIccId = null; mRecordsRequested = false;
mParentApp.registerForReady(this, EVENT_APP_READY, null);
mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
EVENT_APP_READY -> onReady() -> fetchSimRecords()
mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
mRecordsToLoad++;
...
向RIL请求一些 IMSI ICCID ... , 每加一个请求 mRecordsToLoad++
每次消息回来 handleMessage(Message msg) 中都会 boolean isRecordLoadResponse = false;
在具体的 case 中会将 isRecordLoadResponse = true;
最后在 finally 中 if (isRecordLoadResponse) { onRecordLoaded(); }
onRecordLoaded() if (mRecordsToLoad == 0 && mRecordsRequested == true) {onAllRecordsLoaded();}
onAllRecordsLoaded() 更新一些东西,然后会发一消息
mRecordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
IccCardProxy监听了这条消息
mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
->onRecordsLoaded()
->broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
-->Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
接收这条广播类是SubscriptionInfoUpdater
OnReceive -> sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, -1));
->handleSimLoaded(msg.arg1);
->updateSubscriptionInfoByIccId()//这个方法相当的复杂,我们还是只贴影响卡识别的关键代码
->mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i], i);
->iSub.addSubInfoRecord(iccId, slotId);
SubscriptionController
->addSubInfoRecord // 这个方法也超级长,说一下逻辑
如果这张卡之前没有被存到数据库
value.put(SubscriptionManager.ICC_ID, iccId);
// default SIM color differs between slots
value.put(SubscriptionManager.COLOR, color);
value.put(SubscriptionManager.SIM_SLOT_INDEX, slotId);
value.put(SubscriptionManager.CARRIER_NAME, "");
Uri uri = resolver.insert(SubscriptionManager.CONTENT_URI, value);//卡的信息更新到数据库
public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo");
如果已经存过了就更新一下就好,slotId...
// FIXME: Currently we assume phoneId == slotId which in the future
// may not be true, for instance with multiple subs per slot.
// But is true at the moment.
这个也比较重要sSlotIdxToSubId.put(slotId, subId);
获取当前插入卡的接口为List getActiveSubscriptionInfoList
List subList = getSubInfo(
SubscriptionManager.SIM_SLOT_INDEX + ">=0", null);
->Cursor cursor = mContext.getContentResolver().query(SubscriptionManager.CONTENT_URI,
null, selection, selectionArgs, null);
while (cursor.moveToNext())
SubscriptionInfo subInfo = getSubInfoRecord(cursor);
subList.add(subInfo);
卡的信息是从数据库取的。