Uicc之IccFileHandler

  SIM卡的本质是一个文件系统,并且具备不同的分区,而IccFileHandler主要用于从SIM卡读取相应分区的数据。


一、IccFileHandler的功能


        我们来看其提供的public方法有哪些:
  1. public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {}  
  2. public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {}  
  3. public void loadEFLinearFixedAll(int fileid, Message onLoaded) {}  
  4. public void loadEFTransparent(int fileid, Message onLoaded) {}  
  5. public void loadEFTransparent(int fileid, int size, Message onLoaded) {}  
  6. public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, int length, Message onLoaded) {}  
  7. public void getEFLinearRecordSize(int fileid, Message onLoaded) {}  
  8. public void updateEFLinearFixed(int fileid, int recordNum, byte[] data, String pin2, Message onComplete) {}  
  9. public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {}  

        从这些方法可以看出,IccFileHandler的主要作用就是提供SIM卡文件系统的读写操作,当调用这些方法时,需要传递要读写的文件系统地址,以及读写完毕后的回调函数,IccFileHandler会在读取完数据之后通知到调用者,并把返回值传递过去


二、IccFileHandler的创建过程


        由于不同类型的SIM卡分区信息不同,因此在UiccCardApplication中要根据当前的SIM类型创建不同的IccFileHandler对象
  1. @UiccCardApplication.java  
  2. private IccFileHandler createIccFileHandler(AppType type) {  
  3.     switch (type) {  
  4.         case APPTYPE_SIM:  
  5.             return new SIMFileHandler(this, mAid, mCi);  
  6.         case APPTYPE_RUIM:  
  7.             return new RuimFileHandler(this, mAid, mCi);  
  8.         case APPTYPE_USIM:  
  9.             return new UsimFileHandler(this, mAid, mCi);  
  10.         case APPTYPE_CSIM:  
  11.             return new CsimFileHandler(this, mAid, mCi);  
  12.         case APPTYPE_ISIM:  
  13.             return new IsimFileHandler(this, mAid, mCi);  
  14.         default:  
  15.             return null;  
  16.     }  
  17. }  
        这几个类都继承自IccFileHandler。因为不同的SIM卡只是在分区的地址信息上有所差异,所以这几个类的 唯一区别就是重写了父类的getEFPath()方法,比如SIMFileHandler:
  1. @SIMFileHandler.java  
  2. protected String getEFPath(int efid) {  
  3.     switch(efid) {  
  4.         case EF_SMS:  
  5.             return MF_SIM + DF_TELECOM;  
  6.         case EF_EXT6:  
  7.         case EF_MWIS:  
  8.         case EF_MBI:  
  9.         case EF_SPN:  
  10.         case EF_AD:  
  11.         case EF_MBDN:  
  12.         case EF_PNN:  
  13.         case EF_SPDI:  
  14.         case EF_SST:  
  15.         case EF_CFIS:  
  16.         case EF_GID1:  
  17.             return MF_SIM + DF_GSM;  
  18.         case EF_MAILBOX_CPHS:  
  19.         case EF_VOICE_MAIL_INDICATOR_CPHS:  
  20.         case EF_CFF_CPHS:  
  21.         case EF_SPN_CPHS:  
  22.         case EF_SPN_SHORT_CPHS:  
  23.         case EF_INFO_CPHS:  
  24.         case EF_CSP_CPHS:  
  25.             return MF_SIM + DF_GSM;  
  26.     }  
  27.     String path = getCommonIccEFPath(efid);  
  28.     if (path == null) {  
  29.         Rlog.e(LOG_TAG, "Error: EF Path being returned in null");  
  30.     }  
  31.     return path;  
  32. }   
        而UsimFileHandler的getEFPath()是这样的:
  1. @UsimFileHandler.java  
  2. protected String getEFPath(int efid) {  
  3.     switch(efid) {  
  4.         case EF_SMS:  
  5.         case EF_EXT6:  
  6.         case EF_MWIS:  
  7.         case EF_MBI:  
  8.         case EF_SPN:  
  9.         case EF_AD:  
  10.         case EF_MBDN:  
  11.         case EF_PNN:  
  12.         case EF_OPL:  
  13.         case EF_SPDI:  
  14.         case EF_SST:  
  15.         case EF_CFIS:  
  16.         case EF_MAILBOX_CPHS:  
  17.         case EF_VOICE_MAIL_INDICATOR_CPHS:  
  18.         case EF_CFF_CPHS:  
  19.         case EF_SPN_CPHS:  
  20.         case EF_SPN_SHORT_CPHS:  
  21.         case EF_FDN:  
  22.         case EF_MSISDN:  
  23.         case EF_EXT2:  
  24.         case EF_INFO_CPHS:  
  25.         case EF_CSP_CPHS:  
  26.         case EF_GID1:  
  27.             return MF_SIM + DF_ADF;  
  28.   
  29.         case EF_PBR:  
  30.             return MF_SIM + DF_TELECOM + DF_PHONEBOOK;  
  31.     }  
  32.     String path = getCommonIccEFPath(efid);  
  33.     if (path == null) {  
  34.         return MF_SIM + DF_TELECOM + DF_PHONEBOOK;  
  35.     }  
  36.     return path;  
  37. }  
        可以看到,SIMFileHandler与UsimFileHandler的区别就在于分区的地址上。
        然后来看IccFileHandler的构造方法流程:
  1. @IccFileHandler.java  
  2. protected IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) {  
  3.     mParentApp = app;  
  4.     mAid = aid;  
  5.     mCi = ci;  
  6. }  

        由于IccFileHandler的主要作用是被动的查询SIM分区信息,因此在构造方法中,只是将重要的上下文信息保存起来以备使用。


