0%

四大组件的工作过程(四):BroadcastReceiver 的工作过程

1. 广播注册过程概述

  • 广播的注册分为静态注册动态注册,其中静态注册的广播在应用安装时由系统自动完成注册,具体来说是由 PMS: PackageManagerService 来完成整个注册过程。除了广播以外,其他三大组件也都是在应用安装时由 PMS 解析并注册的

  • 只分析动态注册,动态注册的过程是从 ContextWrapperregisterReceiver() 方法开始的,和 Activity 以及 Service 一样,ContextWrapper 并没有做实际的工作,而是将注册过程直接交给了 ContextImpl 来完成

    1
    2
    3
    public Intent registerReceiver (BroadcastReceiver receiver, IntentFilter filter) {
    return mBase.registerReceiver(receiver, filter);
    }
    • ContextImpl 的 registerReceiver() 方法调用了自己的 registerReceiverInternal() 方法
  • 系统首先从 mPackageInfo 获取 IIntentReceiver 对象,然后再采用跨进程的方式向 AMS 发送广播注册的请求。之所以采用 IIntentReceiver 而不是直接采用 BroadcastReceiver,这是因为上述注册过程是一个 IPC 进程间通信的过程,而 BroadcastReceiver 作为 Android 的一个组件是不能直接跨进程传递的,所以需要通过 IIntentReceiver 来中转一下

  • 毫无疑问,IIntentReceiver 必须是一个 Binder 接口,它的具体实现是 LoadedApk.ReceiverDispatcher.InnerReceiverReceiverDispatcher 的内部同时保存了 BroadcastReceiver 和 InnerReceiver,这样当接收到广播时,ReceiverDispatch 可以很方便地调用 BroadcastReceiver 的 onReceive() 方法

  • getReceiverDispatcher() 方法重新创建了一个 ReceiverDispatcher 对象并将其保存的 InnerReceiver 对象作为返回值返回,其中 InnerReceiver 对象和 BroadcastReceiver 都是在 ReceiverDispatcher 的构造方法中被保存起来的

  • 注册广播的真正实现是在 AMS 中,AMS 的 registerReceiver() 方法最终会把远程的 InnerReceiver 对象以及 IntentFilter 对象存储起来,这样整个广播的注册过程就完成了

2. 广播发送和接收过程概述

  • 当通过 send() 方法来发送广播时,AMS 会查找出匹配的广播接收器并将广播发送给它们处理。广播的发送有几种类型:普通广播有序广播粘性广播,有序广播和粘性广播与普通广播相比具有不同的特性,但它们的发送/接收流程是类似的。这里只分析普遍广播的实现

  • 广播的发送和接收,其本质是一个过程的两个阶段。广播的发送仍然开始于 ContextWrappersendBroadcast() 方法,之所以不是 Context,这是因为 Context 的 sendBroadcast() 方法是一个抽象方法。和广播的注册过程一样,ContextWrapper 的 sendBroadcast() 方法仍然什么都不做,只是把事情交给 ContextImpl 去处理

  • 分析 ContextImpl 的 sendBroadcast() 方法源码,ContextImpl 也是几乎什么事都没干,它直接向 AMS 发起了一个异步请求用于发送广播

  • 在 Android 5.0 中,默认情况下广播不会发送给已经停止的应用,实际上不仅仅是 Android 5.0,从 Android 3.1 开始广播已经具有这种特性了。这是因为系统在 Android 3.1 中为 Intent 添加了两个标记位:FLAG_INCLUDE_STOPPED_PACKAGESFLAG_EXCLUDE_STOPPED_PACKAGES,用来控制广播是否要对处于停止状态的应用其作用

    • FLAG_INCLUDE_STOPPED_PACKAGES: 表示包含已经停止的应用,此时广播会发送给已经停止的应用
    • FLAG_EXCLUDE_STOPPED_PACKAGES: 表示不包含已经停止的应用,此时广播不会发送给已经停止的应用
    • Android 3.1 开始,系统为所有广播默认添加了 FLAG_EXCLUDE_STOPPED_PACKAGES 标记,这样做是为了防止广播无意间或者在不必要的时候调起已经停止运行的应用
    • 如果的确需要调起未启动的应用,那么需要为广播的 Intent 添加 FLAG_INCLUDE_STOPPED_PACKAGES 标记。当这两种标记位共存时,以 FLAG_INCLUDE_STOPPED_PACKAGES 为准
    • 一个应用处于停止状态分为两种情形:第一种是应用安装后未运行;第二种是应用被手动或者其他应用强停。Android 3.1 中广播的这个特性同样会影响开机广播,从 Android 3.1 开始,处于停止状态的应用同样无法接收到开机广播,而在 Android 3.1 之前,处于停止状态的应用是可以收到开机广播的
  • broadcastIntentLocked() 方法内部,会根据 intent-filter 查找出匹配的广播接收器并经过一系列的条件过滤,最终户将满足条件的广播接收器添加到 BroadcastQueue 中,接着 BroadcastQueue 就会将广播发送给相应的广播接收器

  • 无序广播存储在 mParallelBroadcast 中,系统会遍历 mParallelBroadcasts 并将其中个广播发送给它们所有的接收器,具体的发送过程是通过 deliverToRegisteredReceiverLocked() 方法来实现的

-------------------- 本文结束感谢您的阅读 --------------------