Andriod广播注册接收过程简析

  为了利于各个进程应用之间的通讯,android提供了一个很方便的处理方式:广播机制。广播机制顾名思义,就是广播发送者无需判断具体某个接收者的存在,把广播发送出去,任务即完成。这样保证了有效通讯的同时又最大限度的下降了android系统各个模块的耦合性。

Android广播有两个很重要的要素: android

   1 广播 - 用于发送广播 app

         有序广播  -  被广播接收器接收后,可被终止,没法往下继续传达。         典型表明:短信广播 ui

         普通广播  -  发送至每个已经注册(订阅)的广播接收器,没法被终止。 典型表明:开机启动广播 this

   2 广播接收器 - 用于订阅广播后接收广播 spa

         静态注册广播 - 在AndroidManifest.xml中设置,程序不用启动亦可接收。 典型表明:不少开机启动的APP,都是接收开机启动广播带起服务的。 rest

         动态注册广播 - 代码中注册广播,程序未启动时,没法接收广播。             典型表明:Go短信,将Go短信强行中止,Go短信没法接收短信。 code

广播注册过程和接收广播顺序过程 component

       

                                             图1 注册广播流程简图 xml

    静态广播接收器 由PackageManagerService负责,当手机启动时(或者新安装了应用),PackageManagerService负责扫描手机中全部已安装的APP应用(题外话,肯定再也不使用的APP须要卸载了),将AndroidManifest.xml中 有关注册广播的信息 解析出来,存储至一个全局静态变量当中 mReceiversblog

  须要注意的是:

1 PackageManagerService扫描目录的顺序以下:

  system/framework

  system/app

  vendor/app

  data/app

  drm/app-private

  2 当处于同一目录下时:按照file.list()的返回顺序。(题外话:由于在data/app下的应用都是用户安装的,而且都是以com.xxx.xxx-1.apk 的形式出现,因此若是打算作手机管家之类的应用,须要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)

   3 在此处并未对 接收顺序作完整的排序。(注意修饰词完整的,毕竟先扫描的固然会有必定优先级)

    动态广播接收器 由ActivityManagerService负责,当APP的服务或者进程起来以后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个全局静态变量

mReceiverResolver中。

    须要注意的是:

    1 这个并不是是一成不变的,当程序被杀死以后,  已注册的动态广播接收器也会被移出mReceiverResolver,直到下次程序启动,再进行动态广播的注册,固然这里面的顺序也已经变动了一次。

    2  这里也并没完整的进行广播的排序,只记录的注册的前后顺序,并未有结合优先级的处理。

当有广播发出时,接收顺序以下:

                                                  图2 广播接收流程简图
   在ActivityManagerService处理广播,当广播为有序广播时,将动态广播接收器和动态广播接收器合并起来,造成最终的有序广播接收顺序。
   上述的 规则1排序为:
                                1 优先级高的先接收
                                2 同优先级的动静态广播接收器,动态优先于静态
                                3 同优先级的动态广播接收器  或者同优先级的静态广播接收器,按照图1 的流程注册顺序。
                                   即静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。
 
   当广播为普通广播时, 规则2排序为:
                                1 无视优先级,动态广播接收器优先于静态广播接收器
                                2 同 规则1排序的第3点

接下来请看代码以片断:

复制代码

 1 private final int broadcastIntentLocked(ProcessRecord callerApp,  2  String callerPackage, Intent intent, String resolvedType,  3 IIntentReceiver resultTo, int resultCode, String resultData,  4  Bundle map, String requiredPermission,  5 boolean ordered, boolean sticky, int callingPid, int callingUid) {  6  7  …………  8  …………  9  10 // 静态广播接收器list  11 List receivers = null;  12  13 // 动态广播接收器List  14 List<BroadcastFilter> registeredReceivers = null;  15  16 // 获取静态广播接收器mReceivers  17 try {  18 if (intent.getComponent() != null) {  19 // Broadcast is going to one specific receiver class...   20 ActivityInfo ai = AppGlobals.getPackageManager().  21  getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);  22 if (ai != null) {  23 receivers = new ArrayList();  24 ResolveInfo ri = new ResolveInfo();  25 ri.activityInfo = ai;  26  receivers.add(ri);  27  }  28 } else {  29 // Need to resolve the intent to interested receivers...   30 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)  31 == 0) {  32 receivers =  33  AppGlobals.getPackageManager().queryIntentReceivers(  34  intent, resolvedType, STOCK_PM_FLAGS);  35  }  36 // 获取动态广播接收器mReceiverResolver  37 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);  38  }  39 } catch (RemoteException ex) {  40 // pm is in same process, this will never happen.   41  }  42  43 final boolean replacePending =  44 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;  45  46 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;  47  ……  48 // 若是接收到的广播 是普通广播。  49 if (!ordered && NR > 0) {  50 // If we are not serializing this broadcast, then send the  51 // registered receivers separately so they don't wait for the  52 // components to be launched.   53 BroadcastRecord r = new BroadcastRecord(intent, callerApp,  54  callerPackage, callingPid, callingUid, requiredPermission,  55  registeredReceivers, resultTo, resultCode, resultData, map,  56 ordered, sticky, false);  57  58 // 很明显接收到普通广播以后,在这只处理了动态广播 registeredReceivers,对于普通广播而言,动态广播接收器要优先于静态广播接收器 无关设置的优先级  59 boolean replaced = false;  60 if (replacePending) {  61 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {  62 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {  63 if (DEBUG_BROADCAST) Slog.v(TAG,  64 "***** DROPPING PARALLEL: " + intent);  65  mParallelBroadcasts.set(i, r);  66 replaced = true;  67 break;  68  }  69  }  70  }  71 if (!replaced) {  72  mParallelBroadcasts.add(r);  73  scheduleBroadcastsLocked();  74  }  75 //将registeredReceivers置为null,后面只处理静态广播接收器,因此不会有冲突。  76 registeredReceivers = null;  77 NR = 0;  78  }  79  80 //若是是有序广播,将静态广播接收器和动态广播接收器组合成一个最终的顺序  81 int ir = 0;  82 if (receivers != null) {  83  ...  84 //合并的过程,注意顺序   85 int NT = receivers != null ? receivers.size() : 0;  86 int it = 0;  87 ResolveInfo curt = null;  88 BroadcastFilter curr = null;  89 while (it < NT && ir < NR) {  90 if (curt == null) {  91 curt = (ResolveInfo)receivers.get(it);  92  }  93 if (curr == null) {  94 curr = registeredReceivers.get(ir);  95  }  96 //若是动态广播接收器优先级高于或者等于静态广播接收器,那么就插到前面  97 //很明显动态的要在静态的前面   98 if (curr.getPriority() >= curt.priority) {  99 // Insert this broadcast record into the final list.  100  receivers.add(it, curr); 101 ir++; 102 curr = null; 103 it++; 104 NT++; 105 } else { 106 // Skip to the next ResolveInfo in the final list.  107 it++; 108 curt = null; 109  } 110  } 111 }

复制代码


最后举个例子:

(如下的静A 表示静态广播接收器,同理动B。)

1 静A (优先级1)

2 动B(优先级1)

3 静C (优先级2,后扫描)

4 静D (优先级2,先扫描)

5 动E   (优先级2,先注册)

6 动F  (优先级2,后注册)

当来了一个 有序广播,接收顺序以下:动E >  动F  > 静D > 静C > 动B > 静A

当来了一个 普通广播,接收顺序以下:动E >  动F  > 动B > 静D > 静C > 静A

参考文章:http://su1216.iteye.com/blog/1776121

相关文章
相关标签/搜索