转载: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卡初始化的流程就结束了。

更多相关文章

  1. android AlertDialog对话框
  2. 不同Activity之间传递数据--Bundle对象和startActivityForResult
  3. Android(安卓)数据库事务处理
  4. android Java 提交数据到服务器的两种方式中四种方法
  5. android之drawable属性
  6. Android(安卓)fragment生命周期解析
  7. 【Gradle】Android(安卓)Gradle 高级自定义
  8. Android(安卓)平板开发关闭一个Fragment的方法
  9. Android如何判断设备为Pad?

随机推荐

  1. osg for android 学习之九:相机
  2. Android:Using shared element transitio
  3. Android(安卓)WIFI热点默认SSID的修改方
  4. GIT命令大全
  5. VMware Workstaion-从零创建centos虚拟机
  6. UEditorPlus v2.1.0发布 演示网站重构,浮
  7. Todo list实践
  8. VSCode配置GIT
  9. Ubuntu 18.04.4 安装docker18.09 (使用阿
  10. 自定义方法通过类名获取对象集合