欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2023-12-10 21:59:28
本文实例讲述了android4.x中sim卡信息初始化过程详解。分享给大家供大家参考,具体如下: phone 对象初始化的过程中,会加载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 发命令读取数据的。他们之间的交互图如下

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

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

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