Android(安卓)9.0 SIM卡初始化流程
转载:https://blog.csdn.net/linyongan/article/details/51406123
本文主要讲述Android 9.0 SIM卡初始化流程,这个过程也涉及到UICC框架的初始化,UICC(Universal Integrated Circuit Card)的架构图如下:
主要的类及其作用:
UiccController:整个Uicc相关信息的控制接口,监控SIM状态变化
UiccCard:Uicc卡的抽象,用来更新卡的状态
IccCardStatus:维护Uicc卡的状态,CardState&PinState
UiccCardApplication:Uicc的一个具体的应用,负责卡中数据读写,存取,pin和puk密码设置,解锁
CatService:主要负责SIM Tollkit相关
IccConstants:SIM卡中文件地址,不同数据在SIM卡上的字段地址。
IccRecords:记录SIM卡的数据
IccFileHandler:读取SIM卡数据以及处理接收的结果。
一、实例化UiccController对象
UiccController是整个UICC相关信息的控制接口,UiccController的实例化就是在RIL与UiccController 之间建立监听关系,这样的话,当SIM卡状态发生变化时,UiccController就可以马上知道并且做出相应的操作。
UiccController对象是在PhoneFacotry.java中的makeDefaultPhone()方法中初始化的,有个细节值得注意的是sCommandsInterfaces数组的i对应的是PhoneId。
public static void makeDefaultPhone(Context context) { // Instantiate UiccController so that all other classes can just //得到UiccController对象 mUiccController = UiccController.make(context, sCommandsInterfaces); for (int i = 0; i < numPhones; i++) { PhoneBase phone = null; int phoneType = TelephonyManager.getPhoneType(networkModes[i]); if (phoneType == PhoneConstants.PHONE_TYPE_GSM) { //sCommandsInterfaces的i对应的是PhoneId;第二小节会再次提到这个i值 phone = TelephonyPluginDelegate.getInstance().makeGSMPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i); } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) { phone = TelephonyPluginDelegate.getInstance().makeCDMALTEPhone(context, sCommandsInterfaces[i], sPhoneNotifier, i); } Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i); sProxyPhones[i] = TelephonyPluginDelegate.getInstance().makePhoneProxy(phone); } } @TelephonyPluginBase.java public PhoneBase makeGSMPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, int phoneId) { return new GSMPhone(context, ci, notifier, phoneId); } }
在UiccController.java的make()方法中new了一个UiccController对象,
public static UiccController make(Context c, CommandsInterface[] ci) { synchronized (mLock) { if (mInstance != null) { throw new RuntimeException("MSimUiccController.make() should only be called once"); } //实例化UiccController对象 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++) { //index对应的是PhoneId Integer index = new Integer(i); //注册监听四种事件 mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index); mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index); mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, index); mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, index); } }
在上面UiccController的构造方法中可以看到,注册了三个事件EVENT_ICC_STATUS_CHANGED(监听SIM卡的状态变化),EVENT_RADIO_UNAVAILABLE(一旦radio变成不可用状态,就清空SIM卡的信息),EVENT_SIM_REFRESH。index对应的是PhoneId,当上面这三种消息上来时,就知道对应哪个Phone对象,也就对应那张卡。
当接收到EVENT_ICC_STATUS_CHANGED消息后,UiccController调用RIL.java的getIccCardStatus()方法给MODEM发送RIL_REQUEST_GET_SIM_STATUS消息,查询SIM卡的状态。
public void handleMessage (Message msg) { ..... //1.首先从Message中取出PhoneId Integer index = getCiIndex(msg); ..... case EVENT_ICC_STATUS_CHANGED: if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus"); //2.查询当前SIM卡的状态 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"); //3.处理查询到的状态信息 onGetIccCardStatusDone(ar, index); break; }
二、实例化UiccCard对象
当查询SIM卡的状态完毕后,先从result中解析出IccCardStatus,依据IccCardStatus来创建UiccCard对象,一个UiccCard 对象代表着一张SIM卡;如果UiccCard对象已存在就直接调它的update()方法更新UiccCard的信息。
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; //1.创建或更新UiccCard if (mUiccCards[index] == null) { //Create new card(Android6.0 调的是4个参数的构造方法) 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"); //2.通知监听UiccController的监听者 mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null)); }
在UiccCard的构造方法中,最终还是调用了update()方法
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; //更新UiccApplications 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); } } //创建CatService,用于读取STK的信息 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(); //先获取radio的状态 RadioState radioState = mCi.getRadioState(); if (DBG) log("update: radioState=" + radioState + " mLastRadioState=" + mLastRadioState); // No notifications while radio is off or we just powering up //根据radio的状态和卡的状态来判断有没有插拔SIM卡动作 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; } }
在UiccCard.java的update()方法中,实例化了UiccCardApplication对象,或者调UiccCardApplication的update()方法更新状态。mCardState记录着卡的状态,根据新旧mCardState就可以知道CARD_ADDED或者CARD_REMOVED。
三、实例化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; 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; //根据AppType实例化IccFileHandler mIccFh = createIccFileHandler(as.app_type); //根据AppType实例化IccRecords mIccRecords = createIccRecords(as.app_type, mContext, mCi); if (mAppState == AppState.APPSTATE_READY) { queryFdn(); //查询PIN1码的状态 queryPin1State(); } //注册监听 mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null); }
在UiccCardApplication初始化的时候,会调用自身的createIccRecords()方法,根据AppType创建对应的IccRecords 对象。
private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) { if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) { //实例化SIMRecords对象 return TelephonyPluginDelegate.getInstance().makeSIMRecords(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; } }
接着会进入TelephonyPluginDelegate.java和TelephonyPluginBase.java的makeSIMRecords()方法
@TelephonyPluginDelegate.java public SIMRecords makeSIMRecords (UiccCardApplication app, Context c, CommandsInterface ci) { return sPlugin.makeSIMRecords (app, c, ci); } @TelephonyPluginBase.java public SIMRecords makeSIMRecords (UiccCardApplication app, Context c, CommandsInterface ci) { return new SIMRecords(app, c, ci); }
到这里就可以看到直接new 了一个SIMRecords对象。
四、实例化SIMRecords对象
public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { super(app, c, ci); mAdnCache = new AdnRecordCache(mFh); mVmConfig = new VoiceMailConstants(); //从spn-conf.xml文件中加载SPN mSpnOverride = new SpnOverride(); // No load request is made till SIM ready mRecordsRequested = false; // 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); //初始化成员变量 resetRecords(); //注册监听,如果已ready,那么开始加载数据 mParentApp.registerForReady(this, EVENT_APP_READY, null); mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null); if (DBG) log("SIMRecords X ctor this=" + this); }
等到AppState变成APPSTATE_READY是,UiccCardApplication会在notifyReadyRegistrantsIfNeeded()方法里通知SIMRecords,那么在SIMRecords的handleMessage()方法就会收到EVENT_APP_READY消息。
public void handleMessage(Message msg) { case EVENT_APP_READY: onReady(); break; } @Override public void onReady() { fetchSimRecords(); }
五、读取EF文件信息
当执行到fetchSimRecords()方法时,才真正开始加载EF文件信息。
具体的读取SIM卡EF文件信息的过程是由 IccFileHandler 来实现的,根据EF文件的类型,调用不同的方法,loadEFTransparent()和loadEFLinearFixed()最终都会调用RIL.java的iccIOForApp()方法。
读取某一项信息时会调用两次RIL.java的iccIOForApp():
第一次:先读取当前分区的长度lc.mRecordSize。
Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, new LoadLinearFixedContext(fileid, recordNum, efPath, onLoaded)); mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath, 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
第二次:再根据lc.mRecordSize去读取具体内容。
case EVENT_GET_RECORD_SIZE_DONE: ...... mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, path, lc.mRecordNum,READ_RECORD_MODE_ABSOLUTE, lc.mRecordSize, null, null, mAid,obtainMessage(EVENT_READ_RECORD_DONE, lc));
某一项信息的加载流程如下流程图。
protected void fetchSimRecords() { mRecordsRequested = true; if (DBG) log("fetchSimRecords " + mRecordsToLoad); //读取IMSI mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); //每开始load一条记录,mRecordsToLoad加1,等加载完一条记录后 //mRecordsToLoad就减1,当mRecordsToLoad等于0时说明已加载完所有数据了。 mRecordsToLoad++; //从EF_ICCID(0x2fe2)读取ICCID 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++; //读取VoiceMail信息 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(); //从EF_SPN(0x6F46)、EF_SPN_CPHS(0x6f14)、EF_SPN_SHORT_CPHS(0x6f18)三个地址上读取SPN getSpnFsm(true, null); //从EF_SPDI(0x6fcd)读取SPDI mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); mRecordsToLoad++; //从EF_PNN(0x6fc5)读取PNN 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++; 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); }
六、读取数据完毕
读取ICCID 、读取SPDI 、读取VoiceMail、读取SPN、读取PNN;
回到fetchSimRecords()方法,每加载一项,mRecordsToLoad就加1;等到某一项读取数据完毕,handleMessage()方法被执行,就会调onRecordLoaded()方法
protected void onRecordLoaded() { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count //每查询完一条记录,mRecordsToLoad减1 mRecordsToLoad -= 1; if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); //当mRecordsToLoad等于0,说明在fetchSimRecords()方法 //中启动加载的数据都已经加载完了。 if (mRecordsToLoad == 0 && mRecordsRequested == true) { onAllRecordsLoaded(); } else if (mRecordsToLoad < 0) { loge("recordsToLoad <0, programmer error suspected"); mRecordsToLoad = 0; } }
mRecordsToLoad的值会减1,直到mRecordsToLoad的值为0时,说明在fetchSimRecords()中启动加载的数据都已异步读取完成。就会进入onAllRecordsLoaded()方法。
@Override protected void onAllRecordsLoaded() { if (DBG) log("record load complete"); Resources resource = Resources.getSystem(); if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) { setSimLanguage(mEfLi, mEfPl); } else { if (DBG) log ("Not using EF LI/EF PL"); } setVoiceCallForwardingFlagFromSimRecords(); if (mParentApp.getState() == AppState.APPSTATE_PIN || mParentApp.getState() == AppState.APPSTATE_PUK) { // reset recordsRequested, since sim is not loaded really mRecordsRequested = false; // lock state, only update language return ; } // Some fields require more than one SIM record to set //获取MCC + MNC String operator = getOperatorNumeric(); if (!TextUtils.isEmpty(operator)) { log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + operator + "'"); log("update icc_operator_numeric=" + operator); mTelephonyManager.setSimOperatorNumericForPhone( mParentApp.getPhoneId(), operator); final SubscriptionController subController = SubscriptionController.getInstance(); subController.setMccMnc(operator, subController.getDefaultSmsSubId()); } else { log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); } if (!TextUtils.isEmpty(mImsi)) { log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : "")); mTelephonyManager.setSimCountryIsoForPhone( mParentApp.getPhoneId(), MccTable.countryCodeForMcc( Integer.parseInt(mImsi.substring(0,3)))); } else { log("onAllRecordsLoaded empty imsi skipping setting mcc"); } setVoiceMailByCountry(operator); setSpnFromConfig(operator); //通知应用层 mRecordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); }
在onAllRecordsLoaded()方法中会对读取到的数据进行处理和存储,到这里,SIM卡初始化的流程就结束了。
更多相关文章
- android AlertDialog对话框
- 不同Activity之间传递数据--Bundle对象和startActivityForResult
- Android(安卓)数据库事务处理
- android Java 提交数据到服务器的两种方式中四种方法
- android之drawable属性
- Android(安卓)fragment生命周期解析
- 【Gradle】Android(安卓)Gradle 高级自定义
- Android(安卓)平板开发关闭一个Fragment的方法
- Android如何判断设备为Pad?