咱们先随便实现一个BroadcastReceiver,静态注册:java
class TestReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.w("TEST-1", "onReceive ${intent?.action}")
}
}
复制代码
<receiver android:name=".TestReceiver">
<intent-filter>
<action android:name="com.xxx.yyy.action_test_receiver" />
</intent-filter>
</receiver>
复制代码
其余诸如Activity什么的就不写了哈,而后咱们启动这个测试App以后,用adb命令发一条广播:android
adb shell am broadcast -p com.xxx.yyy -a com.xxx.yyy.action_test_receiver
复制代码
其中参数p表示广播接收所在进程包名,a表示action。命令执行后终端会输出:shell
Broadcasting: Intent { act=com.xxx.yyy.action_test_receiver flg=0x400000 pkg=com.xxx.yyy }
Broadcast completed: result=0
复制代码
而后查看logcat,咱们能够如愿以偿地看到onReceive中的log。接下来咱们杀掉进程,任意方式都可,这里我仍是用adb命令,方便:安全
adb shell am force-stop com.xxx.yyy
复制代码
杀进程后,再重复上面的广播发送命令,就会发现收不到广播了。这是为何呢?表面看来这个问题很弱智,进程都死了固然不能再搞事。但实际上背后的逻辑仍是值得探索的,系统也不是想象中那么简单地直接判断进程死活而后决定广播发送。bash
很显然咱们要搞明白广播发送的底层逻辑。这里主要分析Framework层面的源码(基于Android 10),涉及到的关键类:app
frameworks/base/core/java/android/content/Intent.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
frameworks/base/services/core/java/com/android/server/IntentResolver.java
复制代码
关于广播发送的细节,能够参考此文:www.jianshu.com/p/c5323a22f…,虽然源码版本不是最新,但基本逻辑差别不大,时序图也画得很是清晰。下面咱们只针对文题简单地分析关键路径便可。ide
当咱们乐呵呵地调用了 sendBroadcast
方法以后,会调用到AMS(ActivityManagerService)的 broadcastIntent
方法,进而调用内部的 broadcastIntentLocked
方法(此处插入一个题外话:不少同窗可能常常见到源码里 xxxLocked
这种方法,这个locked是什么意思呢?顾名思义就是加锁咯,即你要调用这些locked后缀的方法时,必须保证是线程安全的,因此通常就会看到synchronize关键字,这也算是AOSP的编码规范吧)。测试
因为 broadcastIntentLocked
方法很是长,咱们只截取关键片断:优化
final int broadcastIntentLocked(Intent intent/*省略18个参数*/) {
intent = new Intent(intent);
// ...
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// ...
// 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);
}
// ...
}
复制代码
能够看到,起手就是new Intent(intent),为何不直接使用参数中的intent来进行后续操做呢?此处一个小细节能够看出源码逻辑的谨慎,去查Intent的构造方法就知道,这是对入参的拷贝,避免被其余线程修改。 而后最关键的即是下面的 FLAG_EXCLUDE_STOPPED_PACKAGES
,注释也写得很清楚,即广播发送会排除(exclude)已中止运行的进程。ui
但我初次分析时看了半天没发现是怎么排除的,因而找这个flag引用的地方,在 Intent 源码中发现一个方法,判断该intent是否要排除已中止的进程:
public boolean isExcludingStopped() {
return (mFlags&(FLAG_EXCLUDE_STOPPED_PACKAGES|FLAG_INCLUDE_STOPPED_PACKAGES))
== FLAG_EXCLUDE_STOPPED_PACKAGES;
}
复制代码
很是好,咱们直接查 isExcludingStopped
方法的引用,发如今 IntentResolver 中:
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++) {
// ...
if (excludingStopped && isFilterStopped(filter, userId)) {
if (debug) {
Slog.v(TAG, " Filter's target is stopped; skipping");
}
continue;
}
}
// ...
}
复制代码
这是经过intent构造resolve列表的一个私有方法,代码也很是清晰,此判断逻辑 excludingStopped && isFilterStopped
过滤了最后要启动的组件。其中 isFilterStopped
是真正判断进程是否已中止的方法,而 excludingStopped 是咱们刚才传入的flag对应的控制标识。因此要过滤掉已中止进程有两个必要条件,一是这个进程真的死了,二是开发者要经过flag来声明确实须要过滤(是否是超人性化哈哈哈)。
所以,咱们也能够声明不须要过滤,即给intent设置 FLAG_EXCLUDE_STOPPED_PACKAGES
的兄弟flag:FLAG_INCLUDE_STOPPED_PACKAGES
(注意是 include),这样在发送广播时,即使是已中止的进程,也能接收到了。这就是上古时期经过广播唤醒死亡进程的方法,如今基本上被各大ROM厂商给优化没了,通常都是三方应用被禁,系统应用依然能够。
分析到此,其实只是有头有尾,但没有中间过程,broadcastIntentLocked
最终怎么就调到了 buildResolveList
呢? 咱们回到上面的 broadcastIntentLocked
方法,其中的 receivers
对象存储的是静态广播的集合,registeredReceivers
则是动态广播的集合。咱们只看静态广播便可,它来自于 collectReceiverComponents
方法,此方法最后返回的receiver确定是被过滤后的:
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) {
// ...
List<ResolveInfo> receivers = null;
try {
// ...
for (int user : users) {
// ...
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
.queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
// ...
if (newReceivers != null && newReceivers.size() == 0) {
newReceivers = null;
}
if (receivers == null) {
receivers = newReceivers;
// ...
}
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
}
return receivers;
}
复制代码
这个方法内部逻辑较为简单,咱们能够看到最终receivers的来源即是那个 queryIntentReceivers
方法,此方法实如今PMS(PackageManagerService)里面:
@Override
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) {
// ...
synchronized (mPackages) {
String pkgName = intent.getPackage();
if (pkgName == null) {
final List<ResolveInfo> result =
mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
return applyPostResolutionFilter(
result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
intent);
}
final PackageParser.Package pkg = mPackages.get(pkgName);
if (pkg != null) {
final List<ResolveInfo> result = mComponentResolver.queryReceivers(
intent, resolvedType, flags, pkg.receivers, userId);
return applyPostResolutionFilter(
result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
intent);
}
return Collections.emptyList();
}
}
复制代码
最终receiver集合的查询操做在私有方法中,由 mComponentResolver.queryReceivers
得来,彷佛愈来愈接近真相了,立刻查看ComponentResolver:
List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, int userId) {
synchronized (mLock) {
return mReceivers.queryIntent(intent, resolvedType, flags, userId);
}
}
List<ResolveInfo> queryReceivers(Intent intent, String resolvedType, int flags, List<PackageParser.Activity> receivers, int userId) {
synchronized (mLock) {
return mReceivers.queryIntentForPackage(intent, resolvedType, flags, receivers, userId);
}
}
复制代码
这里正好对应上面的两个不一样状况下的调用,它们最终都会调用到 queryIntent
方法,此方法在ComponentResolver的一个静态内部类ActivityIntentResolver中实现:
private static final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
@Override
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {
// ...
return super.queryIntent(intent, resolvedType, defaultOnly, userId);
}
List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) {
// ...
return super.queryIntent(intent, resolvedType,
(flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
userId);
}
// ...
}
复制代码
内部类的中的 queryIntent
方法只是作了一些参数处理,进一步调用的是父类的实现,这个父类也就是起初咱们提到的 IntentResolver:
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) {
// ...
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);
}
filterResults(finalList);
sortResults(finalList);
// ...
return finalList;
}
复制代码
看上面的 buildResolveList
方法,照应了开头分析的结果。最终返回的 finalList 也就是过滤以后的receiver集合。
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
设置了标识,以声明广播不发给已中止的进程,层层调用后最终在 IntentResolver 的 buildResolveList
方法中实现过滤。sendBroadcast
以前,给intent添加 flag:FLAG_INCLUDE_STOPPED_PACKAGES
便可。但鉴于各ROM厂商的正负优化,这个操做已经不适用了。