Android学习笔记:Android10.0.+版本下BroadcastReceiver的工作过程(流程分析文档)
BroadcastReceiver的工作过程,主要包含两方面内容,一是广播的注册过程,二是广播的发送和接收过程。而广播的注册分为静态注册和动态注册,静态注册是通过AndroidManifest.xml配置来完成的,具体来说就是有PMS(PackageManagerService)来完成整个注册过程。我们采用动态注册的方式来分析广播。
首先,创建BroadcastReceiverDemo工程,该工程包含两个类文件,分别是MainActivity和MyReceiver,以及布局文件activity_main.xml,我们通过点击Button来发送广播。MyReceiver的示例代码如下:
MainActivity的示例代码如下:
一、广播的注册过程
我们分析动态注册的过程,如下图所示,动态注册是从调用ContextWrapper#registerReceiver()方法开始的。
我们跳转查看,在ContextWrapper类中,不同参数的registerReceiver()方法各自回调。
通过Context类型的mBase对象回调到Context,但是Context类中封装的都是抽象方法,因为mBase的具体实现类是ContextImpl类,我们进入Context类的实现类ContextImpl类中进行查看,如下所示。
可以看到ContextImpl#registerReceiver()方法又回调了ContextImpl#registerReceiverInternal()方法,如下图所示。
可以看到,系统首先从mPackageInfo获取IIntentReceiver对象,然后再采取跨进程通信的方式向AMS发送广播注册的请求。IIntentReceiver是一个Binder接口,它的具体实现是LoadedApk.ReceiverDispatcher。在方法的最后,通过调用ActivityManager.getService().registerReceiverWithFeature()方法来注册广播,ActivityManager.getService()的实质是AMS,我们跳转到ActivityManagerService类来看该方法的具体实现。
在AMS#registerReceiverWithFeature()方法中,mRegisteredReceivers首先将客户端传递过来的广播接收器保存起来(上图标记1处),在最后(上图标记2处)将客户端传递过来的IntentFilter也保存起来,这样整个广播注册的过程就完成了。
二、广播的发送和接收过程
当通过send方式发送广播时,AMS会找出与之匹配的广播接收者并将广播发送给它们处理。广播的发送从ContextWrapper#sendBroadcast()方法开始,如下图所示。
我们跳转查看,在ContextWrapper类中sendBroadcast()方法回调到Context类中。
在Context类中,定义了sendBroadcast的抽象方法,该方法的实现是在Context类的实现类ContextImpl类中,我们跳转查看。
可以看到,ContextImpl#sendBroadcast()方法基本没有什么操作,而是直接回调ActivityManager.getService()方法来发起异步请求。我们跳转到AMS#broadcastIntentWithFeature()方法查看,如下图所示。
可以看出该方法回调了AMS#broadcastIntentLocked(19个参数)方法,broadcastIntentLocked(19个参数)方法又回调了AMS#broadcastIntentLocked(21个参数)方法,如下所示。
在AMS#broadcastIntentLocked(21个参数)方法中(共698行),会根据intent-filter查找出匹配的广播接收者并经过一系列的过滤条件,最终将满足条件的广播接收者添加到BroadcastQueue中,然后BroadcastQueue就会将广播发送给相应的接收者,如下图所示。
首先,我们跳转到BroadcastQueue#enqueueOrderedBroadcastLocked()方法,该方法又回调到BroadcastDispatcher# enqueueOrderedBroadcastLocked()方法,将广播添加到MessageQueue中,如下图所示。
接下来,我们跳转到BroadcastQueue#scheduleBroadcastsLocked()方法来分析广播的发送过程,如下图所示。
可以看到,BroadcastQueue#scheduleBroadcastsLocked()方法并没有立即发送广播,而是发送了一个BROADCAST_INTENT_MSG类型的消息。我们跳转查看,如下图所示。
BroadcastQueue收到消息后会调用BroadcastQueue#processNextBroadcast()方法,该方法又会回调BroadcastQueue# processNextBroadcastLocked()方法,如下图所示。
我们跳转到BroadcastQueue# processNextBroadcastLocked()方法查看,如下图所示。
可以看到,无序广播存储在mParallelBroadcasts中,系统会遍历mParallelBroadcasts并将其中的广播发送给它们所有的接收者。具体的发送过程是通过BroadcastQueue# deliverToRegisteredReceiverLocked()方法来实现,我们跳转查看。
BroadcastQueue#deliverToRegisteredReceiverLocked()方法负责将一个广播发送给一个特定的接收者,它内部调用了BroadcastQueue#performReceiveLocked()方法来完成具体的发送过程,我们跳转查看。
在BroadcastQueue#performReceiveLocked()方法中,app.thread表示ActivityThread,我们进入ActivityThread#scheduleRegisteredReceiver()方法,可以看到该方法通过IIntentReceiver来实现广播的接收。IIntentReceiver的performReceive()方法会调用,LoadedAPK#performReceive()方法,如下图所示。
我们进入LoadedAPK#performReceive()方法,如下图所示。
在上述代码中,会创建一个Args对象并调用sendFinished()方法,而Args实现了Runnable接口。我们进入LoadedAPK#Args类查看,如下图所示,可以看到在方法中调用了BroadcastReceiver#onReceive()方法,也就是应用已经接收到广播了,同时onReceive()方法是在广播接收者的主线程中被调用的。