Uicc之ICCFileHandler(转)

来源:互联网 发布:帝国cms整合ck 编辑:程序博客网 时间:2024/04/30 13:45

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


一、IccFileHandler的功能


        我们来看其提供的public方法有哪些:

        public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {}        public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {}        public void loadEFLinearFixedAll(int fileid, Message onLoaded) {}        public void loadEFTransparent(int fileid, Message onLoaded) {}        public void loadEFTransparent(int fileid, int size, Message onLoaded) {}        public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, int length, Message onLoaded) {}        public void getEFLinearRecordSize(int fileid, Message onLoaded) {}        public void updateEFLinearFixed(int fileid, int recordNum, byte[] data, String pin2, Message onComplete) {}        public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {}

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


二、IccFileHandler的创建过程


        由于不同类型的SIM卡分区信息不同,因此在UiccCardApplication中要根据当前的SIM类型创建不同的IccFileHandler对象

        @UiccCardApplication.java        private IccFileHandler createIccFileHandler(AppType type) {            switch (type) {                case APPTYPE_SIM:                    return new SIMFileHandler(this, mAid, mCi);                case APPTYPE_RUIM:                    return new RuimFileHandler(this, mAid, mCi);                case APPTYPE_USIM:                    return new UsimFileHandler(this, mAid, mCi);                case APPTYPE_CSIM:                    return new CsimFileHandler(this, mAid, mCi);                case APPTYPE_ISIM:                    return new IsimFileHandler(this, mAid, mCi);                default:                    return null;            }        }
        这几个类都继承自IccFileHandler。因为不同的SIM卡只是在分区的地址信息上有所差异,所以这几个类的唯一区别就是重写了父类的getEFPath()方法,比如SIMFileHandler:

        @SIMFileHandler.java        protected String getEFPath(int efid) {            switch(efid) {                case EF_SMS:                    return MF_SIM + DF_TELECOM;                case EF_EXT6:                case EF_MWIS:                case EF_MBI:                case EF_SPN:                case EF_AD:                case EF_MBDN:                case EF_PNN:                case EF_SPDI:                case EF_SST:                case EF_CFIS:                case EF_GID1:                    return MF_SIM + DF_GSM;                case EF_MAILBOX_CPHS:                case EF_VOICE_MAIL_INDICATOR_CPHS:                case EF_CFF_CPHS:                case EF_SPN_CPHS:                case EF_SPN_SHORT_CPHS:                case EF_INFO_CPHS:                case EF_CSP_CPHS:                    return MF_SIM + DF_GSM;            }            String path = getCommonIccEFPath(efid);            if (path == null) {                Rlog.e(LOG_TAG, "Error: EF Path being returned in null");            }            return path;        } 

        而UsimFileHandler的getEFPath()是这样的:

        @UsimFileHandler.java        protected String getEFPath(int efid) {            switch(efid) {                case EF_SMS:                case EF_EXT6:                case EF_MWIS:                case EF_MBI:                case EF_SPN:                case EF_AD:                case EF_MBDN:                case EF_PNN:                case EF_OPL:                case EF_SPDI:                case EF_SST:                case EF_CFIS:                case EF_MAILBOX_CPHS:                case EF_VOICE_MAIL_INDICATOR_CPHS:                case EF_CFF_CPHS:                case EF_SPN_CPHS:                case EF_SPN_SHORT_CPHS:                case EF_FDN:                case EF_MSISDN:                case EF_EXT2:                case EF_INFO_CPHS:                case EF_CSP_CPHS:                case EF_GID1:                    return MF_SIM + DF_ADF;                case EF_PBR:                    return MF_SIM + DF_TELECOM + DF_PHONEBOOK;            }            String path = getCommonIccEFPath(efid);            if (path == null) {                return MF_SIM + DF_TELECOM + DF_PHONEBOOK;            }            return path;        }

        可以看到,SIMFileHandler与UsimFileHandler的区别就在于分区的地址上。
        然后来看IccFileHandler的构造方法流程:

        @IccFileHandler.java        protected IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) {            mParentApp = app;            mAid = aid;            mCi = ci;        }

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


三、IccFileHandler读取文件的流程


        既然IccFileHandler的主要作用是读取文件信息,那么我们就来跟踪一下他是如何实现信息的读取的。
        我们来看最常用的读取线性固定长度的文件信息时的流程。

