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

来源:互联网 发布:知乎 fade 编辑:程序博客网 时间:2024/05/22 04:55


分类: Android 20543人阅读 评论(34)收藏 举报
androidclassstringnullinteger

        前面我们分析了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发送广播的代码如下所示:

[java] view plaincopy
  1. public class CounterService extends Service implements ICounterService {    
  2.     ......   
  3.   
  4.     public void startCounter(int initVal) {    
  5.         AsyncTask<Integer, Integer, Integer> task = new AsyncTask<Integer, Integer, Integer>() {        
  6.             @Override    
  7.             protected Integer doInBackground(Integer... vals) {    
  8.                 ......    
  9.             }    
  10.   
  11.             @Override     
  12.             protected void onProgressUpdate(Integer... values) {    
  13.                 super.onProgressUpdate(values);    
  14.   
  15.                 int counter = values[0];    
  16.   
  17.                 Intent intent = new Intent(BROADCAST_COUNTER_ACTION);    
  18.                 intent.putExtra(COUNTER_VALUE, counter);    
  19.   
  20.                 sendBroadcast(intent);    
  21.             }    
  22.   
  23.             @Override    
  24.             protected void onPostExecute(Integer val) {    
  25.                 ......   
  26.             }    
  27.   
  28.         };    
  29.   
  30.         task.execute(0);        
  31.     }    
  32.   
  33.     ......  
  34. }  
        在onProgressUpdate函数中,创建了一个BROADCAST_COUNTER_ACTION类型的Intent,并且在这里个Intent中附加上当前的计数器值,然后通过CounterService类的成员函数sendBroadcast将这个Intent发送出去。CounterService类继承了Service类,Service类又继承了ContextWrapper类,成员函数sendBroadcast就是从ContextWrapper类继承下来的,因此,我们就从ContextWrapper类的sendBroadcast函数开始,分析广播发送的过程。

        在继承分析广播的发送过程前,我们先来看一下广播发送过程的序列图,然后按照这个序图中的步骤来一步一步分析整个过程。


点击查看大图

        Step 1. ContextWrapper.sendBroadcast

        这个函数定义在frameworks/base/core/java/android/content/ContextWrapper.java文件中:

[java] view plaincopy
  1. public class ContextWrapper extends Context {  
  2.     Context mBase;  
  3.   
  4.     ......  
  5.   
  6.     @Override  
  7.     public void sendBroadcast(Intent intent) {  
  8.         mBase.sendBroadcast(intent);  
  9.     }  
  10.   
  11.     ......  
  12.   
  13. }  
         这里的成员变量mBase是一个ContextImpl实例,这里只简单地调用ContextImpl.sendBroadcast进一行操作。

         Step 2. ContextImpl.sendBroadcast

         这个函数定义在frameworks/base/core/java/android/app/ContextImpl.java文件中:

[java] view plaincopy
  1. class ContextImpl extends Context {  
  2.     ......  
  3.   
  4.     @Override  
  5.     public void sendBroadcast(Intent intent) {  
  6.         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());  
  7.         try {  
  8.             ActivityManagerNative.getDefault().broadcastIntent(  
  9.                 mMainThread.getApplicationThread(), intent, resolvedType, null,  
  10.                 Activity.RESULT_OK, nullnullnullfalsefalse);  
  11.         } catch (RemoteException e) {  
  12.         }  
  13.     }  
  14.   
  15.     ......  
  16.   
  17. }  
        这里的resolvedType表示这个Intent的MIME类型,我们没有设置这个Intent的MIME类型,因此,这里的resolvedType为null。接下来就调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。

        Step 3. ActivityManagerProxy.broadcastIntent

        这个函数定义在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

