1、概述 广播机制其实本质上它是一种组件间的通信方式。它的发送和接受者事先,不需要知道对方的存在。这样可以使各个组件轻松的耦合在一块。便于扩展,其实这就是一种生产消费模式。(消息 发布/订阅模式的事件驱动模型)消息的生产者发布事件,而使用者订阅感兴趣的事件。在广播机制中,ActivityManagerServices扮演者广播中心的角色,非常的关键。负责和系统所有广播的注册和发布操作。和系统中的组件通过Binder进行通信。
2、注册过程分析。 注册过程分为动态注册和静态注册。 2.1、动态注册的receiver。
IntentFilter filter = new IntentFilter("com.zy.test");
//android.util.Log.d("zy_rec","receiverfour getPriority"+filter.getPriority());// zy
filter.setPriority(999);
MainActivity.this.registerReceiver(mreceiver, filter);
此时是在当前应用的进程当中,最终调用到ContextImpl中的相应的方法,然后调用到registerReceiverInternal。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null; //最终代替receiver传递各种语义(也就是方法的调用)
if (receiver != null) {
//在Android的架构里,应用进程里是用LoadedApk来对应一个apk的,进程里加载了多少个apk,就会有多少LoadedAp
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
//mMainThread : ActivityThread 获得它中的那个H --Handler。处理东西。 至于这个ActivityThread感觉一个进程开始运行应该就有一个。
scheduler = mMainThread.getHandler();
}
// 查找和context对应的“子哈希表”里的ReceiverDispatcher,如果找不到,就重新new一个。
rd = mPackageInfo.getReceiverDispatcher(
//receiver :就是咱们写的那个实例。
receiver, context, scheduler, //zy 这会儿的context就是指向了mainActivity的context
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//远程的代理直接调用AMS的registerReceiver实现。
return ActivityManagerNative.getDefault().registerReceiver(
//zy mBasePackageName 应该是包名吧。
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId); //rd 这个rd是IIntentReceiver的Binder对象传给AMS。
} catch (RemoteException e) {
return null;
}
}
如注释中的说明,此处的关键是IIntentReceiver对象,这个对象以后就承receiver和AMS之间的通信语义的传递IntentRece iver最终的实现是在LoadedApk中。
LoadedApk这个类包含了当前加载的apk的主要的信息。
LoadedApk此处用到它的一个非常重要的成员变量。
private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers = new ArrayMap<Con text,ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();里面存放的是所有
动态注册的receiver。最外层的以key = 当前动态注册的receiver运行的上下文。(有个疑问这个context是application的还是当前activity的?自己对上下文理解不深)
value = 一个集合。(因为当前运行的如Activity肯定可以注册多个receiver的,用一个集合来容纳)
在这个次级的集合中。key = 当前注册的receiver。
value = 对应的ReceiverDispatcher对象。这个类用来管理我们的
IIntentReceiver对象。
总的来说说:
每个context对应一个receiver和
ReceiverDispatcher的集合。
每个receiver对应一个ReceiverDispatcher,用来管理
IIntentReceiver
。
每个
ReceiverDispatcher对应一个
IIntentReceiver。
综上也就是说,每个
receiver对应一个
IIntentReceiver。
为什么说每个
ReceiverDispatcher对应一个
IIntentReceiver那?看
ReceiverDispatcher的构造。
ReceiverDispatcher(BroadcastReceiver receiver, Context context, //ReceiverDispatcher的唯一构造。
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
//zy mIIntentReceiver 此处很关键,可以看出来实例化一个ReceiverDispatcher就会在这个rd中实例化一个InnerReceiver
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;//zy 就是自己新建的那个receiver。
mContext = context; //zy 此处赋值的contex是运行时的那个上下文。
mActivityThread = activityThread;// zy 前面传过来的那个ActivityThread中的H--Handler。
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}
ReceiverDispatcher会在构造中新建一个唯一的
IIntentReceiver的对象。
回到前面的registerReceiverInternal方法,获得到
IIntentReceiver对象rd以后。通过binder机制经行通信,传入
rd。
最终会调到AMS中的对应的registerReceiver方法。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
int callingUid;
int callingPid;
synchronized(this) {
...... //前面是一些callinguid和pid的判断
List allSticky = null;
// Look for any matching sticky broadcasts...
Iterator actions = filter.actionsIterator();
if (actions != null) {
while (actions.hasNext()) {
String action = (String)actions.next();
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(action, filter, allSticky,
UserHandle.getUserId(callingUid));
}
} else {
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.USER_ALL);
allSticky = getStickiesLocked(null, filter, allSticky,
UserHandle.getUserId(callingUid));
}
Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null; //zy 不发送粘性广播那么这里就是null啦。
if (receiver == null) {
return sticky;
}
//zy 此处也很关键动态注册的到这以后第一次rl肯定是null。注意:receiver.asBinder()就是传过来的IIntentReceiver对象。
ReceiverList rl
= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {//zy 再注册一个IntentFilter时候已经不是null了就。!!
//此处只是新建了一个ReceiverList的集合,未在里面添加任何的BroadcastFilter。
rl = new ReceiverList(this, callerApp, callingPid, callingUid, //callerApp 一开始启动的那个进程
userId, receiver); //把IIntentReceiver保存在ReceiverList成员变量中。
if (rl.app != null) {
rl.app.receivers.add(rl); //ProcessRecord.receivers保存这个进程的IIntentReceiver(用来代替我们建的receiver,谁让它不能binder传递数据那)广播接收器。
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);//此时ReceiverList里面没有BroadcastFilter!
}
......
// 创建BroadcastFilter,感觉就把广播接收器列表ReceiverList和filter关联起来.
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);//每个IntenFilter对应一个BroadcastFilter,应该是如此。
mReceiverResolver.addFilter(bf); //zy 至此广播都保存到了AMS相关的变量中。
if (allSticky != null) { // Zy 用于发出粘性广播!
ArrayList receivers = new ArrayList();
receivers.add(bf);
int N = allSticky.size();
for (int i=0; i<N; i++) {
Intent intent = (Intent)allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
null, null, false, true, true, -1);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
此处首先看一下粘性广播的部分,由于此处没有经行实际的验证,一下关于粘性广播只是个人的理解猜测。一些列的
判断后,如果发现是粘性广播那么,直接queue.scheduleBroadcastsLocked(),执行已经注册过的receiver。 然后就是关键的BroadcastFilter部分了。先介绍AMS的一个相关的成员变量。 final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
new HashMap<IBinder, ReceiverList>();
key = Ibinder对象,其实就是我们传过来的
IIntentReceiver对象。(由于本身对binder理解不深)此处暂把,
IIntentReceiver..asBinder()。就当成
IIntentReceiver对象。此处重在理解思想。
value = ReceiverList 对象。此处的
ReceiverList
是一个ArrayList集合,里面存放的只能是BroadcastFilter,这个对象 有一些自己的成员变量。这样看来的话,一个
IIntentReceiver
也就是一个receiver可以有多个
BroadcastFilter。
ReceiverList中的一个值得一提的成员变量:
public final IIntentReceiver receiver;保存传过来的这个
IIntentReceiver对象,也就对应到我们注册receiver。
综上看来:
其实
mRegisteredReceivers
对应于LoadedApk中的
mReceivers 。都是和动态注册相关的。
每个
IIntentReceiver对象对应一个
ReceiverList
对象。
每个
ReceiverList对象可以对应多个
BroadcastFilter。 (个人理解同一个receiver可以注册多个IntentFilter嘛,每个filter对应一个BroadcastFilter。)
那么
BroadcastFilter对象是用来干么的那?对此我理解的也不深,就把它当成了一个封装某些属性的IntentFilter对 象。里面有包名和所需权限等。值的一提的属性final ReceiverList receiverList;标记这个bf属于哪个
ReceiverList。
最后再调用 mReceiverResolver.addFilter(bf),把
BroadcastFilter添加到AMS的成员变量mReceiverResolver中。 至此动态注册相关的知识点介绍完毕,以上都是个人的理解可能存在一些错误,欢迎指正。
2.2、静态注册的receiver。
其实就是在安装APK的时候,对manifest中的receiver节点经行解析,放到相应的内存(成员变量)中。这个解析是有PMS
进行的。注意:常驻内存的是静态receiver的描述信息,而不是receiver本身。
一个重要的接口PMS中的queryIntentReceivers。返回一个List<ResolveInfo>,(个人理解这块查到的好像就是已经按 照propity排好序的,暂无深究)。
ResolveInfo类算是静态注册时包含广播的注册信息的类。关于PMS解析apk,在博客的
另一个文章有个流程,不过那个流程只是详细的分析啦一下和权限相关的,也可以仿照的分析一下静态的。
3、广播的发送过程。
广播的发送有好几种,有序的、普通的、粘性广播等。最终无非就是传入的参数不同,此处对这些基础的就不再总结。不过
在下面的分析中会,依次把各
个参数区别,在注释中写清楚
。
下面是自己在调试的时候写的一个例子。
Intent in = new Intent("com.zy.test");
//ComponentName cn = new ComponentName("com.zy.receiver_test","com.zy.receiver_test.receiverfour");
//in.setComponent(cn);
android.util.Log.d("zy_rec","send_order");
MainActivity.this.sendBroadcast(in);
当前进程最终会调用到ContextImpl中的sendBroadcast接口。
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess();
ActivityManagerNative.getDefault().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null, //IIntentReceiver 是null。
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
getUserId());
} catch (RemoteException e) {
}
}
需要注意一下,此处传入的两个false,代表无序、非粘性。并且
IIntentReceiver传入的是null。然后通过binder调用到了AMS
的broadcastIntent,然后最终调用到AMS的broadcastIntentLocked。
主要的代码和分析如下:
private final int broadcastIntentLocked(ProcessRecord callerApp, //zy
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData, // zy 发送的时候resultTo好像都是null。
Bundle map, String requiredPermission, int appOp,
boolean ordered, boolean sticky, int callingPid, int callingUid, //zy ordered 是否是有序的 ,sticky是否是发送的粘性广播
int userId) {
intent = new Intent(intent);
// By default broadcasts do not go to stopped apps.
//如果一个应用在安装后从来没有启动过,或者已经被用户强制停止了,那么这个应用就处于停止状态:stopped state
//zy FLAG_INCLUDE_STOPPED_PACKAGES、FLAG_EXCLUDE_STOPPED_PACKAGES
//在默认情况下,AMS是不会把intent广播发给“处于停止状态的”应用的。
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //zy
...... //一些合法性的判断和protected-broadcast权限判断
final String action = intent.getAction();
if (action != null) { // zy 各种系统广播的处理。
......
}
// Add to the sticky list if requested.
if (sticky) { // zy 如果是发送的粘性广播,必须把intent记录下来。
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, // 先检查权限。
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
......
}
if (requiredPermission != null) {
......
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; //粘性广播不可以有权限。
}
if (intent.getComponent() != null) {
throw new SecurityException(
"Sticky broadcasts can't target a specific component");//粘性广播不可以指定specific component。
}
if (userId != UserHandle.USER_ALL) {
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i++) {
if (intent.filterEquals(list.get(i))) { //不要和全局的已经存在的粘性广播冲突。
throw new IllegalArgumentException(
"Sticky broadcast " + intent + " for user "
+ userId + " conflicts with existing global broadcast");
}
}
}
}
}
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<String, ArrayList<Intent>>();
mStickyBroadcasts.put(userId, stickies);
}
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list == null) {
list = new ArrayList<Intent>();
stickies.put(intent.getAction(), list);
}
int N = list.size();
int i;
for (i=0; i<N; i++) {//遍历所有的这个action对应的inetnt。
if (intent.filterEquals(list.get(i))) {
// This sticky already exists, replace it.
list.set(i, new Intent(intent)); //如果已经存在覆盖一下。
break;
}
}
if (i >= N) {//一直没存在是上面的for不会break,那么就会大于等于。
//添加进去。到此为止粘性广播就添加到列表中了。然后在注册的时候读取列表看看是不是已经注册,决定是否直接执行广播发送。
list.add(new Intent(intent));
}
}
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); // 收集都是参数中intent相关的通过静态注册或者指定Component的广播。
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
...... // 系统的uid的一些处理
} else {
// zy 前面分析动态注册的时候最终把BroadcastFilter保存在了成员变量mReceiverResolver中。此处取出来和参数中intent相关的广播。
registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false, userId);
}
}
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; //这个好像是用来标记是否以前发送过这个广播。
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) { // r如果不是有序广播,并且有动态注册的receiver。那么下面就开始直接进行处理。
final BroadcastQueue queue = broadcastQueueForIntent(intent);
// BroadcastQueue封装一个类,记录了这个广播是由谁发出的以及要发给谁等相关信息.
//发送一次广播至少有一个BroadcastRecord,也有可能是两个,需要看是发送的什么类型的广播,以及都有那些receiver,通过什么方式注册的。
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
//由前面的注册信息可知,此时的registeredReceivers只包含了BroadcastFilter。
appOp, registeredReceivers, resultTo, resultCode, resultData, map,
ordered, sticky, false, userId);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
//zy 就会把这个广播记录块r放在BroadcastQueue中的mParcelBroadcasts,只会对应动态receiver.也就是说mParcelBroadcasts里面只有BroadcastFilter.
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked(); //通过handler去异步执行的,发送到Handler就不管了。
}
registeredReceivers = null // 发送无序广播的时候处理完动态注册的就直接把registeredReceivers置为null了,方便对不是无序广播的处理。
NR = 0; //通过它控制,下面receiver的列表也不需要整合,直接处理静态的。
}
// Merge into one list. //此处把动态的和静态的合入到一个列表
int ir = 0;
if (receivers != null) { //需要把动态的合入到静态的里面。 receivers 某个intent对应的所有的静态的。
......// 防止一些应用正在安装的时候可以监听 PACKAGE_ADDED,然后利用这个启动起来。
//zy 然后开始整合列表。
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR) {//当NR > 0,也就是不是无序的广播的时候,因为无序广播时有在前面进行处理。
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir); //发送有序广播时,此时registeredReceivers不等于null。
}
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list. //一个个对比 ,如果发现 动态注册的 priority大于静态的,插进去。
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir)); //动态注册的比较长时候,接着往后面加入。至此算是合并完毕。
ir++;
}
//下面开始处理合并好的广播列表。
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) { // resultTo 正常发送的时候传入的是null,但此时是或啊,前面符合也行。
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
//下面的receivers 此时这个BroadcastRecord中的receivers就可能是BroadcastFilter或者ResolveInfo
requiredPermission, appOp, receivers, resultTo, resultCode,
resultData, map, ordered, sticky, false, userId);
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
// 注意此处,就算是r 的receiver=5;也是只有一个BroadcastRecord!
// 那么问题来了,如何有好几个那?个人理解是,通过发送多次广播达到有好几次广播记录。
queue.enqueueOrderedBroadcastLocked(r); //zy 放入到Broadcastqueen的mOrderedBroadcasts当中。
queue.scheduleBroadcastsLocked();// 交给Handler串行处理。
}
}
return ActivityManager.BROADCAST_SUCCESS;
}
说以下主要内容:
1、
先是设置一个flag,防止一些流氓应用通过监听系统广播自启动。
2、处理一些系统的广播如Intent.ACTION_UID_REMOVED
、Intent.ACTION_PACKAGE_CHANGED、Intent.ACTION_PACKAGE_ADDE Intent.ACTION_TIME_CHANGED、Intent.ACTION_TIMEZONE_CHANGED等等。
3、如果发送的是粘性广播对其进行相关处理。
4、分别获取对传过来的intent感兴趣的动态注册的receiver集合和静态注册的receiver集合。
List receivers = null;一开始获取的存放的是静态注册的receiver,有可能后面会合入动态的。
List<BroadcastFilter> registeredReceivers = null;获取的是动态注册的receiver。 通过Log验证此时:
a、
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
没有分析
collectReceiverComponents里面的更具体的实现。
一种是获取的静态注册的,此时获取出来的都是已经按照propity排序好的!(个人感觉propity相同时,应该是按
照先解析的谁,谁在前面。apk在不同的目录下肯定有不同的解析顺序)
一种是获取的是指定
Component的receiver。此时:就算是别的通过静态注册了,也不会查询出来,只会有你指定 的
omponent的那个,而且(写了两个测试程序,竟然有一个死活查询不出来,抽时间真的分析内部实现)
b、
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
也没有分析
queryIntent内部的详细实现。
通过程序测试,发现动态的查询出来也是按照propity排好序的,如果是相同的propity,那么谁先注册先理。 5、接下来通过是否是有序广播,如果是无序的并且有动态注册的receiver对此Intent感兴趣,先创建一个BroadcastRecord一次性处理这些平行
广播。
6、判断是否要合并广播列表。如果需要则按照propity进行合并。并放到
receivers
当中。
7、依次处理
receivers
中的广播了,有可能是动态注册的有可能是静态注册的,也是:BroadcastFilter
、ResolveInfo 综上: 有个类就很关键了,那就是BroadcastRecord.它封装了
这一次的send广播的一些信息,有可能被创建个
BroadcastRecord
重要的成员变量有:
final Intent intent; 用来创建这个
BroadcastRecord的intent
final List receivers; 要接收这个广播的receiver的集合,可以是
BroadcastFilter、或者
ResolveInfo,也可以都有。
int nextReceiver; // 下一个要处理的receiver,用于静态注册的在BroadcastQueen里面使用。
BroadcastRecord(BroadcastQueue _queue,
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission,
int _appOp, List _receivers, IIntentReceiver _resultTo, int _resultCode,
String _resultData, Bundle _resultExtras, boolean _serialized,
boolean _sticky, boolean _initialSticky,
int _userId) {
queue = _queue;
intent = _intent;
targetComp = _intent.getComponent();
callerApp = _callerApp;
callerPackage = _callerPackage;
callingPid = _callingPid;
callingUid = _callingUid;
resolvedType = _resolvedType;
requiredPermission = _requiredPermission;
appOp = _appOp;
receivers = _receivers;
resultTo = _resultTo;
resultCode = _resultCode;
resultData = _resultData;
resultExtras = _resultExtras;
ordered = _serialized;
sticky = _sticky;
initialSticky = _initialSticky;
userId = _userId;
nextReceiver = 0; // zy nextReceiver默认是0
state = IDLE;
}
也就是说每一次的广播发送,对应一个或者两个BroadcastRecord。需要看注册这个action的广播是怎么实现的啊。 a、如果只有动态
注册的或者只有静态注册的(无论是有序还是无序),都只实例化一个
BroadcastRecord,
b、如果既有动态注册的receiver又有静态注册的receiver都对这个intent感兴趣,那么害的分情况
当是无序广播时:会有两个
BroadcastRecord。
当是有序广播时:还是只实例化一个
BroadcastRecord。
综上可见:
a、广播注册的时候不会排序,而在发送的时候实时的去获取并排序receiver。
b、receiver的接受处理顺序。
当发送的是有序广播:按照receiver的propity进行顺序接收,无论是什么注册方式,默认优先级的0。
数字越大,优先级越高。现在没有-1000~1000的限制了,int范围内就行,自
己设置的19999也可以。源码那块并没有进行判断。当时相同propity的时候谁
先注册,谁先收到。 当发送的是无序广播:动态注册的肯定比静态注册的先执行。当都是动态注册的时候,propity高的先执行 而当propity又一样时,先注册的先执行。当都是静态注册的时候,也是propity高的 先执行,(一样的时候感觉是按照解析顺序,谁先解析谁先执行)
4、广播的处理过程。
前面的发送过程我们分析到如下两个地方: a、处理平行广播
queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); b、处理有序广播
queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); 下面我们一个个的分析。 BroadcastQueue的enqueueParallelBroadcastLocked和
enqueueOrderedBroadcastLocked
方法。
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
}
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
mOrderedBroadcasts.add(r);
}
很简单就是分别往成员变量mParallelBroadcasts和mOrderedBroadcasts中添加元素。
final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<BroadcastRecord>();里面的
BroadcastRecord的成员变量
receivers
所携带的只能有BroadcastFilter。
final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<BroadcastRecord>();
里面的
BroadcastRecord的成员变量
receivers可以携带
BroadcastFilter和ResolveInfo。也可以只有
ResolveInfo或者
BroadcastFilter。
此处个人的理解:之所以把mParallelBroadcasts称为平行广播,是因为要在一次processNextBroadcas中对集合里面的所有receiver全部处理完,但是平行广播,内部也是必然有一定的顺序的。mOrderedBroadcasts称为串行广播,因为在处理的时候一次
processNextBroadcas
只能执行
mOrderedBroadcasts集合里面的一个元素。
此处还有一个值得一提的点:在执行a或者b的处理过程前,会调用。BroadcastQueue queue = broadcastQueueForIntent(inte nt);来获得合适的BroadcastQueue。在AMS中有两个:(主要是它们的响应超时的时间长短不同)
BroadcastQueue mFgBroadcastQueue;
BroadcastQueue mBgBroadcastQueue;
final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
他们在构造中分别经行初始化。 mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
“foreground”, BROADCAST_FG_TIMEOUT, false); mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
“background”, BROADCAST_BG_TIMEOUT, true); mBroadcastQueues[0] = mFgBroadcastQueue; mBroadcastQueues[1] = mBgBroadcastQueue; 对应的name和timeoutPeriod不一样,那么就没什么说的,不过这个
timeoutPeriod代表了响应超时的时间。
static final int BROADCAST_BG_TIMEOUT = 60*1000;//后台
Boradcastqueue
60S的时间。
这个响应时间,60S或者10S是针对一个receiver说的。比如说某个前台广播的某个BroadcastRecord携带了5个receiver,那么这一次的广播
记录只要在5*60S内完成即可。事实上AMS考虑啦更多的东西,所以总时限是所有的receiver时限之和的两倍2*5*60S。通过代码观察其实,这个时
限对应的receiver只限于通过queue.enqueueOrderedBroadcastLocked(r)加入到串行广播列表中的receiver。并没有考虑加入到并行广播列表的
receiver的个数。
接下来分析
queue.scheduleBroadcastsLocked()方法。分析之前先看一下BroadcastQueue的构造。
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, long timeoutPeriod, boolean allowDelayBehindServices) {
mService = service;
mHandler = new BroadcastHandler(handler.getLooper());
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
mDelayBehindServices = allowDelayBehindServices;
}
以及BroadcastHandler的实现。
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG, "Received BROADCAST_INTENT_MSG");
processNextBroadcast(true); // 处理广播
} break;
case BROADCAST_TIMEOUT_MSG: { //用来处理超时的事件。
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
};
那么BroadcastQueue的方法scheduleBroadcastsLocked最终会调用到processNextBroadcast如下,通过发送BROADCAST_INTENT_MSG。
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
接下里就是非常重要的processNextBroadcast()的方法介绍了,还是同样先贴出主要的代码以及注释的分析。
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
if (fromMsg) {
mBroadcastsScheduled = false;//设置成false ,让下一个广播可以进入mHandler消息队列当中。
}
//zy 首先处理所有的平行广播mParallelBroadcasts。
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();//通过前面的分析可知,此时的r.receivers里面的都是BroadcastFilter,也就是动态注册的。
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);// 此处去真正的处理,后面再分析。
}
addBroadcastToHistoryLocked(r);
}
//mPendingBroadcast成员变量表示我们即将处理的BroadcastRecord,(等待进程的启动)默认是null。
if (mPendingBroadcast != null) { //首次到这肯定是null的。
boolean isDead;
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
Slog.w(TAG, "pending app ["
+ mQueueName + "]" + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
do {
// 注意此处很关键,用来退出这个处理。
// 在下面的一个判断中mOrderedBroadcasts.remove(0) 这边就有可能变成mOrderedBroadcasts.size() == 0。
if (mOrderedBroadcasts.size() == 0) {
mService.scheduleAppGcsLocked();
if (looped) {
mService.updateOomAdjLocked();
}
return;
}
r = mOrderedBroadcasts.get(0);//取出mOrderedBroadcasts中最顶部的那个BroadcastRecord,进行处理。
boolean forceReceive = false;
//标记的是mOrderedBroadcasts中的receiver的个数。
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
//由下面这个判断就可知总的时间是:(两倍的(mTimeoutPeriod*mOrderedBroadcasts中的receiver的个数))
if ((numReceivers > 0) &&(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
broadcastTimeoutLocked(false); // 强行终止这个广播。
forceReceive = true;
r.state = BroadcastRecord.IDLE;//恢复初始状态。
}
}
if (r.state != BroadcastRecord.IDLE) {
......
return;
}
//此处的判断也是很关键的,默认第一次r.nextReceiver = 0,但是它每次都会++,等待最后一个处理完了,
//它还会再++试图去处理一个不存在的nextReceiver,此时r.nextReceiver >= numReceivers就成立了,就
//会进入到这个判断。当然还有别的条件可以进入如:前面的超时时候forceReceive = true。
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// 还有没有处理的时候r.resultTo != null,通过r.nextReceiver >= numReceivers进来的一般都是null
if (r.resultTo != null) {
try {
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
} catch (RemoteException e) {
}
}
cancelBroadcastTimeoutLocked();//取消超时设置。
// ... and on to the next...
addBroadcastToHistoryLocked(r);
//由于本次正在处理的BroadcastRecord中所有的receiver已经处理完,
//移除掉最上面的BroadcastRecord,假如它里面还有就进行下一个处理。
mOrderedBroadcasts.remove(0);
r = null;//然后置为null,那么此时算是一个BroadcastRecord处理完毕,
looped = true;
continue; // 进入下一个循环。
}
} while (r == null);
//注意此处是先赋值再++。也就是说 recIdx = 当前的receiver的索引。然后到下面的语句的时候r.nextReceiver = recIdx+1啦.
//比如第一次r.nextReceiver = 0, 执行完后 recIdx = 0,r.nextReceiver = 1.
int recIdx = r.nextReceiver++;
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;// diyici 记录一下开始的时间,按照第一个receiver开始处理的时间
r.dispatchClockTime = System.currentTimeMillis();
}
if (!mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
//如果没有设置超时事件,那么就进行设置,从此处也可一看出来是每个timeoutTime对应于一个receiver。
setBroadcastTimeoutLocked(timeoutTime);
}
Object nextReceiver = r.receivers.get(recIdx); //注意!!!它取出来的其实是BoradcastRecord的receivers中的当前正在处理的receiver。
if (nextReceiver instanceof BroadcastFilter) {//看看是不是动态注册的,是的话直接处理。
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered);
if (r.receiver == null || !r.ordered) {
r.state = BroadcastRecord.IDLE;// 初始化
scheduleBroadcastsLocked();// 执行下一个
}
return; //处理完直接返回,保证在mOrderedBroadcasts是串行处理的。
}
ResolveInfo info = (ResolveInfo)nextReceiver;//假如没有返回,那么必定是静态注册的,对应于ResolveInfo
//取出注册对应的ComponentName。注意info.activityInfo.applicationInfo.packageName是包名,info.activityInfo.name类名。
//如:com.android.zy com.android.zy.TestReceiver.(全路径)
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
boolean skip = false;
......// 一系列的权限和进程是否合法等的判断,如果不符合提要求skip = true
if (skip) {
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked(); //如果跳过的话,直接进行下一次的广播处理。
return;
}
r.state = BroadcastRecord.APP_RECEIVE;
String targetProcess = info.activityInfo.processName;
r.curComponent = component;//注意此处包含我们静注册的receiver的信息。
final int receiverUid = info.activityInfo.applicationInfo.uid;
if (r.callingUid != Process.SYSTEM_UID && isSingleton
&& mService.isValidSingletonCall(r.callingUid, receiverUid)) {
info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
r.curReceiver = info.activityInfo;
try {
//开始处理这个广播,那么这个包不能被停止。
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
}
//获得当前需要处理的进程记录。由于是静态注册的那么receiver所在的进程有可能是正在运行的,也有可能格式未启动的。
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
//如果当前进程已经存在那么直接调用processCurBroadcastLocked()做进一步的处理。
if (app != null && app.thread != null) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
android.util.Log.d("zy_rec", "app != null && app.thread != null info.activityInfo.name = "+info.activityInfo.name);
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
} catch (RuntimeException e) {
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
}
// zy 如果不存在,那么我们需要先启动这个进程,通过startProcessLocked()方法。
//启动成功后会调用AMS的attachApplication()。
if ((SystemProperties.getInt("sys.quickboot.enable", 0) == 1 &&
SystemProperties.getInt("sys.quickboot.poweron", 0) == 0 &&
!getWhiteList().contains(info.activityInfo.applicationInfo.packageName))
|| (r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
//启动失败会进入到此方法体内。
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
mPendingBroadcast = r; //然后把当前的BroadcastRecord设置为即将启动的BroadcastRecord。
mPendingBroadcastRecvIndex = recIdx;//设置当前的receiver的索引,用来表示将要启动的。
}
}
个人感觉以上的代码已经十分的精简了,注释也说明的较为详细。通过上面的分析我们发现通过动态注册的也就是receiver是BroadcastFilter最后是通过deliverToRegisteredReceiverLocked去处理的,通过静态注册的也就是receiver是ResolveInfo的最终通processCurBroadcastLocked 那么通过静态注册,但是进程没有启动的那?接下来去分析一下AMS中的
进程启动成功后会调用attachApplication,然后调用到attachApplicationLocked。而在
attachApplicationLocked方法中有调用一个
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
......
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) { //进程成功启动后。
try {
didSomething |= sendPendingBroadcastsLocked(app); //新启动的是刚才receiver的
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
......
}
然后是调用sendPendingBroadcastsLocked
// The app just attached; send any pending broadcasts that it should receive
boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
for (BroadcastQueue queue : mBroadcastQueues) { // zy
didSomething |= queue.sendPendingBroadcastsLocked(app);
}
return didSomething;
}
又调回到BroadcastQueue中的sendPendingBroadcastsLocked方法内。
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
final BroadcastRecord br = mPendingBroadcast;
if (br != null && br.curApp.pid == app.pid) {
try {
mPendingBroadcast = null;
processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
logBroadcastReceiverDiscardLocked(br);
finishReceiverLocked(br, br.resultCode, br.resultData,
br.resultExtras, br.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
br.state = BroadcastRecord.IDLE;
throw new RuntimeException(e.getMessage());
}
}
return didSomething;
}
现在明了了,进程启动完毕后最终会调用到processCurBroadcastLocked对静态注册的receiver经行进一步的处理。 那么接下来就是分析
deliverToRegisteredReceiverLocked和
processCurBroadcastLocked了。
先分析
deliverToRegisteredReceiverLocked方法。
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
boolean skip = false;
......//还是进行以系列的权限相关的判断。不符合要求skip = true。
if (!skip) {
if (ordered) {//如果是有序的广播做一些赋值处理。
r.receiver = filter.receiverList.receiver.asBinder();
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
if (filter.receiverList.app != null) {
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceiver = r;
mService.updateOomAdjLocked(r.curApp);
}
}
try {
//无论是不是有序最终都调用performReceiveLocked做进一步的处理
//注意很关键的一个参数
filter . receiverList . receiver, 对应于这个BroadcastFilter所属的ReceiverList中对应的IInterReceiver对象。 //就是对应于前面动态注册时,从用户进程传过来的 IInterReceiver的一个binder对象,来传递语义。performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
if (ordered) {
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
if (filter.receiverList.app != null) {
filter.receiverList.app.curReceiver = null;
}
}
}
}
}
然后调用BroadcastQueue的performReceiveLocked做进一步的处理。
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
if (app != null) {// app 是注册广播接收器的Activity所在的进程记录块.
if (app.thread != null) {// 此处由于是动态注册的一般进程都是很好的存在的。
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
} else {
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
上述代码的ProcessRecord的thread对象是ApplicationThread类,存在于ActivityThread类当中。
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
//注意这个receiver是IIntentReceiver对象就是我么你前面传过来的,也就是动态注册是生成的。
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
下面就继续走到LoadedApk中的ReceiverDispatcher类中的InnerReceiver内部类当中。调用performReceive。这个方法主要的就是调用了ReceiverDispatcher的performReceive方法。我们接着分析ReceiverDispatcher的
performReceive。
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
//Args 是LoadedApk中的ReceiverDispatcher一个内部类实现了Runnable接口。
Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
//mActivityThread 这就是那个ActivityTherad中的H对象调用post所以放到Args的run方法中执行了。
if (!mActivityThread.post(args)) {
if (mRegistered && ordered) {// 如果是有序的。
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);//发送完成本次广播处理,用来进行下次的广播处理。
}
}
}
上述代码有一个地方我们最后在分析一下,那就是args.sendFinished(mgr),此处是用于有序广播循环处理的。
接下来直接看Args的run方法。
public void run() {
//此处这个mReceiver很关键,它是ReceiverDispatcher的成员变量mReceiver
//它是在注册时在构造中被初始化的,就是我们新建的要注册的额那个receiver。
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
mCurIntent = null;
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//至此终于调用到了我们写的receiver的onReceive方法
//
mContext ReceiverDispatcher的成员变量,在构造中传入的context。//是前面在ContextImpl注册的时候调用
registerReceiverInternal传入的,ContextImpl实例,也就是当前动态注册的Activcity的上下文 //这块不是很确定是当前应用的application的上下文,还是当前activity的上下文?receiver.onReceive(mContext, intent);
} catch (Exception e) {
}
if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
此方法中有个一般都注意不到的点,关于receiver怎么实例化的那?动态注册的来说就很简单,就是我们在自己的代码中new的,然后传入到注册的方法的参数当中,最终在ConTextImpl去getReceiverDispatcher,进而实例化
ReceiverDispatcher,并传入到它的mReceiver当中。那么静态的怎么实例化的那?我们
下面慢慢分析。
至此关于
deliverToRegisteredReceiverLocked处理动态注册的receiver完毕(对应于
BroadcastFilter).
接下来分析用于处理静态注册的receiver的BroadcastQueue中的
processCurBroadcastLocked方法。
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app) throws RemoteException {
if (app.thread == null) {
throw new RemoteException();
}
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceiver = r;
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER); //更新进程的状态。
mService.updateLruProcessLocked(app, false, null); // 处理一下内存
mService.updateOomAdjLocked();
//此处告诉是那个receiver,对应于我门前面在processNextBroadcast中对静态的处理。
r.intent.setComponent(r.curComponent);
boolean started = false;
try {
mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
//下面这个方法又调用到了ActivityThread中的ApplicationThread中对应的方法。
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.repProcState);
started = true;
} finally {
if (!started) {
if (DEBUG_BROADCAST) Slog.v(TAG,
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
app.curReceiver = null;
}
}
}
接下来继续看相应的scheduleReceiver方法。
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
updateProcessState(processState, false);
//封装拉一下数据,ReceiverData extends BroadcastReceiver.PendingResult
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
r.info = info;
r.compatInfo = compatInfo;
//内部类ApplicationThread,直接调用外部类的方法,最终调用到H类的sendMessage
sendMessage(H.RECEIVER, r);
}
然后就会走到H类的handleMessage方法的case RECEIVER:节点下面
case RECEIVER:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
handleReceiver((ReceiverData)msg.obj);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
调用handleReceiver做最后的处理,并把前面封装的ReceiverData传入。
private void handleReceiver(ReceiverData data) {
//这个最初就是在processNextBroadcast处理静态注册的ResolveInfo时,new的ComponentName。
String component = data.intent.getComponent().getClassName();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
IActivityManager mgr = ActivityManagerNative.getDefault();
BroadcastReceiver receiver;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
//此处静态的receiver的实例化,通过反射实例化类。
receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
} catch (Exception e) {
}
try {
Application app = packageInfo.makeApplication(false, mInstrumentation);
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
//调用相应receiver的onReceive方法。有个需要注意的点,这个context的传入。
//静态注册的把app的context封装了一下,ReceiverRestrictedContext extends ContextWrapper。
receiver.onReceive(context.getReceiverRestrictedContext(),data.intent);
} catch (Exception e) {
} finally {
sCurrentBroadcastIntent.set(null);
}
if (receiver.getPendingResult() != null) {
data.finish();//此处也是用于有序广播的循环,因为静态注册的广播哦都是要串行处理的,此处不需要做是否是ordered的判断
}
}
注意一下静态的实例化方式和传入的context就可以。至此算是完成了
processCurBroadcastLocked的实现分析,动态注册的顾杨波最终调用到LoadedApk中的performReceive,进而调用Args的run方法执行,静态注册的广播最终调用到Activity的handleReceiver方法中进行执行
。那么,广播的处理流程到这里也就告一段落,下面分析我们前面你到的有序广播的循环。
5、有序广播的循环处理。 此处的有序广播不是指发出来的是有序广播,而是看在BroadcastQueue中的mOrderedBroadcasts中的广播。
对于动态注册的有序广播,看前面分析的流程,在执行到ReceiverDispatcher的performReceive时候,如果是有序的,会调用Args的sendFinished的方法。
而Args继承于BroadcastReceiver.PendingResult。也就是调用到它下面的
sendFinished。
public void sendFinished(IActivityManager am) {
synchronized (this) {
mFinished = true;
try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
//最终调用传入的am的finishReceiver,也就是AMS的finishReceiver,去做进一步的处理
if (mOrderedHint) {
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast);
} else {
am.finishReceiver(mToken, 0, null, null, false);
}
} catch (RemoteException ex) {
}
}
}
AMS中的finishReceiver如下
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort) {
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;
synchronized(this) {
r = broadcastRecordForReceiverLocked(who);
if (r != null) {
//r.state == BroadcastRecord.APP_RECEIVE || r.state == BroadcastRecord.CALL_DONE_RECEIVE符合要求那么就会返回true。
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
}
//如果返回true,那么就调用processNextBroadcast进行下一个receiver的处理。
if (doNext) {
r.queue.processNextBroadcast(false);
}
trimApplications();
} finally {
Binder.restoreCallingIdentity(origId);
}
}
对于静态注册的有序广播也一样,在最后调用handleReceiver做完最后处理时,调用ReceiverData的finish()方法去通知AMS,做进一步处理。而
ReceiverData
也是继承BroadcastReceiver.PendingResult,也就是最终调用到
PendingResult的
finish。
public final void finish() {
if (mType == TYPE_COMPONENT) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
if (QueuedWork.hasPendingWork()) {
QueuedWork.singleThreadExecutor().execute( new Runnable() {
@Override public void run() {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast after work to component " + mToken);
sendFinished(mgr);
}
});
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to component " + mToken);
sendFinished(mgr);
}
} else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
final IActivityManager mgr = ActivityManagerNative.getDefault();
//再次调用sendFinished向AMS通告receiver已经处理好了,去做进一步的处理
sendFinished(mgr);
}
}
再往下的操作就是上面那我们分析的动态注册的sendFinished的方法啦。至此有序广播就一个个的循环起来了。
6、总结。 广播机制的分析就到此结束了,此文章包含了很多从网上借鉴过来的知识点,加上了自己的分析和理解。下面贴出来参考的大神的文章的路径:
http://my.oschina.net/youranhongcha/blog/226274 大神的博客名字:
悠然红茶 十分感谢您的开源精神,此
如文章只是用于自己的学
习记录,如
文章您觉得抄袭严重,即刻删除。
下面贴出一些疑问,欢迎大家解答。(由于工作原因,新项目来了,暂时没时间继续研究了)
遗留问题:
1、静态注册和动态注册 如何实现的排序?在此文章我们直接通过接口获得,而没有去进一步分析。
2、4.0以后,系统广播是不会发送给没有启动的app的 ?只是看到加了一个flag。而没有具体分析实现的原理。
3、发送广播过程中的权限的处理?此文章完全跳过了发送广播时对权限的一些判断。
4、对AMS的成员变量的mReceiverResolver的理解?
5、pid的问题,在静态注册时,新的进程启动完毕后进入到attachApplication时候,获得的pid。然后 if (!badApp && isPendingBroadcastProcessLocked(pid))判断这个pid,难道新启动的一个进程的pid和以前会是一样 的吗?个人对这个不太理解。 6、Context的问题。 自己对Context理解不深,用倒是会用,只是为什么需要用context等等一些问题都不清楚。此处的问题是在LoadedApk 中的成员变量mReceivers,它的key = 上下文Context。那么这个Context是当前Activity的还是整个应用的?后面找时 间依次分析一下。