当前位置: 移动技术网 > IT编程>移动开发>Android > Android4.X中SIM卡信息初始化过程详解

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

2019年07月24日  | 移动技术网IT编程  | 我要评论

诗人北岛成诺奖热门,无限挑战e310,萹蓄

本文实例讲述了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程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网