[java] view plaincopy
  1. class ActivityManagerProxy implements IActivityManager  
  2. {  
  3.     ......  
  4.   
  5.     public int broadcastIntent(IApplicationThread caller,  
  6.         Intent intent, String resolvedType,  IIntentReceiver resultTo,  
  7.         int resultCode, String resultData, Bundle map,  
  8.         String requiredPermission, boolean serialized,  
  9.         boolean sticky) throws RemoteException  
  10.     {  
  11.         Parcel data = Parcel.obtain();  
  12.         Parcel reply = Parcel.obtain();  
  13.         data.writeInterfaceToken(IActivityManager.descriptor);  
  14.         data.writeStrongBinder(caller != null ? caller.asBinder() : null);  
  15.         intent.writeToParcel(data, 0);  
  16.         data.writeString(resolvedType);  
  17.         data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);  
  18.         data.writeInt(resultCode);  
  19.         data.writeString(resultData);  
  20.         data.writeBundle(map);  
  21.         data.writeString(requiredPermission);  
  22.         data.writeInt(serialized ? 1 : 0);  
  23.         data.writeInt(sticky ? 1 : 0);  
  24.         mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);  
  25.         reply.readException();  
  26.         int res = reply.readInt();  
  27.         reply.recycle();  
  28.         data.recycle();  
  29.         return res;  
  30.     }  
  31.   
  32.     ......  
  33.   
  34. }  
         这里的实现比较简单,把要传递的参数封装好,然后通过Binder驱动程序进入到ActivityManagerService的broadcastIntent函数中。

         Step 4. ctivityManagerService.broadcastIntent

         这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     public final int broadcastIntent(IApplicationThread caller,  
  6.             Intent intent, String resolvedType, IIntentReceiver resultTo,  
  7.             int resultCode, String resultData, Bundle map,  
  8.             String requiredPermission, boolean serialized, boolean sticky) {  
  9.         synchronized(this) {  
  10.             intent = verifyBroadcastLocked(intent);  
  11.   
  12.             final ProcessRecord callerApp = getRecordForAppLocked(caller);  
  13.             final int callingPid = Binder.getCallingPid();  
  14.             final int callingUid = Binder.getCallingUid();  
  15.             final long origId = Binder.clearCallingIdentity();  
  16.             int res = broadcastIntentLocked(callerApp,  
  17.                 callerApp != null ? callerApp.info.packageName : null,  
  18.                 intent, resolvedType, resultTo,  
  19.                 resultCode, resultData, map, requiredPermission, serialized,  
  20.                 sticky, callingPid, callingUid);  
  21.             Binder.restoreCallingIdentity(origId);  
  22.             return res;  
  23.         }  
  24.     }  
  25.   
  26.     ......  
  27. }  
         这里调用broadcastIntentLocked函数来进一步处理。

         Step 5. ActivityManagerService.broadcastIntentLocked

         这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     private final int broadcastIntentLocked(ProcessRecord callerApp,  
  6.             String callerPackage, Intent intent, String resolvedType,  
  7.             IIntentReceiver resultTo, int resultCode, String resultData,  
  8.             Bundle map, String requiredPermission,  
  9.             boolean ordered, boolean sticky, int callingPid, int callingUid) {  
  10.         intent = new Intent(intent);  
  11.   
  12.         ......  
  13.   
  14.         // Figure out who all will receive this broadcast.  
  15.         List receivers = null;  
  16.         List<BroadcastFilter> registeredReceivers = null;  
  17.         try {  
  18.             if (intent.getComponent() != null) {  
  19.                 ......  
  20.             } else {  
  21.                 ......  
  22.                 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);  
  23.             }  
  24.         } catch (RemoteException ex) {  
  25.             ......  
  26.         }  
  27.   
  28.         final boolean replacePending =  
  29.             (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;  
  30.   
  31.         int NR = registeredReceivers != null ? registeredReceivers.size() : 0;  
  32.         if (!ordered && NR > 0) {  
  33.             // If we are not serializing this broadcast, then send the  
  34.             // registered receivers separately so they don't wait for the  
  35.             // components to be launched.  
  36.             BroadcastRecord r = new BroadcastRecord(intent, callerApp,  
  37.                 callerPackage, callingPid, callingUid, requiredPermission,  
  38.                 registeredReceivers, resultTo, resultCode, resultData, map,  
  39.                 ordered, sticky, false);  
  40.             ......  
  41.             boolean replaced = false;  
  42.             if (replacePending) {  
  43.                 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {  
  44.                     if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {  
  45.                         ......  
  46.                         mParallelBroadcasts.set(i, r);  
  47.                         replaced = true;  
  48.                         break;  
  49.                     }  
  50.                 }  
  51.             }  
  52.   
  53.             if (!replaced) {  
  54.                 mParallelBroadcasts.add(r);  
  55.   
  56.                 scheduleBroadcastsLocked();  
  57.             }  
  58.   
  59.             registeredReceivers = null;  
  60.             NR = 0;  
  61.         }  
  62.   
  63.         ......  
  64.   
  65.     }  
  66.   
  67.     ......  
  68. }  
         这个函数首先是根据intent找出相应的广播接收器:
