当前位置:首页 > Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1)
Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析(1)
一、基础知识
广播(Broadcast)是一种Android组件间的通信方式。
从本质上来看,广播信息的载体是intent。在这种通信机制下,发送intent的对象就是广播发送方,接收intent的对象就是广播接收者。
在Android中,为广播接收者定义了一个单独的组件:BroadcastReceiver。
1 BroadcastReceiver的注册类型
在监听广播前,要将BroadcastReceiver注册到系统中。
BroadcastReceiver总体上可以分为两种注册类型:静态注册和动态注册。
静态注册
静态注册是指:通过在AndroidManifest.xml中声明receiver标签,来定义BroadcastReceiver。 PKMS初始化时,通过解析Application的AndroidManifest.xml,就能得到所有静态注册的BroadcastReceiver信息。
当广播发往这种方式注册的BroadcastReceiver时,若该BroadcastReceiver对应的进程没有启动,
AMS需要先启动对应的进程,然后利用Java反射机制构造出BroadcastReceiver,然后才能开始后续的处理。
在AndroidManifest.xml中定义BroadcastReceiver时,对应的标签类似于如下形式:
android:permission=\ android:process=\
其中:
android:enabled表示此broadcastReceiver是否可用,默认值为true。
android:exported表示此broadcastReceiver能否接收其它App的发出的广播; 如果标签中定义了intent-filter字段,则此值默认值为true,否则为false。
android:name表示BroadcastReceiver的类名。
android:permission用于指定广播发送方应该具有的权限;
即具有对应权限的发送者,才能通过AMS将广播发送给此broadcastReceiver;
android:process表示broadcastReceiver运行的进程; BroadcastReceiver默认运行在当前app的进程中,也可以通过此字段指定其运行于其它独立的进程。
intent-filter用于指定该broadcastReceiver接收广播的类型。
动态注册
与静态注册不同,动态注册是指:
应用程序在运行过程中,调用Context的registerReceiver函数注册BroadcastReceiver; 当应用程序不再需要监听广播时,则需要调用unregisterReceiver函数进行反注册。
动态注册BroadcastReceiver时,需要指定对应的IntentFilter。 IntentFilter用于描述该BroadcastReceiver期待接受的广播类型。 同时,动态注册时也可以指定该BroadcastReceiver要求的权限。
2 广播的种类
从广播的发送特点来看,可以将Android中定义的广播分为以下几类:
普通广播
普通广播由发送方调用sendBroadcast及相关重载函数发送。
AMS转发这种类型的广播时,根据BroadcastReceiver的注册方式,进行不同的处理流程。 对于动态注册的广播,理论上可以认为,AMS将在同一时刻,向所有监听此广播的BroadcastReceiver发送消息,因此整体的消息传递的效率比较高。
对于静态注册的广播,AMS将按照有序广播的方式,向BroadcastReceiver发送消息。
有序广播
有序广播由发送方调用sendOrderedBroadcast及相关重载函数发送,是一种串行的广播发送方式。
处理这种类型的广播时,AMS会按照优先级,将广播依次分发给BroadcastReceiver。 AMS收到上一个BroadcastReceiver处理完毕的消息后,才会将广播发送给下一个BroadcastReceiver。
其中,任意一个BroadcastReceiver,都可以中止后续的广播分发流程。 同时,上一个BroadcastReceiver可以将额外的信息添加到广播中。
前文已经指出,当普通广播发送给静态注册的BroadcastReceiver时,AMS实际上是按照有序广播的方式来进行发送,这么做的原因是:
静态注册的BroadcastReceiver仅申明在AndroidManifest.xml中,因此其所在的进程可能并没有启动。
当AMS向这些BroadcastReceiver发送消息时,可能必须先启动对应的进程。 如果同时向静态注册的BroadcastReceiver发送广播,那么可能需要在一段时间内同时创建出大量的进程,
这将对系统造成极大的负担。
若以有序广播的方式来发送,那么系统可以依次创建进程,
同时,每次收到上一个广播处理完毕的消息后,都可以尝试清理掉无用的进程。 这样即可以避免突发创建大量的进程,又可以及时回收一些系统资源。
因此从Android的设计方式可以看出,从接收广播的效率来讲: 排在第一的是,接收普通广播的动态注册的BroadcastReceiver, 其次是,接收有序广播的动态注册的BroadcastReceiver;
最后是,静态注册的BroadcastReceiver,此时接收的广播是否有序,已经不重要了。 实际上,源码就是按这种顺序来处理的,我们后面将进行深入分析。
粘性广播
粘性广播由发送方调用sendStickyBroadcast及相关重载函数发送。
需要注意的是,目前这种广播已经被附上Deprecated标签了,不再建议使用。
Android设计这种广播的初衷是:
正常情况下,假设发送方发送了一个普通广播A。
在广播A发送完毕后,系统中新注册了一个BroadcastReceiver,此时这个BroadcastReceiver是无法收到广播A的。
但是,如果发送方发送的是一个粘性广播B,那么系统将负责存储该粘性广播。
于是,即使BroadcastReceiver在广播B发送完后才注册到系统,这个BroadcastReceiver也会立即收到AMS转发的广播B。
粘性广播和有序广播等概念实际上不是冲突的。
粘性仅仅强调系统将会保存这个广播,它的其它处理过程与上文一致。
3 适时地限制广播发送范围 从上文可知,对于定义了intent-filter的BroadcastReceiver而言,其exported属性默认为true。 这种设计是符合预期的,毕竟我们使用广播的目的,就是使得属于不同应用、不同进程的组件能够彼此通信。
但在某些场景下,这种设计也可能带来一些安全隐患:
1.其它App可能会针对性的发出与当前App intent-filter相匹配的广播,导致当前App不断接收到广播并处理;
2.其它App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。
因此,在必要的时候,需要适时地限制广播发送范围,例如:
1.对于同一App内部发送和接收广播,将exported属性设置成false; 2.在广播发送和接收时,都增加上相应的permission; 3.发送广播时,指定BroadcastReceiver对应的包名。
通过以上三种方式,可以缩小广播的发送和接收范围,提高效率和安全性。
实际上,在framework/support/v4/java/android/support/v4/content目录下,Android定义了LocalBroadcastManager类,用于发送和接收仅在同一个App应用内传递的广播。
这个类仅针对动态注册的BroadcastReceiver有效,具体的使用方式与普通的全局广播类似, 只是注册/反注册BroadcastReceiver和发送广播时,将Context变成了LocalBroadcastManager。
举例如下:
//registerReceiver
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter); ..........
//unregisterReceiver
localBroadcastManager.unregisterReceiver(mBroadcastReceiver); ..........
//send broadcast
Intent intent = new Intent(); intent.setAction(\
localBroadcastManager.sendBroadcast(intent); ...........
以上是Android中关于广播的基础知识,接下来进入到实际的源码分析。
二、registerReceiver流程分析
现在我们看一下广播相关的源码,先从BroadcastReceiver的动态注册流程开始分析。
1 ContextImpl中的registerReceiver
动态注册BroadcastReceiver,将使用Context中定义的registerReceiver函数,具体的实现定义于ContextImpl中:
//这是最常用的接口
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null); }
共分享92篇相关文档