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即可。

  

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。