Android系统源码学习-SIM卡(二)

随着手机的普及,大家从非智能机到智能机的转变,从没有操作系统的定制机到智能手机,但唯一没有变的是,手机中的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.   
  5.     private void onSimReady() {  
  6.         /* broadcast intent SIM_READY here so that we can make sure 
  7.           READY is sent before IMSI ready 
  8.         */  
  9.         ((GSMPhone) phone).mSimCard.broadcastIccStateChangedIntent(  
  10.                 SimCard.INTENT_VALUE_ICC_READY, null);  
  11.   
  12.         fetchSimRecords();  
  13. }  

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

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


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

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.   
  5.         phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),  
  6.                         00, GET_RESPONSE_EF_SIZE_BYTES, nullnull, response);  
  7.     }  

大家注意到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.   
  6.                if (ar.exception != null) {  
  7.                    sendResult(response, null, ar.exception);  
  8.                    break;  
  9.                }  
  10.   
  11.                iccException = result.getException();  
  12.   
  13.                if (iccException != null) {  
  14.                    sendResult(response, null, iccException);  
  15.                    break;  
  16.                }  
  17.   
  18.                data = result.payload;  
  19.   
  20.                fileid = msg.arg1;  
  21.   
  22.                if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {  
  23.                    throw new IccFileTypeMismatch();  
  24.                }  
  25.   
  26.                if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {  
  27.                    throw new IccFileTypeMismatch();  
  28.                }  
  29.   
  30.                size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)  
  31.                       + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);  
  32.   
  33.                phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, getEFPath(fileid),  
  34.                                00, size, nullnull,  
  35.                                obtainMessage(EVENT_READ_BINARY_DONE,  
  36.                                              fileid, 0, response));  
  37.            break;  

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

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值