介绍读取SIM卡中的EF文件的流程。
部分内容参考如下文档:
https://onlinesso.mediatek.com/Pages/FAQ.aspx?List=SW&FAQID=FAQ08976
以读取EF_SPN文件为例
先看下spec中对这个栏位的描述(3GPP TS 51.011):
文件ID是6F46,属于Optional类型,所以SIM卡可以不支持此文件
文件类型是transparent(不同文件类型的读取方法有差异)
文件大小为17个字节,其中第一个字节代表Display Condition,剩下的字节就是SPN信息了。
-
首先用超级终端模拟读取EF_SPN
// 1.获取文件大小
AT+CRSM=192,28486,0,0,15
+CRSM: 0, 0
OK
// 2. 根据之前拿到的文件大小读取文件
AT+CRSM=176,28486,0,0,17
+CRSM: 0, 0
OK
如果你能够从spec中确认文件长度是17的话,第一步也可以省略,但是Android代码中在读文件之前都会先获取文件大小的。
2.再看看相关spec中的描述
(3GPP TS 11.11)
从这里我们能了解到的是:
COMMAND_READ_BINARY = 0xb0
也就是READ BINARY对应的命令是176
COMMAND_GET_RESPONSE = 0xc0
GET RESPONSE对应的命令是192
-
结合代码看流程
SIMRecords.java
// call loadEFTransparent to load EF_SPN
mFh.loadEFTransparent(EF_SPN,
obtainMessage(EVENT_GET_SPN_DONE));
// now we get the EF_SPN
case EVENT_GET_SPN_DONE:
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
// get the first byte
mSpnDisplayCondition = 0xff & data[0];
// get other bytes which is service provider name
setServiceProviderName(IccUtils.adnStringFieldToString(data, 1, data.length - 1));
这里并没有看到需要两次at命令读取EF文件,要了解细节还要继续看loadEFTransparent的实现
public void loadEFTransparent(int fileid, Message onLoaded) {
Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
fileid, 0, onLoaded);
mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
}
这里可以看到,原来处理loadEFTransparent返回事件的Message(EVENT_GET_SPN_DONE)已经被封装到新的Message的obj变量中,而真正的what已经被替换为EVENT_GET_BINARY_SIZE_DONE,所以当iccIOForApp(COMMAND_GET_RESPONSE)这个call返回后处理的事件是EVENT_GET_BINARY_SIZE_DONE.
也请留意:
command是COMMAND_GET_RESPONSE,即192(0xc0)
p1=0, p2 = 0, p3 = GET_RESPONSE_EF_SIZE_BYTES = 15
对应超级终端命令中的:AT+CRSM=192,28486,0,0,15
28486当然是0x6F46啦
case EVENT_GET_BINARY_SIZE_DONE:
ar = (AsyncResult)msg.obj;
response = (Message) ar.userObj;
result = (IccIoResult) ar.result;
data = result.payload;
fileid = msg.arg1;
channel = msg.arg2;
size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
mCi.iccIOForAppEx(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
0, 0, size, null, null, mAid, channel,
obtainMessage(EVENT_READ_BINARY_DONE,
fileid, 0, response));
新的接受response的Message已经从ar.userObj中提取出来啦,就是最初的EVENT_GET_SPN_DONE。
COMMAND_GET_RESPONSE会返回EF文件的大小,存储在data中的第三和第四个字节中,这里应该是17.
新的command已经变成了COMMAND_READ_BINARY,也就是176
这就是读取EF文件的两个步骤。
- 下面看下log信息
// 第一次调用iccIOForApp读取EF文件大小
09-19 14:24:26.369 D/RILJ ( 2242): [3949]> iccIO: SIM_IO 0xc0 0x6f46 path: 3F007FFF,0,0,15 aid: null [SUB0]
09-19 14:24:26.377 D/RIL ( 755): requestSimIo 192, 28486, 3F007FFF, 0, 0, 15 !!
09-19 14:24:26.377 D/RIL ( 755): GET RESPONSE on USIM 3F007FFF:6f46, p3:15
09-19 14:24:26.377 D/RIL ( 755): usimGetResponse, path: 3F007FFF
09-19 14:24:26.377 D/AT ( 755): AT> AT+CRSM=192,28486,0,0,0,,"7FFF"
09-19 14:24:26.377 D/AT ( 755): AT+CRSM=192,28486,0,0,0,,"7FFF"
09-19 14:24:26.402 I/AT ( 755): AT read end: 75:Success
09-19 14:24:26.402 D/AT ( 755): +CRSM: 144, 0, "62168202412183026F468A01058B036F0607800200118800"
09-19 14:24:26.402 D/AT ( 755):
09-19 14:24:26.402 D/AT ( 755): OK
09-19 14:24:26.403 D/RIL ( 755): makeSimRspFromUsimFcp, format_wrong: 0
// 请注意这里,代码中针对USIM的get response命令似乎有特殊的处理,所以这里的数据才是真正返回的数据,而它的第三和第四个字节则对应EF文件的大小:0011,转为十进制就是17
09-19 14:24:26.403 D/RIL ( 755): simRsp done:000000110000040000000000000000
// 至此,第一次条用处理完毕
09-19 14:24:26.403 D/RILJ ( 2242): [3949]< SIM_IO IccIoResponse sw1:0x90 sw2:0x0 [SUB0]
//下面开始根据文件大小读取文件中的信息
09-19 14:24:26.410 D/RILJ ( 2242): [3950]> iccIO: SIM_IO_EX 0xb0 0x6f46 path: 3F007FFF,0,0,17,channel:0 aid: null [SUB0]
//下发 at command
09-19 14:24:26.416 D/AT ( 755): AT> AT+CRSM=176,28486,0,0,17,,"7FFF"
09-19 14:24:26.416 D/AT ( 755): AT+CRSM=176,28486,0,0,17,,"7FFF"
//碰巧我这张SIM卡中没有SPN信息
09-19 14:24:26.451 D/AT ( 755): +CRSM: 144, 0, "00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
//至此,第二次条用处理完毕
09-19 14:24:26.452 D/RILJ ( 2242): [3950]< SIM_IO_EX IccIoResponse sw1:0x90 sw2:0x0 [SUB0]
//最后是调用这SIMRecords处理返回信息:spn信息为空字符串
09-19 14:24:26.455 D/SIMRecords( 2242): [SIMRecords] EF_SPN loaded and try to extract: (slot 0)
09-19 14:24:26.455 D/SIMRecords( 2242): [SIMRecords] getSpnFsm, Got data from EF_SPN (slot 0)
09-19 14:24:26.455 D/SIMRecords( 2242): [SIMRecords] setServiceProviderName: spn= (slot 0)
09-19 14:23:53.760 D/SIMRecords( 2242): [SIMRecords] set spNameInEfSpn to null because parsing result is empty (slot 0)
//spnDisplayCondition为0,但因为spn为空,所以这个值是多少也无关紧要啦。
09-19 14:23:53.760 D/SIMRecords( 2242): [SIMRecords] Load EF_SPN: spnDisplayCondition: 0 (slot 0)
注:代码和log信息参考MT6752平台,Android 5.1