随着手机的普及,大家从非智能机到智能机的转变,从没有操作系统的定制机到智能手机,但唯一没有变的是,手机中的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,才会发出读卡的请求。

[java]  view plain
  1. case EVENT_SIM_READY:
  2. onSimReady();
  3. break;
  4. private void onSimReady() {
  5. /* broadcast intent SIM_READY here so that we can make sure
  6. READY is sent before IMSI ready
  7. */
  8. ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(
  9. SimCard.INTENT_VALUE_ICC_READY, null);
  10. fetchSimRecords();
  11. }

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

[java]  view plain
  1. private void fetchSimRecords() {
  2. recordsRequested = true;
  3. IccFileHandler iccFh = phone.getIccFileHandler();
  4. Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);
  5. phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
  6. recordsToLoad++;
  7. iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
  8. recordsToLoad++;
  9. // FIXME should examine EF[MSISDN]'s capability configuration
  10. // to determine which is the voice/data/fax line
  11. new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,
  12. obtainMessage(EVENT_GET_MSISDN_DONE));
  13. recordsToLoad++;
  14. // Record number is subscriber profile
  15. iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
  16. recordsToLoad++;
  17. iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
  18. recordsToLoad++;
  19. // Record number is subscriber profile
  20. iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
  21. recordsToLoad++;
  22. // Also load CPHS-style voice mail indicator, which stores
  23. // the same info as EF[MWIS]. If both exist, both are updated
  24. // but the EF[MWIS] data is preferred
  25. // Please note this must be loaded after EF[MWIS]
  26. iccFh.loadEFTransparent(
  27. EF_VOICE_MAIL_INDICATOR_CPHS,
  28. obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
  29. recordsToLoad++;
  30. // Same goes for Call Forward Status indicator: fetch both
  31. // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
  32. iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
  33. recordsToLoad++;
  34. iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
  35. recordsToLoad++;
  36. getSpnFsm(true, null);
  37. iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
  38. recordsToLoad++;
  39. iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
  40. recordsToLoad++;
  41. iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
  42. recordsToLoad++;
  43. iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
  44. recordsToLoad++;
  45. // XXX should seek instead of examining them all
  46. if (false) { // XXX
  47. iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
  48. recordsToLoad++;
  49. }
  50. if (CRASH_RIL) {
  51. String sms = "0107912160130310f20404d0110041007030208054832b0120"
  52. + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  53. + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  54. + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  55. + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  56. + "ffffffffffffffffffffffffffffff";
  57. byte[] ba = IccUtils.hexStringToBytes(sms);
  58. iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
  59. obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
  60. }
  61. }

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

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

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

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

[java]  view plain
  1. public void loadEFTransparent(int fileid, Message onLoaded) {
  2. Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
  3. fileid, 0, onLoaded);
  4. phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
  5. 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
  6. }

大家注意到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,处理如下

[java]  view plain
  1. case EVENT_GET_BINARY_SIZE_DONE:
  2. ar = (AsyncResult)msg.obj;
  3. response = (Message) ar.userObj;
  4. result = (IccIoResult) ar.result;
  5. if (ar.exception != null) {
  6. sendResult(response, null, ar.exception);
  7. break;
  8. }
  9. iccException = result.getException();
  10. if (iccException != null) {
  11. sendResult(response, null, iccException);
  12. break;
  13. }
  14. data = result.payload;
  15. fileid = msg.arg1;
  16. if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
  17. throw new IccFileTypeMismatch();
  18. }
  19. if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
  20. throw new IccFileTypeMismatch();
  21. }
  22. size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
  23. + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
  24. phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
  25. 0, 0, size, null, null,
  26. obtainMessage(EVENT_READ_BINARY_DONE,
  27. fileid, 0, response));
  28. break;

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

[java]  view plain
  1. case EVENT_GET_ICCID_DONE:
  2. isRecordLoadResponse = true;
  3. ar = (AsyncResult)msg.obj;
  4. data = (byte[])ar.result;
  5. if (ar.exception != null) {
  6. break;
  7. }
  8. iccid = IccUtils.bcdToString(data, 0, data.length);
  9. Log.d(LOG_TAG, "iccid: " + iccid);
  10. 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.

