题外话:博友们有没有好用的写博客客户端推荐啊,cnblogs推荐的windows live writer和word都试过,都不是很好用啊,本地看着还可以,但发布出来排版就不是那么好看了。

正题:

  Android中短信的接收是这样的一个过程:

  底层先将短信报给FW,FW处理过后,会将短信通过intent广播的形式广播出来,而注册了接收短信广播的APP们,就能收到并处理短信

Default SMS App

  而android在4.2开始,对操作SMS的app进行了限制,增加了default sms app的概念,只有default app才可以操作短信,而且default sms app可以由用户来指定。

  先来看看整个系统初始化时,是如何来初始化default sms app的:

  依然在FW的phone框架初始化里,PhoneFactory. makeDefaultPhone

首先调用一次SmsApplication.getDefaultSmsApplication方法,并且指定第二个参数updateIfNeeded为true,就是如果没有设置过就自动指定一个。

关于getApplication函数我在 《Android 5.0 双模phone初始化分析》 一文中有讲到,其指定default SMS App的规则:

  • 首先尝试从用户指定的默认app,对应的系统setting key为:sms_default_application;
  • 其次看是否有Google的官方 默认sms app;
  • 如果以上两个都没有,那么就从PM中获取所有注册有完整sms有关的broadcast receiver的app,从中找一个优先级最高的,并将其设定为default app。

  default sms app的值保存在setting db中, Settings.Secure.SMS_DEFAULT_APPLICATION

当然,SmsApplication也提供了set方法来让用户可以手动设置他想使用的default sms app

  另外,在PhoneFactory初始化里我们还看到在调用一次getDefaultSmsApplication后,还调用了另外一个方法:

  这个方法会监听应用程序的安装与卸载,并在有应用被安装或者移除的时候,能够及时自动更新default sms app,已保证default sms app是随时都有设定的。

运营商授权SMS App

  后来的版本,android又增加了运营商授权SMS App的实现,原则是如果所有的sms app里,如果有一个是运营商授权指定的短信处理app,那么它就会有第一优先级,不管default app设定的是谁,都会只使用这个授权app来收发和管理显示短信。

  那么这个运营商授权APP是在哪里指定的呢?答案是:是固化在icc卡里的,也就是运营商给你的手机卡(no-uim和no-sim的手机目前是处理不了的),卡在出厂的时候,会在卡里的某个固定单元文件写上授权app的package name以及其签名hash校验值,在卡初始化完成后读取这些值解析后保存,如果手机里有这个package name的app,并且签名hash也一致,那么就说明该App是运营商授权sms app。

  完成这些信息初始化的类为 UiccCarrierPrivilegeRules,其内部完成对卡上文件进行读取和解析,保存信息,并提供对外接口。

因为跟卡直接相关,所以UiccCarrierPrivilegeRules在UiccCard被创建后初始化。

  在UiccCard.update()函数里创建:

UiccCarrierPrivilegeRules

  先看看该类的class注释,

  在构造函数中开启读取文件的流程,事件驱动。

  注释里对该类的功能进行了讲解,而且给出了使用到的icc card文件读取和解析的spec规范文档 GPD_SE_Access_Control_v1.0.20.pdf,可惜他给的链接无效了,可以在百度文库上找到该spec,地址: GPD_SE_Access_Control_v1.0.20.pdf

  具体读取icc文件和解析这里就不分析了,都是依照spec的实现。只说明下几个接口和内部变量:

AccessRule

内部类,用来保存解析到的rules,内部维护单个rule的package name和签名hash值。

List<AccessRule> mAccessRules;

保存所有的rules在list,看来可以支持多个运营商指定app

areCarrierPriviligeRulesLoaded()

是否已经准备好

getCarrierPrivilegeStatus()

验证指定的package name的app是否有运营商授权

getCarrierPrivilegeStatusForCurrentTransaction()

验证当前进程里是否存在有运营商授权的app(多个app可以通过共享id的形式运行在同一个进程里)

