Android广播发送流程中的强停应用判断源码分析

  在Android3.1之后,强停的应用不再能接收系统广播,而是否能接收第三方应用的广播则取决于广播发送方是否允许你接收,下面我们从Android源码中来看一下这些具体是如何实现的:

  当我们使用自定义的Activity或者Service的成员函数sendBroadcast将这个Intent发送出去。自定义的Activity类(或自定义Service类)继承了Activity类(或Service 类),Activity类(或Service 类)又继承了ContextWrapper类,成员函数sendBroadcast就是从ContextWrapper类继承下来的,因 此,我们就从ContextWrapper类的sendBroadcast函数开始,分析广播发送的过程。

  step1、ContextWrapper.sendBroadcast

  Context mBase;
  public ContextWrapper(Context base) {
    mBase = base;
  }

  @Override

  public void sendBroadcast(Intent intent) {
       mBase.sendBroadcast(intent);

  }

  这里Context mBase 是ContextImpl的一个实例,因此直接调用ContextImpl.sendBroadcast(intent);

  step2、ContextImpl.sendBroadcast

  @Override
  public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
      intent.prepareToLeaveProcess();
      ActivityManagerNative.getDefault().broadcastIntent(
      mMainThread.getApplicationThread(), intent, resolvedType, null,
      Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,
      getUserId());
    } catch (RemoteException e) {
    }
  }

  对Android Binder机制比较熟悉的朋友一下就能看出该段代码调用ActivityManagerService的远程接口ActivityManagerProxy把这个广播发送给ActivityManagerService了。

  step3、ActivityManagerService.broadcastIntent

  public final int broadcastIntent(IApplicationThread caller,
    Intent intent, String resolvedType, IIntentReceiver resultTo,
    int resultCode, String resultData, Bundle map,
    String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    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, appOp, serialized, sticky,
        callingPid, callingUid, userId);
      Binder.restoreCallingIdentity(origId);
      return res;
    }
  }

  这里获取调用者的pid,uid等,并作为参数传给broadcastIntentLocked,与我们的讨论没有关系,继续往下看。

  step4、ActivityManagerService.broadcastIntentLocked

  private final int broadcastIntentLocked(ProcessRecord callerApp,
    String callerPackage, Intent intent, String resolvedType,
    IIntentReceiver resultTo, int resultCode, String resultData,
    Bundle map, String requiredPermission, int appOp,
    boolean ordered, boolean sticky, int callingPid, int callingUid,
    int userId) {
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    ......

  }

  这里给intent添加FLAG_EXCLUDE_STOPPED_PACKAGES的flag,意义很好理解:排除已强停的应用(不给强停应用发广播)。

继续往下看:

  private final int broadcastIntentLocked(ProcessRecord callerApp,
    String callerPackage, Intent intent, String resolvedType,
    IIntentReceiver resultTo, int resultCode, String resultData,
    Bundle map, String requiredPermission, int appOp,
    boolean ordered, boolean sticky, int callingPid, int callingUid,
    int userId) {
    ......

    if (intent.getComponent() == null) {
      registeredReceivers = mReceiverResolver.queryIntent(intent,
        resolvedType, false, userId);
    }

    ......

  }

  上面的mReceiverResolver.queryIntent是根据intent找出相应的广播接收器,这里面就包含了是否给强停应用发广播的过滤判断。

  step5、IntentResolver.queryIntent

  public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
    int userId) {

    ......

    FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
    if (firstTypeCut != null) {
      buildResolveList(intent, categories, debug, defaultOnly,
        resolvedType, scheme, firstTypeCut, finalList, userId);
    }
    if (secondTypeCut != null) {
      buildResolveList(intent, categories, debug, defaultOnly,
        resolvedType, scheme, secondTypeCut, finalList, userId);
    }
    if (thirdTypeCut != null) {
      buildResolveList(intent, categories, debug, defaultOnly,
        resolvedType, scheme, thirdTypeCut, finalList, userId);
    }
    if (schemeCut != null) {
      buildResolveList(intent, categories, debug, defaultOnly,
      resolvedType, scheme, schemeCut, finalList, userId);
    }

    ......

  }

  根据关键字过滤集合调用buildResolveList查询相应的receiver,并最后合成返回的receiver列表。

  private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
    boolean debug, boolean defaultOnly,
    String resolvedType, String scheme, F[] src, List<R> dest, int userId) {

    ......

    final boolean excludingStopped = intent.isExcludingStopped();

    ......

    for (i=0; i<N && (filter=src[i]) != null; i++) {
      int match;
      if (debug) Slog.v(TAG, "Matching against filter " + filter);

      if (excludingStopped && isFilterStopped(filter, userId)) {
        if (debug) {
        Slog.v(TAG, "  Filter‘s target is stopped; skipping");
        }
      continue;
    }

    ......

  }

  如果excludingStopped为true,并且检测到应用为强停状态就continue。检测应用强停状态调用isFilterStopped,在IntentResolver中有一个默认实现为返回false。它的具体实现有3处:ActivityIntentResolver.isFilterStopped, ProviderIntentResolver.isFilterStopped, ServiceIntentResolver.isFilterStopped。这3处实现没有任何区别,就是根据uid判断应用是否强停。

  excludingStopped 通过Intent的isExcludingStopped方法获得:

  public boolean isExcludingStopped() {
    // 两个标志位都不设置或者两个标志位都设置,返回false,即不排除强停应用,就需要给强停应用发广播
    // 只设置FLAG_EXCLUDE_STOPPED_PACKAGES时,返回true,即排除已强停应用
    return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))
      == FLAG_EXCLUDE_STOPPED_PACKAGES;
  }

  由于ActivityManagerService默认添加了FLAG_EXCLUDE_STOPPED_PACKAGES,所以通常情况下已强停应用不能收到广播;要向已强停应用发广播,给Intent添加flag:FLAG_INCLUDE_STOPPED_PACKAGES即可。

  

