我们知道在BroadcastReceiver的onReceive方法中执行耗时操作可能导致ANR, 跟踪源码看看anr是如何触发的。
有序广播的使用
// 1.定义广播接收器
public class PriorityBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "PriorityBroadcast";
@Override
public void onReceive(Context context, Intent intent) {
String resultData = getResultData();
Log.d(TAG, "优先级为1的接收到的广播数据resultData---->" + resultData);
}
}
// 2.1 在AndroidManifest.xml中注册广播接收器
<receiver android:name=".broadcast.PriorityBroadcastReceiver"
android:exported="true">
<intent-filter android:priority="1">
<action android:name="order.test.example.xxx" />
</intent-filter>
</receiver>
// 2.2 或在代码中动态注册广播
val intentFilter = IntentFilter()
intentFilter.addAction(“order.test.example.xxx”)
registerReceiver(receiver, intentFilter)
// 3.发送广播
val intent = Intent()
intent.putExtra("data", "有序广播通过intent.putExtra传递的数据")
intent.action = "order.test.example.xxx"
val bundle = Bundle()
bundle.putString("order_data", "有序广播通过bundle传递的数据")
sendOrderedBroadcast(intent, null, PriorityBroadcastReceiver2(), handler, Activity.RESULT_OK,"MainActivity发送了一个有序广播", bundle)
广播的动态注册流程
下面看看广播的动态注册流程:
Activity.registerReceiver(receiver, intentFilter) ->
ContextImpl.registerReceiver(xxx) ->
ContextImpl.registerReceiverInternal(xxx) ->
ActivityManagerService.registerReceiverWithFeature(xxx) ->
来看看在ActivityManagerService中注册广播的方法
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,String callerFeatureId, String receiverId, IIntentReceiver receiver,IntentFilter filter, String permission, int userId, int flags) {
...
// 添加到mRegisteredReceivers中
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
// 新建一个ReceiverList保存Receiver和对应的filter
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
rl.app.mReceivers.addReceiver(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
...
// 创建filter对象
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
exported);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
// 把filter添加到ReceiverList中保存
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
// 保存filter
mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf);
}
...
}
就是把Receiver和IntentFilter保存起来,等发送广播的时候就可以查找。
发送广播的流程
Activity.sendBroadcast(intent) ->
ContextImpl.sendBroadcast(xxx) ->
ActivityManagerService.broadcastIntentWithFeature() ->
ActivityManagerService.broadcastIntentLocked() ->
来看看broadcastIntentLocked方法的实现:
final int broadcastIntentLocked() {
...
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// 从packageManager查找匹配的receiver
receivers = collectReceiverComponents(
intent, resolvedType, callingUid, users, broadcastAllowList);
}
if (intent.getComponent() == null) {
final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot();
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(snapshot, intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
// 查找
registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
...
// 无序广播
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,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, 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;
}
...
// 有序广播
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, 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 {
oldRecord.mIsReceiverAppRunning = true;
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.userId, oldRecord.callingUid, callingUid,
SystemClock.uptimeMillis() - oldRecord.enqueueTime, 0);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["
+ queue.mQueueName + "] sending broadcast result of "
+ intent, e);
}
}
} else {
// 加入有序广播队列
queue.enqueueOrderedBroadcastLocked(r);
// 广播分发
queue.scheduleBroadcastsLocked();
}
...
}
查找符合条件的广播接收者,然后按照有序广播和无序广播分别加到对应的队列中,然后调用BroadcastQueue的scheduleBroadcastsLocked方法开始分发广播到广播接收者,处理的方法是processNextBroadcastLocked
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
...
// 处理无序广播
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
r.mIsReceiverAppRunning = true;
...
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);
}
}
...
// 处理有序广播 取下一个
int recIdx = r.nextReceiver++;
// 记录接收时间
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchRealTime = SystemClock.elapsedRealtime();
r.dispatchClockTime = System.currentTimeMillis();
...
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
// 设置超时时间
setBroadcastTimeoutLocked(timeoutTime);
}
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
r.mIsReceiverAppRunning = true;
// 发送广播
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// 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.
}
}
return;
}
无序广播直接一次性调了所有的广播接收器;有序广播时逐个调用的,所以只有有序广播才设置了超时时间。我们先如何调到应用进程的onReceive的。
BroadcastQueue.deliverToRegisteredReceiverLocked() ->
BroadcastQueue.performReceiveLocked() ->
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser,
int receiverUid, int callingUid, long dispatchDelay,
long receiveDelay) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
final IApplicationThread thread = app.getThread();
if (thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
// 调到ApplicationThread
thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser,
app.mState.getReportedProcState());
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
final String msg = "Failed to schedule " + intent + " to " + receiver
+ " via " + app + ": " + ex;
Slog.w(TAG, msg);
app.killLocked("Can't deliver broadcast", ApplicationExitInfo.REASON_OTHER,
ApplicationExitInfo.SUBREASON_UNDELIVERED_BROADCAST, true);
}
throw ex;
}
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
...
}
接着调到了ApplicationThread:
ApplicationThread.scheduleRegisteredReceiver() ->
// frameworks/base/core/java/android/app/LoadedApk.java
InnerReceiver.performReceive() ->
ReceiveDispatcher.performReceive() ->
mActivityThread.post(args.getRunnable()) ->
看看runnable的代码
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
mContext.getAttributionSource());
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
// 调用onReceive方法
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();
}
反射创建了BroadcastReceiver对象,并调用了Receiver的onReceive方法,最后调用了finish() 方法告诉ActivityManagerService广播结束。这样ActivityManagerService就可以执行下一个广播了。在执行下一个广播前会把前一个广播的超时检测给取消。
cancelBroadcastTimeoutLocked();
再来看看如果没有及时取消,会怎么样:
final void broadcastTimeoutLocked(boolean fromMsg) {
...
ProcessRecord app = null;
String anrMessage = null;
Object curReceiver;
if (r.nextReceiver > 0) {
curReceiver = r.receivers.get(r.nextReceiver-1);
r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
} else {
curReceiver = r.curReceiver;
}
...
if (app != null) {
anrMessage = "Broadcast of " + r.intent.toString();
}
if (mPendingBroadcast == r) {
mPendingBroadcast = null;
}
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
if (!debugging && anrMessage != null) {
// 开始anr处理流程
mService.mAnrHelper.appNotResponding(app, anrMessage);
}
}
这里就直接开始anr的处理流程,这个部分的处理和service是一致的,具体流程可以参考上一篇。
总结:
- 有序广播才会触发anr;
- 前一个广播处理完了,在处理下一个时就会把前一个的超时处理任务给取消掉;如果没有及时取消就会走到anr的处理流程;
- anr的处理流程和service是相同的。