打印BroadcastReceiver的所有接受者

Android中收到短信等事件都是通过广播发送给应用程序的,手机卫士等程序都是通过注册高优先级的BroadcastReceiver来实现短信防火墙等功能。对于我们来说很想知道系统中都有哪些程序注册了BroadcastReceiver,但是通过什么方法能获取系统BroadcastReceiver的列表呢?

我在群里问了一下,他们告诉我的答案居然是分析所有apk的AndroidManifest.xml,再加上解析dex里面的动态注册!而这根本不是我想达到的目的,我要知道的是目前系统中实时的BroadcastReceiver,而不是通过静态分析得到。于是我开始看Android Framework代码,想搞清楚广播的实现机制到底是怎样的。

注册BroadcastReceiver的过程是这样的:Activity调用registerReceiver,然后经过几层内部类接口的调用之后,通过Binder机制与ActivityManagerService通信,而ActivityManagerService里有一个ReceiverList保存着系统所有的BroadcastReceiver。

发送广播的过程是:Activity向ActivityManagerService发送广播,ActivityManagerService查找ReceiverList,通过比对IntentFilter找到所有对应的BroadcastReceiver,根据BroadcastReceiver的优先级进行排序后,扔进广播发送队列里。而后由专门的线程负责投递广播消息。

大致的过程就是这样的,那么目标就是获取ActivityManagerService中的ReceiverList。一开始我想的办法是:因为ActivityManagerService是一个单独的进程(system_server),我们可以通过注入system_server进程来获得ReceiverList。但是由于ActivityManagerService是java实现的,无法直接获得ReceiverList,要解析java的数据结构难度就太大了。

于是又再次查看
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<BroadcastFilter> 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;
    }

    ......

  }

  ......
}

代码:

registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); 

到frameworks\base\services\java\com\android\server\IntentReslover.java中,注意到一个特性:

代码:

public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) {
        String scheme = intent.getScheme();

        ArrayList<R> finalList = new ArrayList<R>();

        final boolean debug = localLOGV ||
                ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0);

        if (debug) Slog.v(
            TAG, "Resolving type " + resolvedType + " scheme " + scheme
            + " of intent " + intent);
       sortResults(finalList);
       ............
        if (debug) {
            Slog.v(TAG, "Final result list:");
            for (R r : finalList) {
                Slog.v(TAG, "  " + r);
            }
        }
        return finalList;
    }

这个有个debug选项可以打印出最终获得的ReceiverList,还是按照优先级排过序的有木有?

于是乎获取接收器列表就太简单了,只需要三行代码即可:

代码:

 Intent intent = new Intent("android.provider.Telephony.SMS_RECEIVED"); intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION);
 sendBroadcast(intent);

重点就是第二句,设置了FLAG_DEBUG_LOG_RESOLUTION,这样就会在LogCat中打印出所有注册了android.provider.Telephony.SMS_RECEIVED的BroadcastReceiver。用IntentResolver作为TAG过滤一下看起来更方便:

时间: 2024-11-08 21:28:30

打印BroadcastReceiver的所有接受者的相关文章

解决在BroadcastReceiver(广播接受者)中不能添加AlertDialog(对话框)的问题(android.view.WindowManager$BadTokenException)

在BroadcastReceiver,当我们创建一个AlertDialog并show出来的时候,出现了下面的错误: 12-24 14:10:57.025: E/AndroidRuntime(17600): java.lang.RuntimeException: Unable to start receiver com.ustc.broadcastreceiver.ForceOfflineReceiver: android.view.WindowManager$BadTokenException:

入门篇:8.组件3:BroadcastReceiver

广播类似于activity和service,同样是android中的基本组件.作为开发者,只需要掌握广播接受者,不必去理解其底层的机制 1.Broadcast(广播)和BroadcastReceiver(广播接受者) 广播是一种广泛运用在应用程序之间传输信息的机制.而广播接受者是对发送出来的广播进行过滤接收并相应的一类组件,它用于接收来自系统和应用中的广播 用途: 开机完成系统会发出一条广播 网络状态发生改变时体统发出一条广播 电池电量改变时,系统发出一条广播. 2.广播接受者的生命周期 广播接

