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

更多相关文章

  1. Android中工作线程与主线程同步方式
  2. Android(安卓)多媒体
  3. android中调用系统功能 来显示本地相册图片 拍照 视频 音频功能
  4. 如何使用arm-eabi-gdb调试android c/c++程序
  5. Android事件分发和View绘制流程分析(三)
  6. Android(安卓)打开相机、相册获取图片文件,支持Android(安卓)9.0
  7. Android手势检测简介
  8. android 项目中规范使用SharedPreferences
  9. 箭头函数的基础使用

随机推荐

  1. Android(安卓)结束进程的方法
  2. Android(安卓)NDK Development ---- Andr
  3. Android的NDK开发(2)————利用Android
  4. android surfaceflinger boot
  5. 解决activity加上Theme.Translucent.NoTi
  6. Android(安卓)支持 Java8
  7. RecyclerView 滚动条的显示与隐藏
  8. Activity页面切换的效果
  9. Android(安卓)设置虚线分割线
  10. Android(安卓)Framework---styles.xml