Android系统源码学习-SIM卡(二)相关推荐

  1. Android系统源码学习——源码目录结构介绍

    2019独角兽企业重金招聘Python工程师标准>>> Android 4.0源码目录结构: 本文介绍Android源码目录结构,以便读者理清Android编译系统核心代码在Andr ...

  2. Android系统源码学习——ramdisk.img、system.img、userdata.img三个文件介绍

    2019独角兽企业重金招聘Python工程师标准>>> Android源码编译后,在out/target/product/generic下生成的三个镜像文件:ramdisk.img, ...

  3. android系统源码学习 -- 蓝牙 bluetooth (一) 入门

    原文地址:http://blog.csdn.net/baimy1985/article/details/8892410 1. 代码分布: packages/apps/Bluetooth/ 看这路径肯定 ...

  4. Android FrameWork学习(二)Android系统源码调试

    点击打开链接 通过上一篇 Android FrameWork学习(一)Android 7.0系统源码下载\编译 我们了解了如何进行系统源码的下载和编译工作. 为了更进一步地学习跟研究 Android ...

  5. Android FrameWork 学习之Android 系统源码调试

    这是很久以前访问掘金的时候 无意间看到的一个关于Android的文章,作者更细心,分阶段的将学习步骤记录在自己博客中,我觉得很有用,想作为分享同时也是留下自己知识的一些欠缺收藏起来,今后做项目的时候会 ...

  6. Android系统源码目录及功能介绍

    Android的移植按如下流程:     1.android linux 内核的普通驱动移植,让内核可以在目标平台上运行起来.     2.正确挂载文件系统,确保内核启动参数和 android 源代码 ...

  7. 【安卓系统源码学习之permission】 系统源代码AndroidManifest.xml分析之permission解读

    上一节,我们讲到了怎么去查找安卓源码中AndroidManifest.xml文件,打开这个文件,你会发现里面有很多<permission ... />的标签,如下图所示: 这个是用来做什么 ...

  8. Android系统源码

    作者:王宇龙 链接:https://www.zhihu.com/question/19759722/answer/29213925 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  9. 大牛们是怎么阅读 Android 系统源码的?

    转载自https://www.zhihu.com/question/19759722 作者:王宇龙 链接:https://www.zhihu.com/question/19759722/answer/ ...

最新文章

  1. 怎么将jenkins打包后的war自动部署到jetty上?
  2. Java集合干货——ArrayList源码分析
  3. javascript创建对象 1
  4. python3.6 mysql 教程_Python3.6与MySQL建立连接
  5. win10 EFI装ubuntu14.04双系统 及初始配置
  6. linux 调整shmmax,科学网—Ubuntu 9.10 中更改 linux kernal 中的shmmax大小 - 孙鹏的博文...
  7. iOS 开源播放器ijkplayer播放视频设置缓存
  8. 人脸识别、活体检测、人脸识别面临的挑战
  9. 查看QQ空间加密相册 真实(视频)
  10. 芭蕉河梯级水电站群监控系统
  11. linux的tomcat日志,linux下查看tomcat的日志
  12. 基于强化学习工具箱的自适应巡航控制系统
  13. UFS/EMMC压力测试
  14. m_sequencer和p_sequencer
  15. creo中公制单位的设定问题(永久设定)
  16. 万国数据表现不佳的风险很高
  17. 修改系统时区(基于Debian的系统)--用Enki学Linux系列(15)
  18. RFID技术与畜牧业保险理赔的应用解决方案
  19. Applications for PacBio circular consensus sequencing
  20. JAVA基础篇(1)

热门文章

  1. Springboot毕设项目学生班级m99pkjava+VUE+Mybatis+Maven+Mysql+sprnig)
  2. 虚拟机克隆的两种方式
  3. 《原阿里云高级产品老麦:企业竞争力之营销能效SaaS,LTD是隐形王者》
  4. 卡巴斯基实锤拼多多 App 恶意代码
  5. 遵义医学院计算机教研室简介,教研室简介
  6. 处理数据库操作中的异常:确保数据的完整性和正确性
  7. 适用于现代制造业的ERP系统有哪些?
  8. krpano 热点显示文字 hotspot的两种方法。
  9. 如何去掉excel中的宏的方法
  10. 推荐系统与深度学习(十四)——GBDT+LR模型原理