史上最详细 最基础的 android 面试 知识点总结(一)

1. 什么是Activity ? 这样的问题 回答的时候 ,首先 Activity 是 四大组件之一,是一个view 对象的容器,可以用来展现一个界面,通过 setcontentView() ,//方法来 设置要显示的布局 activity  是 上下文对象 Context的子类 同时 实现了 window.callback 和 keyevent.callback 这两个接口, 所以 activity 可以响应 与处理 窗体与用户的交互事件,以及与键盘相关的事件.(Context  上下文对象,

Android系统架构概述

目录: 1.Android系统架构 2.Android类库 3.四大组件 ----------------------------------------------------------------------- 1.Android系统架构 从架构图看出架构分为五个部分,由下往上依次为: Linux Kernel:Android基于Linux提供核心系统服务,例如:安全.内存管理.进程管理.网络堆栈.驱动模型.Linux Kernel也作为硬件和软件之间的抽象层,它隐藏具体g硬件细节而为上层

BroadcastReceiver接收电量变化的广播-------在代码中动态创建接受者

本例为动态创建广播接收者即不是在AndroidManifest.xml文件中定义的广播接收着 代码: 1 package com.qf.broadcastreceiver01; 2 3 import android.app.Activity; 4 import android.app.AlertDialog; 5 import android.content.BroadcastReceiver; 6 import android.content.Context; 7 import android

第五十九讲:四大组件之BroadcastReceiver(二)

没有任何动物比蚂蚁更勤奋,然而它却最沉默寡言. 本讲内容: Broadcast Receiver 广播接收者的使用 上一讲我们讲解了一个接收者来接收广播,如果有多个接收者都注册了相同的广播地址,又会是什么情况呢,这就涉及到普通广播和有序广播的概念了. 一.普通广播(Normal Broadcast) 普通广播对于多个接收者来说是完全异步的,通常每个接收者都无需等待即可以接收到广播,接收者相互之间不会有影响.对于这种广播,接收者无法终止广播,即无法阻止其他接收者的接收动作. 我们新建二个Broad

第六十讲:四大组件之BroadcastReceiver(三)

如果把生活比喻为创作的意境,那么阅读就像阳光. 本讲内容:举几个常见的例子加深一下对BroadcastReceiver广播的理解和应用: 一.开机启动服务 我们经常会有这样的应用场合,比如消息推送服务,需要实现开机启动的功能.要实现这个功能,我们就可以订阅系统"启动完成"这条广播,接收到这条广播后我们就可以启动自己的服务了.我们来看一下BootCompleteReceiver和MsgPushService的具体实现: public class BootCompleteReceiver

基础总结篇之五:BroadcastReceiver应用详解

問渠那得清如許?為有源頭活水來.南宋.朱熹<觀書有感> 据说程序员是最爱学习的群体,IT男都知道,这个行业日新月异,必须不断地学习新知识,不断地为自己注入新鲜的血液,才能使自己跟上技术的步伐. 今天我们来讲一下Android中BroadcastReceiver的相关知识. BroadcastReceiver也就是“广播接收者”的意思,顾名思义,它就是用来接收来自系统和应用中的广播. 在Android系统中,广播体现在方方面面,例如当开机完成后系统会产生一条广播,接收到这条广播就能实现开机启动服

学习 BroadcastReceiver

广播分2种 sendBroadcast,sendOrderedBroadcast分别 为有序广播和无序广播. 广播是四大组件之一需要在清单文件中配置. 使用无序广播 发广播: public void click(View view){ //发送一个自定义的广播. Intent intent = new Intent(); intent.setAction("com.lxcay.mybroadcast.xxx"); sendBroadcast(intent);//发送一条无序广播 } 接