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程序设计有所帮助。