Android广播管理三--广播发送(sendBroadcast)流程分析
2018-01-08 17:27
525 查看
前面我们分析了Android应用程序注册广播接收器的过程,接下来它还要等待ActivityManagerService将广播分发过来。ActivityManagerService是如何得到广播并把它分发出去的呢?
广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。概括来说,广播的发送路径就是从发送者到ActivityManagerService,再从ActivityManagerService到接收者,这中间的两个过程都是通过Binder进程间通信机制来完成的。
我们上文介绍了ContextWrapper类是Context类的封装类,ContextImpl是Context类的实现类。这里的成员变量mBase是一个ContextImpl实例,这里只简单地调用ContextImpl.sendBroadcast进一行操作。
这里的resolvedType表示这个Intent的MIME类型,如果没有设置这个Intent的MIME类型,resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。
这里主要是把要传递的参数封装好,然后通过Binder驱动程序进入到ActivityManagerService的broadcastIntent()方法中。
这里注意几个参数:
serialized:表示当前广播是否是order广播,true代表order广播(有序广播);
sticky:表示当前广播是否是sticky广播,true代表sticky广播(粘性广播);
broadcastIntent中对Broadcast对应的Intent进行一些检查后,调用broadcastIntentLocked进行实际的处理。
1、排除Stopped状态的应用
所有的广播Intent在这里都会默认加上这个标记,表示所有的广播都不会发送到Stopped状态的应用,应该在发送的时候会检查应用当前的状态。
2、系统升级广播
Intent.FLAG_RECEIVER_BOOT_UPGRADE是系统升级的flag,允许在系统启动前发送。只有注册了的接收者被调用,所有的BroadcastReceiver组件不会被加载。
3、处理受保护广播
受保护广播是通过查询PMS得到的,如果是受保护广播,抛出异常后直接返回ActivityManager.BROADCAST_SUCCESS,不会进行下面的动作。
4、判断发送者是否是系统进程
isCallerSystem表示系统级用户发送的广播,这部分广播不受限制。
5、处理特定系统广播
对于一些来自PMS的包状态的变化,AMS需要及时的处理相关的Activity,这里是因为AMS兼顾了所有的4大组件,当包的状态发生变化,AMS作为总管需要第一时间内处理完总管要做的事情,然后将对应的广播再转发给对应的应用。
发送广播的第一阶段主要工作有:
(1).根据广播对应的Intent中的信息,判断发送方是否有发送该广播的权限;
(2).检查发送的广播是否是一些特殊的系统广播,特别是从PackageManagerService中发出的有个安装的应用移除的广播,如果检测到,需要将这些包中的Activity从AMS的Activity栈中移除。
broadcastIntentLocked方法第二部分主要是处理粘性广播的,判断发送粘性广播的条件是否满足,然后就粘性广播保存起来,将其保存到AMS的mStickyBroadcasts变量里面,上一篇博客中分析了mStickyBroadcasts是以用户id作为key保存的,首先取出当前用户的所有sticky广播,然后根据当前广播的action保存到action对应的List里面即可。里面还有一个细节,就是如果当前intent和list中的某个intent用filterEquals()比较相等,就直接替换掉以前的,否则直接添加到list末尾。
broadcastIntentLocke第三部分的工作主要包括:
1、查询与当前广播匹配的静态和动态BroadcastReceiver;
2、若当前待发送的广播是无序的,那么为动态注册的BroadcastReceiver,构造该广播对应的BroadcastRecord加入到发送队列中,并触发广播发送流程;最后将动态广播接收器置为null。
从这部分代码可以看出,对于无序广播而言,动态注册的BroadcastReceiver接收广播的优先级,高于静态注册的BroadcastReceiver。
走到这里的话,registerReceivers不为null说明当前发送的是一个order广播。如果是order广播,动态BroadcastReceiver和静态BroadcastReceiver合并到一个队列中进行处理,也就是说order广播下,所有的BroadcastReceiver(静态和动态)处理方式都是一样的(串行化处理)。另外,对于静态BroadcastReceiver而言,始终是和order广播的处理方式是一样的,也就是说静态的BroadcastReceiver只有order模式。
简单来说,broadcastIntentLocked()的第四部分工作就是有序广播,把静态BroadcastReceiver和动态BroadcastReceiver按照优先级合并到receivers中,构造对于的BroadcastRecord,然后将BroadcastRecord加入到Ordered Queue中,并触发广播发送流程。
至此,整个broadcastIntentLocked函数分析完毕,除去一些条件判断的细节外,整个工作流程如下图所示:
1、处理粘性广播。
由于粘性广播的特性(BroadcastReceiver注册即可接收),系统必须首先保存粘性广播。
2、处理普通动态广播。
普通广播是并发的,系统优先为动态注册的BroadcastReceiver发送广播。动态广播对应的BroadcastRecord加入到Parallel Queue中。
3、处理静态广播和有序广播。
这一步主要是为静态注册BroadcastReceiver发送广播,对应的BroadcastRecord加入到Ordered Queue中。
此外,需要注意的是:如果广播是有序的,那么第2步不会为动态注册的BroadcastReceiver发送广播,而是在第三步统一发送。发送有序广播时,AMS将按照BroadcastReceiver的优先级,依次构造BroadcastRecord加入到Ordered Queue中。
上面的代码将发送BROADCAST_INTENT_MSG,触发BroadcastQueue调用processNextBroadcast()方法进行处理。
从上面的代码可以看出,processNextBroadcast方法第一部分主要是为动态注册的BroadcastReceiver发送普通广播。发送普通广播的方法为deliverToRegisteredReceiverLocked方法。
1.deliverToRegisteredReceiverLocked
deliverToRegisteredReceiverLocked方法看起来很长,但大部分内容都是进行权限检查等操作,实际的发送工作交给了performReceiveLocked方法。广播是一种可以携带数据的跨进程、跨APP通信机制,为了避免安全泄露的问题,Android才在此处使用了大量的篇幅进行权限检查的工作。
2.BroadcastQueue.performReceiveLocked
对于动态注册的BroadcastReceiver而言,发送广播的流程应该进入到上述代码的If分支。进程的ApplicationThread调用scheduleRegisteredReceiver函数的流程,我们放在后面单独分析。这一部分整体的流程如下图所示:
这部分代码看起来有点乱,其实主要做了两个工作:
1、判断是否有PendingBroadcast。
当存在PendingBroadcast,且当前正在等待启动的进程并没有死亡,那么不能处理下一个BroadcastRecord,必须等待PendingBroadcast处理完毕。
2、处理mOrderedBroadcasts中的BroadcastRecord。
由于有序广播和静态广播,必须一个接一个的处理。因此每发送完一个广播后,均会重新调用processNextBroadcast方法。
在发送新的BroadcastRecord时,需要先处理旧有BroadcastRecord的状态。于是,这段代码后续部分,主要进行了以下操作:
若所有BroadcastRecord均处理完毕,利用AMS释放掉无用进程;
更新超时BroadcastRecord的状态,同时越过此BroadcastRecord;
当一个BroadcastRecord处理完毕后,将结果发送给指定BroadcastReceiver(指定了接收者,才进行此操作),同时将该BroadcastRecord从mOrderedBroadcasts中移除。
这一系列动作的最终目的,就是选出下一个处理的BroadcastRecord,然后就可以开始向该BroadcastRecord中下一个BroadcastReceiver发送广播了。
这一部分整体的判断逻辑大致上如下图所示:
processNextBroadcast的第3部分,主要是处理有序广播发往动态BroadcastReceiver的场景。
从代码可以看出,有序广播具体的方法流程与普通广播一致,均是调用deliverToRegisteredReceiverLocked函数。唯一不同的是,有序广播发往一个BroadcastReceiver后,必须等待处理结果,才能进行下一次发送过程。
processNextBroadcast第四部分主要是处理静态广播,除了检查是否满足发送条件外,主要进行了以下工作:
1、若BroadcastReceiver对应的进程已经启动,那么将直接调用进程对应ApplicationThread的scheduleReceiver发送广播;
2、若BroadcastReceiver对应的进程没有启动,那么AMS将启动对应的进程。
当对应的进程启动,同时完成Android环境的创建后,AMS在attachApplicationLocked函数中重新处理等待发送的广播,对应代码如下:
这一部分整体的流程大致如下图所示:
ActivityThread.ApplicationThread.scheduleRegisteredReceiver
这里的receiver的具体类型是LoadedApk.ReceiverDispatcher.InnerReceiver,即定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,这里调用它的performReceive方法。
这里只是简单地调用ReceiverDispatcher的performReceive方法来进一步处理,这里的ReceiverDispatcher是LoadedApk类里面的一个内部类。
这里mActivityThread成员变量的类型是Handler,它是Activity在注册广播接收器时,从ActivityThread取得的。这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到Activity所在的ActivityThread的消息队列中去,因此,ReceiverDispatcher不等这个广播被Activity处理就返回了,这里也体现了广播的发送和处理是异步进行的。
注意这里处理消息的方式是通过Handler.post方法进行的,post方法的参数是Runnable类型的,这个消息最终会调用这个参数的run方法来处理。这里的Args类是LoadedApk类的内部类ReceiverDispatcher的一个内部类,Args类实现了Runnable接口,因此,可以作为mActivityThread.post方法的参数,代表这个广播的intent也保存在这个Args实例中。
Args.run()
这里的mReceiver是ReceiverDispatcher类的成员变量,类型是BroadcastReceiver,就是Activity注册广播接收器时创建的BroadcastReceiver实例了,有了这个ReceiverDispatcher实例之后,就可以调用它的onReceive方法把这个广播发给它处理了。我们写的广播接收器继承了BroadcastReceiver,并且重写onReceive方法,因此这里就调用到我们自己写的onReceive方法中了。之后调用了BroadcastReceiver.PendingResult.finish()方法,来结束处理流程。
这里的mType是在创建Args对象的时候传进来的,在Args的构造函数中,对于动态注册的广播接收器,参数mRegistered为true,mType就是TYPE_REGISTERED,对于非order广播而言,ordered变量是false,这样BroadcastReceiver.PendingResult中的mOrderedHint为false,mType是TYPE_REGISTERED;根据finish方法,if和else if条件都不成立,因此对于非order的动态广播而言,finish方法什么都没做。
最后,我们总结一下这个Android应用程序发送广播的过程:
1.通过sendBroadcast方法把一个广播通过Binder进程间通信机制发送给ActivityManagerService,AMS根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;
2.AMS在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进Activity所在的线程的消息队列中去,就完成第二个阶段对这个广播的异步分发了;
3.ReceiverDispatcher的内部类Args在Activity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive分发进行处理。
BroadcastReceiver.PendingResult.sendFinished
对于order广播而言,if(mOrderedHint)语句成立,其中参数mAbortBroadcast代表当前高优先级的广播接收器是否需要disable掉低优先级的广播接收器接收当前的广播。我们接着看下finishReceiver方法。
ActivityManagerService.finishReceiver
首先辨别出当前的receiver所在的BroadcastRecord属于前台广播还是后台广播,然后在对应的BroadcastQueue中找出对应的BroadcastRecord,里面的finishReceiverLocked方法主要是重新设置BroadcastRecord的一些状态变量,以便于BroadcastRecord将广播发送给下一个接收者。这里尤其是,如果签名的mAbortBroadcast设置为true,那么BroadcastRecord的成员resultAbort会设置为true。
接下来调用BroadcastQueue.processNextBroadcast方法继续驱动里面的mParallelBroadcasts和mOrderedBroadcasts中的BroadcastRecord处理下一个接收者,里面有这样一个判断:
如果r.resultAbort为true,会停止处理当前正在发送的BroadcastRecord,这样优先级低的接收者也就收不到这个广播了。
3.静态广播的处理流程(scheduleReceiver)
ActivityThread.scheduleReceiver
ActivityThread.scheduleReceiver方法处理应用进程中接收到的静态广播消息,实际处理该广播的是ActivityThread.handleReceiver方法,我们看下代码调用过程:
使用handler发送消息机制,调用到ActivityThread.handleReceiver方法处理。
创建BroadcastReceiver对象
首先从AMS传递的intent中获取当前处理该广播的组件名称,然后通过反射创建一个BroadcastReceiver对象。从这里可以看出,静态广播处理的时候,每次都会创建一个新的BroadcastReceiver对象。
执行onReceive方法
这里的receiver就是上面第一步创建的BroadcastReceiver对象,这里首先尝试创建一个Application对象,但是如果进程已经启动,Application对象已经建立,那么直接返回。下面调用BroadcastReceiver.onReceive方法,就是调用到我们自己写的onReceive方法。
向AMS发送处理结束消息
静态广播是一种有序广播,处理结束后,需要通知AMS继续处理下一个广播接收者或者下一条BroadcastRecord。看看这次PendingResult的finish函数流程:
进程处理静态广播时,主要流程与处理动态广播时一致。主要的差别就是:进程需要反射创建出BroadcastReceiver,同时广播处理完毕后,一定要向AMS返回结果。
从实现原理看上,Android中的广播机制使用了观察者模式,基于消息的发布/订阅模型。广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅两端,AMS属于中间的处理中心。
整体来看,流程可粗略概括如下:
1.广播接收者BroadcastReceiver,通过Binder通信向AMS进行注册;
2.广播发送者通过Binder通信向AMS发送广播;
3.AMS收到广播后,查找与之匹配的BroadcastReceiver,然后将广播发送到BroadcastReceiver对应进程的消息队列中;
4.BroadcastReceiver对应进程的处理该消息时,将回调BroadcastReceiver中的onReceive()方法;
5.广播处理完毕后,BroadcastReceiver对应进程按需将执行结果通知给AMS,以便触发下一次广播发送。
对于不同的广播类型,以及不同的BroadcastReceiver注册方式,具体实现上会有不同,但整体的通信流程大致相似。
我们通过下面的流程图再来熟悉一下广播发送流程,如下:
首先明确AMS只会对order模式的广播设置超时时间,而order模式有两种情形:
(1)、发送者以sendOrderedBroadcast/sendOrderedBroadcastAsUser方法发送的广播,这时候无论是动态注册还是静态注册,AMS都会以order模式处理所有的接收者,也就是所有的接收者以同步的方式处理。这种方式一般比较少。
(2)、静态注册的广播接收器。
以上两种情况时可能出现广播ANR的情形。
根据上面ANR超时的机制来看,只要保证order模式下BroadcastReceiver的处理能够尽快的返回即可。结合广播的超时机制,可以有一下两种避免超时的思路:
(1)、BroadcastReceiver.onReceive方法尽快返回
如果需要完成一项比较耗时的工作,可以通过发送Intent给Service,由Service来完成;如果用子线程的方式来处理,BroadcastReceiver的生命周期很短(在onReceive方法执行后BroadcastReceiver的实例就会被销毁),子线程可能还没有结束BroadcastReceiver就先结束了。如果BroadcastReceiver结束了,它的宿主进程还在运行,那么子线程还会继续执行,但宿主进程此时很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程),进程的优先级很低。
(2)、采用没有超时时间限制的非order模式的动态注册广播。
广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。概括来说,广播的发送路径就是从发送者到ActivityManagerService,再从ActivityManagerService到接收者,这中间的两个过程都是通过Binder进程间通信机制来完成的。
发送广播
ContextWrapper.sendBroadcast
这个函数定义在frameworks/base/core/java/android/content/ContextWrapper.java文件中:public class ContextWrapper extends Context { Context mBase; ...... @Override public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } ...... }
我们上文介绍了ContextWrapper类是Context类的封装类,ContextImpl是Context类的实现类。这里的成员变量mBase是一个ContextImpl实例,这里只简单地调用ContextImpl.sendBroadcast进一行操作。
ContextImpl.sendBroadcast
这个函数定义在frameworks/base/core/java/android/app/ContextImpl.java文件中:public void sendBroadcast(Intent intent) { ............ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { //StrictMode下,对一些Action需要进行检查 intent.prepareToLeaveProcess(this); //调用AMS中的接口 ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch(RemoteException e) { .............. } }
这里的resolvedType表示这个Intent的MIME类型,如果没有设置这个Intent的MIME类型,resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。
ActivityManagerProxy.broadcastIntent
这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:class ActivityManagerProxy implements IActivityManager { ...... public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); intent.writeToParcel(data, 0); data.writeString(resolvedType); ...... mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); reply.recycle(); data.recycle(); return res; } ...... }
这里主要是把要传递的参数封装好,然后通过Binder驱动程序进入到ActivityManagerService的broadcastIntent()方法中。
ActivityManagerService.broadcastIntent
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean serialized, boolean sticky) { synchronized(this) {//verifyBroadcastLocked方法检查Broadcast中intent携带的信息是否有问题(不能携带文件描述符,避免安全隐患) intent = verifyBroadcastLocked(intent);//同时检查intent的flag final ProcessRecord callerApp = getRecordForAppLocked(caller);//获取调用方(发送广播)的ProcessRecord final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, map, requiredPermission, serialized, sticky, callingPid, callingUid); Binder.restoreCallingIdentity(origId); return res; } } ...... }
这里注意几个参数:
serialized:表示当前广播是否是order广播,true代表order广播(有序广播);
sticky:表示当前广播是否是sticky广播,true代表sticky广播(粘性广播);
broadcastIntent中对Broadcast对应的Intent进行一些检查后,调用broadcastIntentLocked进行实际的处理。
ActivityManagerService.broadcastIntentLocked
这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,代码量较大,分段分析。Part I
final int broadcastIntentLocked(.....) { intent = new Intent(intent); // By default broadcasts do not go to stopped apps. // Android系统对所有app的运行状态进行了跟踪 // 当应用第一次安装但未使用过,或从程序管理器被强行关闭后,将处于停止状态 // 在发送广播时,不管是什么广播类型,系统默认增加了FLAG_EXCLUDE_STOPPED_PACKAGES的flag // 使得对于所有BroadcastReceiver而言,如果其所在进程的处于停止状态,该BroadcastReceiver将无法接收到广播 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); //大量条件检查,例如: //有些Action只能由系统来发送; //有些Action需要发送方申明了对应权限 ................... //某些Action,例如Package增加或移除、时区或时间改变、清除DNS、代理变化等,需要AMS来处理 //AMS需要根据Action,进行对应的操作 .................. }
1、排除Stopped状态的应用
// By default broadcasts do not go to stopped apps. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
所有的广播Intent在这里都会默认加上这个标记,表示所有的广播都不会发送到Stopped状态的应用,应该在发送的时候会检查应用当前的状态。
2、系统升级广播
// If we have not finished booting, don't allow this to launch new processes. if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); }
Intent.FLAG_RECEIVER_BOOT_UPGRADE是系统升级的flag,允许在系统启动前发送。只有注册了的接收者被调用,所有的BroadcastReceiver组件不会被加载。
3、处理受保护广播
// Verify that protected broadcasts are only being sent by system code,受保护的广播只能有系统发送 // and that system code is only sending protected broadcasts. final String action = intent.getAction(); final boolean isProtectedBroadcast; try { isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action); } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); return ActivityManager.BROADCAST_SUCCESS; }
受保护广播是通过查询PMS得到的,如果是受保护广播,抛出异常后直接返回ActivityManager.BROADCAST_SUCCESS,不会进行下面的动作。
4、判断发送者是否是系统进程
final boolean isCallerSystem; switch (UserHandle.getAppId(callingUid)) {//如果是root、system、phone、bluetooth、nfc等的UID,则广播不受限制 case Process.ROOT_UID: case Process.SYSTEM_UID: case Process.PHONE_UID: case Process.BLUETOOTH_UID: case Process.NFC_UID: isCallerSystem = true; break; default: isCallerSystem = (callerApp != null) && callerApp.persistent; break; }
isCallerSystem表示系统级用户发送的广播,这部分广播不受限制。
5、处理特定系统广播
if (action != null) { switch (action) { case Intent.ACTION_UID_REMOVED: case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_PACKAGE_CHANGED: case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED: // Handle special intents: if this broadcast is from the package // manager about a package being removed, we need to remove all of // its activities from the history stack.
对于一些来自PMS的包状态的变化,AMS需要及时的处理相关的Activity,这里是因为AMS兼顾了所有的4大组件,当包的状态发生变化,AMS作为总管需要第一时间内处理完总管要做的事情,然后将对应的广播再转发给对应的应用。
发送广播的第一阶段主要工作有:
(1).根据广播对应的Intent中的信息,判断发送方是否有发送该广播的权限;
(2).检查发送的广播是否是一些特殊的系统广播,特别是从PackageManagerService中发出的有个安装的应用移除的广播,如果检测到,需要将这些包中的Activity从AMS的Activity栈中移除。
Part II
.............. // Add to the sticky list if requested. // 处理粘性广播相关的内容 if (sticky) { //检查是否有发送权限,在AndroidManifest.xml中必须声明android.permission.BROADCAST_STICKY权限 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY, callingPid, callingUid) != PackageManager.PERMISSION_GRANTED) { ..................//抛出SecurityException异常 } //粘性广播不能指定接收权限,即发送时不能有requiredPermission权限信息 if (requiredPermissions != null && requiredPermissions.length > 0) { .............. return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { //发送的intent里面不能指定接收者,即粘性广播不能指定接收方 ............ } // We use userId directly here, since the "all" target is maintained // as a separate set of sticky broadcasts. //当粘性广播是针对特定userId时,判断该粘性广播与系统保存的是否冲突 if (userId != UserHandle.USER_ALL) { //取出发送给所有user的粘性广播,关于mStickyBroadcasts的介绍可参考上一篇博客 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++) { //发送给特定user的粘性广播,与发送给所有user的粘性广播,action一致时,发生冲突 if (intent.filterEquals(list.get(i))) { //抛出异常 ............. } } } } ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<>(); //按userId保存粘性广播 //即一个user,可能有多个粘性广播 mStickyBroadcasts.put(userId, stickies); } //按照Action保存粘性广播 //即一个Action,可能对应中多个广播 ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null) { //list为null时,直接加入 list = new ArrayList<>(); stickies.put(intent.getAction(), list); } final int stickiesCount = list.size(); int i; for (i = 0; i < stickiesCount; i++) { //新的粘性广播与之前的重复,则保留新的 //即当发送多个相同的粘性广播时,系统仅会保留最新的 if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= stickiesCount) { //不重复时,直接加入 list.add(new Intent(intent)); } } } ...............
broadcastIntentLocked方法第二部分主要是处理粘性广播的,判断发送粘性广播的条件是否满足,然后就粘性广播保存起来,将其保存到AMS的mStickyBroadcasts变量里面,上一篇博客中分析了mStickyBroadcasts是以用户id作为key保存的,首先取出当前用户的所有sticky广播,然后根据当前广播的action保存到action对应的List里面即可。里面还有一个细节,就是如果当前intent和list中的某个intent用filterEquals()比较相等,就直接替换掉以前的,否则直接添加到list末尾。
Part III
............. // Figure out who all will receive this broadcast.弄清楚谁会接收这个广播 //receivers主要用于保存匹配当前广播的静态注册的BroadcastReceiver //若当前广播是有序广播时,还会插入动态注册的BroadcastReceiver List receivers = null; //registeredReceivers用于保存匹配当前广播的动态注册的BroadcastReceiver //BroadcastFilter中有对应的BroadcastReceiver的引用 List<BroadcastFilter> registeredReceivers = null; // Need to resolve the intent to interested receivers... // 若设置了FLAG_RECEIVER_REGISTERED_ONLY,那么只有此时完成了注册的BroadcastReceiver才会收到信息 // 简单讲就是,有FLAG_RECEIVER_REGISTERED_ONLY时,不通知静态注册的BroadcastReceiver // 此处处理未设置该标记的场景 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { //利用PKMS的queryIntentReceivers接口,查询满足条件的静态BroadcastReceiver receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } //广播没有指定特定接收者时 if (intent.getComponent() == null) { //这里的要求比较特殊,针对所有user,且从shell发送的广播 //即处理调试用的广播 if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { // Query one target user at a time, excluding shell-restricted users for (int i = 0; i < users.length; i++) { //user不允许调试时,跳过 if (mUserController.hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) { continue; } //得到当前user对应的满足Intent要求的BroadcastReceiver //mReceiverResolver中保存的都是动态注册的BroadcastReceiver对应的BroadcastFilter List<BroadcastFilter> registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false, users[i]); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } else if (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else { //一般没有指定接收者的广播,都会走到这里,这是通常的处理流程 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } } //检查广播中是否有REPLACE_PENDING标签 //如果设置了这个标签,那么新的广播可以替换掉AMS广播队列中,与之匹配的且还未被处理的旧有广播 //这么做的目的是:尽可能的减少重复广播的发送 final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; ..................... //先处理动态注册的BroadcastReceiver对应的广播 int NR = registeredReceivers != null ? registeredReceivers.size() : 0; //处理无序的广播,即普通广播 if (!ordered && NR > 0) { // If we are not serializing this broadcast, then send the // registered receivers separately so they don't wait for the // components to be launched. //根据Intent的Flag决定BroadcastQueue,获取前台或后台的广播队列 final BroadcastQueue queue = broadcastQueueForIntent(intent); //构造广播对应的BroadcastRecord //BroadcastRecord中包含了该广播的所有接收者 BroadcastRecord r = new BroadcastRecord(........); ................ //设置了REPLACE_PENDING标签,同时与旧有广播匹配时,才会进行替换 //若能够替换,replaceParallelBroadcastLocked方法中就会将新的广播替换到队列中 final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { //没有替换时,才需要将新的广播加入到BroadcastQueue.mParallelBroadcasts队列中 queue.enqueueParallelBroadcastLocked(r);//这里非常重要,也就是说动态广播都放在了BroadcastQueue.mParallelBroadcasts中 //触发广播发送流程 queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } .....................
broadcastIntentLocke第三部分的工作主要包括:
1、查询与当前广播匹配的静态和动态BroadcastReceiver;
2、若当前待发送的广播是无序的,那么为动态注册的BroadcastReceiver,构造该广播对应的BroadcastRecord加入到发送队列中,并触发广播发送流程;最后将动态广播接收器置为null。
从这部分代码可以看出,对于无序广播而言,动态注册的BroadcastReceiver接收广播的优先级,高于静态注册的BroadcastReceiver。
Part IV
................. // Merge into one list.将receivers和registerReceiver合并到一个列表(receivers)中。 int ir = 0; if (receivers != null) {//静态BroadcastReceiver // A special case for PACKAGE_ADDED: do not allow the package // being added to see this broadcast. This prevents them from // using this as a back door to get run as soon as they are // installed. Maybe in the future we want to have a special install // broadcast or such for apps, but we'd like to deliberately make // this decision. //处理特殊的Action,例如PACKAGE_ADDED,系统不希望有些应用一安装就能启动 //APP安装后,PKMS将发送PACKAGE_ADDED广播 //若没有这个限制,在刚安装的APP内部静态注册监听该消息的BroadcastReceiver,新安装的APP就能直接启动 String skipPackages[] = null; if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { Uri data = intent.getData(); if (data != null) { String pkgName = data.getSchemeSpecificPart(); if (pkgName != null) { skipPackages = new String[] { pkgName };//将广播对应的包名添加到skipPackages中 } } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {//移动app之后发出的广播(APP2SD) skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (skipPackages != null && (skipPackages.length > 0)) { for (String skipPackage : skipPackages) { if (skipPackage != null) { int NT = receivers.size(); for (int it=0; it<NT; it++) { ResolveInfo curt = (ResolveInfo)receivers.get(it); if (curt.activityInfo.packageName.equals(skipPackage)) { //将skipPackages对应的BroadcastReceiver移出receivers;这就是上面说的限制,因此,应用不能接收到自己的PACKAGE_ADDED广播 receivers.remove(it); it--; NT--; } } } } } int NT = receivers != null ? receivers.size() : 0; int it = 0; ResolveInfo curt = null; BroadcastFilter curr = null; //NT对应的是静态BroadcastReceiver的数量 //NR对应的是动态BroadcastReceiver的数量 //若发送的是无序广播,此时NR为0 //若是有序广播,才会进入下面两个while循环 //下面两个while循环就是将静态注册的BroadcastReceiver和动态注册的BroadcastReceiver //按照优先级合并到一起(有序广播才会合并) while (it < NT && ir < NR) { if (curt == null) { curt = (ResolveInfo)receivers.get(it); } if (curr == null) { curr = registeredReceivers.get(ir); } //动态优先级大于静态时,将动态插入到receivers中 if (curr.getPriority() >= curt.priority) { // Insert this broadcast record into the final list. 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(); } //插入剩下的动态BroadcastReceiver receivers.add(registeredReceivers.get(ir)); ir++; } if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent);//根据intent的FLAG获取前台或后台广播队列 //构造对应的BroadcastRecord BroadcastRecord r = new BroadcastRecord(........); ............ //同样判断是否需要替换,这里是Ordered Queue boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { //没替换时,就加入Ordered Queue queue.enqueueOrderedBroadcastLocked(r); //触发发送流程 queue.scheduleBroadcastsLocked(); } } else { // There was nobody interested in the broadcast, but we still want to record // that it happened. if (intent.getComponent() == null && intent.getPackage() == null && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. //没有处理的静态或有序广播,保存起来 //感觉保存起来也没什么用啊 addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0); } } ...............
走到这里的话,registerReceivers不为null说明当前发送的是一个order广播。如果是order广播,动态BroadcastReceiver和静态BroadcastReceiver合并到一个队列中进行处理,也就是说order广播下,所有的BroadcastReceiver(静态和动态)处理方式都是一样的(串行化处理)。另外,对于静态BroadcastReceiver而言,始终是和order广播的处理方式是一样的,也就是说静态的BroadcastReceiver只有order模式。
简单来说,broadcastIntentLocked()的第四部分工作就是有序广播,把静态BroadcastReceiver和动态BroadcastReceiver按照优先级合并到receivers中,构造对于的BroadcastRecord,然后将BroadcastRecord加入到Ordered Queue中,并触发广播发送流程。
至此,整个broadcastIntentLocked函数分析完毕,除去一些条件判断的细节外,整个工作流程如下图所示:
1、处理粘性广播。
由于粘性广播的特性(BroadcastReceiver注册即可接收),系统必须首先保存粘性广播。
2、处理普通动态广播。
普通广播是并发的,系统优先为动态注册的BroadcastReceiver发送广播。动态广播对应的BroadcastRecord加入到Parallel Queue中。
3、处理静态广播和有序广播。
这一步主要是为静态注册BroadcastReceiver发送广播,对应的BroadcastRecord加入到Ordered Queue中。
此外,需要注意的是:如果广播是有序的,那么第2步不会为动态注册的BroadcastReceiver发送广播,而是在第三步统一发送。发送有序广播时,AMS将按照BroadcastReceiver的优先级,依次构造BroadcastRecord加入到Ordered Queue中。
BroadcastQueue.scheduleBroadcastsLocked
从上面的代码,我们知道广播发送方调用sendBroadcast后,AMS会构造对应的BroadcastRecord加入到BroadcastQueue中,返回调用BroadcastQueue的scheduleBroadcastsLocked()方法。现在我们看下这个方法。public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) {//避免短时间内重复发送BROADCAST_INTENT_MSG return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }
/** * Set when we current have a BROADCAST_INTENT_MSG in flight. */ boolean mBroadcastsScheduled = false;
上面的代码将发送BROADCAST_INTENT_MSG,触发BroadcastQueue调用processNextBroadcast()方法进行处理。
BroadcastQueue.processNextBroadcast
processNextBroadcast方法较长,分段进行分析。Part I
final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; .............. //更新CPU的使用情况 //处理静态广播时,可能需要拉起对应进程,因此在这里先记录一下CPU情况 mService.updateCpuStats(); if (fromMsg) { //处理BROADCAST_INTENT_MSG后,将mBroadcastsScheduled置为false //scheduleBroadcastsLocked就可以再次被调用了 mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. //先处理“并发”发送的普通广播(无序广播),mParallelBroadcasts中保存动态注册的广播接收器 while (mParallelBroadcasts.size() > 0) { //依次取出BroadcastRecord r = mParallelBroadcasts.remove(0); //记录发送的时间 r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); ................ for (int i=0; i<N; i++) { //mParallelBroadcasts中的每个成员均为BroadcastFilter类型 Object target = r.receivers.get(i); ............ //为该BroadcastRecord对应的每个Receiver发送广播 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); } //将这里处理过的信息加入到历史记录中 addBroadcastToHistoryLocked(r); } ........................ } }
从上面的代码可以看出,processNextBroadcast方法第一部分主要是为动态注册的BroadcastReceiver发送普通广播。发送普通广播的方法为deliverToRegisteredReceiverLocked方法。
1.deliverToRegisteredReceiverLocked
private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) { boolean skip = false; //检查广播发送方是否有BroadcastReceiver指定的权限 if (filter.requiredPermission != null) { int perm = mService.checkComponentPermission(filter.requiredPermission, r.callingPid, r.callingUid, -1, true); if (perm != PackageManager.PERMISSION_GRANTED) { ............ skip = true; } else { //进一步检查权限的合理性 final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission); if (opCode != AppOpsManager.OP_NONE && mService.mAppOpsService.noteOperation(opCode, r.callingUid, r.callerPackage) != AppOpsManager.MODE_ALLOWED) { ............ skip = true; } } } //检查BroadcastReceiver是否有Broadcast要求的权限 if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) { for (int i = 0; i < r.requiredPermissions.length; i++) { String requiredPermission = r.requiredPermissions[i]; int perm = mService.checkComponentPermission(requiredPermission, filter.receiverList.pid, filter.receiverList.uid, -1, true); if (perm != PackageManager.PERMISSION_GRANTED) { ................. //只要一条权限不满足,就结束 skip = true; break; } //进一步检查权限的合理性 int appOp = AppOpsManager.permissionToOpCode(requiredPermission); if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp && mService.mAppOpsService.noteOperation(appOp, filter.receiverList.uid, filter.packageName) != AppOpsManager.MODE_ALLOWED) { ........... skip = true; break; } } } //这段代码我看的有些懵逼,发送方没要求权限,还检查啥? if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) { int perm = mService.checkComponentPermission(null, filter.receiverList.pid, filter.receiverList.uid, -1, true); if (perm != PackageManager.PERMISSION_GRANTED) { ............ skip = true; } } //还有一些其它的检查,不再分析代码了。。。。。 //包括是否允许以background的方式发送、IntentFirewall是否允许广播中的Intent发送 ............................... if (skip) { //不满足发送条件的话,标记一下,结束发送 r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; return; } // If permissions need a review before any of the app components can run, we drop // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. //特殊情况,还需要再次检查权限,中断广播发送 //再次满足发送条件后,会重新进入到后续的发送流程 if (Build.PERMISSIONS_REVIEW_REQUIRED) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName, filter.owningUserId)) { r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; return; } } //可以发送了,标记一下 r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED; // If this is not being sent as an ordered broadcast, then we // don't want to touch the fields that keep track of the current // state of ordered broadcasts. if (ordered) { //如果发送的是有序广播,则记录一些状态信息等,不涉及广播发送的过程 ............. } try { .............. //若BroadcastReceiver对应的进程处于fullBackup状态(备份和恢复),则不发送广播 if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) { if (ordered) { //有序广播必须处理完一个,才能处理下一个,因此这里主动触发一下 skipReceiverLocked(r); } } else { //执行发送工作 performReceiveLocked(.............); } if (ordered) { r.state = BroadcastRecord.CALL_DONE_RECEIVE; } } catch (RemoteException e) { ............. } }
deliverToRegisteredReceiverLocked方法看起来很长,但大部分内容都是进行权限检查等操作,实际的发送工作交给了performReceiveLocked方法。广播是一种可以携带数据的跨进程、跨APP通信机制,为了避免安全泄露的问题,Android才在此处使用了大量的篇幅进行权限检查的工作。
2.BroadcastQueue.performReceiveLocked
void performReceiveLocked(.........) { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { if (app.thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. try { //通过Binder通信,将广播信息发往BroadcastReceiver处在的进程 app.thread.scheduleRegisteredReceiver(.......); } catch (RemoteException ex) { // Failed to call into the process. It's either dying or wedged. Kill it gently. ....... app.scheduleCrash("can't deliver broadcast"); } throw ex; } else { // Application has died. Receiver doesn't exist. throw new RemoteException("app.thread must not be null"); } } else { //直接通过Binder通信,将消息发往BroadcastReceiver的IIntentReceiver接口 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } }
对于动态注册的BroadcastReceiver而言,发送广播的流程应该进入到上述代码的If分支。进程的ApplicationThread调用scheduleRegisteredReceiver函数的流程,我们放在后面单独分析。这一部分整体的流程如下图所示:
Part II
至此,processNextBroadcast函数已经发送完所有的动态普通广播,我们看看该函数后续的流程:.......... // Now take care of the next serialized one... // If we are waiting for a process to come up to handle the next // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. // 对于有序或静态广播而言,需要依次向每个BroadcastReceiver发送广播,前一个处理完毕后才能发送下一个广播 // 如果BroadcastReceiver对应的进程还未启动,则需要等待 // mPendingBroadcast就是用于保存,因为对应进程还未启动,而处于等待状态的BroadcastRecord if (mPendingBroadcast != null) { ................ boolean isDead; synchronized (mService.mPidsSelfLocked) { //通过AMS得到对应进程的信息 //BroadRecord对应多个BroadcastReceiver,即对应多个进程 //此处curApp保存当前正在等待的进程 ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid); isDead = proc == null || proc.crashing; } if (!isDead) { // It's still alive, so keep waiting // 注意到有序和静态广播必须依次处理 // 因此,若前一个BroadcastRecord对应的某个进程启动较慢,不仅会影响该BroadcastRecord中后续进程接收广播 // 还会影响到后续所有BroadcastRecord对应进程接收广播 return; } else { ............ mPendingBroadcast.state = BroadcastRecord.IDLE; mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; //处理之前发送BroadcastRecord的状态 do { if (mOrderedBroadcasts.size() == 0) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked(); //当至少一个BroadcastRecord被处理完毕后,looped才会被置变为true if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. // 因为静态广播和有序广播,可能拉起进程 // 因此这些广播处理完毕后,AMS需要释放掉一些不需要的进程 mService.updateOomAdjLocked(); } return; } //每次均处理当前的第一个 r = mOrderedBroadcasts.get(0); boolean forceReceive = false; // 这里用于判断此广播是否处理超时 // 仅在系统启动完毕后,才进行该判断,因为PRE_BOOT_COMPLETED广播可能由于系统升级需要等待较长时间 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && //单个广播处理的超时时间,定义为2 * 每个接收者处理的最长时间(10s)* 接收者的数量 (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { ............... //如果超时,则强制结束这条广播的处理 broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { //BroadcastRecord还未处理或处理完毕后,状态为IDLE态 ............ return; } //如果广播处理完毕,或中途被取消 if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { .......... //广播处理完毕,将该广播的处理结果发送给resultTo对应BroadcastReceiver performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); } catch (RemoteException e) { ............. } } ................. cancelBroadcastTimeoutLocked(); addBroadcastToHistoryLocked(r); //作一下记录 if (r.intent.getComponent() == null && r.intent.getPackage() == null && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage, r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime); } mOrderedBroadcasts.remove(0); //一个BroadcastRecord处理完毕后,将r置为null r = null; //如果一个广播处理完毕,说明可能拉起过进程,于是looped置为true looped = true; continue; } //r == null时,可以处理下一个BroadcastRecord //r != null, 继续处理当前BroadcastRecord的下一个BroadReceiver } while (r == null); ....................
这部分代码看起来有点乱,其实主要做了两个工作:
1、判断是否有PendingBroadcast。
当存在PendingBroadcast,且当前正在等待启动的进程并没有死亡,那么不能处理下一个BroadcastRecord,必须等待PendingBroadcast处理完毕。
2、处理mOrderedBroadcasts中的BroadcastRecord。
由于有序广播和静态广播,必须一个接一个的处理。因此每发送完一个广播后,均会重新调用processNextBroadcast方法。
在发送新的BroadcastRecord时,需要先处理旧有BroadcastRecord的状态。于是,这段代码后续部分,主要进行了以下操作:
若所有BroadcastRecord均处理完毕,利用AMS释放掉无用进程;
更新超时BroadcastRecord的状态,同时越过此BroadcastRecord;
当一个BroadcastRecord处理完毕后,将结果发送给指定BroadcastReceiver(指定了接收者,才进行此操作),同时将该BroadcastRecord从mOrderedBroadcasts中移除。
这一系列动作的最终目的,就是选出下一个处理的BroadcastRecord,然后就可以开始向该BroadcastRecord中下一个BroadcastReceiver发送广播了。
这一部分整体的判断逻辑大致上如下图所示:
Part III
.............. // Get the next receiver... // 开始处理当前BroadcastRecord的下一个BroadcastReceiver int recIdx = r.nextReceiver++; // Keep track of when this receiver started, and make sure there // is a timeout message pending to kill it if need be. // 记录单个广播的起始时间 r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { //记录整个BroadcastRecord的起始时间 r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); ................ } if (! mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; .................... //设置广播处理的超时时间为10s setBroadcastTimeoutLocked(timeoutTime); } final BroadcastOptions brOptions = r.options; //取出下一个广播接收者 final Object nextReceiver = r.receivers.get(recIdx); if (nextReceiver instanceof BroadcastFilter) { // Simple case: this is a registered receiver who gets // a direct call. //动态注册的BroadcastReceiver,即处理的是有序广播 BroadcastFilter filter = (BroadcastFilter)nextReceiver; ............ //与处理普通广播一样,调用deliverToRegisteredReceiverLocked //将广播发送给BroadcastReceiver对应进程的ApplicationThread deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); //从代码流程来看,deliverToRegisteredReceiverLocked发送广播出现问题时,r.receiver才可能是null //代码运行到这个位置,加入到Ordered Queue的Broadcast一定是order的 if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. ............... //因此这里应该是有序广播发送错误,因此重新发送BROADCAST_INTENT_MSG,触发下一次发送广播的流程 r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } else { //处理特殊的选项 //向DeviceIdleController发送消息,赋予白名单内的应用, //在Doze模式的激活窗口中,额外的可以访问网络和持锁的时间 if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(filter.owningUid, brOptions.getTemporaryAppWhitelistDuration(), r); } } //对于有序广播而言,已经通知了一个BroadcastReceiver,需要等待处理结果,因此返回 return; } .......................
processNextBroadcast的第3部分,主要是处理有序广播发往动态BroadcastReceiver的场景。
从代码可以看出,有序广播具体的方法流程与普通广播一致,均是调用deliverToRegisteredReceiverLocked函数。唯一不同的是,有序广播发往一个BroadcastReceiver后,必须等待处理结果,才能进行下一次发送过程。
Part IV
................... // Hard case: need to instantiate the receiver, possibly // starting its application process to host it. // 开始处理静态广播 ResolveInfo info = (ResolveInfo)nextReceiver; //得到静态广播对应的组件名 ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); boolean skip = false; //以下与deliverToRegisteredReceiverLocked中类似,进行发送广播前的检查工作 //判断发送方和接收方要求的权限,是否互相满足 //判断Intent是否满足AMS的IntentFirewall要求 ................... boolean isSingleton = false; try { //判断BroadcastReceiver是否是单例的 isSingleton = mService.isSingleton(info.activityInfo.processName, info.activityInfo.applicationInfo, info.activityInfo.name, info.activityInfo.flags); } catch (SecurityException e) { ................. } //BroadcastReceiver要求SINGLE_USER //那么必须申明INTERACT_ACROSS_USERS权限 if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { if (ActivityManager.checkUidPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, info.activityInfo.applicationInfo.uid) != PackageManager.PERMISSION_GRANTED) { .............. skip = true; } } if (!skip) { r.manifestCount++; } else { r.manifestSkipCount++; } if (r.curApp != null && r.curApp.crashing) { ......... skip = true; } if (!skip) { boolean isAvailable = false; try { isAvailable = AppGlobals.getPackageManager().isPackageAvailable( info.activityInfo.packageName, UserHandle.getUserId(info.activityInfo.applicationInfo.uid)); } catch (Exception e) { .......... } if (!isAvailable) { ......... skip = true; } } //判断BroadcastReceiver对应进程是否允许后台启动 //不允许也会skip .............. if (skip) { .................. r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; //跳过该广播,发送下一个广播 scheduleBroadcastsLocked(); return; } r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED; r.state = BroadcastRecord.APP_RECEIVE; r.curComponent = component; r.curReceiver = info.activityInfo; ................ if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { //与处理有序普通广播一样,在此处理特殊的选项 scheduleTempWhitelistLocked(receiverUid, brOptions.getTemporaryAppWhitelistDuration(), r); } // Broadcast is being executed, its package can't be stopped. try { //发送静态广播前,修改BroadcastReceiver对应的Package状态 AppGlobals.getPackageManager().setPackageStoppedState( r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { ............... } // Is this receiver's application already running? if (app != null && app.thread != null) { try { app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); //BroadcastReceiver对应进程启动时,调用ApplicationThread的scheduleReceiver processCurBroadcastLocked(r, app); //等待结果,故return return; } catch (RemoteException e) { //这可能是对应进程死亡,可以重新拉起进程发送 .......... } catch (RuntimeException e) { ......... //发送失败,结束本次发送 finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); //继续发送后续的广播 scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; return; } } ............. //启动进程处理广播 if ((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) { //创建进程失败 ............... //发送失败,结束本次发送 finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); //继续发送后续的广播 scheduleBroadcastsLocked(); r.state = BroadcastRecord.IDLE; return; } //进程启动成功时,mPendingBroadcast保存当前的BroadcastRecord,及待发送广播的下标 //当进程启动后,将根据这两个值处理广播 mPendingBroadcast = r; mPendingBroadcastRecvIndex = recIdx; .............
processNextBroadcast第四部分主要是处理静态广播,除了检查是否满足发送条件外,主要进行了以下工作:
1、若BroadcastReceiver对应的进程已经启动,那么将直接调用进程对应ApplicationThread的scheduleReceiver发送广播;
2、若BroadcastReceiver对应的进程没有启动,那么AMS将启动对应的进程。
当对应的进程启动,同时完成Android环境的创建后,AMS在attachApplicationLocked函数中重新处理等待发送的广播,对应代码如下:
............... // Check if a next-broadcast receiver is in this process... if (!badApp && isPendingBroadcastProcessLocked(pid)) { try { //发送因目标进程还未启动,而处于等待状态的广播 //sendPendingBroadcastsLocked将调用BroadcastQueue中的sendPendingBroadcastsLocked函数 //sendPendingBroadcastsLocked最后仍会调用进程对应ApplicationThread的scheduleReceiver函数 didSomething |= sendPendingBroadcastsLocked(app); } 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; } } .............
这一部分整体的流程大致如下图所示:
应用进程处理广播
最后,我们看看应用进程收到广播处理请求后的流程。1.动态广播的处理流程
在上面的performReceiveLocked方法中,调用了app.thread.scheduleRegisteredReceiver方法,最后通过Binder通信调用的是进程对应ApplicationThread的scheduleRegisteredReceiver接口。ActivityThread.ApplicationThread.scheduleRegisteredReceiver
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException { .............. //调用的是LoadedApk中ReceiverDispatcher的内部类InnerReceiver的接口 receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); }
这里的receiver的具体类型是LoadedApk.ReceiverDispatcher.InnerReceiver,即定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,这里调用它的performReceive方法。
InnerReceiver.performReceive()
static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); mStrongRef = strong ? rd : null; } @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final LoadedApk.ReceiverDispatcher rd; if (intent == null) { ........ rd = null; } else { rd = mDispatcher.get(); } ....... if (rd != null) { rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);//调用ReceiverDispatcher的performReceive方法 } else { // The activity manager dispatched a broadcast to a registered // receiver in this process, but before it could be delivered the // receiver was unregistered. Acknowledge the broadcast on its // behalf so that the system's broadcast sequence can continue. //处理特殊情况,在收到广播前,BroadcastReceiver已经unregister了。 IActivityManager mgr = ActivityManagerNative.getDefault(); try { if (extras != null) { extras.setAllowFds(false); } mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());//通知AMS结束 } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } }
这里只是简单地调用ReceiverDispatcher的performReceive方法来进一步处理,这里的ReceiverDispatcher是LoadedApk类里面的一个内部类。
ReceiverDispatcher.performReceive()
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser);//创建Args对象 .......... //mActivityThread是一个Handler对象,若创建BroadcastReceiver时没有指定Handler对象,则默认时ActivityThread主线程对应的Handler if (intent == null || !mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); ........... args.sendFinished(mgr); } } }
这里mActivityThread成员变量的类型是Handler,它是Activity在注册广播接收器时,从ActivityThread取得的。这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到Activity所在的ActivityThread的消息队列中去,因此,ReceiverDispatcher不等这个广播被Activity处理就返回了,这里也体现了广播的发送和处理是异步进行的。
注意这里处理消息的方式是通过Handler.post方法进行的,post方法的参数是Runnable类型的,这个消息最终会调用这个参数的run方法来处理。这里的Args类是LoadedApk类的内部类ReceiverDispatcher的一个内部类,Args类实现了Runnable接口,因此,可以作为mActivityThread.post方法的参数,代表这个广播的intent也保存在这个Args实例中。
Args.run()
final class Args extends BroadcastReceiver.PendingResult implements Runnable { private Intent mCurIntent; private final boolean mOrdered; private boolean mDispatched; public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, int sendingUser) { super(resultCode, resultData, resultExtras, mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags()); mCurIntent = intent; mOrdered = ordered; } public void run() { final BroadcastReceiver receiver = mReceiver; final boolean ordered = mOrdered; ........... final IActivityManager mgr = ActivityManagerNative.getDefault(); final Intent intent = mCurIntent; .......... mCurIntent = null; mDispatched = true; if (receiver == null || intent == null || mForgotten) { if (mRegistered && ordered) { ........... sendFinished(mgr); } return; } .......... try {//这里处理的是动态广播的注册,默认认为BroadcastReceiver已经存在 ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this);//设置BroadcastReceiver的PendingResult receiver.onReceive(mContext, intent);//调用BroadcastReceiver的onReceive方法 } catch (Exception e) { ...... } //当调用BroadcastReceiver的goAsync方法时,会把mPendingResult设为null;于是不会结束发送流程,直到调用PendingResult的finish方法 if (receiver.getPendingResult() != null) { finish();//Args继承PendingResult,此处也是调用PendingResult的finish方法。 } .......... } }
这里的mReceiver是ReceiverDispatcher类的成员变量,类型是BroadcastReceiver,就是Activity注册广播接收器时创建的BroadcastReceiver实例了,有了这个ReceiverDispatcher实例之后,就可以调用它的onReceive方法把这个广播发给它处理了。我们写的广播接收器继承了BroadcastReceiver,并且重写onReceive方法,因此这里就调用到我们自己写的onReceive方法中了。之后调用了BroadcastReceiver.PendingResult.finish()方法,来结束处理流程。
BroadcastReceiver.PendingResult.finish()
/** * Finish the broadcast. The current result will be sent and the * next broadcast will proceed.发送当前结果,下一个广播将会被处理。 */ public final void finish() { if (mType == TYPE_COMPONENT) {//对于动态广播而言,mType为TYPE_REGISTERED或TYPE_UNREGISTERED 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(mgr);//Binder通信,调用AMS的finishReceiver方法。 } }
这里的mType是在创建Args对象的时候传进来的,在Args的构造函数中,对于动态注册的广播接收器,参数mRegistered为true,mType就是TYPE_REGISTERED,对于非order广播而言,ordered变量是false,这样BroadcastReceiver.PendingResult中的mOrderedHint为false,mType是TYPE_REGISTERED;根据finish方法,if和else if条件都不成立,因此对于非order的动态广播而言,finish方法什么都没做。
最后,我们总结一下这个Android应用程序发送广播的过程:
1.通过sendBroadcast方法把一个广播通过Binder进程间通信机制发送给ActivityManagerService,AMS根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;
2.AMS在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进Activity所在的线程的消息队列中去,就完成第二个阶段对这个广播的异步分发了;
3.ReceiverDispatcher的内部类Args在Activity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive分发进行处理。
2.串行化广播处理(scheduleRegisteredReceiver)
前面分析到,对于接收者进程而言,order和非order广播都调用scheduleRegisterReceiver方法处理,只是上面处理的时候BroadcastReceiver.PendingResult中的mOrderedHint为true,mType为TYPE_REGISTERED,在finish()方法里面会调用sendFinished()方法:BroadcastReceiver.PendingResult.sendFinished
/** @hide */ public void sendFinished(IActivityManager am) { synchronized (this) { if (mFinished) { throw new IllegalStateException("Broadcast already finished"); } mFinished = true; try { ......... if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, mAbortBroadcast, mFlags);//调用AMS的finishReceiver方法 } else { // This broadcast was sent to a component; it is not ordered, // but we still need to tell the activity manager we are done. am.finishReceiver(mToken, 0, null, null, false, mFlags); } } catch (RemoteException ex) { } } }
对于order广播而言,if(mOrderedHint)语句成立,其中参数mAbortBroadcast代表当前高优先级的广播接收器是否需要disable掉低优先级的广播接收器接收当前的广播。我们接着看下finishReceiver方法。
ActivityManagerService.finishReceiver
public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, int flags) { .......... final long origId = Binder.clearCallingIdentity(); try { boolean doNext = false; BroadcastRecord r; synchronized(this) { BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0 ? mFgBroadcastQueue : mBgBroadcastQueue;//根据flags标记,获取前台或后台广播队列 r = queue.getMatchingOrderedReceiver(who); if (r != null) {//结束当前正在发送的广播,判断是否需要发送后续广播 doNext = r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, true); } } if (doNext) {//立马调度一次广播发送,发送下一个广播,processNextBroadcast是一个同步函数,一次只能处理一个请求 r.queue.processNextBroadcast(false); } trimApplications();//释放不必要的进程 } finally { Binder.restoreCallingIdentity(origId); } }
首先辨别出当前的receiver所在的BroadcastRecord属于前台广播还是后台广播,然后在对应的BroadcastQueue中找出对应的BroadcastRecord,里面的finishReceiverLocked方法主要是重新设置BroadcastRecord的一些状态变量,以便于BroadcastRecord将广播发送给下一个接收者。这里尤其是,如果签名的mAbortBroadcast设置为true,那么BroadcastRecord的成员resultAbort会设置为true。
接下来调用BroadcastQueue.processNextBroadcast方法继续驱动里面的mParallelBroadcasts和mOrderedBroadcasts中的BroadcastRecord处理下一个接收者,里面有这样一个判断:
如果r.resultAbort为true,会停止处理当前正在发送的BroadcastRecord,这样优先级低的接收者也就收不到这个广播了。
3.静态广播的处理流程(scheduleReceiver)
ActivityThread.scheduleReceiver
ActivityThread.scheduleReceiver方法处理应用进程中接收到的静态广播消息,实际处理该广播的是ActivityThread.handleReceiver方法,我们看下代码调用过程:public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean sync, int sendingUser, int processState) { ......... ReceiverData r = new ReceiverData(intent, resultCode, data, extras, sync, false, mAppThread.asBinder(), sendingUser); r.info = info; r.compatInfo = compatInfo; sendMessage(H.RECEIVER, r); }
private void sendMessage(int what, Object obj) { sendMessage(what, obj, 0, 0, false); }
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) { if (DEBUG_MESSAGES) Slog.v( TAG, "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj); Message msg = Message.obtain(); msg.what = what; msg.obj = obj; msg.arg1 = arg1; msg.arg2 = arg2; if (async) { msg.setAsynchronous(true); } mH.sendMessage(msg); }
final H mH = new H();
private class H extends Handler { ...... public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { ...... case RECEIVER: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp"); handleReceiver((ReceiverData)msg.obj); maybeSnapshot(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; ......
使用handler发送消息机制,调用到ActivityThread.handleReceiver方法处理。
ActivityThread.handleReceive
handleReceive方法处理中,主要包含三大步骤:创建BroadcastReceiver对象
private void handleReceiver(ReceiverData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); 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 = (BroadcastReceiver)cl.loadClass(component).newInstance(); } catch (Exception e) { if (DEBUG_BROADCAST) Slog.i(TAG, "Finishing failed broadcast to " + data.intent.getComponent()); data.sendFinished(mgr); throw new RuntimeException( "Unable to instantiate receiver " + component + ": " + e.toString(), e); } ...... }
首先从AMS传递的intent中获取当前处理该广播的组件名称,然后通过反射创建一个BroadcastReceiver对象。从这里可以看出,静态广播处理的时候,每次都会创建一个新的BroadcastReceiver对象。
执行onReceive方法
...... try { Application app = packageInfo.makeApplication(false, mInstrumentation); ......... ContextImpl context = (ContextImpl)app.getBaseContext(); sCurrentBroadcastIntent.set(data.intent); receiver.setPendingResult(data); receiver.onReceive(context.getReceiverRestrictedContext(), data.intent);//调用BroadcastReceiver的onReceive方法 } catch (Exception e) { ....... data.sendFinished(mgr);//静态广播出问题,需要通知AMS ......... } finally { sCurrentBroadcastIntent.set(null);//处理完毕,将进程的静态变量置为null } ......
这里的receiver就是上面第一步创建的BroadcastReceiver对象,这里首先尝试创建一个Application对象,但是如果进程已经启动,Application对象已经建立,那么直接返回。下面调用BroadcastReceiver.onReceive方法,就是调用到我们自己写的onReceive方法。
向AMS发送处理结束消息
if (receiver.getPendingResult() != null) { data.finish();//再次调用PendingResult的finish方法,此时type为TYPE_COMPONENT }
静态广播是一种有序广播,处理结束后,需要通知AMS继续处理下一个广播接收者或者下一条BroadcastRecord。看看这次PendingResult的finish函数流程:
public final void finish() { if (mType == TYPE_COMPONENT) { final IActivityManager mgr = ActivityManagerNative.getDefault(); //静态广播一定是由主线程处理事件 //若主线程的QueuedWork中有事情还未处理完,则必须让事情做完后,才通知结果 //保证AMS不会将进程kill掉 if (QueuedWork.hasPendingWork()) { //主线的QueuedWork是单线程依次处理任务的 QueuedWork.singleThreadExecutor().execute( new Runnable() { @Override public void run() { ............ //通知AMS sendFinished(mgr); } }); } else { ............ //无等待处理的事件,直接通知AMS处理结果 sendFinished(mgr); } } else (mOrderedHint && mType != TYPE_UNREGISTERED){ ................. }
进程处理静态广播时,主要流程与处理动态广播时一致。主要的差别就是:进程需要反射创建出BroadcastReceiver,同时广播处理完毕后,一定要向AMS返回结果。
总结
至此,Android中广播相关的流程分析完毕。从实现原理看上,Android中的广播机制使用了观察者模式,基于消息的发布/订阅模型。广播发送者和广播接收者分别属于观察者模式中的消息发布和订阅两端,AMS属于中间的处理中心。
整体来看,流程可粗略概括如下:
1.广播接收者BroadcastReceiver,通过Binder通信向AMS进行注册;
2.广播发送者通过Binder通信向AMS发送广播;
3.AMS收到广播后,查找与之匹配的BroadcastReceiver,然后将广播发送到BroadcastReceiver对应进程的消息队列中;
4.BroadcastReceiver对应进程的处理该消息时,将回调BroadcastReceiver中的onReceive()方法;
5.广播处理完毕后,BroadcastReceiver对应进程按需将执行结果通知给AMS,以便触发下一次广播发送。
对于不同的广播类型,以及不同的BroadcastReceiver注册方式,具体实现上会有不同,但整体的通信流程大致相似。
我们通过下面的流程图再来熟悉一下广播发送流程,如下:
避免广播ANR
上面熟悉了广播的发送流程,其中涉及到了广播ANR的问题,这里我们顺便了解下。首先明确AMS只会对order模式的广播设置超时时间,而order模式有两种情形:
(1)、发送者以sendOrderedBroadcast/sendOrderedBroadcastAsUser方法发送的广播,这时候无论是动态注册还是静态注册,AMS都会以order模式处理所有的接收者,也就是所有的接收者以同步的方式处理。这种方式一般比较少。
(2)、静态注册的广播接收器。
以上两种情况时可能出现广播ANR的情形。
根据上面ANR超时的机制来看,只要保证order模式下BroadcastReceiver的处理能够尽快的返回即可。结合广播的超时机制,可以有一下两种避免超时的思路:
(1)、BroadcastReceiver.onReceive方法尽快返回
如果需要完成一项比较耗时的工作,可以通过发送Intent给Service,由Service来完成;如果用子线程的方式来处理,BroadcastReceiver的生命周期很短(在onReceive方法执行后BroadcastReceiver的实例就会被销毁),子线程可能还没有结束BroadcastReceiver就先结束了。如果BroadcastReceiver结束了,它的宿主进程还在运行,那么子线程还会继续执行,但宿主进程此时很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程),进程的优先级很低。
(2)、采用没有超时时间限制的非order模式的动态注册广播。
相关文章推荐
- [学习记录]Android4.0耳机插入广播发送流程分析
- [学习记录]Android4.0耳机插入广播发送流程分析
- Android广播管理二--广播注册(registerReceiver)流程分析
- Android 4.0按键事件以及电源管理流程分析
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android入门-MMS-短信/彩信发送流程+代码分析
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android AlarmManagerService TIME_TICK 广播发送流程
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android 4.0按键事件以及电源管理流程分析
- android安全问题(七) 抢先接收广播 - 内因篇之广播发送流程
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android应用程序发送广播(sendBroadcast)的过程分析(2)
- 基于N源码的广播注册和发送流程分析
- Android应用程序发送广播(sendBroadcast)的过程分析
- android MMS/SMS 收发流程分析(接收发送)
- 广播——Android应用程序发送广播(sendBroadcast)的过程分析
- Android应用程序发送广播(sendBroadcast)的过程分析
- Android4.4 Framework分析——广播的注册(BroadcastReceiver)和发送(sendbroadcast)过程分析