摘要:以為例不同卡主要區別就是文件結構不同,因此各自實現方法接記錄卡的文件信息,具體的讀取卡文件信息的過程是由來實現的,以為例。構造方法在初始化時,卡狀態是狀態并且會廣播出去然后在中設置模式。
1.UiccController 是處理SIM卡的核心類,其他關鍵類都是通過他產生
* 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}
2 分析UiccController是如何初始化的
2.1 Phone進程初始化PhoneApp.java
public void onCreate() { if (UserHandle.myUserId() == 0) { // We are running as the primary user, so should bring up the // global phone state. mPhoneGlobals = new PhoneGlobals(this); mPhoneGlobals.onCreate(); mTelephonyGlobals = new TelephonyGlobals(this); mTelephonyGlobals.onCreate(); } }
2.2 在PhoneGlobals.java的onCreate()中創建Phone
if (mCM == null) { // Initialize the telephony framework PhoneFactory.makeDefaultPhones(this);
2.3 PhoneFactory類makeDefaultPhone方法中初始化UiccController,UiccController是UICC的控制接口,與RIL建立監聽關系,當SIM卡狀態變化時,RIL通知UiccController.
sCommandsInterfaces = new RIL[numPhones]; sCommandsInterfaces[i] = new RIL(context, networkModes[i],cdmaSubscription, i); sUiccController = UiccController.make(context, sCommandsInterfaces); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_GSM, TelephonyComponentFactory.getInstance()); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, TelephonyComponentFactory.getInstance()); }
2.4 看看UiccController的make方法中都對RIL注冊了哪些監聽
public static UiccController make(Context c, CommandsInterface[] ci) { synchronized (mLock) { if (mInstance != null) { throw new RuntimeException("MSimUiccController.make() should only be called once"); } mInstance = new UiccController(c, ci); return (UiccController)mInstance; } }
private UiccController(Context c, CommandsInterface []ci) {
if (DBG) log("Creating UiccController"); mContext = c; mCis = ci; for (int i = 0; i < mCis.length; i++) { Integer index = new Integer(i); mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index); // TODO remove this once modem correctly notifies the unsols // If the device has been decrypted or FBE is supported, read SIM when radio state is // available. // Else wait for radio to be on. This is needed for the scenario when SIM is locked -- // to avoid overlap of CryptKeeper and SIM unlock screen. if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) || StorageManager.isFileEncryptedNativeOrEmulated()) { mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index); } else { mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index); } mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index); mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index); } }
監聽了三個事件:EVENT_ICC_STATUS_CHANGED/EVENT_RADIO_UNAVAILABLE/EVENT_SIM_REFRESH
index對應phoneId
registerForIccStatusChanged方法是CommandsInterface接口中定義 抽象類BaseCommands中實現 @Override public void registerForIccStatusChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mIccStatusChangedRegistrants.add(r); } mIccStatusChangedRegistrants是在RIL中發出通知 private void processUnsolicited (Parcel p, int type) { .... case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: if (RILJ_LOGD) unsljLog(response); if (mIccStatusChangedRegistrants != null) { mIccStatusChangedRegistrants.notifyRegistrants(); } break;
2.5 UiccController handleMessage方法中處理事件EVENT_ICC_STATUS_CHANGED,請求RIL getIccCardStatus()方法發送RIL_REQUEST_GET_SIM_STATUS消息給modem查詢SIM卡狀態,通過onGetIccCardStatusDone處理
@Override public void handleMessage (Message msg) { synchronized (mLock) { Integer index = getCiIndex(msg); if (index < 0 || index >= mCis.length) { Rlog.e(LOG_TAG, "Invalid index : " + index + " received with event " + msg.what); return; } AsyncResult ar = (AsyncResult)msg.obj; switch (msg.what) { case EVENT_ICC_STATUS_CHANGED: if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index)); break; case EVENT_GET_ICC_STATUS_DONE: if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE"); onGetIccCardStatusDone(ar, index); break; case EVENT_RADIO_UNAVAILABLE: if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card"); if (mUiccCards[index] != null) { mUiccCards[index].dispose(); } mUiccCards[index] = null; mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); break; case EVENT_SIM_REFRESH: if (DBG) log("Received EVENT_SIM_REFRESH"); onSimRefresh(ar, index); break; default: Rlog.e(LOG_TAG, " Unknown Event " + msg.what); } } } RIL.java @Override public void getIccCardStatus(Message result) { //Note: This RIL request has not been renamed to ICC, // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); }
2.6 在onGetIccCardStatusDone方法中,依據IccCardStatus創建UiccCard,每個UiccCard對應一張SIM卡,方法的最后通知注冊UiccController監聽,UiccCard的構造方法也是調用update方法
private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
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; } if (!isValidCardIndex(index)) { Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index); return; } IccCardStatus status = (IccCardStatus)ar.result; 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); } if (DBG) log("Notifying IccChangedRegistrants"); mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); }
UiccController總結:
3.UiccCard
3.1 UiccCard構造方法
public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) { mCardState = ics.mCardState; mPhoneId = phoneId; update(c, ci, ics); } public void update(Context c, CommandsInterface ci, IccCardStatus ics) { synchronized (mLock) { 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); } } createAndUpdateCatService(); // 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(); 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) { //根據mCardState 和oldState 判斷是ADD還是REMOVE card 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方法,在update中創建或者更新UiccCardApplication,
根據mCardState 和oldState 判斷是ADD還是REMOVE card,當SIM卡拔出時,通知IccCardProxy, 以及promptForRestart。
createAndUpdateCatService();建CatService,用于讀取STK的信息
protected void createAndUpdateCatService() { if (mUiccApplications.length > 0 && mUiccApplications[0] != null) { // Initialize or Reinitialize CatService if (mCatService == null) { mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId); } else { ((CatService)mCatService).update(mCi, mContext, this); } } else { if (mCatService != null) { mCatService.dispose(); } mCatService = null; } }
UiccCard主要就是創建UiccCardApplication和CatService,以及通知SIM Card ADD和REMOVE事件
4.UiccCardApplication
主要方法:
public void registerForReady(Handler h, int what, Object obj) {} public void registerForLocked(Handler h, int what, Object obj) {} public void registerForNetworkLocked(Handler h, int what, Object obj) {} public AppState getState() {} public AppType getType() {} public PersoSubState getPersoSubState() {} public String getAid() {} public PinState getPin1State() {} public IccFileHandler getIccFileHandler() {} public IccRecords getIccRecords() {} public void supplyPin (String pin, Message onComplete) {} public void supplyPuk (String puk, String newPin, Message onComplete) {} public void supplyPin2 (String pin2, Message onComplete) {} public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {} public void supplyNetworkDepersonalization (String pin, Message onComplete) {} public boolean getIccLockEnabled() {} public boolean getIccFdnEnabled() {} public void setIccLockEnabled (boolean enabled, String password, Message onComplete) {} public void setIccFdnEnabled (boolean enabled, String password, Message onComplete) {} public void changeIccLockPassword(String oldPassword, String newPassword, Message onComplete) {} public void changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete) {}
UiccCardApplication的主要功能:創建對象IccFileHandler、IccRecords,并提供獲取對象的接口;FDN/PIN/PUK設置和查詢接口(通過RIL實現);查詢UiccCardApplication狀態信息(mAppState、mAppType)
public 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; mAuthContext = getAuthContext(mAppType); 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); if (mAppState == AppState.APPSTATE_READY) { queryFdn(); queryPin1State(); } mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null); }
創建IccFileHandler:SIMFileHandler/RuimFileHandler/UsimFileHandler/CsimFileHandler/IsimFileHandler
創建IccRecords:SIMRecords/RuimRecords/IsimUiccRecords
查詢Fdn號碼/查詢Pin碼狀態
4.1 UiccCardApplication的更新
SIM卡或者Radio狀態改變時,ril通過UiccController更新UiccCard,由UiccCard更新UiccCardApplication調用update()
public 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; mAuthContext = getAuthContext(mAppType); 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; //更新IccRecords和IccFileHandler 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(); queryPin1State(); } notifyPinLockedRegistrantsIfNeeded(null); notifyReadyRegistrantsIfNeeded(null); } } }
4.2
// 根據modem返回的不同卡類型,創建不同 IccRecords 對象 private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) { if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) { return new SIMRecords(this, c, ci); } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){ return new RuimRecords(this, c, ci); } else if (type == AppType.APPTYPE_ISIM) { return new IsimUiccRecords(this, c, ci); } else { // Unknown app type (maybe detection is still in progress) return null; } } // 根據modem返回的不同卡類型,創建不同 IccFileHandler 對象 private IccFileHandler createIccFileHandler(AppType type) { switch (type) { case APPTYPE_SIM: return new SIMFileHandler(this, mAid, mCi); case APPTYPE_RUIM: return new RuimFileHandler(this, mAid, mCi); case APPTYPE_USIM: return new UsimFileHandler(this, mAid, mCi); case APPTYPE_CSIM: return new CsimFileHandler(this, mAid, mCi); case APPTYPE_ISIM: return new IsimFileHandler(this, mAid, mCi); default: return null; } }
5.CatService(接3)
6.IccFileHandler(接4)
從這些方法可以看出,IccFileHandler的主要作用就是提供SIM卡文件系統的讀寫操作,當調用這些方法時,需要傳遞要讀寫的文件系統地址,以及讀寫完畢后的回調函數,IccFileHandler會在讀取完數據之后通知到調用者,并把返回值傳遞過去。
6.1 以UsimFileHandler為例
protected String getEFPath(int efid) { // TODO(): DF_GSM can be 7F20 or 7F21 to handle backward compatibility. // Implement this after discussion with OEMs. switch(efid) { case EF_SMS: return MF_SIM + DF_TELECOM; case EF_EXT6: case EF_MWIS: case EF_MBI: case EF_SPN: case EF_AD: case EF_MBDN: case EF_PNN: case EF_SPDI: case EF_SST: case EF_CFIS: case EF_GID1: case EF_GID2: case EF_MAILBOX_CPHS: case EF_VOICE_MAIL_INDICATOR_CPHS: case EF_CFF_CPHS: case EF_SPN_CPHS: case EF_SPN_SHORT_CPHS: case EF_INFO_CPHS: case EF_CSP_CPHS: return MF_SIM + DF_GSM; } String path = getCommonIccEFPath(efid); if (path == null) { Rlog.e(LOG_TAG, "Error: EF Path being returned in null"); } return path; }
不同SIM卡主要區別就是文件結構不同,因此各自實現getEFPath方法
6.2
6.3
7.IccRecords(接4)
IccRecords 記錄SIM卡的EF文件信息,具體的讀取SIM卡EF文件信息的過程是由 IccFileHandler 來實現的,以 SIMRecords 為例。
7.1
主要方法:
父類的方法
// * Constructor
public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) { mContext = c; mCi = ci; mFh = app.getIccFileHandler(); mParentApp = app; mTelephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); } // ***** Constructor public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { super(app, c, ci); 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(); mParentApp.registerForReady(this, EVENT_APP_READY, null); mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null); if (DBG) log("SIMRecords X ctor this=" + this); IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); c.registerReceiver(mReceiver, intentfilter); }
以上的創建過程完成了兩個重要任務:
創建Adn和VoiceMail緩存,這里的Adn緩存用于SIM卡聯系人的增、刪、改、查等功能;
監聽UiccCardApplication的Ready狀態;
@Override public void onReady() { fetchSimRecords(); }
7.2 SIMRecords更新
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, getExtFromEf(EF_MSISDN), 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. loadCallForwardingRecords(); 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++; mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); mRecordsToLoad++; mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE)); mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE)); mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE)); mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE)); mFh.loadEFTransparent(EF_FPLMN, obtainMessage(EVENT_GET_FPLMN_DONE)); mRecordsToLoad++; loadEfLiAndEfPl(); // 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); }
從log中可以看到更新流程:
1572:09-12 15:33:37.899 2237 2237 D UiccCardApplication: Notifying 1 registrant: READY 1588:09-12 15:33:37.956 2237 2237 D SIMRecords: [SIMRecords] fetchSimRecords 0 查詢IMSI: 1589:09-12 15:33:37.957 2237 2237 D RILJ : [3749]> getIMSI: GET_IMSI aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢ICCID: 1590:09-12 15:33:37.962 2237 2237 D RILJ : [3750]> iccIO: SIM_IO 0xc0 0x2fe2 path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢電話號碼: 1593:09-12 15:33:37.969 2237 2237 D RILJ : [3751]> iccIO: SIM_IO 0xc0 0x6f40 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_MBI 語音信箱號碼: 1594:09-12 15:33:37.971 2237 2237 D RILJ : [3752]> iccIO: SIM_IO 0xc0 0x6fc9 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 返回IMSI: 1597:09-12 15:33:37.971 2237 2299 D RILJ : [3749]< GET_IMSI [SUB0] 查詢EF_AD: 1598:09-12 15:33:37.975 2237 2237 D RILJ : [3753]> iccIO: SIM_IO 0xc0 0x6fad path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_MWIS: 1602:09-12 15:33:37.978 2237 2237 D RILJ : [3754]> iccIO: SIM_IO 0xc0 0x6fca path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_VOICE_MAIL_INDICATOR_CPHS: 1603:09-12 15:33:37.979 2237 2237 D RILJ : [3755]> iccIO: SIM_IO 0xc0 0x6f11 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢call forwarding EF_CFIS: 1604:09-12 15:33:37.984 2237 2237 D RILJ : [3756]> iccIO: SIM_IO 0xc0 0x6fcb path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_CFF_CPHS: 1605:09-12 15:33:37.989 2237 2237 D RILJ : [3757]> iccIO: SIM_IO 0xc0 0x6f13 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_SPN: 1606:09-12 15:33:37.991 2237 2237 D RILJ : [3758]> iccIO: SIM_IO 0xc0 0x6f46 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_SPDI: 1608:09-12 15:33:37.995 2237 2237 D RILJ : [3759]> iccIO: SIM_IO 0xc0 0x6fcd path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 查詢EF_PNN: 1609:09-12 15:33:37.997 2237 2237 D RILJ : [3760]> iccIO: SIM_IO 0xc0 0x6fc5 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 其他查詢: 1610:09-12 15:33:37.999 2237 2237 D RILJ : [3761]> iccIO: SIM_IO 0xc0 0x6f38 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1611:09-12 15:33:38.001 2237 2237 D RILJ : [3762]> iccIO: SIM_IO 0xc0 0x6f16 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1612:09-12 15:33:38.002 2237 2299 D RILJ : [3751]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0] 1613:09-12 15:33:38.003 2237 2237 D RILJ : [3763]> iccIO: SIM_IO 0xc0 0x6f15 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1614:09-12 15:33:38.005 2237 2237 D RILJ : [3764]> iccIO: SIM_IO 0xc0 0x6f3e path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1615:09-12 15:33:38.010 2237 2237 D RILJ : [3765]> iccIO: SIM_IO 0xc0 0x6f3f path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1616:09-12 15:33:38.024 2237 2299 D RILJ : [3753]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0] 1633:09-12 15:33:38.206 2237 2237 D RILJ : [3766]> iccIO: SIM_IO 0xc0 0x6f60 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1634:09-12 15:33:38.213 2237 2237 D RILJ : [3767]> iccIO: SIM_IO 0xc0 0x6f61 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1636:09-12 15:33:38.231 2237 2237 D RILJ : [3768]> iccIO: SIM_IO 0xc0 0x6f62 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1638:09-12 15:33:38.235 2237 2237 D RILJ : [3769]> iccIO: SIM_IO 0xc0 0x6fd9 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1639:09-12 15:33:38.237 2237 2237 D RILJ : [3770]> iccIO: SIM_IO 0xc0 0x6f7b path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1641:09-12 15:33:38.241 2237 2299 D RILJ : [3764]< SIM_IO IccIoResult sw1:0x90 sw2:0x0 [SUB0] 1642:09-12 15:33:38.241 2237 2237 D RILJ : [3771]> iccIO: SIM_IO 0xc0 0x6f05 path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1644:09-12 15:33:38.247 2237 2237 D RILJ : [3772]> iccIO: SIM_IO 0xc0 0x2f05 path: 3F00,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1646:09-12 15:33:38.248 2237 2237 D RILJ : [3773]> iccIO: SIM_IO 0xc0 0x6f3c path: 3F007FFF,0,0,15 aid: a0000000871002ff86ffff89ffffffff [SUB0] 1648:09-12 15:33:38.250 2237 2237 D SIMRecords: [SIMRecords] fetchSimRecords 20 requested: true
在ICCCardProxy中注冊IccRecords事件監聽
private void registerUiccCardEvents() { if (mUiccCard != null) { mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null); } if (mUiccApplication != null) { mUiccApplication.registerForReady(this, EVENT_APP_READY, null); mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null); mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null); } if (mIccRecords != null) { mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null); mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); } }
加載完IMSI/record load complete會通知IccCardProxy更新SIM卡狀態
7.3
8.IccCardProxy
在PhoneFactory makeDefaultPhone是會創建Phone,在Phone的初始化時會創建IccCardProxy,UiccController初始化之后.IccCardProxy實現IccCard接口,通過Phone getIccCard返回IccCardProxy實例,接口的注釋:
/** * {@hide} * @Deprecated use UiccController.getUiccCard instead. * * Integrated Circuit Card (ICC) interface * An object of a class implementing this interface is used by external * apps (specifically PhoneApp) to perform icc card related functionality. * * Apps (those that have access to Phone object) can retrieve this object * by calling phone.getIccCard() * * This interface is implemented by IccCardProxy and the object PhoneApp * gets when it calls getIccCard is IccCardProxy. */
接口定義的方法都是通過持有UiccController/UiccCard/UiccCardApplication/IccRecords來實現
8.1 IccCardProxy初始化
makeDefaultPhone方法: phone = new GsmCdmaPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i, PhoneConstants.PHONE_TYPE_CDMA_LTE, TelephonyComponentFactory.getInstance()); 構造方法: public GsmCdmaPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode, int phoneId, int precisePhoneType, TelephonyComponentFactory telephonyComponentFactory) { super(precisePhoneType == PhoneConstants.PHONE_TYPE_GSM ? "GSM" : "CDMA", notifier, context, ci, unitTestMode, phoneId, telephonyComponentFactory); // phone type needs to be set before other initialization as other objects rely on it mPrecisePhoneType = precisePhoneType; initOnce(ci); initRatSpecific(precisePhoneType); mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi); // DcTracker uses SST so needs to be created after it is instantiated mDcTracker = mTelephonyComponentFactory.makeDcTracker(this); mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null); logd("GsmCdmaPhone: constructor: sub = " + mPhoneId); } initOnce方法: mIccCardProxy = mTelephonyComponentFactory.makeIccCardProxy(mContext, mCi, mPhoneId); IccCardProxy實例的個數是與Phone的個數相對應的,有2個phone就會有兩個IccCardProxy對象。 IccCardProxy構造方法: public IccCardProxy(Context context, CommandsInterface ci, int phoneId) { if (DBG) log("ctor: ci=" + ci + " phoneId=" + phoneId); mContext = context; mCi = ci; mPhoneId = phoneId; mTelephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); mCdmaSSM = CdmaSubscriptionSourceManager.getInstance(context, ci, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null); mUiccController = UiccController.getInstance(); mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null); ci.registerForOn(this,EVENT_RADIO_ON, null); ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null); resetProperties(); setExternalState(State.NOT_READY, false); }
在IccCardProxy初始化時,SIM卡狀態是NOT_READY狀態并且會broadcastIccStateChangedIntent廣播出去;然后在Phone中設置radio模式setVoiceRadioTech。
8.2 IccCardProxy事件處理
IccCardProxy構造方法中向UiccController中注冊ICC_CARD_STATUS_CHANGED消息,UiccController在更新完自己內部的UiccCard之后會notify IccCardProxy更新內部各個實例,處理EVENT_ICC_CHANGED的方法updateIccAvailability():
private void updateIccAvailability() { synchronized (mLock) { //獲取UiccCard UiccCard newCard = mUiccController.getUiccCard(mPhoneId); CardState state = CardState.CARDSTATE_ABSENT; UiccCardApplication newApp = null; IccRecords newRecords = null; if (newCard != null) { state = newCard.getCardState(); //獲取UiccCardApplication newApp = newCard.getApplication(mCurrentAppType); if (newApp != null) { //獲取IccRecords newRecords = newApp.getIccRecords(); } } if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) { if (DBG) log("Icc changed. Reregestering."); unregisterUiccCardEvents(); mUiccCard = newCard; mUiccApplication = newApp; mIccRecords = newRecords; //注冊UiccCard/UiccCardApplication/IccRecords 監聽 registerUiccCardEvents(); } //更新SIM卡狀態判斷是否發送廣播 updateExternalState(); } }
監聽事件:
private void registerUiccCardEvents() { if (mUiccCard != null) { //SIM卡拔出事件對外發送廣播 mUiccCard.registerForAbsent(this, EVENT_ICC_ABSENT, null); } if (mUiccApplication != null) { //SIM卡Ready對外發送廣播 mUiccApplication.registerForReady(this, EVENT_APP_READY, null); mUiccApplication.registerForLocked(this, EVENT_ICC_LOCKED, null); mUiccApplication.registerForNetworkLocked(this, EVENT_NETWORK_LOCKED, null); } if (mIccRecords != null) { mIccRecords.registerForImsiReady(this, EVENT_IMSI_READY, null); mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); mIccRecords.registerForRecordsEvents(this, EVENT_ICC_RECORD_EVENTS, null); } }
UiccController負責對卡槽的卡實時實例化或銷毀對象,IccCardProxy監聽UiccController里的變化并及時更新自己內部的狀態,Phone實例通過getIccCard得到IccCardProxy實例來獲取各種卡狀態。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/70419.html
摘要:一介紹了解全稱意思應用程序,理解就是手機軟件,主要是指安裝在智能手機上面的軟件,完善原始安卓系統的不足和多樣性,或者說個性化,以此滿足各個人群的需求,例如微信抖音這些,都是。測試測試就是要找出中的。可以更好的模擬用戶操作,確保的穩定性 ...
摘要:在今年杭州云棲大會上,阿里云正式對外發布產品,向客戶提供低成本軟硬結合多安全等級的物聯網安全解決方案。具體而言,采用阿里云安全技術,實現復用卡安全載體和卡商安全產線,每個卡實現預置一機一密物聯網安全解決方案。 2016年在美國發生的攝像頭安全漏洞導致大半個美國斷網、攝像頭偷窺、智能門鎖被破解,這些事件都給物聯網安全敲響警鐘。 在今年杭州云棲大會上,阿里云Link正式對外發布LinkSec...
閱讀 1876·2021-09-28 09:36
閱讀 2426·2021-09-08 09:35
閱讀 3067·2019-08-30 15:53
閱讀 1554·2019-08-30 14:08
閱讀 665·2019-08-29 18:40
閱讀 2843·2019-08-29 13:57
閱讀 2702·2019-08-29 13:55
閱讀 681·2019-08-26 13:45