<span style="color:#333333;">        @IccFileHandler.java        public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {            //先去读取Record的Size            Message response = </span><span style="color:#3333ff;background-color: rgb(255, 255, 255);">obtainMessage</span><span style="color:#333333;">(<span style="background-color: rgb(255, 0, 0);">EVENT_GET_RECORD_SIZE_DONE</span>, new LoadLinearFixedContext(fileid, recordNum, onLoaded));            //调用RILJ向Modem读取SIM卡当前分区的长度            mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid), 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);        }</span>

        在这个读取过程中,并不是直接去读取相应的分区内容,而是先读取当前分区记录的长度,当拿到长度之后再去读取当前记录的具体内容:

<span style="color:#333333;">        public void<span style="background-color: rgb(255, 255, 255);"> </span></span><span style="color:#3366ff;background-color: rgb(255, 255, 255);">handleMessage</span><span style="color:#333333;">(Message msg) {            AsyncResult ar;            IccIoResult result;            Message response = null;            String str;            LoadLinearFixedContext lc;            byte data[];            int size;            int fileid;            int recordSize[];            try {                switch (msg.what) {                    case EVENT_GET_RECORD_SIZE_IMG_DONE:                    case <span style="background-color: rgb(255, 0, 0);">EVENT_GET_RECORD_SIZE_DONE</span>:                        //得到从Modem拿到的原始数据                        ar = (AsyncResult)msg.obj;                        lc = (LoadLinearFixedContext) ar.userObj;                        result = (IccIoResult) ar.result;                        response = lc.mOnLoaded;                        if (processException(response, (AsyncResult) msg.obj)) {                            break;                        }                        data = result.payload;                        if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {                            throw new IccFileTypeMismatch();                        }                        if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {                            throw new IccFileTypeMismatch();                        }                        //得到当前记录的长度                        lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;                        size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);                        lc.mCountRecords = size / lc.mRecordSize;                        if (lc.mLoadAll) {                            lc.results = new ArrayList<byte[]>(lc.mCountRecords);                        }                        //加上要读取的记录长度再次读取数据                        mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),                                lc.mRecordNum,                                READ_RECORD_MODE_ABSOLUTE,                                lc.mRecordSize, null, null, mAid,                                obtainMessage(EVENT_READ_RECORD_DONE, lc));                        break;                }} catch (Exception exc) {                }        }</span>
        这里看到,IccFileHandler拿到记录的长度后,再次通过iccIOForApp()去读取记录的数据,然后就可以拿到真正需要的数据了

        public void handleMessage(Message msg) {            AsyncResult ar;            IccIoResult result;            Message response = null;            String str;            LoadLinearFixedContext lc;            byte data[];            int size;            int fileid;            int recordSize[];            try {                switch (msg.what) {                    case EVENT_READ_IMG_DONE:                    case EVENT_READ_RECORD_DONE:                        ar = (AsyncResult)msg.obj;                        lc = (LoadLinearFixedContext) ar.userObj;                        result = (IccIoResult) ar.result;                        response = lc.mOnLoaded;                        if (processException(response, (AsyncResult) msg.obj)) {                            break;                        }                        if (!lc.mLoadAll) {                            sendResult(response, result.payload, null);                        } else {                            lc.results.add(result.payload);                            lc.mRecordNum++;                            //循环读取记录                            if (lc.mRecordNum > lc.mCountRecords) {                                sendResult(response, lc.results, null);                            } else {                                mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),                                        lc.mRecordNum,                                        READ_RECORD_MODE_ABSOLUTE,                                        lc.mRecordSize, null, null, mAid,                                        obtainMessage(EVENT_READ_RECORD_DONE, lc));                            }                        }                        break;                }} catch (Exception exc) {                }        }

        我们看到,在读取记录过程中仍然是循环读取的过程,直到记录完全读取完毕(lc.mRecordNum > lc.mCountRecords)后,才调用sendResult()方法将记录数据发送给当初的请求者。
        这种先读取长度再读取内容的方式,同样适用于调用loadEFLinearFixed()、loadEFImgLinearFixed()、loadEFTransparent()这三个方法。

        这就是IccFileHandler的读取机制。

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

原博文地址:http://blog.csdn.net/u010961631/article/details/38373967
handleMessage()为处理函数,处理obtainMessage()中的情况。

0 0
原创粉丝点击