Android4.X中SIM卡信息初始化过程详解

本文实例讲述了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.

希望本文所述对大家Android程序设计有所帮助。

(0)

相关推荐

  • Android获取手机通讯录、sim卡联系人及调用拨号界面方法

    android获取手机通讯录联系人信息 复制代码 代码如下: private void getPhoneContacts() {        ContentResolver resolver = this.getContentResolver();                // 获取手机联系人       Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,                  new String[] { Phone

  • Android4.X读取SIM卡短信和联系人相关类实例分析

    本文实例讲述了Android4.X读取SIM卡短信和联系人相关类.分享给大家供大家参考,具体如下: 1. IccSmsInterfaceManager 这个类的主要作用有两个 <1>通过 SMSDispatcher,发送短信数据 <2>更新和查询SIM卡的短信数据 IccSmsInterfaceManager 是一个Binder 服务类,Binder接口是 ISms. IccSmsInterfaceManager 被创造时 Binder服务会被注册. IccSmsInterface

  • 举例讲解Android应用中SimpleAdapter简单适配器的使用

    SimpleAdapter,跟名字一样,一个简单的适配器,既为简单,就只是被设计来做简单的应用的,比如静态数据的绑定,不过仍然有自定义的空间,比如说在每一个ListItem中加一个按钮并添加响应事件.首先还是先看一下SimpleAdapter的定义吧,直接翻译下SDK doc 吧: 这是一个简单的适配器,可以将静态数据映射到XML文件中定义好的视图.你可以指定由Map组成的List(比如ArrayList)类型的数据.在ArrayList中的每个条目对应List中的一行.Maps包含每一行的数据

  • android监控sim卡有没有服务示例(sim卡管理)

    复制代码 代码如下: public class UniteqService {public static final String LOG_TAG = "UniteqService";public boolean DEBUG = true;private boolean hasService = false;//是否有服务private PhoneStateListener[] mPhoneStateListener;//监听双卡private TelephonyManager mPh

  • 浅析Android手机卫士sim卡绑定

    读取sim卡的序列号,保存起来,一旦sim发生变更了,认为是小偷的sim卡,发出警告 读取sim卡序列号 获取TelephonyManager对象,通过getSystemService(TELEPHONY_SERVICE) 调用TelephonyManager对象的getSimSerialNumber()方法,得到String类型的序列号 把序列号保存在SharedPreences里面 需要加权限 android.permission.READ_PHONE_STATE 检测sim卡是否变更 使用

  • Android 判断SIM卡属于哪个移动运营商的实现代码

    复制代码 代码如下: [java]public String getProvidersName()  {    String str = "N/A";    try    {      this.IMSI = this.telephonyManager.getSubscriberId();      System.out.println(this.IMSI);      if (this.IMSI.startsWith("46000"))       str = &

  • Android获取手机SIM卡运营商信息的方法

    本文实例讲述了Android获取手机SIM卡运营商信息的方法,对于Android程序设计有非常实用的价值.分享给大家供大家参考之用.具体方法如下: 主要功能代码如下: /** * 获取SIM卡运营商 * * @param context * @return */ public static String getOperators(Context context) { TelephonyManager tm = (TelephonyManager) context .getSystemServic

  • Android手机卫士之绑定sim卡序列号

    现在开始具体 处理每一个导航页面的逻辑,首先看第二个导航页 这里需要实现绑定sim卡序列号的功能,注意添加相应的权限:uses-permission android:name="android.permission.READ_PHONE_STATE" private SettingItemView siv_sim_bound; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(sa

  • Android 判断SIM卡是中国移动\中国联通\中国电信(移动运营商)

    第一种方法: 获取手机的IMSI码,并判断是中国移动\中国联通\中国电信 TelephonyManager telManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); /** 获取SIM卡的IMSI码 * SIM卡唯一标识:IMSI 国际移动用户识别码(IMSI:International Mobile Subscriber Identification Number)是区别移动用户的标志, * 储存在

  • Android读取用户号码,手机串号,SIM卡序列号的实现代码

    1.使用TelephonyManager提供的方法,核心代码: 复制代码 代码如下: TelephonyManager tm = (TelephonyManager) this.getSystemService(TELEPHONY_SERVICE);String imei = tm.getDeviceId();       //取出IMEILog.d(TAG, "IMEI:"+imei);String tel = tm.getLine1Number();     //取出MSISDN,

随机推荐