Android4.X 的SIM卡信息的初始化过程

           Phone 对象初始化的过程中,会加载SIM卡的部分数据信息,这些信息会保存在IccRecords 和 AdnRecordCache 中。SIM卡的数据信息的初始化过程主要分为如下几个步骤
     1.RIL 和 UiccController 建立监听关系 ,SIM卡状态发生变化时,UiccController 第一个去处理。
     Phone 应用初始化 Phone 对象时会建立一个 RIL 和UiccController 的监听关系:UiccController 监听 RIL,相关代码如下
      sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);                  UiccController.make(context, sCommandsInterface);
    UiccController 构造的过程
    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 对象被注册为RIL对象的监听者,当 RIL 检测到 uicc card 状态发生变化或者 radio on UiccController 都会处理对应的数据变化。UiccController 是 SIM卡状态发生变化后的第一个处理者。
   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  上报 SIM卡状态发生变化后,做了两件事,一是获取SIM卡的具体状态,二是处理这个状态。
    UiccController 处理具体的SIM卡状态
    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();
   }
   从代码中可以看出,做了两件事,一是 创建或者 更新 UiccCard
   二是 通知监听 UiccController 的监听者。
   2.创建或者更新 UiccCard,UiccCard 创建或者更新与SIM卡类型对应的UiccCardApplication.
   一个UiccCard 对象代表着一张SIM卡,UiccCard 根据获取的SIM卡信息创建 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 根据 IccCardStatus 中记录的应用程序信息,创建 UiccCardApplication.
   UiccCard 还创建了 CatService,用于读取 STK 的信息。
   创建或者更新 UiccCardApplication
   UiccCardApplication,会记录对应的卡的状态,类型,以及卡的记录信息。
   //创建 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);
               }
           }
       }
     在更新和创建UiccCardApplication的过程中,有如下几个重要的变量
   IccRecords
   记录 SIM卡上的EF 文件信息,实现类有SIMRecords,RuimRecords,IsimUiccRecords,对应于不同的类型的SIM卡。
   IccFileHandler
   根据SIM卡的类型,去读取SIM卡上的信息,实现类有SIMFileHandler,RuimFileHandler,UsimFileHandler,CsimFileHandler,IsimFileHandler,对应于不同的SIM卡。
    创建 IccRecords 对象
    正如前面所描述的,IccRecords 记录SIM卡的EF文件信息,具体的读取SIM卡EF文件信息的过程是由 IccFileHandler 来实现的,以 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);
       }
   这个过程包含两个重要的步骤
   创建AdnRecordCache,用于保存电话本数据,根据EF的ID,可以分别读取SIM卡和USIM卡的电话本数据。AdnRecordCache 中持有一个UsimPhoneBookManager,它就是用来读取USIM卡电话本数据的。GSM的SIM卡和WCDMA的USIM卡都是对应的 SimRecords.
   读取SIM卡的所有重要记录信息,在fetchSimRecords 方法中实现。
    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);
   }
   总的来说,创建 SimRecords 的过程就是读取并且保存SIM卡重要信息的过程。其中,电话本的信息保存在 mAdnCache 中,其他信息保存在 SimRecords 中,但是在Phone对象完成初始化后,mAdnCache 里是空的,也就是说,在IccRecords 初始化的过程中,AdnRecordCache 并没有主动去请求SIM卡联系人的数据。

   所有的IccRecords 是通过 IccFileHandler 向Modem 发命令读取数据的。他们之间的交互图如下

           

   
    3.通知UiccController 的监听者,与UiccCardApplication的相关信息可以更新了。根据分析源代码,我们可以看到,PhoneBase ,ServiceStateTracker,IccCardProxy,DcTrackerBase,这些类是 UiccController 的监听者。他们都会处理UiccController 的变化。我们可以这么理解,这些类是SIM卡状态发生变化后,第二批处理SIM卡状态变化的实体。第一个处理SIM卡状态变化的是 UiccController.

你可能感兴趣的:(Android4.X 的SIM卡信息的初始化过程)