Android4.X中SIM卡信息初始化過(guò)程詳解
本文實(shí)例講述了Android4.X中SIM卡信息初始化過(guò)程詳解。分享給大家供大家參考,具體如下:
Phone 對(duì)象初始化的過(guò)程中,會(huì)加載SIM卡的部分?jǐn)?shù)據(jù)信息,這些信息會(huì)保存在IccRecords 和 AdnRecordCache 中。SIM卡的數(shù)據(jù)信息的初始化過(guò)程主要分為如下幾個(gè)步驟
1.RIL 和 UiccController 建立監(jiān)聽關(guān)系 ,SIM卡狀態(tài)發(fā)生變化時(shí),UiccController 第一個(gè)去處理。
Phone 應(yīng)用初始化 Phone 對(duì)象時(shí)會(huì)建立一個(gè) RIL 和UiccController 的監(jiān)聽關(guān)系:UiccController 監(jiān)聽 RIL,相關(guān)代碼如下
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); UiccController.make(context, sCommandsInterface);
UiccController 構(gòu)造的過(guò)程
private UiccController(Context c, CommandsInterface ci) {
if (DBG) log("Creating UiccController");
mContext = c;
mCi = ci;
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);
}
從代碼中可以看出,UiccController 對(duì)象被注冊(cè)為RIL對(duì)象的監(jiān)聽者,當(dāng) RIL 檢測(cè)到 uicc card 狀態(tài)發(fā)生變化或者 radio on UiccController 都會(huì)處理對(duì)應(yīng)的數(shù)據(jù)變化。UiccController 是 SIM卡狀態(tài)發(fā)生變化后的第一個(gè)處理者。
UiccController 處理 EVENT_ICC_STATUS_CHANGED
public void handleMessage (Message msg) {
synchronized (mLock) {
switch (msg.what) {
case EVENT_ICC_STATUS_CHANGED:
if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
mCi.getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
break;
case EVENT_GET_ICC_STATUS_DONE:
if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
AsyncResult ar = (AsyncResult)msg.obj;
onGetIccCardStatusDone(ar);
break;
default:
Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
}
}
}
從代碼中可以看出,RIL 上報(bào) SIM卡狀態(tài)發(fā)生變化后,做了兩件事,一是獲取SIM卡的具體狀態(tài),二是處理這個(gè)狀態(tài)。
UiccController 處理具體的SIM卡狀態(tài)
private synchronized void onGetIccCardStatusDone(AsyncResult ar) {
if (ar.exception != null) {
Rlog.e(LOG_TAG,"Error getting ICC status. "
+ "RIL_REQUEST_GET_ICC_STATUS should "
+ "never return an error", ar.exception);
return;
}
IccCardStatus status = (IccCardStatus)ar.result;
if (mUiccCard == null) {
//Create new card
mUiccCard = new UiccCard(mContext, mCi, status);
} else {
//Update already existing card
mUiccCard.update(mContext, mCi , status);
}
if (DBG) log("Notifying IccChangedRegistrants");
mIccChangedRegistrants.notifyRegistrants();
}
從代碼中可以看出,做了兩件事,
一是 創(chuàng)建或者 更新 UiccCard
二是 通知監(jiān)聽 UiccController 的監(jiān)聽者。
2.創(chuàng)建或者更新 UiccCard,UiccCard 創(chuàng)建或者更新與SIM卡類型對(duì)應(yīng)的UiccCardApplication.
一個(gè)UiccCard 對(duì)象代表著一張SIM卡,UiccCard 根據(jù)獲取的SIM卡信息創(chuàng)建 UiccCardApplication,UiccCardApplication去讀取具體的SIM卡里的信息。
更新UiccCard
public void update(Context c, CommandsInterface ci, IccCardStatus ics) {
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);
}
} 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);
}
}
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);
// 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;
}
}
IccCardStatus,記錄了RIL 讀取的SIM卡的信息,UiccCard 根據(jù) IccCardStatus 中記錄的應(yīng)用程序信息,創(chuàng)建 UiccCardApplication.
UiccCard 還創(chuàng)建了 CatService,用于讀取 STK 的信息。
創(chuàng)建或者更新 UiccCardApplication
UiccCardApplication,會(huì)記錄對(duì)應(yīng)的卡的狀態(tài),類型,以及卡的記錄信息。
//創(chuàng)建 UiccCardApplication
UiccCardApplication(UiccCard uiccCard,
IccCardApplicationStatus as,
Context c,
CommandsInterface ci) {
if (DBG) log("Creating UiccApp: " + as);
mUiccCard = uiccCard;
mAppState = as.app_state;
mAppType = as.app_type;
mPersoSubState = as.perso_substate;
mAid = as.aid;
mAppLabel = as.app_label;
mPin1Replaced = (as.pin1_replaced != 0);
mPin1State = as.pin1;
mPin2State = as.pin2;
mContext = c;
mCi = ci;
mIccFh = createIccFileHandler(as.app_type);
mIccRecords = createIccRecords(as.app_type, mContext, mCi);
///讀取 SIM卡上的 EF 文件信息
if (mAppState == AppState.APPSTATE_READY) {
queryFdn(); // FDN 信息
queryPin1State(); // Pin State
}
}
//更新UiccCardApplication
void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
synchronized (mLock) {
if (mDestroyed) {
loge("Application updated after destroyed! Fix me!");
return;
}
if (DBG) log(mAppType + " update. New " + as);
mContext = c;
mCi = ci;
AppType oldAppType = mAppType;
AppState oldAppState = mAppState;
PersoSubState oldPersoSubState = mPersoSubState;
mAppType = as.app_type;
mAppState = as.app_state;
mPersoSubState = as.perso_substate;
mAid = as.aid;
mAppLabel = as.app_label;
mPin1Replaced = (as.pin1_replaced != 0);
mPin1State = as.pin1;
mPin2State = as.pin2;
if (mAppType != oldAppType) {
if (mIccFh != null) { mIccFh.dispose();}
if (mIccRecords != null) { mIccRecords.dispose();}
mIccFh = createIccFileHandler(as.app_type);
mIccRecords = createIccRecords(as.app_type, c, ci);
}
if (mPersoSubState != oldPersoSubState &&
mPersoSubState == PersoSubState.PERSOSUBSTATE_SIM_NETWORK) {
notifyNetworkLockedRegistrantsIfNeeded(null);
}
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();
}
notifyPinLockedRegistrantsIfNeeded(null);
notifyReadyRegistrantsIfNeeded(null);
}
}
}
在更新和創(chuàng)建UiccCardApplication的過(guò)程中,有如下幾個(gè)重要的變量
IccRecords
記錄 SIM卡上的EF 文件信息,實(shí)現(xiàn)類有SIMRecords,RuimRecords,IsimUiccRecords,對(duì)應(yīng)于不同的類型的SIM卡。
IccFileHandler
根據(jù)SIM卡的類型,去讀取SIM卡上的信息,實(shí)現(xiàn)類有SIMFileHandler,RuimFileHandler,UsimFileHandler,CsimFileHandler,IsimFileHandler,對(duì)應(yīng)于不同的SIM卡。
創(chuàng)建 IccRecords 對(duì)象
正如前面所描述的,IccRecords 記錄SIM卡的EF文件信息,具體的讀取SIM卡EF文件信息的過(guò)程是由 IccFileHandler 來(lái)實(shí)現(xiàn)的,以 SIMRecords 為例。
public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
super(app, c, ci);
// 1.電話本的緩存
mAdnCache = new AdnRecordCache(mFh);
mVmConfig = new VoiceMailConstants();
mSpnOverride = new SpnOverride();
mRecordsRequested = false; // No load request is made till SIM ready
// recordsToLoad is set to 0 because no requests are made yet
mRecordsToLoad = 0;
mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null);
// Start off by setting empty state
resetRecords();
//2. 讀取 SIM卡的所有重要的記錄信息
mParentApp.registerForReady(this, EVENT_APP_READY, null);
if (DBG) log("SIMRecords X ctor this=" + this);
}
這個(gè)過(guò)程包含兩個(gè)重要的步驟
創(chuàng)建AdnRecordCache,用于保存電話本數(shù)據(jù),根據(jù)EF的ID,可以分別讀取SIM卡和USIM卡的電話本數(shù)據(jù)。AdnRecordCache 中持有一個(gè)UsimPhoneBookManager,它就是用來(lái)讀取USIM卡電話本數(shù)據(jù)的。GSM的SIM卡和WCDMA的USIM卡都是對(duì)應(yīng)的 SimRecords.
讀取SIM卡的所有重要記錄信息,在fetchSimRecords 方法中實(shí)現(xiàn)。
protected void fetchSimRecords() {
mRecordsRequested = true;
if (DBG) log("fetchSimRecords " + mRecordsToLoad);
mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
mRecordsToLoad++;
// FIXME should examine EF[MSISDN]'s capability configuration
// to determine which is the voice/data/fax line
new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, EF_EXT1, 1,
obtainMessage(EVENT_GET_MSISDN_DONE));
mRecordsToLoad++;
// Record number is subscriber profile
mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
mRecordsToLoad++;
// Record number is subscriber profile
mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
mRecordsToLoad++;
// Also load CPHS-style voice mail indicator, which stores
// the same info as EF[MWIS]. If both exist, both are updated
// but the EF[MWIS] data is preferred
// Please note this must be loaded after EF[MWIS]
mFh.loadEFTransparent(
EF_VOICE_MAIL_INDICATOR_CPHS,
obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
mRecordsToLoad++;
// Same goes for Call Forward Status indicator: fetch both
// EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
mRecordsToLoad++;
getSpnFsm(true, null);
mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
mRecordsToLoad++;
mFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
mRecordsToLoad++;
mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
mRecordsToLoad++;
// XXX should seek instead of examining them all
if (false) { // XXX
mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
mRecordsToLoad++;
}
if (CRASH_RIL) {
String sms = "0107912160130310f20404d0110041007030208054832b0120"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ "ffffffffffffffffffffffffffffff";
byte[] ba = IccUtils.hexStringToBytes(sms);
mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
}
if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
}
總的來(lái)說(shuō),創(chuàng)建 SimRecords 的過(guò)程就是讀取并且保存SIM卡重要信息的過(guò)程。其中,電話本的信息保存在 mAdnCache 中,其他信息保存在 SimRecords 中,但是在Phone對(duì)象完成初始化后,mAdnCache 里是空的,也就是說(shuō),在IccRecords 初始化的過(guò)程中,AdnRecordCache 并沒有主動(dòng)去請(qǐng)求SIM卡聯(lián)系人的數(shù)據(jù)。
所有的IccRecords 是通過(guò) IccFileHandler 向Modem 發(fā)命令讀取數(shù)據(jù)的。他們之間的交互圖如下