三、IccFileHandler读取文件的流程


        既然IccFileHandler的主要作用是读取文件信息,那么我们就来跟踪一下他是如何实现信息的读取的。
        我们来看最常用的读取线性固定长度的文件信息时的流程。
  1. @IccFileHandler.java  
  2. public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {  
  3.     //先去读取Record的Size  
  4.     Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, new LoadLinearFixedContext(fileid, recordNum, onLoaded));  
  5.     //调用RILJ向Modem读取SIM卡当前分区的长度  
  6.     mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), 00, GET_RESPONSE_EF_SIZE_BYTES, nullnull, mAid, response);  
  7. }  
        在这个读取过程中,并不是直接去读取相应的分区内容,而是先读取当前分区记录的长度,当拿到长度之后再去读取当前记录的具体内容:
  1. public void handleMessage(Message msg) {  
  2.     AsyncResult ar;  
  3.     IccIoResult result;  
  4.     Message response = null;  
  5.     String str;  
  6.     LoadLinearFixedContext lc;  
  7.   
  8.     byte data[];  
  9.     int size;  
  10.     int fileid;  
  11.     int recordSize[];  
  12.     try {  
  13.         switch (msg.what) {  
  14.             case EVENT_GET_RECORD_SIZE_IMG_DONE:  
  15.             case EVENT_GET_RECORD_SIZE_DONE:  
  16.                 //得到从Modem拿到的原始数据  
  17.                 ar = (AsyncResult)msg.obj;  
  18.                 lc = (LoadLinearFixedContext) ar.userObj;  
  19.                 result = (IccIoResult) ar.result;  
  20.                 response = lc.mOnLoaded;  
  21.   
  22.                 if (processException(response, (AsyncResult) msg.obj)) {  
  23.                     break;  
  24.                 }  
  25.   
  26.                 data = result.payload;  
  27.                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {  
  28.                     throw new IccFileTypeMismatch();  
  29.                 }  
  30.                 if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {  
  31.                     throw new IccFileTypeMismatch();  
  32.                 }  
  33.   
  34.                 //得到当前记录的长度  
  35.                 lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;  
  36.   
  37.                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);  
  38.   
  39.                 lc.mCountRecords = size / lc.mRecordSize;  
  40.                 if (lc.mLoadAll) {  
  41.                     lc.results = new ArrayList<byte[]>(lc.mCountRecords);  
  42.                 }  
  43.   
  44.                 //加上要读取的记录长度再次读取数据  
  45.                 mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),  
  46.                         lc.mRecordNum,  
  47.                         READ_RECORD_MODE_ABSOLUTE,  
  48.                         lc.mRecordSize, nullnull, mAid,  
  49.                         obtainMessage(EVENT_READ_RECORD_DONE, lc));  
  50.                 break;  
  51.   
  52.   
  53.         }} catch (Exception exc) {  
  54.         }  
  55. }  
        这里看到,IccFileHandler拿到记录的长度后, 再次通过iccIOForApp()去读取记录的数据,然后就可以拿到真正需要的数据了
  1. public void handleMessage(Message msg) {  
  2.     AsyncResult ar;  
  3.     IccIoResult result;  
  4.     Message response = null;  
  5.     String str;  
  6.     LoadLinearFixedContext lc;  
  7.   
  8.     byte data[];  
  9.     int size;  
  10.     int fileid;  
  11.     int recordSize[];  
  12.     try {  
  13.         switch (msg.what) {  
  14.             case EVENT_READ_IMG_DONE:  
  15.             case EVENT_READ_RECORD_DONE:  
  16.                 ar = (AsyncResult)msg.obj;  
  17.                 lc = (LoadLinearFixedContext) ar.userObj;  
  18.                 result = (IccIoResult) ar.result;  
  19.                 response = lc.mOnLoaded;  
  20.                 if (processException(response, (AsyncResult) msg.obj)) {  
  21.                     break;  
  22.                 }  
  23.   
  24.                 if (!lc.mLoadAll) {  
  25.                     sendResult(response, result.payload, null);  
  26.                 } else {  
  27.                     lc.results.add(result.payload);  
  28.                     lc.mRecordNum++;  
  29.   
  30.                     //循环读取记录  
  31.                     if (lc.mRecordNum > lc.mCountRecords) {  
  32.                         sendResult(response, lc.results, null);  
  33.                     } else {  
  34.                         mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),  
  35.                                 lc.mRecordNum,  
  36.                                 READ_RECORD_MODE_ABSOLUTE,  
  37.                                 lc.mRecordSize, nullnull, mAid,  
  38.                                 obtainMessage(EVENT_READ_RECORD_DONE, lc));  
  39.                     }  
  40.                 }  
  41.   
  42.                 break;  
  43.   
  44.   
  45.         }} catch (Exception exc) {  
  46.         }  
  47. }  
        我们看到,在读取记录过程中仍然是循环读取的过程,直到记录完全读取完毕(lc.mRecordNum > lc.mCountRecords)后,才调用sendResult()方法将记录数据发送给当初的请求者。
        这种先读取长度再读取内容的方式,同样适用于调用loadEFLinearFixed()、loadEFImgLinearFixed()、loadEFTransparent()这三个方法。

        这就是IccFileHandler的读取机制。

        下一章将介绍IccRecords相关流程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值