[java] view plaincopy
  1.    // Figure out who all will receive this broadcast.  
  2.    List receivers = null;  
  3.    List<BroadcastFilter> registeredReceivers = null;  
  4.    try {  
  5. if (intent.getComponent() != null) {  
  6.         ......  
  7. else {  
  8.     ......  
  9.     registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);  
  10. }  
  11.    } catch (RemoteException ex) {  
  12. ......  
  13.    }  
        回忆一下前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 6(ActivityManagerService.registerReceiver)中,我们将一个filter类型为BROADCAST_COUNTER_ACTION类型的BroadcastFilter实例保存在了ActivityManagerService的成员变量mReceiverResolver中,这个BroadcastFilter实例包含了我们所注册的广播接收器,这里就通过mReceiverResolver.queryIntent函数将这个BroadcastFilter实例取回来。由于注册一个广播类型的接收器可能有多个,所以这里把所有符合条件的的BroadcastFilter实例放在一个List中,然后返回来。在我们这个场景中,这个List就只有一个BroadcastFilter实例了,就是MainActivity注册的那个广播接收器。

       继续往下看:

[java] view plaincopy
  1. final boolean replacePending =  
  2.   (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。

       再接着往下看:

[java] view plaincopy
  1.   int NR = registeredReceivers != null ? registeredReceivers.size() : 0;  
  2.   if (!ordered && NR > 0) {  
  3. // If we are not serializing this broadcast, then send the  
  4. // registered receivers separately so they don't wait for the  
  5. // components to be launched.  
  6. BroadcastRecord r = new BroadcastRecord(intent, callerApp,  
  7.     callerPackage, callingPid, callingUid, requiredPermission,  
  8.     registeredReceivers, resultTo, resultCode, resultData, map,  
  9.     ordered, sticky, false);  
  10. ......  
  11. boolean replaced = false;  
  12. if (replacePending) {  
  13.     for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {  
  14.         if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {  
  15.             ......  
  16.             mParallelBroadcasts.set(i, r);  
  17.             replaced = true;  
  18.             break;  
  19.         }  
  20.     }  
  21. }  
  22.   
  23. if (!replaced) {  
  24.     mParallelBroadcasts.add(r);  
  25.   
  26.     scheduleBroadcastsLocked();  
  27. }  
  28.   
  29. registeredReceivers = null;  
  30. NR = 0;  
  31.    }  
        前面我们说到,这里得到的列表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文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     private final void scheduleBroadcastsLocked() {  
  6.         ......  
  7.   
  8.         if (mBroadcastsScheduled) {  
  9.             return;  
  10.         }  
  11.   
  12.         mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);  
  13.         mBroadcastsScheduled = true;  
  14.     }  
  15.   
  16.     ......  
  17. }  
        这里的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函数来真正处理这个消息:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     final Handler mHandler = new Handler() {  
  6.         public void handleMessage(Message msg) {  
  7.             switch (msg.what) {  
  8.             ......  
  9.             case BROADCAST_INTENT_MSG: {  
  10.                 ......  
  11.                 processNextBroadcast(true);  
  12.             } break;  
  13.             ......  
  14.             }  
  15.         }  
  16.     }  
  17.   
  18.     ......  
  19. }   
        这里又调用了ActivityManagerService的processNextBroadcast函数来处理下一个未处理的广播。

        Step 8. ActivityManagerService.processNextBroadcast

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     private final void processNextBroadcast(boolean fromMsg) {  
  6.         synchronized(this) {  
  7.             BroadcastRecord r;  
  8.   
  9.             ......  
  10.   
  11.             if (fromMsg) {  
  12.                 mBroadcastsScheduled = false;  
  13.             }  
  14.   
  15.             // First, deliver any non-serialized broadcasts right away.  
  16.             while (mParallelBroadcasts.size() > 0) {  
  17.                 r = mParallelBroadcasts.remove(0);  
  18.                 ......  
  19.                 final int N = r.receivers.size();  
  20.                 ......  
  21.                 for (int i=0; i<N; i++) {  
  22.                     Object target = r.receivers.get(i);  
  23.                     ......  
  24.   
  25.                     deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);  
  26.                 }  
  27.                 addBroadcastToHistoryLocked(r);  
  28.                 ......  
  29.             }  
  30.   
  31.             ......  
  32.   
  33.         }  
  34.     }  
  35.   
  36.     ......  
  37. }  
        这里传进来的参数fromMsg为true,于是把mBroadcastScheduled重新设为false,这样,下一个广播就能进入到消息队列中进行处理了。前面我们在Step 5中,把一个广播记录块BroadcastRecord放在了mParallelBroadcasts中,因此,这里就把它取出来进行处理了。广播记录块BroadcastRecord的receivers列表中包含了要接收这个广播的目标列表,即前面我们注册的广播接收器,用BroadcastFilter来表示,这里while循环中的for循环就是把这个广播发送给每一个订阅了该广播的接收器了,通过deliverToRegisteredReceiverLocked函数执行。

        Step 9. ActivityManagerService.deliverToRegisteredReceiverLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,  
  6.             BroadcastFilter filter, boolean ordered) {  
  7.         boolean skip = false;  
  8.         if (filter.requiredPermission != null) {  
  9.             ......  
  10.         }  
  11.         if (r.requiredPermission != null) {  
  12.             ......  
  13.         }  
  14.   
  15.         if (!skip) {  
  16.             // If this is not being sent as an ordered broadcast, then we  
  17.             // don't want to touch the fields that keep track of the current  
  18.             // state of ordered broadcasts.  
  19.             if (ordered) {  
  20.                 ......  
  21.             }  
  22.   
  23.             try {  
  24.                 ......  
  25.                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,  
  26.                     new Intent(r.intent), r.resultCode,  
  27.                     r.resultData, r.resultExtras, r.ordered, r.initialSticky);  
  28.                 ......  
  29.             } catch (RemoteException e) {  
  30.                 ......  
  31.             }  
  32.         }  
  33.   
  34.     }  
  35.   
  36.     ......  
  37. }  
         函数首先是检查一下广播发送和接收的权限,在我们分析的这个场景中,没有设置权限,因此,这个权限检查就跳过了,这里得到的skip为false,于是进入下面的if语句中。由于上面传时来的ordered参数为false,因此,直接就调用performReceiveLocked函数来进一步执行广播发送的操作了。

        Step 10. ActivityManagerService.performReceiveLocked

        这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

