查询SIM卡联系人

查询SIM卡中的联系人使用的方法为 query( ) 方法,与操作数据库中的查询方法极其类似,使用方式与如下类似:

getContentResolver().query("content://icc/adn/subId/1", null, null, null, null);

那么我们就来探究一下该方法的流程。

流程

  • IccProvider.java —— query( )
@Override
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());case ADN_SUB:return loadFromEf(IccConstants.EF_ADN, getRequestSubId(url));//……省略其它代码……//}
}

从 IccProvider 中的 query 方法开始。我们首先匹配到的是 ADN 的情况,并且由于是双卡,所以下一步需要执行第二种情况的 loadFromEf 方法。该方法中可以看到 IccConstants.EF_ADN 值为6F3A,这就是SIM卡上的地址。

参考: android telephony 工作流程(一)–UICC概述及SIM卡文件系统

  • IccProvider.java —— loadFromEf( )
private MatrixCursor loadFromEf(int efType, int subId) {List<AdnRecord> adnRecords = null;try {IIccPhoneBook iccIpb = getIccPhbService();if (iccIpb != null) {adnRecords = iccIpb.getAdnRecordsInEfForSubscriber(subId, efType);}} //……省略其它代码……//return new MatrixCursor(ADDRESS_BOOK_COLUMN_NAMES);
}

可以看到接下来就是 IIccPhoneBook 中的 getAdnRecordsInEfForSubscriber 方法。实际上接下来执行的是 IccPhoneBookManager.java 中的 getAdnRecordInEf 方法,其中经过了 IIccPhoneBook.java –> UiccPhoneBookController.java –> IccPhoneBookManager.java 的跳转与转换,使用了 Binder 和 AIDL 实现跨进程通信以及使用了代理模式(Proxy Pattern)控制访问,如果不了解这两方面的知识,就会有点看不懂代码的意图与具体实现的内涵,关于这两点,在文章最后进行简单的描述。

  • IccPhoneBookManager.java —— getAdnRecordsInEf( )
public synchronized List<AdnRecord> getAdnRecordsInEf(int efid) {//……省略其它代码……//efid = updateEfForIccType(efid);// Check if we are trying to read ADN records//……省略其它代码……//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);} else {loge("Failure while trying to load from SIM due to uninitialised adncache");}}return mRecords;
}

