Android调用getSimSerialNumber获取iccid不完整
1、在Android中我们可以通过下面这段代码获取SIM的iccid,关于手机中常用术语简介可参考《Android中CS域和PS域以及手机中常用术语简介》
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE); String simSerialNumber = telephonyManager.getSimSerialNumber();
注:ICCID (Integrate circuit card identity ) 集成电路卡识别码(固化在手机SIM 卡中) ICCID 为IC 卡的唯一识别号码,共有20 位数字组成。
但调用这个方法有时候并不能获取到20位完整的SIM iccid,怀着好奇心看了下android源码,下面就来一层层揭开这面纱。
frameworks/base/telephony/java/android/telephony/TelephonyManager.java public String getSimSerialNumber(int subId) { android.util.SeempLog.record_str(388, ""+subId); try { IPhoneSubInfo info = getSubscriberInfo(); if (info == null) return null; return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName()); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { // This could happen before phone restarts due to crashing return null; } }
getIccSerialNumberForSubscriber是在PhoneSubInfoController.java中实现,具体方式如下:
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneSubInfoController.java public String getIccSerialNumberForSubscriber(int subId, String callingPackage) { Phone phone = getPhone(subId); if (phone != null) { if (!checkReadPhoneState(callingPackage, "getIccSerialNumber")) { return null; } return phone.getIccSerialNumber(); } else { loge("getIccSerialNumber phone is null for Subscription:" + subId); return null; } }
getIccSerialNumber是在GsmCdmaPhone.java实现:
frameworks/opt/telephony/src/java/com/android/internal/telephony/GsmCdmaPhone.java @Override public String getIccSerialNumber() { IccRecords r = mIccRecords.get(); if (!isPhoneTypeGsm() && r == null) { // to get ICCID form SIMRecords because it is on MF. r = mUiccController.getIccRecords(mPhoneId, UiccController.APP_FAM_3GPP); } return (r != null) ? r.getIccId() : null; }
getIccId是IccRecords.java中定义的,但其赋值是在IccRecords的两个子类SIMRecords.java和RuimRecords.java中赋值的
frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/SIMRecords.java // ***** Overridden from Handler @Override public void handleMessage(Message msg) { AsyncResult ar; AdnRecord adn; byte data[]; boolean isRecordLoadResponse = false; if (mDestroyed.get()) { loge("Received message " + msg + "[" + msg.what + "] " + " while being destroyed. Ignoring."); return; } try { switch (msg.what) { case EVENT_GET_ICCID_DONE: isRecordLoadResponse = true; ar = (AsyncResult)msg.obj; data = (byte[])ar.result; if (ar.exception != null) { break; } mIccId = IccUtils.bcdToString(data, 0, data.length); mFullIccId = IccUtils.bchToString(data, 0, data.length); log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId)); break; ... default: super.handleMessage(msg); // IccRecords handles generic record load responses }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal logw("Exception parsing SIM record", exc); } finally { // Count up record load responses even if they are fails if (isRecordLoadResponse) { onRecordLoaded(); } } }
EVENT_GET_ICCID_DONE是在IccFileHandler.java@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); }
这里会调用RIL.java里的iccIOForApp向modem发送查询请求,有结果返回后便会调用EVENT_GET_ICCID_DONE对mIccId进行赋值
frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/IccUtils.java public static String bcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); for (int i = offset ; i < offset + length ; i++) { int v; v = data[i] & 0xf; if (v > 9) break; ret.append((char)('0' + v)); v = (data[i] >> 4) & 0xf; // Some PLMNs have 'f' as high nibble, ignore it if (v == 0xf) continue; if (v > 9) break; ret.append((char)('0' + v)); } return ret.toString(); }
可以看到在bcdToString时,如果data里面包含非0-9的字符,就只取第一个非0-9的字段
eg:8986011785a113040534 ,按照这个方法获取的为8986011785
当然在GsmCdmaPhone@getFullIccSerialNumber,这个方法在调用的时候,只是调用了IccUtils.bchToString
/** * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH */ public static String bchToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); for (int i = offset ; i < offset + length ; i++) { int v; v = data[i] & 0xf; ret.append("0123456789abcdef".charAt(v)); v = (data[i] >> 4) & 0xf; ret.append("0123456789abcdef".charAt(v)); } return ret.toString(); }
此时获取到的iccid才是完整的,然而现在很多sim卡的iccid包含0-f之外的字符,还是不能取到完整的iccid,如果你有好的方案,欢迎留言指教,谢谢!
eg:8986011785N113040534,不能获取到正确完整的20位iccid
更多相关文章
- Android中工作线程与主线程同步方式
- Android(安卓)多媒体
- android中调用系统功能 来显示本地相册图片 拍照 视频 音频功能
- 如何使用arm-eabi-gdb调试android c/c++程序
- Android事件分发和View绘制流程分析(三)
- Android(安卓)打开相机、相册获取图片文件,支持Android(安卓)9.0
- Android手势检测简介
- android 项目中规范使用SharedPreferences
- 箭头函数的基础使用