zoukankan      html  css  js  c++  java
  • Andriod广播注册接收过程简析

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

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

       1 广播 - 用于发送广播

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

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

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

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

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

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

            

                                                 图1 注册广播流程简图

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

      需要注意的是:

     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://www.cnblogs.com/tearaway/archive/2013/05/23/3094070.html

  • 相关阅读:
    java fork/join简单实践
    java 中的字符串处理--正则表达式
    那些年,我们追过的java8
    openssl与java(读取加密码的密钥)
    SpringMVC 常用注解的使用和解释
    Spring 常用注解的使用
    java web 一次请求编码设置的过程
    Spring让程序生成程序
    设置session超时的三种方式
    为什么 cookie.getMaxAge() 总是得到 -1 ?
  • 原文地址:https://www.cnblogs.com/dongye/p/3645811.html
Copyright © 2011-2022 走看看