天天看點

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

卡的資訊是從資料庫取的。