读取SIM卡中联系人流程

本文主要讲USIM卡插入手机后读取卡中contacts信息的流程。

整体流程总结

  1. 每次插拔SIM卡都会将联系人数据库中关于SIM卡的联系人删除
  2. SimStateReceiver 通过接收 RIL 上报的关于 SIM 卡状态变化的广播去启动 SimContactsService
  3. SimContactsService 异步启动 IccProvider 去查询 SIM 卡联系人
  4. 通过 IccPhoneBookInterfaceManager 一层层调用到 RIL 然后层层返回,最后构造MatrixCursor 插入数据库

先介绍几个类的作用:

  • IccProvider:对外暴露的接口,我们通过它来查询SIM卡中的contacts信息
  • IccPhoneBookInterfaceManager: PhoneBook操作的服务
  • IccPhoneBookInterfaceManagerProxy:对外的PhoneBook操作服务, 上面类的代理.
  • IccRecord:存储与卡相关的一些信息
  • AdnRecord:一条联系人信息读取后被封装的类型
  • AdnRecordCache:对SIM卡中联系人信息进行Cache
  • AdnRecordLoader:实际通过IccFileHandler去获取adn信息的类
  • IccFileHandler:向RIL发起请求,或者接受反馈
  • RIL:向底层发起请求,并接收反馈

大体流程图如下:

读取SIM卡中联系人流程_第1张图片
读取SIM卡中联系人流程_第2张图片

重要的几个方法:

    public List getAdnRecordsInEf(int efid) {

        if (mPhone.getContext().checkCallingOrSelfPermission(
                android.Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED) {
            throw new SecurityException(
                    "Requires android.permission.READ_CONTACTS permission");
        }

        synchronized(mLock) {
            checkThread();
            AtomicBoolean status = new AtomicBoolean(false);
            Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE, status);
            efid = updateEfForIccType(efid);
            if (DBG) logd("getAdnRecordsInEF: efid=" + efid);

            if (mAdnCache != null) {
                mAdnCache.requestLoadAllAdnLike(efid,
                        mAdnCache.extensionEfForEf(efid), null, response);
                waitForResult(status);
            } else {
                loge("Failure while trying to load from SIM due to uninitialised adncache");
            }
            if (mRecords == null && efid == IccConstants.EF_PBR && !mAdnCache.isPbrPresent()) {//如果通过EF_PBR得不到值就通过EF_ADN的路径拿数据
                logd("getAdnRecordsInEF: Load from EF_ADN as pbr is not present");
                mForceAdnUsage = true;
                return getAdnRecordsInEf(IccConstants.EF_ADN);
            }
        }
        return mRecords;
    }

    private int updateEfForIccType(int efid) {
        // Check if we are trying to read ADN records
        if (efid == IccConstants.EF_ADN && !mForceAdnUsage) {
            if (mPhone.getCurrentUiccAppType() == AppType.APPTYPE_USIM ||
                    mPhone.getCurrentUiccAppType() == AppType.APPTYPE_CSIM) {
                return IccConstants.EF_PBR; //SIM卡返回:EF_ADN 、USIM卡返回EF_PBR 这个返回值影响着我们应该读取UICC中的那个文件路径
            }
        }
        return efid;
    }
    public ArrayList loadEfFilesFromUsim() {
        synchronized (mLock) {
            if (!mPhoneBookRecords.isEmpty()) {
                if (mRefreshCache) {
                    mRefreshCache = false;
                    refreshCache();
                }
                return mPhoneBookRecords;
            }

            if (!mIsPbrPresent) return null;

            // Check if the PBR file is present in the cache, if not read it
            // from the USIM.
            if (mPbrFile == null) {
                readPbrFileAndWait();
            }

            if (mPbrFile == null) return null;

            int numRecs = mPbrFile.mFileIds.size();

            if ((mAnrFlagsRecord == null) && (mEmailFlagsRecord == null)) {
                mAnrFlagsRecord = new ArrayList[numRecs];
                mEmailFlagsRecord = new ArrayList[numRecs];
                for (int i = 0; i < numRecs; i++) {
                    mAnrFlagsRecord[i] = new ArrayList();
                    mEmailFlagsRecord[i] = new ArrayList();
                }
            }

            for (int i = 0; i < numRecs; i++) { //一直读取里面的信息,并放mPhoneBookRecords当中,这个值会影响到contacts里面MemoryStatusActivity中显示sim 卡total的值

                readAdnFileAndWait(i);
                readEmailFileAndWait(i);
                readAnrFileAndWait(i);
            }
            // All EF files are loaded, post the response.
        }
        return mPhoneBookRecords;
    }

