本文讲解SIMRecords
/frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/SIMRecords.java
构造方法:
public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) { super(app, c, ci); mAdnCache = new AdnRecordCache(mFh); mVmConfig = new VoiceMailConstants(); mSpnOverride = new SpnOverride(); mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);//消息注册,当Ci接收到EVENT_SMS_ON_SIM消息通知SIMRecords mCi.registerForIccRefresh(this, EVENT_SIM_REFRESH, null); // Start off by setting empty state resetRecords(); mParentApp.registerForReady(this, EVENT_APP_READY, null);//当卡准备好,UiccCardApplication会通过notifyReadyRegistrantsifNeeded()通知SIMRecords mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);//EVENT_APP_LOCKED消息同样处理 if (DBG) log("SIMRecords X ctor this=" + this); IntentFilter intentfilter = new IntentFilter(); intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); c.registerReceiver(mReceiver, intentfilter); //接收ACTION_CARRIER_CONFIG_CHANGED消息的处理 }
接收UiccCardApplication 的通知,消息EVENT_APP_READY、EVENT_APP_LOCKED 的处理:
try { switch (msg.what) { case EVENT_APP_READY: onReady(); break; case EVENT_APP_LOCKED: onLocked(); break; }
onReady() 方法,直接调用fetchSimRecords(),到这里开始加载EF文件信息:
具体的读取SIM卡EF文件信息的过程是有IccFileHandler来实现的,根据EF文件的类型,调用不同的方法loadEFTransparent()和loadEFLinearFixed(),最终都会调用RILJ 的iccIOForApp() 方法;
protected void fetchSimRecords() { if (DBG) log("fetchSimRecords " + mRecordsToLoad); mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));//获取IMSI信息,返回的数据在该类handleMessage()中处理 mRecordsToLoad++; //没读取一项信息,计数值就加1 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));//获取ICCID mRecordsToLoad++; // Same goes for Call Forward Status indicator: fetch both // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. loadCallForwardingRecords(); getSpnFsm(true, null); loadEfLiAndEfPl(); 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); }
loadEFTransparent() 方法:
public void loadEFTransparent(int fileid, Message onLoaded) { Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, fileid, 0, onLoaded); mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response); }
消息EVENT_GET_IMSI_DONE、EVNET_GET_ICCID_DONE在handleMessage() 中处理,解析出IMSI、ICCID值:
/* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; ar = (AsyncResult)msg.obj; mImsi = (String) ar.result;//获取MCC、MNC、MSIN // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more // than 15 (and usually 15). if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) { loge("invalid IMSI " + mImsi); mImsi = null; } log("IMSI: mMncLength=" + mMncLength); log("IMSI: " + mImsi.substring(0, 6) + "xxxxxxx"); ......... mImsiReadyRegistrants.notifyRegistrants(); break;
case EVENT_GET_ICCID_DONE: isRecordLoadResponse = true; ar = (AsyncResult)msg.obj; data = (byte[])ar.result; mIccId = IccUtils.bcdToString(data, 0, data.length);//转换BCD码 mFullIccId = IccUtils.bchToString(data, 0, data.length); log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId)); break;
handleMessage() 方法解析数据后,调用onRecordLoaded()方法,mRecordsToLoad减1:
protected void onRecordLoaded() { // One record loaded successfully or failed, In either case // we need to update the recordsToLoad count mRecordsToLoad -= 1;//SIM数据读取成功一次,该参数就减1 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); if (mRecordsToLoad == 0 && mRecordsRequested == true) {//mRecordsToLoad值为0,代表fetchSimRecords()中启动加载的数据都已异步读取完成 onAllRecordsLoaded(); } else if (mRecordsToLoad < 0) { loge("recordsToLoad <0, programmer error suspected"); mRecordsToLoad = 0; } }
mRecordsToLoad 值为0,进入onAllRecordsLoaded() 方法,对读取的数据进行处理与存储:
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 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.getDefaultSubId()); } 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); mRecordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); }
到此sim卡初始化基本流程就结束了。