Android应用程序发送广播(sendBroadcast)的过程分析

最后更新于:2022-04-02 05:06:26

原文出处——>[Android应用程序发送广播(sendBroadcast)的过程分析](http://blog.csdn.net/luoshengyang/article/details/6744448) 前面我们分析了Android应用程序注册广播接收器的过程,这个过程只完成了万里长征的第一步,接下来它还要等待ActivityManagerService将广播分发过来。ActivityManagerService是如何得到广播并把它分发出去的呢?这就是本文要介绍的广播发送过程了。 广播的发送过程比广播接收器的注册过程要复杂得多了,不过这个过程仍然是以ActivityManagerService为中心。广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。概括来说,广播的发送路径就是从发送者到ActivityManagerService,再从ActivityManagerService到接收者,这中间的两个过程都是通过Binder进程间通信机制来完成的,因此,希望读者在继续阅读本文之前,对Android系统的Binder进程间通信机制有所了解,具体可以参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。 本文继续以Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所开发的应用程序为例子,并且结合上文Android应用程序注册广播接收器(registerReceiver)的过程分析的内容,一起来分析Android应用程序发送广播的过程。 回顾一下Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所开发的应用程序的组织架构,MainActivity向ActivityManagerService注册了一个CounterService.BROADCAST_COUNTER_ACTION类型的计数器服务广播接收器,计数器服务CounterService在后台线程中启动了一个异步任务(AsyncTask),这个异步任务负责不断地增加计数,并且不断地将当前计数值通过广播的形式发送出去,以便MainActivity可以将当前计数值在应用程序的界面线程中显示出来。 计数器服务CounterService发送广播的代码如下所示: ~~~ public class CounterService extends Service implements ICounterService { ...... public void startCounter(int initVal) { AsyncTask task = new AsyncTask() { @Override protected Integer doInBackground(Integer... vals) { ...... } @Override protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); int counter = values[0]; Intent intent = new Intent(BROADCAST_COUNTER_ACTION); intent.putExtra(COUNTER_VALUE, counter); sendBroadcast(intent); } @Override protected void onPostExecute(Integer val) { ...... } }; task.execute(0); } ...... } ~~~ 在onProgressUpdate函数中,创建了一个BROADCAST_COUNTER_ACTION类型的Intent,并且在这里个Intent中附加上当前的计数器值,然后通过CounterService类的成员函数sendBroadcast将这个Intent发送出去。CounterService类继承了Service类,Service类又继承了ContextWrapper类,成员函数sendBroadcast就是从ContextWrapper类继承下来的,因此,我们就从ContextWrapper类的sendBroadcast函数开始,分析广播发送的过程。 在继承分析广播的发送过程前,我们先来看一下广播发送过程的序列图,然后按照这个序图中的步骤来一步一步分析整个过程。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/959de7e1166d219bda159db2bb76c467_1024x708.gif) **Step 1. 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); } ...... } ~~~ 这里的成员变量mBase是一个ContextImpl实例,这里只简单地调用ContextImpl.sendBroadcast进一行操作。 **Step 2. ContextImpl.sendBroadcast** 这个函数定义在frameworks/base/core/java/android/app/ContextImpl.java文件中: ~~~ class ContextImpl extends Context { ...... @Override public void sendBroadcast(Intent intent) { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false); } catch (RemoteException e) { } } ...... } ~~~ 这里的resolvedType表示这个Intent的MIME类型,我们没有设置这个Intent的MIME类型,因此,这里的resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。 **Step 3. 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); data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null); data.writeInt(resultCode); data.writeString(resultData); data.writeBundle(map); data.writeString(requiredPermission); data.writeInt(serialized ? 1 : 0); data.writeInt(sticky ? 1 : 0); mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0); reply.readException(); int res = reply.readInt(); reply.recycle(); data.recycle(); return res; } ...... } ~~~ 这里的实现比较简单,把要传递的参数封装好,然后通过Binder驱动程序进入到ActivityManagerService的broadcastIntent函数中。 **Step 4. ctivityManagerService.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) { intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); 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; } } ...... } ~~~ 这里调用broadcastIntentLocked函数来进一步处理。 **Step 5. ActivityManagerService.broadcastIntentLocked** 这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中: ~~~ public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, boolean ordered, boolean sticky, int callingPid, int callingUid) { intent = new Intent(intent); ...... // Figure out who all will receive this broadcast. List receivers = null; List registeredReceivers = null; try { if (intent.getComponent() != null) { ...... } else { ...... registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); } } catch (RemoteException ex) { ...... } final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; 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. BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false); ...... boolean replaced = false; if (replacePending) { for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) { ...... mParallelBroadcasts.set(i, r); replaced = true; break; } } } if (!replaced) { mParallelBroadcasts.add(r); scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } ...... } ...... } ~~~ 这个函数首先是根据intent找出相应的广播接收器: ~~~ // Figure out who all will receive this broadcast. List receivers = null; List registeredReceivers = null; try { if (intent.getComponent() != null) { ...... } else { ...... registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); } } catch (RemoteException ex) { ...... } ~~~ 回忆一下前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 6(ActivityManagerService.registerReceiver)中,我们将一个filter类型为BROADCAST_COUNTER_ACTION类型的BroadcastFilter实例保存在了ActivityManagerService的成员变量mReceiverResolver中,这个BroadcastFilter实例包含了我们所注册的广播接收器,这里就通过mReceiverResolver.queryIntent函数将这个BroadcastFilter实例取回来。由于注册一个广播类型的接收器可能有多个,所以这里把所有符合条件的的BroadcastFilter实例放在一个List中,然后返回来。在我们这个场景中,这个List就只有一个BroadcastFilter实例了,就是MainActivity注册的那个广播接收器。 继续往下看: ~~~ final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; ~~~ 这里是查看一下这个intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位有没有设置,如果设置了的话,ActivityManagerService就会在当前的系统中查看有没有相同的intent还未被处理,如果有的话,就有当前这个新的intent来替换旧的intent。这里,我们没有设置intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位,因此,这里的replacePending变量为false。 再接着往下看: ~~~ 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. BroadcastRecord r = new BroadcastRecord(intent, callerApp, callerPackage, callingPid, callingUid, requiredPermission, registeredReceivers, resultTo, resultCode, resultData, map, ordered, sticky, false); ...... boolean replaced = false; if (replacePending) { for (int i=mParallelBroadcasts.size()-1; i>=0; i--) { if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) { ...... mParallelBroadcasts.set(i, r); replaced = true; break; } } } if (!replaced) { mParallelBroadcasts.add(r); scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } ~~~ 前面我们说到,这里得到的列表registeredReceivers的大小为1,且传进来的参数ordered为false,表示要将这个广播发送给所有注册了BROADCAST_COUNTER_ACTION类型广播的接收器,因此,会执行下面的if语句。这个if语句首先创建一个广播记录块BroadcastRecord,里面记录了这个广播是由谁发出的以及要发给谁等相关信息。由于前面得到的replacePending变量为false,因此,不会执行接下来的if语句,即不会检查系统中是否有相同类型的未处理的广播。 这样,这里得到的replaced变量的值也为false,于是,就会把这个广播记录块r放在ActivityManagerService的成员变量mParcelBroadcasts中,等待进一步处理;进一步处理的操作由函数scheduleBroadcastsLocked进行。 **Step 6. ActivityManagerService.scheduleBroadcastsLocked** 这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中: ~~~ public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final void scheduleBroadcastsLocked() { ...... if (mBroadcastsScheduled) { return; } mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG); mBroadcastsScheduled = true; } ...... } ~~~ 这里的mBroadcastsScheduled表示ActivityManagerService当前是不是正在处理其它广播,如果是的话,这里就先不处理直接返回了,保证所有广播串行处理。 注意这里处理广播的方式,它是通过消息循环来处理,每当ActivityManagerService接收到一个广播时,它就把这个广播放进自己的消息队列去就完事了,根本不管这个广播后续是处理的,因此,这里我们可以看出广播的发送和处理是异步的。 这里的成员变量mHandler是一个在ActivityManagerService内部定义的Handler类变量,通过它的sendEmptyMessage函数把一个类型为BROADCAST_INTENT_MSG的空消息放进ActivityManagerService的消息队列中去。这里的空消息是指这个消息除了有类型信息之外,没有任何其它额外的信息,因为前面已经把要处理的广播信息都保存在mParcelBroadcasts中了,等处理这个消息时,从mParcelBroadcasts就可以读回相关的广播信息了,因此,这里不需要把广播信息再放在消息内容中。 **Step 7. Handler.sendEmptyMessage** 这个自定义的Handler类实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中,它是ActivityManagerService的内部类,调用了它的sendEmptyMessage函数来把一个消息放到消息队列后,一会就会调用它的handleMessage函数来真正处理这个消息: ~~~ public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... final Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { ...... case BROADCAST_INTENT_MSG: { ...... processNextBroadcast(true); } break; ...... } } } ...... } ~~~ 这里又调用了ActivityManagerService的processNextBroadcast函数来处理下一个未处理的广播。 **Step 8. ActivityManagerService.processNextBroadcast** 这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中: ~~~ public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final void processNextBroadcast(boolean fromMsg) { synchronized(this) { BroadcastRecord r; ...... if (fromMsg) { mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); ...... final int N = r.receivers.size(); ...... for (int i=0; i ';