随着手机的普及,大家从非智能机到智能机的转变,从没有操作系统的定制机到智能手机,但唯一没有变的是,手机中的SIM,今天我们就来谈谈手机中SIM卡相关的内容。在日常生活中,SIM卡就是一张很小的卡片,但这个卡片上却存储了很重要的信息。  同样,Android作为一个智能手机操作系统,也对SIM卡的读取有相关的操作。下面就以Android2.2的SIM卡读写过程进行讲述。

在上次博客中,有讲述STK,大家可以点这个链接进行查看。android STK 实现原理 (一)。STK与SIM卡是紧密相关的,讲到STK,不可能不说到SIM卡,下面就回到正题。

在Android的源码中,SIM卡相关的操作,都封装在framework中,

源码所在的目录

这个文件夹下,存储了所有与手机通讯业务相关的类文件,其中也包括了SIM,STK,CALL, PS数据业务。在上面的图片中,大家可以看到GSM和CDMA两个文件夹,这也是SIM卡相关的,如果插入的是CDMA卡片,就使用CDMA文件夹中的源码,如果是2G SIM卡,或是3G 联通卡(即GSM/WCDMA)都是使用GSM文件夹。当打开GSM文件夹,可以看到有一个STK 文件夹,里面装的就是上面那个链接里面的源码。如果是2G SIM卡,或是3G 联通卡(即GSM/WCDMA)都是使用GSM文件夹。当打开GSM文件夹,可以看到有一个STK 文件夹,里面装的就是上面那个链接里面的源码。

和SIM卡相关的类主要有以下几个,

IccConstants  (里面记录很多的常量,主要用来存储某个字段在SIM卡上的位置是什么,比如ADN(sim卡上的电话本),6F3A,  FDN(固定拔号 6F3B)),

IccCardStatus(记录SIM卡的状态,如ABSENT, READY,UNKNOW,ETC),

IccFileHandler(这个是用来SIM卡上的RECORD读完后,要处理什么事情),

IccRecords(SIM卡上的文件内容,每一个字段,一个RECORD),

IccProvider(手机上的数据库,读出来的数据全放这),

IccUtils(里面一般全是静态方法,主要用来码制转换),

IccSmsInterfaceManager,IccCard(这个是一个抽象类,会根据上面手机的制式,自动起一个SIMCARD 或者RUIMCARD).

下面就以GSM为例说下读取的过程,

在GSM中就对应上面说的这些会有自己的类,如

SimCard,

SIMRecords,

SimPhoneBookInterfaceManager,

1,手机启动时,

根据SIM卡的类型,进入SIMRecords, 开始探测SIM卡的状态,因为,有些SIM卡会设置有PIN码,如果SIM卡有PIN码的话,手机会弹出输入PIN码的框,等待用户进行解码,注意,这个时候,如果PIN码如果没有解的话,手机是不会去读SIM卡的,因为,读SIM卡时,必须通过PIN才能去读,只有一些比较特殊的字段,可以不用,比如ECC 也就是紧急呼叫号码(一般存在卡上,运营商定制的)。同时,这PIN码未解的情况,手机中SIM卡的状态也是PIN_REQURIED_BLOCK,

2,当解完PIN码,或是手机没有设置PIN码,这时,手机的会探测到SIM是READY的状态,手机只有检测到SIM READY,才会发出读卡的请求。

case EVENT_SIM_READY:onSimReady();break;private void onSimReady() {/* broadcast intent SIM_READY here so that we can make sureREADY is sent before IMSI ready*/((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(SimCard.INTENT_VALUE_ICC_READY, null);fetchSimRecords();
}

PIN验证通过,会发出一个广播,通知其它的手机应用,SIM卡好了。

private void fetchSimRecords() {recordsRequested = true;IccFileHandler iccFh = phone.getIccFileHandler();Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));recordsToLoad++;iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));recordsToLoad++;// FIXME should examine EF[MSISDN]'s capability configuration// to determine which is the voice/data/fax linenew AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,obtainMessage(EVENT_GET_MSISDN_DONE));recordsToLoad++;// Record number is subscriber profileiccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));recordsToLoad++;iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));recordsToLoad++;// Record number is subscriber profileiccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));recordsToLoad++;// 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]iccFh.loadEFTransparent(EF_VOICE_MAIL_INDICATOR_CPHS,obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));recordsToLoad++;// Same goes for Call Forward Status indicator: fetch both// EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));recordsToLoad++;iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));recordsToLoad++;getSpnFsm(true, null);iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));recordsToLoad++;iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));recordsToLoad++;iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));recordsToLoad++;iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));recordsToLoad++;// XXX should seek instead of examining them allif (false) { // XXXiccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));recordsToLoad++;}if (CRASH_RIL) {String sms = "0107912160130310f20404d0110041007030208054832b0120"+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"+ "ffffffffffffffffffffffffffffff";byte[] ba = IccUtils.hexStringToBytes(sms);iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));}}