[java] view plaincopy
  1. public final class ActivityManagerService extends ActivityManagerNative  
  2.         implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
  3.     ......  
  4.   
  5.     static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,  
  6.             Intent intent, int resultCode, String data, Bundle extras,  
  7.             boolean ordered, boolean sticky) throws RemoteException {  
  8.         // Send the intent to the receiver asynchronously using one-way binder calls.  
  9.         if (app != null && app.thread != null) {  
  10.             // If we have an app thread, do the call through that so it is  
  11.             // correctly ordered with other one-way calls.  
  12.             app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,  
  13.                     data, extras, ordered, sticky);  
  14.         } else {  
  15.             ......  
  16.         }  
  17.     }  
  18.   
  19.     ......  
  20. }  
        注意,这里传进来的参数app是注册广播接收器的Activity所在的进程记录块,在我们分析的这个场景中,由于是MainActivity调用registerReceiver函数来注册这个广播接收器的,因此,参数app所代表的ProcessRecord就是MainActivity所在的进程记录块了;而参数receiver也是注册广播接收器时传给ActivityManagerService的一个Binder对象,它的类型是IIntentReceiver,具体可以参考上一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 2。

       MainActivity在注册广播接收器时,已经把自己的ProcessRecord记录下来了,所以这里的参数app和app.thread均不为null,于是,ActivityManagerService就调用app.thread.scheduleRegisteredReceiver函数来把这个广播分发给MainActivity了。这里的app.thread是一个Binder远程对象,它的类型是ApplicationThreadProxy,我们在前面介绍应用程序的Activity启动过程时,已经多次看到了,具体可以参考主题Android应用程序的Activity启动过程简要介绍和学习计划。

       Step 11. ApplicationThreadProxy.scheduleRegisteredReceiver
       这个函数定义在frameworks/base/core/java/android/app/ApplicationThreadNative.java文件中:

