天天看点

Android(M) Telephony Framework SIM card recognization flow

1.RIL从modem收到主动上报的消息

RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED

2.UiccController监听了这条消息,mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);

===========================UICC框架结构=================================

===========================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<SubscriptionInfo> getActiveSubscriptionInfoList

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

卡的信息是从数据库取的。