IccProvider概述

读取卡联系人的provider定义于:

/packages/services/Telephony/AndroidManifest.xml

            
packages/services/Telephony/src/com/android/phone/IccProvider.java

public class IccProvider extends com.android.internal.telephony.IccProvider {    public IccProvider() {        super();    }}
Telephony目录下的IccProvider其实是空的,实现全部在framework的同名文件中

frameworks/opt/telephony/src/java/com/android/internal/telephony/IccProvider.java

public class IccProvider extends ContentProvider {

IccProvider读取卡联系人流程

    static {        URL_MATCHER.addURI("icc", "adn", ADN);        URL_MATCHER.addURI("icc", "adn/subId/#", ADN_SUB);        ...    }
static块中加入了adn的uri,adn/subid/#可以指定读取的sim卡
  public Cursor query(Uri url, String[] projection, String selection,            String[] selectionArgs, String sort) {        ...        switch (URL_MATCHER.match(url)) {          case ADN:              return loadFromEf(IccConstants.EF_ADN, mSubscriptionManager.getDefaultSubId());        ...  }
query方法,调用loadFromEf
  private MatrixCursor loadFromEf(int efType, int subId) {        List adnRecords = null;        try {            IIccPhoneBook iccIpb = getIccPhbService();            if (iccIpb != null) {                adnRecords = iccIpb.getAdnRecordsInEfForSubscriber(subId, efType);            }        } catch (RemoteException ex) {            log(ex.toString());        } catch (SecurityException ex) {            log(ex.toString());        }        if (adnRecords != null) {            // Load the results            final int size = adnRecords.size();            final MatrixCursor cursor = new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES, size);            if (DBG) {                log("adnRecords.size=" + size);            }            for (int i = 0; i < size; i++) {                loadRecord(adnRecords.get(i), cursor, i);            }            return cursor;        }        ...  }
首先获取AdnRecord列表然后,然后loadRecord依据这个列表生成cursor返回。生成cursor的函数很简单,不做分析了。
    private IIccPhoneBook getIccPhbService() {        IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(                ServiceManager.getService("simphonebook"));        return iccIpb;    }
读取的服务名称叫做simphonebook,该服务添加的代码在UiccPhoneBookController中: frameworks/opt/telephony/src/java/com/android/internal/telephony/UiccPhoneBookController.java
    public UiccPhoneBookController(Phone[] phone) {        if (ServiceManager.getService("simphonebook") == null) {               ServiceManager.addService("simphonebook", this);        }        mPhone = phone;    }
构造函数中添加了服务,UiccPhoneBookController实例是在phone进程启动就初始化的,phone进程又是常驻的,所以phone的相关服务基本等于是永远可用的。
    public List getAdnRecordsInEfForSubscriber(int subId, int efid)           throws android.os.RemoteException {        IccPhoneBookInterfaceManagerProxy iccPbkIntMgrProxy =                             getIccPhoneBookInterfaceManagerProxy(subId);        if (iccPbkIntMgrProxy != null) {            return iccPbkIntMgrProxy.getAdnRecordsInEf(efid);        }         ...    }
然后调用IccPhoneBookInterfaceManagerProxy的getAdnRecordsInEf
  private IccPhoneBookInterfaceManagerProxy            getIccPhoneBookInterfaceManagerProxy(int subId) {        ...        try {            return ((PhoneProxy)mPhone[(int)phoneId]).getIccPhoneBookInterfaceManagerProxy();        ...  }
frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneProxy.java
    public IccPhoneBookInterfaceManagerProxy getIccPhoneBookInterfaceManagerProxy() {        return mIccPhoneBookInterfaceManagerProxy;    }
  public PhoneProxy(PhoneBase phone) {        ...        mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(                phone.getIccPhoneBookInterfaceManager());        ...  }
IccPhoneBookInterfaceManagerProxy是在PhoneProxy构造函数中初始化的。 frameworks/opt/telephony/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java
   public List getAdnRecordsInEf(int efid) {        return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid);    }
这里的mIccPhoneBookInterfaceManager就是PhoneProxy构造函数传递进去的phone.getIccPhoneBookInterfaceManager() 该对象实际是在Phone的构造函数中初始化的,拿GsmPhone举例 frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java
            mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
SimPhoneBookInterfaceManager的基类是IccPhoneBookInterfaceManager /home/lgy/code/mtk6797/frameworks/opt/telephony/src/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
    public synchronized List getAdnRecordsInEf(int efid) {        ...        synchronized (mLock) {            checkThread();            AtomicBoolean status = new AtomicBoolean(false);            Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE, status);            if (mAdnCache != null) {                mAdnCache.requestLoadAllAdnLike(efid, mAdnCache.extensionEfForEf(efid), response);                waitForResult(status);            }            ...        }        return mRecords;    }
frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/AdnRecordCache.java
   public void    requestLoadAllAdnLike (int efid, int extensionEf, Message response) {        ArrayList waiters;        ArrayList result;        if (efid == EF_PBR) {            result = mUsimPhoneBookManager.loadEfFilesFromUsim();        } else {            result = getRecordsIfLoaded(efid); //该方法实际是从缓存读取数据        }        logd("requestLoadAllAdnLike result = null ?" + (result == null));        // Have we already loaded this efid?        if (result != null) {   //如果缓存已有数据,return            if (response != null) {                AsyncResult.forMessage(response).result = result;                response.sendToTarget();            }            return;        }        // Have we already *started* loading this efid?        waiters = mAdnLikeWaiters.get(efid);        if (waiters != null) { //正在读取中,把回调消息加入等待队列中,return            waiters.add(response);            return;        }        waiters = new ArrayList();        waiters.add(response);        mAdnLikeWaiters.put(efid, waiters);        ...        new AdnRecordLoader(mFh).loadAllFromEF(efid, extensionEf,            obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));  //正真读取    }
流程分析已经写在注释中,usim是另一条分支(本流程不做解析),继续看loadAllFromEF frameworks/opt/telephony/src/java/com/android/internal/telephony/uicc/AdnRecordLoader.java
   public void    loadAllFromEF(int ef, int extensionEF,                Message response) {          ...          mFh.mCi.queryPhbStorageInfo(               type,               obtainMessage(EVENT_PHB_QUERY_STAUTS));          ...    }
调用ril的queryPhbStorageInfo向modem发送请求,读取结果会在handleMessage中处理
                case EVENT_PHB_QUERY_STAUTS:                    /*                     * response.obj.result[0] is number of current used entries                     * response.obj.result[1] is number of total entries in the                     * storage                     */                    ar = (AsyncResult) (msg.obj);                    int[] info = (int[]) (ar.result);                    if (ar.exception != null) {                        throw new RuntimeException("PHB Query Info Error",                                ar.exception);                    }                    type = getPhbStorageType(mEf);                    readInfo = new int[3];                    readInfo[0] = 1; // current_index;                    readInfo[1] = info[0]; // # of remaining entries                    readInfo[2] = info[1]; // # of total entries                    mAdns = new ArrayList(readInfo[2]);                    for (int i = 0; i < readInfo[2]; i++) {                        // fillin empty entries to mAdns                        adn = new AdnRecord(mEf, i + 1, "", "");                        mAdns.add(i, adn);                    }                    readEntryFromModem(type, readInfo);                    mPendingExtLoads = 1;                    break;
获取到了卡联系人总数目,先用空值初始化mAdn列表,然后调用readEntryFromModem正真的读取数据
    private void readEntryFromModem(int type, int[] readInfo) {        ...        mFh.mCi.ReadPhbEntry(type, readInfo[0], eIndex,                obtainMessage(EVENT_PHB_LOAD_ALL_DONE, readInfo));    }
消息处理:
          case EVENT_PHB_LOAD_ALL_DONE:                    ar = (AsyncResult) (msg.obj);                    readInfo = (int[]) (ar.userObj);                    entries = (PhbEntry[]) (ar.result);                    ...                    for (int i = 0; i < entries.length; i++) {                        adn = getAdnRecordFromPhbEntry(entries[i]);                        if (adn != null) {                            mAdns.set(adn.mRecordNumber - 1, adn);                            readInfo[1]--;                            Rlog.d(LOG_TAG, "Read entries: " + adn);                        }                    }                    ...
for循环中向mAdns添加数据。AdnRecordLoader会向AdnRecordCache发消息,EVENT_LOAD_ALL_ADN_LIKE_DONE消息处理:
            case EVENT_LOAD_ALL_ADN_LIKE_DONE:                ...                if (ar.exception == null) {                    mAdnLikeFiles.put(efid, (ArrayList) ar.result);                } else {                    Rlog.d(LOG_TAG, "EVENT_LOAD_ALL_ADN_LIKE_DONE exception", ar.exception);                }                notifyWaiters(waiters, ar);                ...                break;
一路向上传递消息,这里的ar其实就包含了联系人数据列表ArrayList

回到IccPhoneBookInterfaceManager.java

                case EVENT_LOAD_DONE:                    ar = (AsyncResult)msg.obj;                    ...                       mRecords = (List) ar.result;                    ...
整个流程走完了。可以看出名称叫做IccProvider,其实没有建立任何数据库。第一次的查询是通过发送ril请求读取sim卡得到数据,后续用缓存返回数据。

Contacts读取Sim卡联系人的流程

分析的以mtk的代码为例,高通的代码和mtk差异很大,且不在Contacts目录下。是在vendor目录下,单独作为一个app。 /home/lgy/code/mtk6797/packages/apps/Contacts/AndroidManifest.xml
                                                                                                              
packages/apps/Contacts/src/com/mediatek/contacts/simcontact/BootCmpReceiver.java
public void onReceive(Context context, Intent intent) {    ...    if (action.equals(TelephonyIntents.ACTION_PHB_STATE_CHANGED)) {                processPhoneBookChanged(context, intent);            }    ...}
收到TelephonyIntents.ACTION_PHB_STATE_CHANGED广播后,该广播表示卡联系人可用不可用,调用processPhoneBookChanged
 private void processPhoneBookChanged(Context context, Intent intent) {        ...        if (phbReady && subId > 0) {            startSimService(context, subId, SIMServiceUtils.SERVICE_WORK_IMPORT);        } else if (subId > 0 && !phbReady) {            startSimService(context, subId, SIMServiceUtils.SERVICE_WORK_REMOVE);        }    }
广播处理有两个分支,一个是删除卡联系人,一个是导入卡联系人 packages/apps/Contacts/src/com/mediatek/contacts/simservice/SIMProcessorService.java
    @Override    public void onCreate() {        super.onCreate();        Log.i(TAG, "[onCreate]...");        mProcessorManager = new SIMProcessorManager(this, mListener);    }    @Override    public void onStart(Intent intent, int startId) {        super.onStart(intent, startId);        processIntent(intent);    }
 private void processIntent(Intent intent) {        ...        mProcessorManager.handleProcessor(getApplicationContext(), subId, workType, intent);    }
一路调用到handleProcessor,注意mProcessorManager初始化的时候传入了接口的实现,这样mProcessorManager就可以通知SIMProcessorService工作开始或者完毕
private SIMProcessorManager.ProcessorManagerListener mListener 
packages/apps/Contacts/src/com/mediatek/contacts/simservice/SIMProcessorManager.java
    public void handleProcessor(Context context, int subId, int workType, Intent intent) {        Log.i(TAG, "[handleProcessor] subId=" + subId + ",time=" + System.currentTimeMillis());        SIMProcessorBase processor = createProcessor(context, subId, workType, intent);        if (processor != null && mListener != null) {            Log.d(TAG, "[handleProcessor]Add processor [subId=" + subId + "] to threadPool.");            mListener.addProcessor(/* 1000 + slotId * 300 */0, processor);        }    }
    private SIMProcessorBase createProcessor(Context context, int subId, int workType,            Intent intent, ProcessorCompleteListener listener) {        ...        if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT) {            processor = new SIMImportProcessor(context, subId, intent, listener);        ...    }
createProcessor生成了processor,然后调用mListener的方法,这个就是SIMProcessorService中实现的,addProcessor开始导入联系人的工作:
     @Override        public void addProcessor(long scheduleTime, ProcessorBase processor) {            if (processor != null) {                try {                    mExecutorService.execute(processor);                } catch (RejectedExecutionException e) {                    Log.e(TAG, "[addProcessor] RejectedExecutionException: " + e.toString());                }            }        }
processor是继承自ProcessorBase。
packages/apps/ContactsCommon/src/com/android/contacts/common/vcard/ProcessorBase.java
public abstract class ProcessorBase implements RunnableFuture {ProcessorBase实现了RunnableFuture,所以它可以放到线程池区运行。             packages/apps/Contacts/src/com/mediatek/contacts/simservice/SIMProcessorBase.java             
   public void run() {        try {            doWork();        } finally {            mDone = true;            if (mListener != null && !mCanceled) {                mListener.onProcessorCompleted(mIntent);            }        }    }
线程池是调用run方法开启工作的,run函数中调用doWork完成工作,用mListener接口通知SIMProcessorManager工作完毕
packages/apps/Contacts/src/com/mediatek/contacts/simservice/SIMImportProcessor.java
    @Override    public void doWork() {        ...        SIMServiceUtils.deleteSimContact(mContext, mSubId);        ...        int simType = SimCardUtils.getSimTypeBySubId(mSubId);        final Uri iccUri = SubInfoUtils.getIccProviderUri(mSubId);        Cursor simCursor = querySimContact(mContext, mSubId, simType, iccUri);        Log.i(TAG, "[dowork]simType = " + simType + ",simType =" + simType + ",mSubId = " + mSubId);        importAllSimContacts(mContext, mSubId, simCursor, simType);        if (simCursor != null) {            simCursor.close();        }    }
首先删除所有数据库中的卡联系人,然后查询卡联系人,获取卡联系人数据后导入到ContactsProvider中。
 private Cursor querySimContact(Context context, int subId, int simType, Uri iccUri) {        ...        cursor = context.getContentResolver().query(iccUri, COLUMN_NAMES, null, null, null);        ...        return cursor;    }
通过IccProvider查询卡联系人
   private void importAllSimContacts(Context context, final Cursor cursor,            final ContentResolver resolver, int subId, int simType, HashSet insertSimIdSet,            boolean importSdnContacts) {       ...       while (cursor.moveToNext()) {                ...                i = actuallyImportOneSimContact(context, cursor, resolver, subId, simType,                        indexInSim, importSdnContacts, operationList, i, account, isUsim,                        accountSubId, countryCode);                ...                if (i > MAX_OP_COUNT_IN_ONE_BATCH) {                    ...                    resolver.applyBatch(ContactsContract.AUTHORITY, operationList);                    ...                }       }       ...    }
基本流程是依据cursor利用actuallyImportOneSimContact生成数据库插入的operationlist,然后在每大于90个operation就批量操作一次,循环上诉流程直到处理完毕。 doWork结束后会回调接口ProcessorCompleteListener,然后关闭线程池和关闭service,这个流程简单不再做分析。


更多相关文章

  1. Android(安卓)Java方法链起来!链式调用方法、仿Builder 等。
  2. Android(安卓)HttpGet和HttpPost设置超时
  3. android 9.0 在rk3326平台上hidl的使用
  4. Android(安卓)调用系统相机拍照的返回结果
  5. android 分享功能
  6. android学习小结3
  7. Android(安卓)使用ContentObserver监听短信的变化,并发送信息给特
  8. Android(安卓)实现手机震动功能
  9. Android(安卓)获取通讯录联系人

随机推荐

  1. ffmpeg compile with neon support for a
  2. android bitmap(图片)旋转90度
  3. android实现截屏
  4. Android自动判定输入的是电话号码还是网
  5. Android:New Google Play Developer Conso
  6. Android(安卓)发送通知
  7. setCompoundDrawables与setCompoundDrawa
  8. android之单选框
  9. Android(安卓)实现拨打电话功能
  10. android 监听Home键和亮灭屏