【ActivityManagerService】Android 广播拉起后台进程那些事

  Android 8.0 版本以后,在Manifest中静态注册的广播基本都被禁用了,第三方应用通过AndroidManifest.xml 监听系统广播拉起自身进程的情况被大大抑制,但依然有例外情况:

  • BOOT_COMPLETE 广播可以拉起应用;
  • TIME_SET 广播可以拉起应用;

  安卓官方提供了隐式广播(Implicit Broadcast)例外情况的列表。
  本文主要分析广播如何能拉起应用的流程,以便对第三方应用后台静默启动加以管控。

1. Android 系统发送广播流程分析

【ActivityManagerService】Android 广播拉起后台进程那些事_第1张图片
broadcast.png

  Android系统发送广播的基本流程如上图所示:

  • 客户端进程通过contenxt.sendBroadCast 接口发送广播;具体实现在ContextImpl中;
  • ContextImpl.sendBroadCast 通过AMS的binder 接口,最终调用broadcastIntentLocked方法发送广播。
  • broadcastIntentLocked 是个上千行的复杂方法,基本任务是要确定广播是发送并行广播还是串行广播,并行和串行对应者BroadcastQueue的两个广播队列。
  • 如果接收端是动态注册的广播,默认走并行广播队列,效率高;
  • 否则走ordered 串行广播队列,判断权限,判断是否需要拉起进程;
  • 需要注意的是,客户端不使用contenxt.sendOrderedBroadCast接口,也可能走BroadcastQueue的Ordered broadcast流程。
  • 如果需要实例化客户端进程,BroadcastQueue通过Ams的startProcessLocked接口拉起第三方进程。

2. AMS对隐式广播的限制

  在上述流程中,在 BroadcastQueue.processNextBroadcast 过程中对隐式广播加以限制:

  • 如果广播包含 Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND,直接拒绝发送;
Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND
  • 如果广播不包含接受者信息,并且没有声明为 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND,也拒绝发送。
 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
 (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
        || (r.intent.getComponent() == null
            && r.intent.getPackage() == null
            && ((r.intent.getFlags()
                    & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
            && !isSignaturePerm(r.requiredPermissions))) {
    mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
            component.getPackageName());
    Slog.w(TAG, "Background execution not allowed: receiving "
            + r.intent + " to "
            + component.flattenToShortString());
    skip = true;
}

3. AMS对STOPPED_PACKAGE的限制

  PackageManagerService中,对每一个app维护一个stopped标志位,AMS force-stop 强制关闭的应用也会被标记上stopped,应用启动过以后会清除这个标志位。

adb shell am force-stop com.package.name

  AMS对stopped package 也有接收广播的限制。
  AMS 在 broadcastIntentLocked 调用开始,对每一个Intent都设置了FLAG_EXCLUDE_STOPPED_PACKAGES,只有当 FLAG_INCLUDE_STOPPED_PACKAGES 标志也被设置的时候,Intent状态才能生效。

    /**

     * If set, this intent will not match any components in packages that

     * are currently stopped.  If this is not set, then the default behavior

     * is to include such applications in the result.

     */

    public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010;

    /**

     * If set, this intent will always match any components in packages that

     * are currently stopped.  This is the default behavior when

     * {@link #FLAG_EXCLUDE_STOPPED_PACKAGES} is not set.  

If both of these

     * flags are set, this one wins (it allows overriding of exclude for

     * places where the framework may automatically set the exclude flag).

     */

    public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;

IntentFilter 使用如下方法判断是否需要把stopped package排除在外。

    public boolean isExcludingStopped() {

        return (mFlags & 

(FLAG_EXCLUDE_STOPPED_PACKAGES | FLAG_INCLUDE_STOPPED_PACKAGES ) ) == FLAG_EXCLUDE_STOPPED_PACKAGES;

    }
/**

     * Set whether the given package should be considered stopped, making

     * it not visible to implicit intents that filter out stopped packages.

     */

public void setPackageStoppedState(java.lang.String packageName, boolean stopped, int userId) throws android.os.RemoteException;

4. android.intent.action.TIME_SET 广播的发送流程

  AlarmManagerService中的AlarmThread开机启动监控线程,当系统时间变化时,kernel通知此线程发送TIME_SET 广播:

Intent intent = new Intent(Intent.ACTION_TIME_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
                               |Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
                               |Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                               |Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
getContext().sendBroadcastAsUser(intent, UserHandle.ALL);

Intent.FLAG_RECEIVER_REPLACE_PENDING 替换队列中之前的广播
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT BOOT_COMPLETE 之前也注册的receiver也能收到广播
Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 后台应用可以被拉起
Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS INSTANT_APPS 可以被拉起。
所以,起作用的是 Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND 标志。

5. 拉起进程监控

   如果需要监控哪些应用被隐式广播拉起,可以在BroadcastQueue.processNextBroadbroadcast 打点,监控所有通过广播启动的进程。

if ((r.curApp=mService.startProcessLocked(targetProcess,

                    info.activityInfo.applicationInfo, true,

                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,

                    "broadcast",r.curComponent,

              (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))

可以在BroadcastQueue增加打点监控,或者在AMS startProcessLocked增加打点监控。

你可能感兴趣的:(【ActivityManagerService】Android 广播拉起后台进程那些事)