在该方法中,首先先检查 efid 是否是 IccConstants.EF_ADN,判断一下下面的 efid 是使用 IccConstants.EF_ADN 还是 IccConstants.EF_PBR。然后就是执行 requestLoadAllAdnLike 方法,可以看到从该方法开始,使用了 Message 来通知获取结果。

  • AdnRecordCache.java —— requestLoadAllAdnLike( )
 public void requestLoadAllAdnLike (int efid, int extensionEf, Message response) {ArrayList<Message> waiters;ArrayList<AdnRecord> result;if (efid == EF_PBR) {result = mUsimPhoneBookManager.loadEfFilesFromUsim();} else {result = getRecordsIfLoaded(efid);}// Have we already loaded this efid?if (result != null) {if (response != null) {AsyncResult.forMessage(response).result = result;response.sendToTarget();}return;}//……省略其它代码……//}

这里我们需要看的是 loadEfFilesFromUsim 方法,可以看到先对各种情况进行判断,如果已经存在纪录,刚只需要 refresh 一下,否则循环读取。

  • UsimPhoneBookManager.java —— loadEfFilesFromUsim( )
 public ArrayList<AdnRecord> loadEfFilesFromUsim() {//……省略其它代码……//int numRecs = mPbrFile.mFileIds.size();// read adn by CPBR, not by read record from EF , So we needn't read// for every pbr record.if (mFh instanceof CsimFileHandler) { //fzl add for Uicc card start// fzl comment: UICC card need CRSM, not CPBR. and need read for every pbr record.for (int i = 0; i < numRecs; i++) {Rlog.d(LOG_TAG, "readAdnFileAndWaitForUicc: numRecs = " + i);readAdnFileAndWaitForUICC(i);}} else {readAdnFileAndWait(0);}  //fzl add for Uicc card end//……省略其它代码……//mAasForAnrRec.clear();for (int i = 0; i < numRecs; i++) {readAASFileAndWait(i);readSneFileAndWait(i);readAnrFileAndWait(i);readEmailFileAndWait(i);}readGrpIdsAndWait();// All EF files are loaded, post the response.return mPhoneBookRecords;
}

这个方法的再接着往下跳转可以看到 RIL.java 文件里的 iccIO 方法,在 IO 方法中可以找到一个 TAG,根据这个 TAG 可以在 Reference-ril.c 文件中找到处理这个 Case 的分支,因为对于这种 IO 指令不了解,大概就只能看个热闹了。

以上流程参考:android – sim/usim卡导联系人

AIDL跨进程通信

loadFromEf( ) 方法中调用了 IIccPhoneBook.java 中的方法,事实上,这是用了 AIDL 方式生成的类。

通过添加 IIccPhoneBook.aidl 文件,描述了方法接口,然后编译生成了 IIccPhoneBook.java 文件,然后 UiccPhoneBookController.java 继承于 IIccPhoneBook.Stub。一般而言,继承于 Stub 的称之为 Binder。

这种方式可以实现跨进程通信,在 Android 中的 Binder 机制是一个庞大的体系模块,而 Android 考虑到了逻辑的复杂性,提供了一个简便的方式即 AIDL (Android Interface Description Language)来生成所需要的文件。

代理模式

代理模式适用于无法或不想直接访问某个对象或者访问某个对象有困难时可以通过一个代理对象来间接访问。

在这里我们可以看一下源码中是怎么实现代理模式的。
首先定义一个接口 Phone.java

public interface Phone {// ……省略代码
}   

然后 PhoneBase.java 实现接口

public abstract class PhoneBase extends Handler implements Phone {// ……省略代码
}

然后几种不同制式的SIM卡手机继承了 PhoneBase.java。比如 CDMAPhone.java 、GSMPhone.java 等。
最后定义一个代理类来整合继承于 PhoneBase.java 的类。

public class PhoneProxy extends Handler implements Phone {// ……省略代码 private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy;// ……省略代码 public PhoneProxy(PhoneBase phone) {mActivePhone = phone;mResetModemOnRadioTechnologyChange = SystemProperties.getBoolean(TelephonyProperties.PROPERTY_RESET_ON_RADIO_TECH_CHANGE, false);mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(phone.getIccPhoneBookInterfaceManager());mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());// ……省略代码 }
}

以上三个类的构造是代理模式常用的实现:一个公共接口、一个被代理类、一个代理类。

可以看到,在 PhoneProxy 代理类中还包含了其他的代理类,比如流程中所用的 IccPhoneBookInterfaceManagerProxy。事实上 UiccPhoneBookController.java 就是通过 IccPhoneBookInterfaceManagerProxy 来访问 IccPhoneBookInterfaceManager 中的 getAdnRecordsInEf( ) 方法,而在这个方法中:

public synchronized List<AdnRecord> getAdnRecordsInEf(int efid) {if (mPhone.getContext().checkCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires android.permission.READ_CONTACTS permission");}//……省略其它代码……//mAdnCache.requestLoadAllAdnLike(efid, mAdnCache.extensionEfForEf(efid), response);//……省略其它代码……//         return mRecords;
}

可以看到除了业务逻辑之外还调用了 PhoneBase 的方法来检查权限问题。

由此可以看出代理模式的优点和其使用方式,通过代理来控制对原始对象的访问,而在访问原始对象时执行一些自己的附加操作,实现了代理类与被代理类之间的解耦,符合面向对象原则。

查询SIM卡联系人——源码流程简介相关推荐

  1. Ansroid系统(262)---MTK安卓sim卡相关源码分析

    MTK安卓sim卡相关源码分析 原文地址:http://m.blog.csdn.net/article/details?id=50039589 最近由于一个sim卡相关的需求,就去了解了一下Andro ...

  2. MTK安卓sim卡相关源码分析

    最近由于一个sim卡相关的需求,就去了解了一下Android Sim卡相关的一些代码.在此记录一下. 简要说一下需求吧,需要在插拔卡的时候弹出对话框,提供界面让用户选择开启默认卡数据链接或者转移到另一 ...

  3. Android SIM卡识别加载流程

    文章目录 总述 代码路径 UICC框架 SIM卡识别加载流程 日志分析举例 总述 本文基于Android N(Android 7) 首先要知道SIM卡一般是挂载在CP侧(MODEM侧)的,由MODEM ...

  4. Android SIM卡联系人操作总结

    --- by Ruiming.Lv 在Android中,对SIM中的联系人进行操作,需要通过系统提供的Content Provider进行,该Provider就是Telphony中的IccProvid ...

  5. android中对sim卡联系人的增删改查以及监听sim卡联系数据的改变

    sim卡联系人的增删改查主要是通过ContentProvider来进行操作的,在android中对sim卡联系人操作的provider是定义在IccProvider.java这个类中的,这个类位于an ...

  6. 会员直推奖php程序_PHP自适应卡益源码 前台直销源码 报单费 直推奖 有内部商城...

    演示地址:如有演示站请以演示为准,无演示站以截图为准,源码太多服务器有限,无法搭建所有源码演示站,请谅解! 新手购买指导:1.在本站注册账号 丨 2.登录已注册账号充值源码所需金币 丨 3.登录账号下 ...

  7. 第5章 SIM卡锁定PIN解锁流程

    第5章 SIM卡锁定PIN解锁流程 1.插卡后,在卡初始化过程中,UiccController会从底层获取card状态,会知道要不要进行PIN校验,如果开启就暂停卡初始化流程,并弹出PIN输入框,输入 ...

  8. Android学习之——操作SIM卡联系人

    今天!!!对,就是就是今天,,,,我终于换手机啦啦啦,四儿子拿到手啦...虽然是个二手货,不过人家他爸也不卖了,只能买二手货了,五儿子那凸凸的摄像头和价格又有点难以下咽. 嗯.....新机子到手,折腾 ...

  9. 物联网数据卡系统源码——物联网的主要应用领域

    万物互联时代,物联网的潜力毋庸置疑,其预言也在市场中得到论证.物联网,顾名思义,就是物物相连的互联网.这里有两层意思:其一,物联网的核心和基础仍然是互联网,是在互联网基础上的延伸和扩展的网络: 其二, ...

最新文章

  1. 算法--06年华为面试:求两个数组的最小差值(Java实现)
  2. 区间比较_表观健康儿童 HLAB27 的参考值区间建立和验证
  3. D3.js系列——布局:打包图和地图
  4. android 6.0版本名字,棉花糖Marshmallow 是Android 6.0的名字
  5. 手把手教你入门Git --- Git使用指南(Linux)
  6. 汇编语言(第2版)2011040201
  7. 【慢慢学算法】:qsort()与sort的用法(收藏)
  8. JavaScript中sort方法的使用及原理详解
  9. 小雷:我的核心定位和远大志向(上次更新2013年11月9日)
  10. 谈谈JS中的函数节流
  11. Android实现“是否退出”对话框和“带图标的列表”对话框
  12. bootstrap-select 插件使用详解
  13. java 自动装载_JAVA反射技术之自动装载/自动验参
  14. PostgreSQL ALTER TABLE 命令
  15. 浙大PAT 1102
  16. app浮层html,App设计之五:弹窗与浮层
  17. Nii切片->2D ndarray灰色图->PIL灰色图->PIL RGB彩色图
  18. c中纠结不清的点(1)
  19. python三级等级考试有什么,python考级有几个级别
  20. 计算机截图工具无法运行,重装win7系统后打开截图工具显示“截图工具当前未在计算机上运行”如何解决...

热门文章

  1. JavaScript百度地图经纬度转高德地图经纬度
  2. Solr 中的commit与optimize
  3. 《心理瘦身不反弹》公开出版问世
  4. Uibutton 左对齐
  5. asp.net957-网上招聘信息管理系统
  6. 初识Direct3D
  7. java swing 技术简介,javaswing开发简介
  8. 化工企业通用SEO友好型网站源码
  9. 日记侠:高端卖茶人的朋友圈生意经
  10. [define的用法]define用法集锦