getCarrierPackageNamesForIntent()

通过从package manager中取出所有符合传入的Intent的app,也就是取出所有可以处理传入的Intent的app,并检查这些app里是否有符合运营商授权的,并返回符合的list

具体使用示例

  以一条新短信的接收为例:

  在InboundSmsHandler里的processMessagePart()函数中,processMessagePart()函数用来将缓存的短信分段进行组装,如果已经收全,就会将短信广播出去,当然,如果是单段的独立短信该函数也就直接广播了,来看打包Intent广播的部分:

  注意上面代码中黄色高亮的部分,首先是新建一个intent,而这个intent的action直接指定为Intents.SMS_FILTER_ACTION?这个是什么鬼,以前没见过啊。。。跳转过去:

  注释已经很清晰明了了,这个action只会发送给carrier app,而且carrier app可以通过set result为RESULT_CANCELED来终止这个广播,这样别的app就永远没有机会收到这个广播了。

  回到之前的打包intent的代码,其会去UiccCard里通过 getCarrierPackageNamesForIntent()方法来得到可以处理SMS_FILTER_ACTION的符合运营商授权的app name list,如果能取到,那么就将intent的目标package直接设定为那个app,这样这个短信广播就只会发送给这个授权app;

intent.setPackage(carrierPackages.get(0));

  而如果没有运营商授权app,那么就会调用setAndDirectIntent (intent, destPort);来设定广播app,这里才轮到default sms app:

  短信的desPort都是-1,所以可以只看上面这个if分支,首先先将intent的action修改为 Intents.SMS_DELIVER_ACTION, 这个是android的新短信常规intent action,顶替掉之前的SMS_FILTER_ACTION;然后通过getDefaultSmsApplication获取到default sms app,如果能取到,那么通过intent.setComponent(componentName)设置目标package为这个app,如果没有,那么就setComponent(null),这样就可以广播给所有可以接收SMS_DELIVER_ACTION的app。

另外,提一点另外的细节,打包广播短信的地方:

  dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,

  AppOpsManager.OP_RECEIVE_SMS, resultReceiver, UserHandle.OWNER);

  第4个参数,传入的resultReceiver,是个内部类SmsBroadcastReceiver对象,用来处理短信广播的结果,对每种intent action广播出去之后的处理结果都有分别处理,如从缓存数据库总删除短信、更新短信内容等。也用来如果发出去的广播没人处理,则使用最低级的SMS_RECEIVED_ACTION重新将广播广播出去等机制。。

总结

  FW初始化时,首先尝试设定一个default sms app,同时,在卡槽的icc卡准备好后,开始读取卡上的运营商授权app数据,并保存下来;新短信接收时首先通过接口获取到运营商授权app,如果没有,再通过接口获取到default sms app,如果还没有,就直接广播啦。

  运营商授权app的优先级大于default sms app。

更多相关文章

  1. Android(安卓)Broadcast Receiver 基础详解
  2. Android(安卓)3.1后, 新安装的以及用户强行停止的apk, 无法监听
  3. Android(安卓)5.0状态栏通知图标的实现
  4. Android群发短信草稿保存与发送机制
  5. android优点和不足
  6. Android(安卓)四大组件你都知道吗
  7. 实战Android读取USB数据到手机自带存储中
  8. 第十五章 Android的广播机制和BroadCast Receiver
  9. android手机短信利器

随机推荐

  1. Android如何获取网络连接状态及怎样调用
  2. Android 网络状态实时监测
  3. Android系统信息(内存、cpu、sd卡、电量、
  4. android 升级包检测并更新实现
  5. Android(安卓)API 实验记录 (三)
  6. Android中Adapter中edittext,checkbox记住
  7. Android 调用系统相机拍照保存以及调用系
  8. Android中DownLoadManager的使用
  9. 学习笔记----Android的对话框
  10. tabactivty中加入地图