简介
Android O对隐式广播进行了限制, 其限制链接说明:后台执行限制
按照谷歌的说法是:如果应用注册为接收广播,则在每次发送广播时,应用的接收器都会消耗资源。 如果多个应用注册为接收基于系统事件的广播,则会引发问题:触发广播的系统事件会导致所有应用快速地连续消耗资源,从而降低用户体验。 为了缓解这一问题,Android 7.0(API 级别 24)对广播施加了一些限制,如后台优化中所述。 Android 8.0(API 级别 26)让这些限制更为严格。
1.适配 Android 8.0 或更高版本的应用无法继续在其清单中为隐式广播注册广播接收器。 隐式广播是一种不专门针对该应用的广播。 例如,ACTION_PACKAGE_REPLACED 就是一种隐式广播,因为该广播将被发送给所有已注册侦听器,让后者知道设备上的某些软件包已被替换。 不过,ACTION_MY_PACKAGE_REPLACED 不是隐式广播,因为不管已为该广播注册侦听器的其他应用有多少,它都会只被发送给软件包已被替换的应用。
2.应用可以继续在它们的清单中注册显式广播。
3.应用可以在运行时使用 Context.registerReceiver() 为任意广播(不管是隐式还是显式)注册接收器。
4.需要签名权限的广播不受此限制所限,因为这些广播只会发送到使用相同证书签名的应用,而不是发送到设备上的所有应用。
源码分析
动态注册广播接收者和静态广播接收者
动态注册广播接收者是那些在应用代码中使用registerReceiver或registerReceiverXXX注册的广播接收者,静态注册广播接收者是那些仅注册在AndroidManifest.xml里面的广播。
1.动态注册广播接收者不是常驻型广播接收者,也就是说广播接收者跟随activity的生命周期。注意需要在activity结束前,移除广播接收者;按以前的设计标准,静态注册广播接收者是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。
2.动态注册广播接收者和静态广播接收者处理的优先级有区别,后面会详述。
在AMS的广播派发函数broadcastIntentLocked中,会先收集符合入参Intent的这两种广播接收者集合。其中receivers是静态注册广播接收者的集合,registeredReceivers是动态注册广播接收者的集合。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// 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) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
优先处理无序发送下的动态注册广播接收者
对于发的不是有序广播(有序广播的接收者包括了动态注册广播接收者和静态注册广播接收者,只不过是用sendOrderedBroadcast发送的广播),且存在对应的动态注册广播接收者的话,预先处理这些动态注册广播接收者。这次的预先处理会生成一个BroadcastRecord,放入到BroadcastQueue的并行广播集合mParallelBroadcasts中,并调用BroadcastQueue#scheduleBroadcastsLocked提醒BroadcastQueue有新的广播到来,需要开始处理了。
简单介绍一下BroadcastQueue。BroadcastQueue里面包含了两个广播集合:mOrderedBroadcasts和mParallelBroadcasts。mParallelBroadcasts存放了非有序且带有动态注册广播接收者的BroadcastRecord,处理优先级比较高;mOrderedBroadcasts存放了有序发送或者带有静态注册广播接收者的BroadcastRecord,处理优先级比mParallelBroadcasts中的低。系统中存在三种BroadcastQueue:mOffloadBroadcastQueue,mFgBroadcastQueue和mBgBroadcastQueue。带有FLAG_RECEIVER_OFFLOAD的flag的广播会被送至mOffloadBroadcastQueue,带有FLAG_RECEIVER_FOREGROUND的flag的广播会被送至mFgBroadcastQueue,其他情况会被送至mBgBroadcastQueue。mOffloadBroadcastQueue是用来使发送的广播在一个减载BroadcastQueue中被处理,不用在其他BroadcastQueue排队;mFgBroadcastQueue的广播会比mFgBroadcastQueue获得更多的CPU资源。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
BroadcastRecord广播记录
BroadcastRecord是一个相当重要的数据结构,记录了很多上下文信息。
frameworks/base/services/core/java/com/android/server/am/BroadcastRecord.java
final class BroadcastRecord extends Binder {
final Intent intent; // the original intent that generated us ||广播使用的intent
final ComponentName targetComp; // original component name set on the intent ||intent使用的组件名,可以为空
final ProcessRecord callerApp; // process that sent this ||发送广播intent的进程ProcessRecord
final String callerPackage; // who sent this ||发送广播intent的包名
final int callingPid; // the pid of who sent this ||发送广播intent的进程pid
final int callingUid; // the uid of who sent this ||发送广播intent的进程uid
final boolean callerInstantApp; // caller is an Instant App? ||是否是instant app
final boolean ordered; // serialize the send to receivers? ||是否是有序广播
final boolean sticky; // originated from existing sticky data? ||是否是sticky广播(现在已经被废弃)
final boolean initialSticky; // initial broadcast from register to sticky? ||一般为false,不知道是干什么的
final int userId; // user id this broadcast was for ||广播的受众id
final String resolvedType; // the resolved data type ||intent的type
final String[] requiredPermissions; // permissions the caller has required ||发送广播时要求的权限
final int appOp; // an app op that is associated with this broadcast ||发送广播时要求的appop
final BroadcastOptions options; // BroadcastOptions supplied by caller ||发送广播时f附带的额外信息
final List receivers; // contains BroadcastFilter and ResolveInfo ||这个BroadcastRecord的目标广播接收者,包含BroadcastFilter(动态注册广播接收者)和ResolveInfo(静态注册广播接收者)
final int[] delivery; // delivery state of each receiver ||一个容量和receivers相同的数组,描述每个广播接收者的广播递送状态,有四种状态:DELIVERY_PENDING(默认),DELIVERY_DELIVERED(广播已经递送到对应下标的广播接收者),DELIVERY_SKIPPED(跳过本次递送),DELIVERY_TIMEOUT(递送超时)
final long[] duration; // duration a receiver took to process broadcast ||一个容量和receivers相同的数组,描述每个广播接收者的接收处理耗时
IIntentReceiver resultTo; // who receives final result if non-null ||有序广播的最终处理程序,可以为null
boolean deferred;||暂时没研究
int splitCount; // refcount for result callback, when split ||暂时没研究
int splitToken; // identifier for cross-BroadcastRecord refcount ||暂时没研究
long enqueueClockTime; // the clock time the broadcast was enqueued ||BroadcastRecord被放进BroadcastQueue的时间点,使用currentTimeMillis计算
long dispatchTime; // when dispatch started on this set of receivers ||BroadcastRecord被开始派发的时间点,使用uptimeMillis计算
long dispatchClockTime; // the clock time the dispatch started ||BroadcastRecord被开始派发的时间点,使用currentTimeMillis计算
long receiverTime; // when current receiver started for timeouts. ||开始计算ANR超时的时间点
long finishTime; // when we finished the broadcast. ||开始广播接受者收尾工作的时间点
boolean timeoutExempt; // true if this broadcast is not subject to receiver timeouts ||这个广播时是否受超时机制影响
int resultCode; // current result code value. ||有序发送的情况下传给下一个广播接受者的数值
String resultData; // current result data value. ||有序发送的情况下传给下一个广播接受者的字符串
Bundle resultExtras; // current result extra data values. ||有序发送的情况下传给下一个广播接受者的额外信息
boolean resultAbort; // current result abortBroadcast value. ||是否中断有序广播的传递
int nextReceiver; // next receiver to be executed. ||下一个广播接收者的下标
IBinder receiver; // who is currently running, null if none. ||当前广播接收者所在的ActivityThread的Binder对象
int state; ||BroadcastRecord的状态值,取值有IDLE(默认),APP_RECEIVE(传递给静态注册广播接受者),CALL_IN_RECEIVE(有序发送广播的情况下动态注册广播接收者准备执行onReceive),CALL_DONE_RECEIVE(有序发送广播的情况下动态注册广播接收者执行完onReceive),WAITING_SERVICES(后台启动服务数量超过系统限制,需要等待后台启动服务完成)
int anrCount; // has this broadcast record hit any ANRs? ||派发广播过程中发生ANR的次数
int manifestCount; // number of manifest receivers dispatched. ||派发到的静态注册广播接受者数量
int manifestSkipCount; // number of manifest receivers skipped. ||被跳过的静态注册广播接受者数量
BroadcastQueue queue; // the outbound queue handling this broadcast ||所处的BroadcastQueue
// if set to true, app's process will be temporarily whitelisted to start activities
// from background for the duration of the broadcast dispatch ||能否后台启动Activity
final boolean allowBackgroundActivityStarts;
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
static final int CALL_IN_RECEIVE = 2;
static final int CALL_DONE_RECEIVE = 3;
static final int WAITING_SERVICES = 4;
static final int DELIVERY_PENDING = 0;
static final int DELIVERY_DELIVERED = 1;
static final int DELIVERY_SKIPPED = 2;
static final int DELIVERY_TIMEOUT = 3;
// The following are set when we are calling a receiver (one that
// was found in our list of registered receivers).||当前派发到的动态注册广播接收者
BroadcastFilter curFilter;
// The following are set only when we are launching a receiver (one
// that was found by querying the package manager).
ProcessRecord curApp; // hosting application of current receiver. ||广播接收者所在进程的ProcessRecord
ComponentName curComponent; // the receiver class that is currently running. ||广播接收者所在进程的包名
ActivityInfo curReceiver; // info about the receiver that is currently running. ||广播接收者的相关信息
合并剩余广播接收者再处理
以下这部分是针对动态注册广播接收者(有序发送的情况下)和静态注册广播接收者的,旨在将有序动态注册广播接收者和静态注册广播接受者按一定顺序放在一个集合里面。排序规则如下:
1.如果发送的是无序广播,符合入参Intent的静态注册广播接受者按照PMS扫描的先后顺序排列好的集合就是最终结果。无序广播的动态注册广播接受者已经被优先处理,走到这段代码时会被忽略的;
2.如果发送的是有序广播,且只有符合入参Intent的静态注册广播接受者,按1中的说明得到集合;
3.如果发送的是有序广播,且同时存在对应的静态注册广播接受者和动态注册广播接受者。则优先级高的排在前面(android:priority的数值高),如果优先级相同,动态广播接收者排在前面。对于同类的广播接收者,静态注册广播接收者的策略是按照PMS扫描的先后顺序排列,动态注册广播接受者按向AMS注册的先后顺序排列。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// Merge into one list.
int ir = 0;
if (receivers != null) {
// A special case for PACKAGE_ADDED: do not allow the package
// being added to see this broadcast. This prevents them from
// using this as a back door to get run as soon as they are
// installed. Maybe in the future we want to have a special install
// broadcast or such for apps, but we'd like to deliberately make
// this decision.
String skipPackages[] = null;
if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null) {
String pkgName = data.getSchemeSpecificPart();
if (pkgName != null) {
skipPackages = new String[] { pkgName };
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
if (skipPackages != null && (skipPackages.length > 0)) {
for (String skipPackage : skipPackages) {
if (skipPackage != null) {
int NT = receivers.size();
for (int it=0; it<NT; it++) {
ResolveInfo curt = (ResolveInfo)receivers.get(it);
if (curt.activityInfo.packageName.equals(skipPackage)) {
receivers.remove(it);
it--;
NT--;
}
}
}
}
}
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir++;
}
排列好的有序动态注册广播接收者和静态注册广播接收者放在receivers里面。还是按一样的操作,找到一个合适的BroadcastQueue,生成一个对应的BroadcastRecord,这个BroadcastRecord是存放在mOrderedBroadcasts中的,最后调用BroadcastQueue#scheduleBroadcastsLocked传递广播。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
final BroadcastRecord oldRecord =
replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
if (oldRecord != null) {
// Replaced, fire the result-to receiver.
if (oldRecord.resultTo != null) {
final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
try {
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.userId);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ queue.mQueueName + "] sending broadcast result of "
+ intent, e);
}
}
} else {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
} else {
// There was nobody interested in the broadcast, but we still want to record
// that it happened.
if (intent.getComponent() == null && intent.getPackage() == null
&& (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
}
}
mBroadcastsScheduled如果为true,表示BroadcastQueue还在处理广播过程中,直接返回。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
+ mQueueName + "]");
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
分步处理:processNextBroadcastLocked
可以见到,处理广播的第一步是依次从mParallelBroadcasts拿出包含非有序发送的动态注册广播接收者的BroadcastRecord,通过deliverToRegisteredReceiverLocked递送到这个BroadcastRecord的各个广播接收者。第二步是确认当前有没有正在处理的BroadcastRecord,如果有继续处理,如果没有,从mOrderedBroadcasts中拿出一个包含有序发送的动态注册广播接收者或者一个包含静态注册广播接收者的BroadcastRecord,如果是一个包含有序发送的动态注册广播接收者的BroadcastRecord,通过deliverToRegisteredReceiverLocked递送到这个BroadcastRecord的各个广播接收者;如果是一个包含静态注册广播接收者的BroadcastRecord,则通过processCurBroadcastLocked进行进行下一步的处理,如果静态注册广播接收者所在进程还没存在,则启动进程后再通过processCurBroadcastLocked进行进行下一步的处理。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
+ mQueueName + "]: "
+ mParallelBroadcasts.size() + " parallel broadcasts; "
+ mDispatcher.describeStateLocked());
mService.updateCpuStats();
if (fromMsg) {
mBroadcastsScheduled = false;
}
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {//首先处理非有序发送的动态注册广播接收者
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
// Now take care of the next serialized one...
// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {//mPendingBroadcast在启动静态注册广播所在进程时被设置,这里的目的是检测静态注册广播所在进程是否还存在,不存在就打印相关log以及将mPendingBroadcast置成null后继续处理
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"processNextBroadcast [" + mQueueName + "]: waiting for "
+ mPendingBroadcast.curApp);
boolean isDead;
if (mPendingBroadcast.curApp.pid > 0) {
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(
mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.isCrashing();
}
} else {
final ProcessRecord proc = mService.mProcessList.mProcessNames.get(
mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
isDead = proc == null || !proc.pendingStart;
}
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
Slog.w(TAG, "pending app ["
+ mQueueName + "]" + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
do {
final long now = SystemClock.uptimeMillis();
r = mDispatcher.getNextBroadcastLocked(now);//获取mOrderedBroadcasts的一个BroadcastRecord
if (r == null) {
// No more broadcasts are deliverable right now, so all done!
mDispatcher.scheduleDeferralCheckLocked(false);
mService.scheduleAppGcsLocked();
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
}
// when we have no more ordered broadcast on this queue, stop logging
if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
mLogLatencyMetrics = false;
}
return;
}
boolean forceReceive = false;
// Ensure that even if something goes awry with the timeout
// detection, we catch "hung" broadcasts here, discard them,
// and continue to make progress.
//
// This is only done if the system is ready so that early-stage receivers
// don't get executed with timeouts; and of course other timeout-
// exempt broadcasts are ignored.
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {//派发时间超时处理
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
Slog.w(TAG, "Hung broadcast ["
+ mQueueName + "] discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
+ " intent=" + r.intent
+ " numReceivers=" + numReceivers
+ " nextReceiver=" + r.nextReceiver
+ " state=" + r.state);
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
"processNextBroadcast("
+ mQueueName + ") called when not idle (state="
+ r.state + ")");
return;
}
// Is the current broadcast is done for any reason?
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {//在以下四种情况下取消广播的发送:1.广播没有相应的接收者;2.已经派送完毕;3.某个接收者abort掉了广播的发送;4.广播派发超时
// Send the final result if requested
if (r.resultTo != null) {/使用了BroadcastReceiver参数发送的有序广播resultTo才不为null
boolean sendResult = true;
// if this was part of a split/deferral complex, update the refcount and only
// send the completion when we clear all of them
if (r.splitToken != 0) {
int newCount = mSplitRefcounts.get(r.splitToken) - 1;
if (newCount == 0) {
// done! clear out this record's bookkeeping and deliver
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST,
"Sending broadcast completion for split token "
+ r.splitToken + " : " + r.intent.getAction());
}
mSplitRefcounts.delete(r.splitToken);
} else {
// still have some split broadcast records in flight; update refcount
// and hold off on the callback
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST,
"Result refcount now " + newCount + " for split token "
+ r.splitToken + " : " + r.intent.getAction()
+ " - not sending completion yet");
}
sendResult = false;
mSplitRefcounts.put(r.splitToken, newCount);
}
}
if (sendResult) {
try {
if (DEBUG_BROADCAST) {
Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
}
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
Slog.w(TAG, "Failure ["
+ mQueueName + "] sending broadcast result of "
+ r.intent, e);
}
}
}
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
cancelBroadcastTimeoutLocked();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Finished with ordered broadcast " + r);
// ... and on to the next...
addBroadcastToHistoryLocked(r);
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
mDispatcher.retireBroadcastLocked(r);//抛弃当前处理的这个BroadcastRecord。下面的continue会获取下一个BroadcastRecord进行处理
r = null;
looped = true;
continue;
}
// Check whether the next receiver is under deferral policy, and handle that
// accordingly. If the current broadcast was already part of deferred-delivery
// tracking, we know that it must now be deliverable as-is without re-deferral.
if (!r.deferred) {
final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
if (mDispatcher.isDeferringLocked(receiverUid)) {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
+ " at " + r.nextReceiver + " is under deferral");
}
// If this is the only (remaining) receiver in the broadcast, "splitting"
// doesn't make sense -- just defer it as-is and retire it as the
// currently active outgoing broadcast.
BroadcastRecord defer;
if (r.nextReceiver + 1 == numReceivers) {
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Sole receiver of " + r
+ " is under deferral; setting aside and proceeding");
}
defer = r;
mDispatcher.retireBroadcastLocked(r);
} else {
// Nontrivial case; split out 'uid's receivers to a new broadcast record
// and defer that, then loop and pick up continuing delivery of the current
// record (now absent those receivers).
// The split operation is guaranteed to match at least at 'nextReceiver'
defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "Post split:");
Slog.i(TAG_BROADCAST, "Original broadcast receivers:");
for (int i = 0; i < r.receivers.size(); i++) {
Slog.i(TAG_BROADCAST, " " + r.receivers.get(i));
}
Slog.i(TAG_BROADCAST, "Split receivers:");
for (int i = 0; i < defer.receivers.size(); i++) {
Slog.i(TAG_BROADCAST, " " + defer.receivers.get(i));
}
}
// Track completion refcount as well if relevant
if (r.resultTo != null) {
int token = r.splitToken;
if (token == 0) {
// first split of this record; refcount for 'r' and 'deferred'
r.splitToken = defer.splitToken = nextSplitTokenLocked();
mSplitRefcounts.put(r.splitToken, 2);
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST,
"Broadcast needs split refcount; using new token "
+ r.splitToken);
}
} else {
// new split from an already-refcounted situation; increment count
final int curCount = mSplitRefcounts.get(token);
if (DEBUG_BROADCAST_DEFERRAL) {
if (curCount == 0) {
Slog.wtf(TAG_BROADCAST,
"Split refcount is zero with token for " + r);
}
}
mSplitRefcounts.put(token, curCount + 1);
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "New split count for token " + token
+ " is " + (curCount + 1));
}
}
}
}
mDispatcher.addDeferredBroadcast(receiverUid, defer);
r = null;
looped = true;
continue;
}
}
} while (r == null);
// Get the next receiver...
//nextReceiver表示下一个要处理的广播接收者的下标,初始值为0
int recIdx = r.nextReceiver++;
// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
//receiverTime表示当前正在处理广播的ANR计算开始时间,dispatchTime表示开始分派广播到各个广播接受者的时间,一般来说dispatchTime早于或等于receiverTime
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
if (mLogLatencyMetrics) {
StatsLog.write(
StatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
r.dispatchClockTime - r.enqueueClockTime);
}
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
System.identityHashCode(r));
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
System.identityHashCode(r));
}
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
}
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {//有序发送的动态注册接收者依次处理广播
// Simple case: this is a registered receiver who gets
// a direct call.
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {//如果有序发送的动态注册广播接收者已经处理完毕或者发送广播不是有序的,重新调用scheduleBroadcastsLocked进行下一轮的处理,在下一轮处理中,会把广播交给下标为nextReceiver的广播接收者处理。
// The receiver has already finished, so schedule to
// process the next one.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
if (filter.receiverList != null) {
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
// r is guaranteed ordered at this point, so we know finishReceiverLocked()
// will get a callback and handle the activity start token lifecycle.
}
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(filter.owningUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
}
return;
}
// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
//静态注册广播接收者处理
ResolveInfo info =
(ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
boolean skip = false;
if (brOptions != null &&
(info.activityInfo.applicationInfo.targetSdkVersion
< brOptions.getMinManifestReceiverApiLevel() ||
info.activityInfo.applicationInfo.targetSdkVersion
> brOptions.getMaxManifestReceiverApiLevel())) {
skip = true;
}
if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
Slog.w(TAG, "Association not allowed: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
skip = true;
}
if (!skip) {
skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
if (skip) {
Slog.w(TAG, "Firewall blocked: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ") to " + component.flattenToShortString());
}
}
int perm = mService.checkComponentPermission(info.activityInfo.permission,
r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
info.activityInfo.exported);
if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
if (!info.activityInfo.exported) {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ " due to receiver " + component.flattenToShortString());
} else {
Slog.w(TAG, "Permission Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid=" + r.callingPid
+ ", uid=" + r.callingUid + ")"
+ " requires " + info.activityInfo.permission
+ " due to receiver " + component.flattenToShortString());
}
skip = true;
} else if (!skip && info.activityInfo.permission != null) {
final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
if (opCode != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(opCode, r.callingUid,
r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: broadcasting "
+ r.intent.toString()
+ " from " + r.callerPackage + " (pid="
+ r.callingPid + ", uid=" + r.callingUid + ")"
+ " requires appop " + AppOpsManager.permissionToOp(
info.activityInfo.permission)
+ " due to registered receiver "
+ component.flattenToShortString());
skip = true;
}
}
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
r.requiredPermissions != null && r.requiredPermissions.length > 0) {
for (int i = 0; i < r.requiredPermissions.length; i++) {
String requiredPermission = r.requiredPermissions[i];
try {
perm = AppGlobals.getPackageManager().
checkPermission(requiredPermission,
info.activityInfo.applicationInfo.packageName,
UserHandle
.getUserId(info.activityInfo.applicationInfo.uid));
} catch (RemoteException e) {
perm = PackageManager.PERMISSION_DENIED;
}
if (perm != PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires " + requiredPermission
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
&& mService.mAppOpsService.noteOperation(appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires appop " + AppOpsManager.permissionToOp(
requiredPermission)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
break;
}
}
}
if (!skip && r.appOp != AppOpsManager.OP_NONE
&& mService.mAppOpsService.noteOperation(r.appOp,
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName)
!= AppOpsManager.MODE_ALLOWED) {
Slog.w(TAG, "Appop Denial: receiving "
+ r.intent + " to "
+ component.flattenToShortString()
+ " requires appop " + AppOpsManager.opToName(r.appOp)
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
boolean isSingleton = false;
try {
isSingleton = mService.isSingleton(info.activityInfo.processName,
info.activityInfo.applicationInfo,
info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
Slog.w(TAG, e.getMessage());
skip = true;
}
if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
if (ActivityManager.checkUidPermission(
android.Manifest.permission.INTERACT_ACROSS_USERS,
info.activityInfo.applicationInfo.uid)
!= PackageManager.PERMISSION_GRANTED) {
Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
+ " requests FLAG_SINGLE_USER, but app does not hold "
+ android.Manifest.permission.INTERACT_ACROSS_USERS);
skip = true;
}
}
if (!skip && info.activityInfo.applicationInfo.isInstantApp()
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")"
+ " Instant Apps do not support manifest receivers");
skip = true;
}
if (!skip && r.callerInstantApp
&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
&& r.callingUid != info.activityInfo.applicationInfo.uid) {
Slog.w(TAG, "Instant App Denial: receiving "
+ r.intent
+ " to " + component.flattenToShortString()
+ " requires receiver have visibleToInstantApps set"
+ " due to sender " + r.callerPackage
+ " (uid " + r.callingUid + ")");
skip = true;
}
if (r.curApp != null && r.curApp.isCrashing()) {
// If the target process is crashing, just skip it.
Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
+ " to " + r.curApp + ": process crashing");
skip = true;
}
if (!skip) {
boolean isAvailable = false;
try {
isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
info.activityInfo.packageName,
UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
} catch (Exception e) {
// all such failures mean we skip this receiver
Slog.w(TAG, "Exception getting recipient info for "
+ info.activityInfo.packageName, e);
}
if (!isAvailable) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid
+ " : package no longer available");
skip = true;
}
}
// If permissions need a review before any of the app components can run, we drop
// the broadcast and if the calling app is in the foreground and the broadcast is
// explicit we launch the review UI passing it a pending intent to send the skipped
// broadcast.
if (!skip) {
if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
info.activityInfo.packageName, UserHandle.getUserId(
info.activityInfo.applicationInfo.uid))) {
skip = true;
}
}
// This is safe to do even if we are skipping the broadcast, and we need
// this information now to evaluate whether it is going to be allowed to run.
final int receiverUid = info.activityInfo.applicationInfo.uid;
// If it's a singleton, it needs to be the same app or a special app
if (r.callingUid != Process.SYSTEM_UID && isSingleton
&& mService.isValidSingletonCall(r.callingUid, receiverUid)) {
info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
String targetProcess = info.activityInfo.processName;
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
if (!skip) {
final int allowed = mService.getAppStartModeLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
} else if (((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;
}
}
}
if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
&& !mService.mUserController
.isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
0 /* flags */)) {
skip = true;
Slog.w(TAG,
"Skipping delivery to " + info.activityInfo.packageName + " / "
+ info.activityInfo.applicationInfo.uid + " : user is not running");
}
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery of ordered [" + mQueueName + "] "
+ r + " for reason described above");
r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
r.receiver = null;
r.curFilter = null;
r.state = BroadcastRecord.IDLE;
r.manifestSkipCount++;
scheduleBroadcastsLocked();
return;
}
r.manifestCount++;
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+ info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+ receiverUid);
}
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
scheduleTempWhitelistLocked(receiverUid,
brOptions.getTemporaryAppWhitelistDuration(), r);
}
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.curComponent.getPackageName() + ": " + e);
}
// Is this receiver's application already running?
//静态注册广播接者所在进程存在的情况下
if (app != null && app.thread != null && !app.killed) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
//processCurBroadcastLocked处理当前的广播
processCurBroadcastLocked(r, app, skipOomAdj);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// Not running -- get it started, to be executed when the app comes up.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Need to start app ["
+ mQueueName + "] " + targetProcess + " for broadcast " + r);
//静态注册广播接收者进程不存在的情况下,启动进程,在启动进程后的ActivityManagerService#attachApplicationLocked会检测三个BroadcastQueue:mFgBroadcastQueue,mBgBroadcastQueue,mOffloadBroadcastQueue是否存在mPendingBroadcast,如果存在就调用processCurBroadcastLocked继续处理广播
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
new HostingRecord("broadcast", r.curComponent),
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ receiverUid + " for broadcast "
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
动态注册广播递送:deliverToRegisteredReceiverLocked
动态注册广播接受者统一使用deliverToRegisteredReceiverLocked进行处理,核心在于使用performReceiveLocked->scheduleRegisteredReceiver进入广播接受者的onReceive流程;静态广播接收者使用processCurBroadcastLocked进行处理,核心在于使用scheduleReceiver进入广播接收者的onReceive流程。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
if (skip) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}
...
r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;
...
} else {
r.receiverTime = SystemClock.uptimeMillis();
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
// parallel broadcasts are fire-and-forget, not bookended by a call to
// finishReceiverLocked(), so we manage their activity-start token here
if (r.allowBackgroundActivityStarts && !r.ordered) {
postActivityStartTokenRemoval(filter.receiverList.app, r);
}
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
...
}
}
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app, boolean skipOomAdj) throws RemoteException {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
throw new RemoteException();
}
if (app.inFullBackup) {
skipReceiverLocked(r);
return;
}
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
mService.mProcessList.updateLruProcessLocked(app, false, null);
if (!skipOomAdj) {
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
}
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
boolean started = false;
try {
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Delivering to component " + r.curComponent
+ ": " + r);
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.getReportedProcState());
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
} finally {
if (!started) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
app.curReceivers.remove(r);
}
}
}
先看看动态注册广播接收者对应的scheduleRegisteredReceiver。receiver参数是来自注册的广播接受者端的一个InnerReceiver对象,InnerReceiver是ReceiverDispatcher的一个静态内部类,继承自Binder类,实现了IIntentReceiver接口,具有跨进程通信功能。其内部mDispatcher还持有对外部类ReceiverDispatcher对象的引用。所以流程是这样的:InnerReceiver#performReceive->ReceiverDispatcher#performReceive。
frameworks/base/core/java/android/app/ActivityThread.java
// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
frameworks/base/core/java/android/app/LoadedApk.java
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
//InnerReceiver#performReceive
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
...
//ReceiverDispatcher#performReceive
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
ReceiverDispatcher#performReceive的实现中会post出一个Runnable,Runnable中主要执行:1.BroadcastReceiver(广播接收者)执行onReceive流程,其中onReceive由app开发者实现;2.BroadcastReceiver.PendingResult#finish ->ActivityManagerService#finishReceiver进行广播接收者接受广播后的收尾工作。ActivityManagerService#finishReceiver是动态注册广播接受者和静态注册广播接收者处理完广播后都要进行的收尾工作。
frameworks/base/core/java/android/app/LoadedApk.java
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
+ (mRunCalled ? ", run() has already been called" : ""));
}
mCurIntent = null;
mDispatched = true;
mRunCalled = true;
if (receiver == null || intent == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
return;
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}
if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
};
}
}
广播接收者收尾工作
收尾工作分为两步:1.调用BroadcastQueue#finishReceiverLocked复位BroadcastRecord的记录,包括将状态由CALL_DONE_RECEIVE(有序&动态)或APP_RECEIVE(静态)转为IDLE,统计这个广播接收者的接收用时,清空这个BroadcastRecord关于这个广播接受者的数据等等。收尾工作完成后,也就意味着当前的广播接受者已经被系统遗忘,不再记录,随时可能被GC回收。
2.调用processNextBroadcastLocked进行下一步的调度。一旦finishReceiverLocked返回true,意味着当前的广播接收者不会再被记录,如果在onReceive执行了耗时的操作,返回时可能的广播接收者已经失效了,这个时候可以尝试在onReceive中使用goAsync避免过早进入BroadcastQueue#finishReceiverLocked流程,待耗时操作执行完后,再调用BroadcastReceiver.PendingResult#finish进行收尾工作。具体使用方法可以参考:BroadcastReceiver 使用goAsync 执行异步操作
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;
BroadcastQueue queue;
synchronized(this) {
if (isOnOffloadQueue(flags)) {
queue = mOffloadBroadcastQueue;
} else {
queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
}
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
if (doNext) {
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
// updateOomAdjLocked() will be done here
trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
静态注册广播递送:processCurBroadcastLocked
静态注册广播递送的核心是:ApplicationThread#scheduleReceiver->ActivityThread#handleReceiver。ActivityThread#handleReceiver
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app, boolean skipOomAdj) throws RemoteException {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " for app " + app);
if (app.thread == null) {
throw new RemoteException();
}
if (app.inFullBackup) {
skipReceiverLocked(r);
return;
}
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceivers.add(r);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
mService.mProcessList.updateLruProcessLocked(app, false, null);
if (!skipOomAdj) {
mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
}
// Tell the application to launch this receiver.
r.intent.setComponent(r.curComponent);
boolean started = false;
try {
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Delivering to component " + r.curComponent
+ ": " + r);
mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.getReportedProcState());
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
} finally {
if (!started) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + ": NOT STARTED!");
r.receiver = null;
r.curApp = null;
app.curReceivers.remove(r);
}
}
}
handleReceiver的主要步骤有:1.利用类加载器实例化一个BroadcastReceiver;2.实例化的BroadcastReceiver执行onReceive函数;3.调用BroadcastReceiver.PendingResult#finish进行收尾工作。handleReceiver和动态注册广播接收者的scheduleRegisteredReceiver不同之处是:handleReceiver是临时实例化一个BroadcastReceiver来进行onReceive回调的,scheduleRegisteredReceiver是将BroadcastReceiver记录在AMS里面的,需要取出来进行onReceive回调。
frameworks/base/core/java/android/app/ActivityThread.java
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private void handleReceiver(ReceiverData data) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
String component = data.intent.getComponent().getClassName();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
IActivityManager mgr = ActivityManager.getService();
Application app;
BroadcastReceiver receiver;
ContextImpl context;
try {
app = packageInfo.makeApplication(false, mInstrumentation);
context = (ContextImpl) app.getBaseContext();
if (data.info.splitName != null) {
context = (ContextImpl) context.createContextForSplit(data.info.splitName);
}
java.lang.ClassLoader cl = context.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
receiver = packageInfo.getAppFactory()
.instantiateReceiver(cl, data.info.name, data.intent);
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
data.sendFinished(mgr);
throw new RuntimeException(
"Unable to instantiate receiver " + component
+ ": " + e.toString(), e);
}
try {
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + packageInfo.getPackageName()
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
data.sendFinished(mgr);
if (!mInstrumentation.onException(receiver, e)) {
throw new RuntimeException(
"Unable to start receiver " + component
+ ": " + e.toString(), e);
}
} finally {
sCurrentBroadcastIntent.set(null);
}
if (receiver.getPendingResult() != null) {
data.finish();
}
}
广播限制
广播限制只针对静态注册广播接收者,不针对动态广播注册者,从代码就可以看出来:这段限制代码加在动态广播注册者处理之后,静态注册广播接收者处理之前。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
if (!skip) {
final int allowed = mService.getAppStartModeLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
} else if (((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;
}
}
}
app启动模式
getAppStartModeLocked用来获取app启动模式。启动模式有4种:
APP_START_MODE_NORMAL
APP_START_MODE_DISABLED
APP_START_MODE_DELAYED
APP_START_MODE_DELAYED_RIGID
alwaysRestrict是true,ephemeral为false(非instant app),所以启动模式由appRestrictedInBackgroundLocked决定。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ (uidRec != null ? uidRec.idle : false));
if (uidRec == null || alwaysRestrict || forcedStandby || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
UserHandle.getUserId(uid), packageName);
} else {
ephemeral = uidRec.ephemeral;
}
if (ephemeral) {
// We are hard-core about ephemeral apps not running in the background.
return ActivityManager.APP_START_MODE_DISABLED;
} else {
if (disabledOnly) {
// The caller is only interested in whether app starts are completely
// disabled for the given package (that is, it is an instant app). So
// we don't need to go further, which is all just seeing if we should
// apply a "delayed" mode for a regular app.
return ActivityManager.APP_START_MODE_NORMAL;
}
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
if (DEBUG_BACKGROUND_CHECK) {
Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
+ " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
+ " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
}
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
// This is an old app that has been forced into a "compatible as possible"
// mode of background check. To increase compatibility, we will allow other
// foreground apps to cause its services to start.
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}
if (proc != null &&
!ActivityManager.isProcStateBackground(proc.getCurProcState())) {
// Whoever is instigating this is in the foreground, so we will allow it
// to go through.
return ActivityManager.APP_START_MODE_NORMAL;
}
}
}
return startMode;
}
}
return ActivityManager.APP_START_MODE_NORMAL;
}
可见,当静态注册广播接收者所在的app targetsdk大于等于Android O时,直接返回APP_START_MODE_DELAYED_RIGID。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// Unified app-op and target sdk check
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
if (packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
// ...and legacy apps get an AppOp check
int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, packageName);
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
// If force-background-check is enabled, restrict all apps that aren't whitelisted.
if (mForceBackgroundCheck &&
!UserHandle.isCore(uid) &&
!isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ true)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Force background check: " +
uid + "/" + packageName + " restricted");
}
return ActivityManager.APP_START_MODE_DELAYED;
}
return ActivityManager.APP_START_MODE_NORMAL;
case AppOpsManager.MODE_IGNORED:
return ActivityManager.APP_START_MODE_DELAYED;
default:
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
}
allowed是APP_START_MODE_DELAYED_RIGID的情况下,在以下两种情况会跳过当前的广播接收者:1.广播的intent带有FLAG_RECEIVER_EXCLUDE_BACKGROUND的flag(默认不带);2.广播的intent没有指组件名和包名&没有带FLAG_RECEIVER_INCLUDE_BACKGROUND的flag&发送广播的权限参数为null或者不仅仅是一个签名级别的权限。
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
if (!skip) {
final int allowed = mService.getAppStartModeLocked(
info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
// (depending on how getAppStartModeLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
+ component.flattenToShortString());
skip = true;
} else if (((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;
}
}
}
因此,我们知道,用最传统的public void sendBroadcast(Intent intent)发送的广播是无法传递到静态注册广播接收者的,要传递到静态注册广播接收者,可以按以下方式之一做:
1.广播的intent使用setComponent指定广播接收者的组件名;
2.广播的intent使用setPackage指定广播接收者的包名;
3.广播的intent带上FLAG_RECEIVER_INCLUDE_BACKGROUND的flag;
4.使用public void sendBroadcast(Intent intent, String receiverPermission)或其他带权限参数的函数发送广播,receiverPermission所有权限全是仅签名级别的权限(不清楚这点的用意何在)。