默认情况下,如果系统版本是 Android 8.0 以上,则收不到。如果是 Android 7.0,需要设置 directBootAware 为 true。
如果想在 Android 8.0 以上版本中收到,需要先设置 directBootAware,然后广播发送时需要添加 FLAG_RECEIVER_INCLUDE_BACKGROUND
。
不管是什么版本,如果 BroadcastReceiver
所在的应用从来没有启动过(停止状态),则广播发送者需要额外添加 FLAG_INCLUDE_STOPPED_PACKAGES
。
发送广播是调用 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;
}
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();
}}
MATCH_DIRECT_BOOT_UNAWARE
在 PackageManager
中声明,在注释中说明了,如果 MATCH_DIRECT_BOOT_AWARE
和 MATCH_DIRECT_BOOT_UNAWARE
都没有指定,则只能匹配运行中的组件。当 user locked 状态下只能匹配 MATCH_DIRECT_BOOT_AWARE
的组件,当 user unlocked 的时候会匹配 MATCH_DIRECT_BOOT_AWARE
和 MATCH_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()
*/