[java] view plaincopy
  1. class ApplicationThreadProxy implements IApplicationThread {  
  2.     ......  
  3.   
  4.     public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,  
  5.             int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky)  
  6.             throws RemoteException {  
  7.         Parcel data = Parcel.obtain();  
  8.         data.writeInterfaceToken(IApplicationThread.descriptor);  
  9.         data.writeStrongBinder(receiver.asBinder());  
  10.         intent.writeToParcel(data, 0);  
  11.         data.writeInt(resultCode);  
  12.         data.writeString(dataStr);  
  13.         data.writeBundle(extras);  
  14.         data.writeInt(ordered ? 1 : 0);  
  15.         data.writeInt(sticky ? 1 : 0);  
  16.         mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,  
  17.             IBinder.FLAG_ONEWAY);  
  18.         data.recycle();  
  19.     }  
  20.   
  21.     ......  
  22. }  
        这里通过Binder驱动程序就进入到ApplicationThread.scheduleRegisteredReceiver函数去了。ApplicationThread是ActivityThread的一个内部类,具体可以参考Activity启动主题Android应用程序的Activity启动过程简要介绍和学习计划。

        Step 12. ApplicaitonThread.scheduleRegisteredReceiver
        这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

[java] view plaincopy
  1. public final class ActivityThread {  
  2.     ......  
  3.   
  4.     private final class ApplicationThread extends ApplicationThreadNative {  
  5.         ......  
  6.   
  7.         // This function exists to make sure all receiver dispatching is  
  8.         // correctly ordered, since these are one-way calls and the binder driver  
  9.         // applies transaction ordering per object for such calls.  
  10.         public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,  
  11.                 int resultCode, String dataStr, Bundle extras, boolean ordered,  
  12.                 boolean sticky) throws RemoteException {  
  13.             receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);  
  14.         }  
  15.   
  16.         ......  
  17.     }  
  18.   
  19.     ......  
  20.   
  21. }  
        这里的receiver是在前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 4中创建的,它的具体类型是LoadedApk.ReceiverDispatcher.InnerReceiver,即定义在LoadedApk类的内部类ReceiverDispatcher里面的一个内部类InnerReceiver,这里调用它的performReceive函数。

        Step 13. InnerReceiver.performReceive

        这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

[java] view plaincopy
  1. final class LoadedApk {    
  2.     ......   
  3.   
  4.     static final class ReceiverDispatcher {    
  5.   
  6.         final static class InnerReceiver extends IIntentReceiver.Stub {   
  7.             ......  
  8.   
  9.             public void performReceive(Intent intent, int resultCode,  
  10.                     String data, Bundle extras, boolean ordered, boolean sticky) {  
  11.               
  12.                 LoadedApk.ReceiverDispatcher rd = mDispatcher.get();  
  13.                 ......  
  14.                 if (rd != null) {  
  15.                     rd.performReceive(intent, resultCode, data, extras,  
  16.                             ordered, sticky);  
  17.                 } else {  
  18.                     ......  
  19.                 }  
  20.             }  
  21.         }  
  22.   
  23.         ......  
  24.     }  
  25.   
  26.     ......  
  27. }  
         这里,它只是简单地调用ReceiverDispatcher的performReceive函数来进一步处理,这里的ReceiverDispatcher类是LoadedApk类里面的一个内部类。

         Step 14. ReceiverDispatcher.performReceive

         这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

