0. 先说结论

默认情况下,如果系统版本是 Android 8.0 以上,则收不到。如果是 Android 7.0,需要设置 directBootAware 为 true。

如果想在 Android 8.0 以上版本中收到,需要先设置 directBootAware,然后广播发送时需要添加 FLAG_RECEIVER_INCLUDE_BACKGROUND

不管是什么版本,如果 BroadcastReceiver 所在的应用从来没有启动过(停止状态),则广播发送者需要额外添加 FLAG_INCLUDE_STOPPED_PACKAGES

1. 发送广播到查找相关 Receiver

发送广播是调用 Context 类的 sendBroadcast() 方法,最终会调用 ActivityManagerService 类的 broadcastIntent() 方法,然后它又会调用 broadcastIntentLocked() 方法。

// com.android.server.am.ActivityManagerService
public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {
    synchronized(this) {
        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, resultExtras,
                requiredPermissions, appOp, bOptions, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
}}

broadcastIntentLocked() 方法中根据 intent 查找相应的 BroadcastReceiver 对象。方法中创建两个局部变量,receivers 存储静态注册的 BroadcastReceiver 对象,registeredReceivers 存储动态注册的 BroadcastReceiver 对象。

Boot compete 之前三方应用没有启动过,所以也没有动态注册的广播。我们关注 receivers 变量的赋值过程。

// com.android.server.am.ActivityManagerService
final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    // Figure out who all will receive this broadcast.
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    // Need to resolve the intent to interested receivers...
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
    }
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
            ...
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false /*defaultOnly*/, userId);
}}}

receivers 的值有 collectReceiverComponents() 方法返回 。该方法会调用 PackageManagerService 类的 queryIntentReceivers() 方法,因为静态广播是由 PackageManagerService 类在系统启动的时候扫描解析 AndroidManifest 文件获取的。

// com.android.server.am.ActivityManagerService
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
        int callingUid, int[] users) {
    int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;
    List<ResolveInfo> receivers = null;
    for (int user : users) {
        List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
        if (receivers == null) {
            receivers = newReceivers;
        } else if (newReceivers != null) {
            ...
    }}
    return receivers;
}

2. 获取 receiver 的三种情况

ParceledListSlice 类是在进程间通信过程中用于传输一堆元素组成 List 对象的。queryIntentReceivers() 方法再调用 queryIntentReceiversInternal() 方法。在这个方法分三种情况,一个是 intent.getComponent() 不是 null,另外两个是 intent.getPackage() 不是 null 和是 null 的情况。我们在 2.1 和 2.2 中分析这三种情况。

// com.android.server.pm.PackageManagerService
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
        String resolvedType, int flags, int userId) {
    return new ParceledListSlice<>(
            queryIntentReceiversInternal(intent, resolvedType, flags, userId,
                    false /*allowDynamicSplits*/));
}

private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
        String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
    if (!sUserManager.exists(userId)) return Collections.emptyList();
    final int callingUid = Binder.getCallingUid();
    flags = updateFlagsForResolve(flags, userId, intent, callingUid,
            false /*includeInstantApps*/);
    ComponentName comp = intent.getComponent();
    // ---- 1 ----
    if (comp != null) {
        final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
        if (ai != null) {
            ...
            // blockResolution is related to instant app
            if (!blockResolution) {
                ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
        }}
        return applyPostResolutionFilter(
                list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                intent);
    }

    // reader
    synchronized (mPackages) {
        String pkgName = intent.getPackage();
        // ---- 2 ----
        if (pkgName == null) {
            final List<ResolveInfo> result =
                    mReceivers.queryIntent(intent, resolvedType, flags, userId);
            return applyPostResolutionFilter(
                    result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                    intent);
        }
        // ---- 3 ----
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if (pkg != null) {
            final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                    intent, resolvedType, flags, pkg.receivers, userId);
            return applyPostResolutionFilter(
                    result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                    intent);
        }
        return Collections.emptyList();
}}

2.0 MATCH_DIRECT_BOOT_UNAWARE

MATCH_DIRECT_BOOT_UNAWAREPackageManager 中声明,在注释中说明了,如果 MATCH_DIRECT_BOOT_AWAREMATCH_DIRECT_BOOT_UNAWARE 都没有指定,则只能匹配运行中的组件。当 user locked 状态下只能匹配 MATCH_DIRECT_BOOT_AWARE 的组件,当 user unlocked 的时候会匹配 MATCH_DIRECT_BOOT_AWAREMATCH_DIRECT_BOOT_UNAWARE 的组件。

有点饶,对于我们的情况有什么用处,当系统开启的时候 boot complete 之前是 user locked 状态,boot complete 之后会转到 user unlocked 状态。调用 UserManager 类的 isUserUnlocked() 可以获取 unlocked 状态。

/**
 * Querying flag: match components which are direct boot <em>unaware</em> in
 * the returned info, regardless of the current user state.
 * <p>
 * When neither {@link #MATCH_DIRECT_BOOT_AWARE} nor
 * {@link #MATCH_DIRECT_BOOT_UNAWARE} are specified, the default behavior is
 * to match only runnable components based on the user state. For example,
 * when a user is started but credentials have not been presented yet, the
 * user is running "locked" and only {@link #MATCH_DIRECT_BOOT_AWARE}
 * components are returned. Once the user credentials have been presented,
 * the user is running "unlocked" and both {@link #MATCH_DIRECT_BOOT_AWARE}
 * and {@link #MATCH_DIRECT_BOOT_UNAWARE} components are returned.
 *
 * @see UserManager#isUserUnlocked()
 */