这里,手机开始读卡第一个是

IMSI(International Mobile SubscriberIdentification Number)主要用来查找运营商的网络,里面有MCC,MNC,

ICCID(Integrate circuit card identity)唯一标识一个移动用户。

然后,大家可以看到有很多类似这样的函数调用iccFh.loadEFTransparent,这个就是调用IccFileHandler,读取SIM卡字段

public void loadEFTransparent(int fileid, Message onLoaded) {Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,fileid, 0, onLoaded);phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);}

大家注意到phone.mCM.iccIO,这个东东就是我们的RIL.JAVA, 向低层的MODEM 发送一个读取SIM卡的命令,在RIL.JAVA 中。Fileid 是字段的地址,如上面说的AND(在这为6F3A),FDN(在这为6F3B).

3.当低层的MODEM读到字段结果后,会有一个返回结果,由于发送读取请求时,有一个事件信息EVENT_GET_BINARY_SIZE_DONE,当有返回时,会直接交给IccFileHandler,然后由IccFileHandler转发给SIMRecords,最后进行处理该字段读完后应该执行的操作。由RIL.JAVA通知IccFileHandler,处理如下

 case EVENT_GET_BINARY_SIZE_DONE:ar = (AsyncResult)msg.obj;response = (Message) ar.userObj;result = (IccIoResult) ar.result;if (ar.exception != null) {sendResult(response, null, ar.exception);break;}iccException = result.getException();if (iccException != null) {sendResult(response, null, iccException);break;}data = result.payload;fileid = msg.arg1;if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {throw new IccFileTypeMismatch();}if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {throw new IccFileTypeMismatch();}size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),0, 0, size, null, null,obtainMessage(EVENT_READ_BINARY_DONE,fileid, 0, response));break;

回到SIMRecords,处理ICCID读完后相关操作,代码如下:

case EVENT_GET_ICCID_DONE:isRecordLoadResponse = true;ar = (AsyncResult)msg.obj;data = (byte[])ar.result;if (ar.exception != null) {break;}iccid = IccUtils.bcdToString(data, 0, data.length);Log.d(LOG_TAG, "iccid: " + iccid);break;

到此,一个完整的SIM卡读取过程就完成了。

PS:有可能有人会问,为什么有时候是

iccFh.loadEFTransparent

有时候是

iccFh.loadEFLinearFixed

这主要是跟所要读取EF的类型有关系,SIM卡上的文件类型有Elementary File, Delicated File, Cyclic File,其中EF又分为Linear fixed EF,Transparent EF,Cyclic EF,所以读取的方式是不一样的,可能参考3GPP 11.11,  3GPP 51.011.

OK, 累了,有什么问题,可以在下面问,

