SIM卡的本质是一个文件系统,并且具备不同的分区,而IccFileHandler主要用于从SIM卡读取相应分区的数据。
这几个类都继承自IccFileHandler。因为不同的SIM卡只是在分区的地址信息上有所差异,所以这几个类的
唯一区别就是重写了父类的getEFPath()方法,比如SIMFileHandler:
而UsimFileHandler的getEFPath()是这样的:
可以看到,SIMFileHandler与UsimFileHandler的区别就在于分区的地址上。
然后来看IccFileHandler的构造方法流程:
我们来看最常用的读取线性固定长度的文件信息时的流程。
在这个读取过程中,并不是直接去读取相应的分区内容,而是先读取当前分区记录的长度,当拿到长度之后再去读取当前记录的具体内容:
这里看到,IccFileHandler拿到记录的长度后,
再次通过iccIOForApp()去读取记录的数据,然后就可以拿到真正需要的数据了:
我们看到,在读取记录过程中仍然是循环读取的过程,直到记录完全读取完毕(lc.mRecordNum > lc.mCountRecords)后,才调用sendResult()方法将记录数据发送给当初的请求者。
这种先读取长度再读取内容的方式,同样适用于调用loadEFLinearFixed()、loadEFImgLinearFixed()、loadEFTransparent()这三个方法。
一、IccFileHandler的功能
- 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的创建过程
- @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;
- }
- }
- @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.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;
- }
然后来看IccFileHandler的构造方法流程:
- @IccFileHandler.java
- protected IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) {
- mParentApp = app;
- mAid = aid;
- mCi = ci;
- }
由于IccFileHandler的主要作用是被动的查询SIM分区信息,因此在构造方法中,只是将重要的上下文信息保存起来以备使用。
三、IccFileHandler读取文件的流程
我们来看最常用的读取线性固定长度的文件信息时的流程。
- @IccFileHandler.java
- public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {
- //先去读取Record的Size
- Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, 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);
- }
- 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_GET_RECORD_SIZE_IMG_DONE:
- case EVENT_GET_RECORD_SIZE_DONE:
- //得到从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) {
- }
- }
- 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) {
- }
- }
这种先读取长度再读取内容的方式,同样适用于调用loadEFLinearFixed()、loadEFImgLinearFixed()、loadEFTransparent()这三个方法。
这就是IccFileHandler的读取机制。
下一章将介绍IccRecords相关流程。