随着手机的普及,大家从非智能机到智能机的转变,从没有操作系统的定制机到智能手机,但唯一没有变的是,手机中的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 sure          READY 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 line        new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1,                    obtainMessage(EVENT_GET_MSISDN_DONE));        recordsToLoad++;        // Record number is subscriber profile        iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));        recordsToLoad++;        iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));        recordsToLoad++;        // Record number is subscriber profile        iccFh.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 all        if (false) { // XXX            iccFh.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, 累了,有什么问题,可以在下面问,

 

更多相关文章

  1. 门道儿众多 购买Android手机注意事项
  2. Android之监测手机网络状态的广播
  3. Android完整实现Find My Phone功能 可远程对手机加密
  4. Android(安卓)手机如何防范吸费插件
  5. 体验论成败 2011智能手机系统谁唱主角
  6. 使用GameBench进行android性能测试
  7. Android各大手机系统打开权限管理页面
  8. 如何将旧手机数据转移至iPhone7?旧Android数据转移到新iPhone全攻
  9. Android(安卓)中的文件操作

随机推荐

  1. Android(安卓)ListView圆角实现
  2. Android使用FFmpeg(二)--Android Studio
  3. Android五个布局
  4. Android SVG动画PathView源码解析与使用
  5. Android Framework 基础理解
  6. Google Developing for Android 三 - Perf
  7. Android- NDK编译APK中native死机调试
  8. 转载 android 利用ksoap2方式连接webserv
  9. 【Android 系统开发】 编译 Android文件
  10. Android 开发小技巧