Android 源码开发系列(二)Android SIM/USIM相关推荐

  1. 从零开始搭建Ubuntu 环境下的Android 源码开发环境

    本文从一个干净的Ubuntu 10.04 操作系统出发,一步一步引导你搭建自己的基于eclipse IDE 的Android源码开发环境. 正文会包含一下这些内容: 获得源码 编译源码准备工作 编译工 ...

  2. 玩转Android10源码开发定制(二)之基于Pixel 3手机超级详细演示recovery刷机

    玩转Android10源码开发定制(二)之基于Pixel 3手机超级详细演示recovery刷机 本节主要内容: Pixel 3通过fastboot方式刷入Android 11.0官方工厂镜像 Pix ...

  3. 玩转Android10源码开发定制(二)之基于Pixel 3手机超级详细演示fastboot刷机

    玩转Android10源码开发定制(二)之基于Pixel 3手机超级详细演示fastboot刷机 本节主要内容: Pixel 3通过fastboot方式刷入Android 11.0官方工厂镜像 Pix ...

  4. Tomcat源码解析系列二:Tomcat总体架构

    Tomcat即是一个HTTP服务器,也是一个servlet容器,主要目的就是包装servlet,并对请求响应相应的servlet,纯servlet的web应用似乎很好理解Tomcat是如何装载serv ...

  5. android 自定义关机界面,android源码探索之定制android关机界面的方法

    本文实例讲述了android源码探索之定制android关机界面的方法.分享给大家供大家参考.具体如下: 在Android系统中,长按Power键默认会弹出对话框让你选择"飞行模式" ...

  6. Android 源码开发调试方法

    最近忙修改Launcher,不知道大家都是怎么做开发和调试的,可能遇到最大的问题就是源码太大,打开很慢,修改的时候也很慢.调试更是需要打日志,重新编译,痛苦不堪.最近学到一个方法,不知道是不是自己ou ...

  7. Android4.0源码Launcher启动流程分析【android源码Launcher系列一】

    最近研究ICS4.0的Launcher,发现4.0和2.3有稍微点区别,但是区别不是特别大,所以我就先整理一下Launcher启动的大致流程. Launcher其实是贯彻于手机的整个系统的,时时刻刻都 ...

  8. Android中ICS4.0源码Launcher启动流程分析【android源码Launcher系列一】

    最近研究ICS4.0的Launcher,发现4.0和2.3有稍微点区别,但是区别不是特别大,所以我就先整理一下Launcher启动的大致流程.Launcher其实是贯彻于手机的整个系统的,时时刻刻都在 ...

  9. android 源码开发 关于编译等小知识点总结

    fastboot flash boot out/target/product/generic/boot.img不管用,提示< waiting for device >    原因查找:   ...

最新文章

  1. Python基础04 运算
  2. 8000字干货 | 教你打造电商产品的用户体系
  3. python流获取控制台_对Python捕获控制台输出流的方法详解
  4. iis php网站500错误原因_因为曾经错误安装过PHP5.2而导致IIS7无法正常工作,显示500错误提示,大家帮忙看看!...
  5. 工作191:loading不声明
  6. JAVA进阶教学之(StrngBuffer进行字符串拼接)
  7. 谈谈Java虚拟机——Class文件结构
  8. 苹果AirPods Pro将提供8种配色选择 或成最贵真无线耳机
  9. jmeter报“msg“:“Content type ‘application/x-www-form-urlencoded;charset=UTF-8‘ not supported“的解决方法
  10. HttpURLConnection的使用步骤
  11. MSCNN算法:饭堂人群密度检测实现
  12. linux重启配置文件,rEFInd启动管理器配置文件详解
  13. linux机器crt连接不上,SecureCRT连不上Linux主机了,求破
  14. 网络:简述传统CPE向VCPE的演进
  15. 对皮尔逊相关系数进行假设检验
  16. debian dos2unix
  17. 数据库文档自动生成工具
  18. 老九学堂 学习 C++ 第五天
  19. 快手用计算机弹奏,【图片】【CJ他家】弹计算器视频传送门、计算器谱等随时更新!_计算器音乐吧_百度贴吧...
  20. CVPR2021 MotionRNN: A Flexible Model for Video Prediction with Spacetime-Varying Motions

热门文章

  1. process.env.NODE_ENV与@vue/cli-service及其.env.*默认外部环境配置文件之跨域部署
  2. 403 - 禁止访问: 访问被拒绝。
  3. mac os Sierra 原生壁纸分享
  4. Excel计算BMI
  5. Futures timed out after [10 seconds]. This timeout is controlled by spark.executor.heartbeatInterva
  6. 求矩形中心点坐标编程c语言,三角函数在图形学里的应用(四) ​已知矩形的中心点、边长、phi求四个顶点的坐标...
  7. ajax同时调用两个jsonp,使用JSONP进行跨域Ajax 调用
  8. 图片去水印工具 Inpaint 3.0
  9. 思科网第十一章pt实验(注意看文字说明)
  10. Windows访问共享报错 “不能访问此文件夹,因为你组织的安全策略.........”。