时间: 2024-10-05 23:24:45

Android广播发送流程中的强停应用判断源码分析的相关文章

java中的==、equals()、hashCode()源码分析(转载)

在java编程或者面试中经常会遇到 == .equals()的比较.自己看了看源码,结合实际的编程总结一下. 1. ==  java中的==是比较两个对象在JVM中的地址.比较好理解.看下面的代码: 1 public class ComAddr{ 2 public static void main(String[] args) throws Exception { 3 String s1 = "nihao"; 4 String s2 = "nihao"; 5 Str

Android研发中对String的思考(源码分析)

1.常用创建方式思考: String text = "this is a test text "; 上面这一句话实际上是执行了三件事 1.声明变量 String text; 2.在内存中开辟空间 (内存空间一) 3.将变量的text的引用指向开辟的内存空间 当有 text = "this is a change text"; 这一句话执行了两件事 1.在内存中开辟空间 2.将变量text 的引用指向 新开辟的内存空间 3.内存空间一此时依然存在,这就是说明了Stri

Android逆向之旅---反编译利器Apktool和Jadx源码分析以及错误纠正

一.前言 在之前的破解过程中可以看到我们唯一离不开的一个神器那就是apktool了,这个工具多强大就不多说了,但是如果没有他我们没法涉及到后面的破解工作了,这个工具是开源的,也是使用Java语言开发的,代码相对简单,我们今天就来分析一下他的大体逻辑,注意是大体逻辑哦,因为如果要一行一行代码分析,首先觉得没必要,其次浪费时间,有了源码,谁看不懂呢.至于为什么要分析这个工具其实原因只有一个,就是我们在之前的反编译过程中会发现,总是有那么几个apk应用不让我们那么容易的反编译,他们就利用apktool

详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析] good

目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口的具体应用 常用HandlerMethodArgumentResolver介绍 常用HandlerMethodReturnValueHandler介绍 本文开头现象解释以及解决方案 编写自定义的HandlerMet

【MVC - 参数原理】详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]

前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门blog:http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html SpringMVC中Controller的方法参数可以是Integer,Double,自定义对象,ServletRequest,ServletResponse,ModelAndView等等,非常灵活.本文将分析SpringMVC是如何对这些参数进行处理的,

2、JDK8中的HashMap实现原理及源码分析

本篇提纲.png 本篇所述源码基于JDK1.8.0_121 在写上一篇线性表的文章的时候,笔者看的是Android源码中support24中的Java代码,当时发现这个ArrayList和LinkedList的源码和Java官方的没有什么区别,然而在阅读HashMap源码的时候,却发现Android中的Java与官方版的出入略大,遂不得不转而用Eclipse导入jdk源码阅读,这里不得不吐槽一句,用惯了IDEA的快捷键,Eclispe还真是用不习惯~~好了,接下来我们言归正传: 一.什么是Has

Java并发包中Semaphore的工作原理、源码分析及使用示例

1. 信号量Semaphore的介绍 我们以一个停车场运作为例来说明信号量的作用.假设停车场只有三个车位,一开始三个车位都是空的.这时如果同时来了三辆车,看门人允许其中它们进入进入,然后放下车拦.以后来的车必须在入口等待,直到停车场中有车辆离开.这时,如果有一辆车离开停车场,看门人得知后,打开车拦,放入一辆,如果又离开一辆,则又可以放入一辆,如此往复. 在这个停车场系统中,车位是公共资源,每辆车好比一个线程,看门人起的就是信号量的作用.信号量是一个非负整数,表示了当前公共资源的可用数目(在上面的

JDK1.8中ArrayList的实现原理及源码分析

一.概述 ArrayList是Java开发中使用比较频繁的一个类,通过对源码的解读,可以了解ArrayList的内部结构以及实现方法,清楚它的优缺点,以便我们在编程时灵活运用. 二.源码分析 2.1 类结构 JDK1.8源码中的ArrayList类结构定义如下: public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Se

Android图片异步加载框架Universal Image Loader的源码分析

项目地址:https://github.com/nostra13/android-universal-image-loader 1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL. 简单的说 UIL 就做了一件事--获取图片并显示在相应的控件上. 1.2 基本使用 1.2.1 初始化 添加完依赖后在Application或Activity中初始化I