[java] view plaincopy
  1. final class LoadedApk {    
  2.     ......   
  3.   
  4.     static final class ReceiverDispatcher {    
  5.         ......  
  6.   
  7.         public void performReceive(Intent intent, int resultCode,  
  8.                 String data, Bundle extras, boolean ordered, boolean sticky) {  
  9.             ......  
  10.   
  11.             Args args = new Args();  
  12.             args.mCurIntent = intent;  
  13.             args.mCurCode = resultCode;  
  14.             args.mCurData = data;  
  15.             args.mCurMap = extras;  
  16.             args.mCurOrdered = ordered;  
  17.             args.mCurSticky = sticky;  
  18.             if (!mActivityThread.post(args)) {  
  19.                 ......  
  20.             }   
  21.         }  
  22.   
  23.         ......  
  24.     }  
  25.   
  26.     ......  
  27. }  
        这里mActivityThread成员变量的类型为Handler,它是前面MainActivity注册广播接收器时,从ActivityThread取得的,具体可以参考前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 3。这里ReceiverDispatcher借助这个Handler,把这个广播以消息的形式放到MainActivity所在的这个ActivityThread的消息队列中去,因此,ReceiverDispatcher不等这个广播被MainActivity处理就返回了,这里也体现了广播的发送和处理是异步进行的。

        注意这里处理消息的方式是通过Handler.post函数进行的,post函数的参数是Runnable类型的,这个消息最终会调用这个这个参数的run成员函数来处理。这里的Args类是LoadedApk类的内部类ReceiverDispatcher的一个内部类,它继承于Runnable类,因此,可以作为mActivityThread.post的参数传进去,代表这个广播的intent也保存在这个Args实例中。

        Step 15. Hanlder.post

        这个函数定义在frameworks/base/core/java/android/os/Handler.java文件中,这个函数我们就不看了,有兴趣的读者可以自己研究一下,它的作用就是把消息放在消息队列中,然后就返回了,这个消息最终会在传进来的Runnable类型的参数的run成员函数中进行处理。

        Step 16. Args.run

        这个函数定义在frameworks/base/core/java/android/app/LoadedApk.java文件中:

[java] view plaincopy
  1. final class LoadedApk {    
  2.     ......   
  3.   
  4.     static final class ReceiverDispatcher {  
  5.         ......  
  6.   
  7.         final class Args implements Runnable {  
  8.             ......  
  9.   
  10.             public void run() {  
  11.                 BroadcastReceiver receiver = mReceiver;  
  12.   
  13.                 ......  
  14.   
  15.                 Intent intent = mCurIntent;  
  16.                   
  17.                 ......  
  18.   
  19.                 try {  
  20.                     ClassLoader cl =  mReceiver.getClass().getClassLoader();  
  21.                     intent.setExtrasClassLoader(cl);  
  22.                     if (mCurMap != null) {  
  23.                         mCurMap.setClassLoader(cl);  
  24.                     }  
  25.                     receiver.setOrderedHint(true);  
  26.                     receiver.setResult(mCurCode, mCurData, mCurMap);  
  27.                     receiver.clearAbortBroadcast();  
  28.                     receiver.setOrderedHint(mCurOrdered);  
  29.                     receiver.setInitialStickyHint(mCurSticky);  
  30.                     receiver.onReceive(mContext, intent);  
  31.                 } catch (Exception e) {  
  32.                     ......  
  33.                 }  
  34.   
  35.                 ......  
  36.             }  
  37.   
  38.             ......  
  39.         }  
  40.   
  41.         ......  
  42.     }  
  43.   
  44.     ......  
  45. }  
        这里的mReceiver是ReceiverDispatcher类的成员变量,它的类型是BroadcastReceiver,这里它就是MainActivity注册广播接收器时创建的BroadcastReceiver实例了,具体可以参考前面一篇文章Android应用程序注册广播接收器(registerReceiver)的过程分析中的Step 2。

        有了这个ReceiverDispatcher实例之后,就可以调用它的onReceive函数把这个广播分发给它处理了。

        Step 17. BroadcastReceiver.onReceive

        这个函数定义Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中所介绍的Android应用程序Broadcast的工程目录下的src/shy/luo/broadcast/MainActivity.java文件中:

