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

时间: 2024-09-12 18:12:26

Android4.X中SIM卡信息初始化过程详解的相关文章

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

本文实例讲述了Android4.X中SIM卡信息初始化过程详解.分享给大家供大家参考,具体如下: Phone 对象初始化的过程中,会加载SIM卡的部分数据信息,这些信息会保存在IccRecords 和 AdnRecordCache 中.SIM卡的数据信息的初始化过程主要分为如下几个步骤 1.RIL 和 UiccController 建立监听关系 ,SIM卡状态发生变化时,UiccController 第一个去处理. Phone 应用初始化 Phone 对象时会建立一个 RIL 和UiccCont

Linux操作系统的内核初始化过程详解

概况 系统的引导和初始化是操作系统实现控制的第一步,也是集中体现系统优劣的重要部分.LINUX作为一个免费的准UNIX操作系统,在众多业余爱好者以及小型商业处理市场表现不俗,成为继WINDOWS系列后的另一个主流.了解LINUX系统的初始化,对于进一步掌握UNIX系统是十分有帮助的. 通常,LINUX系统的初始化可以分为两部分:内核部分和init程序部分.内核主要完成系统的硬件检测和初始化,init程序则主要完成系统的各项配置. 内核初始化详解 通常情况下,计算机首先用LILO程序引导内核的一部

Java程序初始化过程详解

觉得Core Java在Java 初始化过程的总体顺序没有讲,只是说了构造器时的顺序,作者似乎认为路径很多,列出来比较混乱.我觉得还是要搞清楚它的过程比较好.所以现在结合我的学习经验写出具体过程: 过程如下: 1.在类的声明里查看有无静态元素(static element, 我姑且这么叫吧),比如: static int x = 1, { //block float sss = 333.3; String str = "hello"; } 或者 比如 static { //(stati

thinkphp中ajax与php响应过程详解_php实例

本文实例分析了thinkphp中ajax与php响应过程.分享给大家供大家参考.具体分析如下: 一般将前台页面搜索结果中,不喜欢的内容(链接),删除掉,因为整个网站的编程框架式thinkphp,运用js中的ajax对页面进行响应,调用后台php接口,实现前台和后台数据库的同时更新. 首先我们需要做的就是在前台页面中添加一个文本"删除",可以这么添加: 复制代码 代码如下: <a href="javascript:void(0);" id= "<

WinXP系统中修改Netbios名的过程详解

  首先和大家说一下,计算机名也就是我们常说的主机名,如下图: 上图中的XP1即为计算机名,而今天我们要谈的是netbios名,简要的说,netbios名是在win98这样的系统下用于标示计算机的,在现行的一些操作系统中,它亦然存在,只是默认和计算机名相同,但仅限其前15位,因为netbios名最大也才16位,最后一位用来某种服务或应用程序.那如何查看呢? 这两个红框分别是计算机名和netbios名,默认也就是一样的. 现在我们来修改,请打开注册表,并找到下面的键值 HKEY_LOCAL_MAC

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

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

JAVA中对象创建和初始化过程

分析一下JAVA中对象创建和初始化过程中涉及的相关概念问题,java中栈(stack)与堆(heap),对象.引用.句柄的概念. 1.Java中的数据类型 Java中有3个数据类型: 基本数据类型(在Java中,boolean.byte.short.int.long.char.float.double这八种是基本数据类型) 引用类型 null类型 其中,引用类型包括类类型(含数组).接口类型. 下列语句声明了一些变量: 以下是引用片段: int k ; A a; //a是A数据类型的对象变量名.

Android的init过程详解(一)init的初始化

本文使用的软件版本 Android:4.2.2 Linux内核:3.1.10 本文及后续几篇文章将对Android的初始化(init)过程进行详细地.剥丝抽茧式地分析,并且在其中穿插了大量的知识,希望对读者了解Android的启动过程又所帮助.本章主要介绍了与硬件相关初始化文件名的确定以及属性服务的原理和实现. Android本质上就是一个基于Linux内核的操作系统.与Ubuntu Linux.Fedora Linux类似.只是Android在应用层专门为移动设备添加了一些特有的支持.既然An

linux中了minerd之后的完全清理过程(详解)_Linux

一不小心装了一个Redis服务,开了一个全网的默认端口,一开始以为这台服务器没有公网ip,结果发现之后悔之莫及啊 某天发现cpu load高的出奇,发现一个minerd进程 占了大量cpu,google了一下,发现自己中招了 下面就是清理过程 第一步 1.立即停止redis服务,修改端口权限,增加密码措施 2.按照网上的资料 删除 crontab 里的两个内容 sudo rm /var/spool/cron/root sudo rm /var/spool/cron/crontabs/root 3