3.通知UiccController 的監(jiān)聽者,與UiccCardApplication的相關(guān)信息可以更新了。根據(jù)分析源代碼,我們可以看到,PhoneBase ,ServiceStateTracker,IccCardProxy,DcTrackerBase,這些類是 UiccController 的監(jiān)聽者。他們都會(huì)處理UiccController 的變化。我們可以這么理解,這些類是SIM卡狀態(tài)發(fā)生變化后,第二批處理SIM卡狀態(tài)變化的實(shí)體。第一個(gè)處理SIM卡狀態(tài)變化的是 UiccController.
希望本文所述對(duì)大家Android程序設(shè)計(jì)有所幫助。
- Android 利用反射+try catch實(shí)現(xiàn)sdk按需引入依賴庫(kù)的方法
- 解決Android Studio sdk emulator directory is missing問(wèn)題
- Android Studio下載、安裝和配置+SDK+tools下載(無(wú)敵超級(jí)詳細(xì)版本)
- Android Studio報(bào)錯(cuò)unable to access android sdk add-on list解決方案
- Android Studio設(shè)置或修改Android SDK路徑方法
- Android中實(shí)現(xiàn)自動(dòng)生成布局View的初始化代碼方法
- Android使用ContentProvider初始化SDK庫(kù)方案小結(jié)
相關(guān)文章
Okhttp3實(shí)現(xiàn)爬取驗(yàn)證碼及獲取Cookie的示例
本篇文章主要介紹了Okhttp3實(shí)現(xiàn)爬取驗(yàn)證碼及獲取Cookie的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-10-10
Android 程序執(zhí)行Linux命令的解決方法及注意事項(xiàng)
這篇文章主要介紹了Android 程序執(zhí)行LINUX命令的解決方法及注意事項(xiàng),本文通過(guò)問(wèn)題描述最終到解決方法,給大家介紹的非常詳細(xì),需要的朋友可以參考下2017-12-12
Android中實(shí)現(xiàn)EditText密碼顯示隱藏的方法
這篇文章主要介紹了Android中實(shí)現(xiàn)EditText密碼顯示隱藏的方法,需要的朋友可以參考下2017-01-01
Android常用三方庫(kù)混淆規(guī)則整理(小結(jié))
這篇文章主要介紹了Android常用三方庫(kù)混淆規(guī)則整理(小結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07
Android實(shí)現(xiàn)系統(tǒng)重新啟動(dòng)的功能
有些Android版本沒有系統(tǒng)重啟的功能,非常不方便。需要我們自己開發(fā)一個(gè)能夠重新啟動(dòng)的應(yīng)用2013-11-11
Android實(shí)現(xiàn)一個(gè)簡(jiǎn)單帶動(dòng)畫的展開收起功能
今天給大家?guī)?lái)一個(gè)展開和收起的簡(jiǎn)單效果,如果只是代碼中簡(jiǎn)單設(shè)置顯示或隱藏,熟悉安卓系統(tǒng)的朋友都知道,那一定是閃現(xiàn),所以筆者結(jié)合了動(dòng)畫,使得體驗(yàn)效果瞬間提升一個(gè)檔次,感興趣的小伙伴可以自己動(dòng)手試一試2023-08-08
Android Studio 視頻播放失敗 start called in state1 異常怎么解決
很多朋友問(wèn)小編在使用MediaPlayer播放音頻時(shí)報(bào)出 E/MediaPlayerNative: start called in state 1, mPlayer(0x0)問(wèn)題,該如何處理呢,今天小編給大家?guī)?lái)了Android Studio 視頻播放失敗 start called in state1 異常問(wèn)題,需要的朋友可以參考下2020-03-03