[java] view plaincopy
  1. public class MainActivity extends Activity implements OnClickListener {      
  2.     ......    
  3.   
  4.     private BroadcastReceiver counterActionReceiver = new BroadcastReceiver(){    
  5.         public void onReceive(Context context, Intent intent) {    
  6.             int counter = intent.getIntExtra(CounterService.COUNTER_VALUE, 0);    
  7.             String text = String.valueOf(counter);    
  8.             counterText.setText(text);    
  9.   
  10.             Log.i(LOG_TAG, "Receive counter event");    
  11.         }      
  12.     }  
  13.   
  14.     ......    
  15.   
  16. }  
        这样,MainActivity里面的定义的BroadcastReceiver实例counterActionReceiver就收到这个广播并进行处理了。
        至此,Android应用程序发送广播的过程就分析完成了,结合前面这篇分析广播接收器注册过程的文章Android应用程序注册广播接收器(registerReceiver)的过程分析,就会对Android系统的广播机制且个更深刻的认识和理解了。

        最后,我们总结一下这个Android应用程序发送广播的过程:

        1. Step 1 - Step 7,计数器服务CounterService通过sendBroadcast把一个广播通过Binder进程间通信机制发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;

        2. Step 8 - Step 15,ActivityManagerService在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去,就完成第二阶段对这个广播的异步分发了;

        3. Step 16 - Step 17, ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。

        这样,Android系统广播机制就学习完成了,希望对读者有所帮助。重新学习Android系统的广播机制,请回到Android系统中的广播(Broadcast)机制简要介绍和学习计划一文中。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

21
2
查看评论
18楼 abuseyou2013-01-09 15:45发表 [回复]
关于Step6,Step7有个问题请教一下。假如连续发送2个广播,考虑这样一个Timing,Intent 1在Step6的处理中发完Message使得mBroadcastsScheduled被设置为true,但Step7中的消息队列中该消息还没有被处理。这个时候Intent 2在Step6中的处理中看到mBroadcastsScheduled = true,于是直接返回。我想问的是,当消息队列中Intent 1的那条消息被处理完成使得mBroadcastsScheduled又被设置为false之后,Intent 2是在哪里又能进入Step6的函数重新进行处理,发Message进消息队列呢?
Re: 罗升阳2013-01-09 15:56发表 [回复]
回复abuseyou:mBroadcastsScheduled表示的是一次调度,它的调度队列中有若干过Intent在等待发送,这些Intent都会在当前调度中被处理,因此,你说的Intent2会得到处理。
Re: abuseyou2013-01-09 17:22发表 [回复]
回复Luoshengyang:Step6是由于APP的sendBroadcast调用引发的一连串调用的一环,Intent 2在看到当前有消息再处理时暂时退出Step6,那么Intent 2什么时候才能被放到消息队列呢?毕竟已经调用过了sendBroadCast(intent 2)了,只是当时没有处理。这个地方我看了好久,不太明白。
Re: 罗升阳2013-01-09 19:00发表 [回复]
回复abuseyou:Step 5不是已经放到mParallelBroadcasts里面去了,然后Step 8会将它取出来。
Re: abuseyou2013-01-10 11:42发表 [回复]
回复Luoshengyang:我明白了。由于ActivityManagerService的broadcastIntent()方法里在Synchronize同步块中调用的broadcastIntentLocked()方法,所以我说的那种Intent 1的处理进行到Step 8中mBroadcastsScheduled=false这个语句之前时,Intent 2的处理进入Step6中检查mBroadcastsScheduled从而退出Step6的情况应该不存在。
17楼 androidchuxueze2012-12-22 11:45发表 [回复]
不错,花两天时间总算把广播机制弄明白了
16楼 tianxuexuankui2012-12-13 15:31发表 [回复]
引用“Luoshengyang”的评论:回复tianxuexuankui:你是说运行在PC上的Java程序么?如果...