重要的log信息

        Line 10831: 07-15 18:52:30.427 D/IccProvider( 3714): [IccProvider] query  
        Line 10835: 07-15 18:52:30.427 D/IccProvider( 3714): [IccProvider] loadFromEf: efType=28474, subscription=3   //ADN
        Line 10837: 07-15 18:52:30.429 D/SimPhoneBookIM( 3714): [SimPbInterfaceManager] getAdnRecordsInEF: efid=20272   //PBR
        Line 10843: 07-15 18:52:30.429 D/UsimFH  ( 3714): Using Global Phonebook 
        Line 10845: 07-15 18:52:30.429 D/UsimFH  ( 3714): Using Local Phonebook  
        Line 10847: 07-15 18:52:30.429 D/IccProvider( 3714): [IccProvider] adnRecords.size=500 
        Line 10849: 07-15 18:52:30.429 D/IccProvider( 3714): [IccProvider] loadRecord: Luoyi, 15202863711, 
        Line 33763: 07-15 18:54:38.049 D/UsimPhoneBookManager( 3714): Loading PBR done    
        Line 53039: 07-15 18:55:34.067 D/AdnRecordCache( 3714): Using Local Phonebook  

SIM卡基础知识

SIM卡上的所有数据都是以文件的形式存放在卡片数据存储区中的,如下图所示:
读取SIM卡中联系人流程_第3张图片
MF:代表根目录,DF:代表目录,EF:代表文件
三种EF文件:透明文件Transparent/记录文件Linear fixed/循环文件Cydic
卡片上,每个目录或文件都有自己的ID,称为FID

SIM 看文件结构如下:

读取SIM卡中联系人流程_第4张图片

SIM卡文件系统结构如下:

读取SIM卡中联系人流程_第5张图片
其中:
- 3F Master file (MF,文件系统根目录)
- 7F Dedicated file (DF,专用文件目录)
- 2F Elementary file(MF,位于主文件目录下)
- 6F Elementary file(MF,位于专用文件目录下)
- SIM: 用户识别模块(Subscriber Identity Module) (GSM/WCDMA/TD-SCDMA) UICC卡上存储GSM用户签约信息的一个应用
- USIM: 通用用户识别模块(Universal Subscriber Identity Module) (GSM/WCDMA/TD-SCDMA) UICC卡上存储3G用户签约信息的一个应用。
- USIM可以同时包括USIM和SIM两个逻辑模块,也可以只包括USIM逻辑模块,第一种叫做复合USIM卡,也就是说可以兼容2G与3G终端,第二种是纯粹的USIM卡,只能在3G终端中使用。

USIM与SIM对比

  • USIM采用双向鉴权,SIM采用单向鉴权,所以USIM的安全性能更高;
  • USIM卡机卡接口的速率约为230bits/s,远优于SIM;
  • USIM可以同时支持4个并发的逻辑应用,优于SIM;
  • 相对与SIM对STK功能的支持,USIM支持更丰富的STK逻辑通道,也让基于USIM主动发起多业务变成可能(USAT)。
  • 相对于SIM,USIM中的电话号码簿每个联系人都可以对应有多个号码以及多个昵称

你可能感兴趣的:(contacts)