嗯,是在PC段执行的程序,我想在java中潜入cmd命令或者是socket通信之类的是否可以实现发送broadcast给手机,让手机端接收这个命令,进行相关的操作。
Re: tianxuexuankui2012-12-13 15:33发表 [回复]
回复tianxuexuankui:最近在做一个项目,里面可能会需要相类似的操作。我的联系方式:QQ975398325.希望罗老师能够给予指导,也很欢迎给位朋友加我好友一起研究。
15楼 tianxuexuankui2012-12-13 15:16发表 [回复]
老罗你好,我想问个问题,就是在java程序中能否向手机发送Broadcast,然后在手机端安装一个写好的带有BroadcastReceiver的程序进行接收,然后进行相关的操作呢?
Re: 罗升阳2012-12-13 15:25发表 [回复]
回复tianxuexuankui:你是说运行在PC上的Java程序么?如果是的话,你只能通过网络来接收。。。
14楼 pentiumchen2012-10-31 14:17发表 [回复]
罗老师,看了你的分析收获很大,但是还有一点我不是很理解,就是android的广播适用于哪些应用场景,按照我的理解,您据的那个计数器的例子,如果没有跨进程的话用一个最简单的监听者模式就可以实现了,广播涉及到了远程调用有些性能消耗,广播是不是只适用跨进程的情况?
Re: 罗升阳2012-10-31 14:26发表 [回复]
回复pentiumchen:广播一般用作事件通知,一般是一些全局性的事件通知,可以在不同模块或者不同进程之间进行。广播一般包含有两个直接的角色,一个叫做生产者,另一个叫消费者。这种事件通知的最大好处是生产者所在的模块和消费者所在的模块是非常松耦合的,即生产者不需要知道消费者的存在,而消费者也不需要知道生产者的存在。这样对系统来说,就好维护和扩展。当然,从它的实现角度来说,也是基于binder来实现的,同时有一个服务来维护生产者和消费者的关系。
13楼 yhh51582012-09-28 17:49发表 [回复]
广播发送者如何能有选择性的去设置发送给广播接受者呢?
Re: 罗升阳2012-09-30 15:22发表 [回复]
回复yhh5158:可以的,调用Intent的setComponent方法来指定。
12楼 shangyu08012012-07-11 14:51发表 [回复]
厉害,顶一下。
11楼 songjam2012-06-20 17:09发表 [回复]
写得很详细,看代码在Step 16. Args.run在执行完onReceive之后,好像还要通知AMS,本Receiver处理完成,作为Step 18咋样?
Re: 罗升阳2012-06-20 17:43发表 [回复]
回复songjam:如果是有序广播,接收完之后需要向AMS发一个回包,以便AMS可以将这个有序广播发送给下一个广播接收者。这一步可以作为Step 18继续分析下去。
10楼 a060631752012-06-06 11:35发表 [回复]
能收到您的回复很激动啊,呵呵,找到了。您说的很对
broadcastIntentLocked方法中的mReceiverResolver.queryIntent方法,就是
frameworks\base\services\java\com\android\server\IntentReslover.java 里的queryIntent(),其中有调用了sortResults(finalList);最后是:
protected void sortResults(List<R> results) {
Collections.sort(results, mResolvePrioritySorter);
}
不知道我找的对不对。之前把frameworks中含有Collections.sort的文件都搜了一遍都没找到,真是思路有大问题,衷心的感谢您!
Re: Sailent2012-06-08 20:32发表 [回复]
回复a06063175:官方说优先级的设置范围是-1000到1000,但是源码中好像没看到有这个限制,仅仅是2个int型在做比较,实际的优先级范围应该是+-2147483647吧?
另外,那2个列表合并的代码在哪里啊?
Re: a060631752012-06-09 11:01发表 [回复]
回复Sailent:对啊,我就是想给这个方法一个可能的解释,或者是其运行流程。目前对这块掌握还不是很有把握,再看看
Re: 罗升阳2012-06-09 00:03发表 [回复]
回复Sailent:在Step 5中,不过这篇文章没有把这部分代码贴出来。
Re: 罗升阳2012-06-06 13:27发表 [回复]
回复a06063175:对于有序广播来说,ActivityManagerService.broadcastIntentLocked是这样处理的:
1. 找到静态注册的广播接收者,存在有一个列表里面,并且已经是按照优先级排好序了的。
2. 找到动态注册的广播接收者,也是存在一个列表里面,也是已经按照优先级排好序了的。
3. 对上面两个列表的广播接收者进行合并,合并的规则是优先级高的排在前面,优先级低的排在后面。如果一个静态注册的广播接收者的优先级和一个动态注册的广播接收者的优先级一样,那么动态注册的广播接收者排在前面。
对所有的广播接收者排好序之后,就可以依次把广播发送它们了。