[Framework] 记录 BroadcastReceiver 导致的 can't deliver broadcast 崩溃

888 阅读10分钟

[Framework] 记录 BroadcastReceiver 导致的 can't deliver broadcast 崩溃

在我们公司的多个应用上经常能够看到以下的崩溃:

android.app.RemoteServiceException: can't deliver broadcast
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1813)
   at android.os.Handler.dispatchMessage(Handler.java:102)
   at android.os.Looper.loop(Looper.java:154)
   at android.app.ActivityThread.main(ActivityThread.java:6776)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)

最后记录到的崩溃方法栈在 ActivityThread 中的 H Handler 对象:

// ...
case SCHEDULE_CRASH:  
    throw new RemoteServiceException((String)msg.obj);
// ...    

其实这个崩溃方法栈没有什么太大的作用,这个崩溃是由 system_server 进程通过 binder 发送过来的,就是简单通知应用进程出现了异常,导致这个崩溃还有更加深层次的原因。

我在 StackOverflow 中也看到了有人提出这个问题:
StackOverflow

总结下有两种解决方案:

  1. onResuem()onPause() 中去注册/反注册 BroadcastReceiver 导致有几率出现上面的崩溃,所以将 BroadcastReceiver 的注册与反注册移动到 onCreate()onDestory() 生命周期中能够解决这个问题。
  2. 使用 LocalBroadcastManager 来发送本地广播,不过假如你要是监听的是系统的广播,这个方法就没有办法使用。(在我自己看来进程内传递消息,我并不会使用 BroadcastReceiver

我发现我们的应用崩溃都是在 API 30 及其以下的机型,而且都是在 Activity 进入 onPause() 生命周期后导致的崩溃,所以我就怀疑导致我们崩溃的就是解决方案1中的原因,在我写这篇文章的时候还没有验证这种修改方案是否有效。

Google Issue Tracker 中有人提出 Android 13 上有这个问题,不过我自己倒是没有在 Android 13 上遇到这个问题:

Google Issue Tracker

借助这个契机,我想简单看看 Broadcast 工作的原理,如果对源码不感兴趣的同学就不用看后面的内容了。

源码阅读基于 Android 11

注册广播

应用进程

我们注册广播通常是调用 Context#registerReceiver() 方法,最终会调用到 ContextImpl#registerReceiver() 方法:

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }
    
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), 0);
    }
    
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        // 这个对象非常重要,它是 AMS 通知广播来了的 binder 服务端    
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                // scheduler 是回调广播的的线程,默认是主线程
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                // 通过 LoadedApk#getReceiverDispatcher() 方法来获取 IIntentReceiver 对象
                rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            // 通过 binder 调用 AMS#registerReceiverWithFeature() 方法
            final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                    mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
                    filter, broadcastPermission, userId, flags);
            if (intent != null) {
                intent.setExtrasClassLoader(getClassLoader());
                intent.prepareToEnterProcess();
            }
            return intent;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

经过各种绕,会调用 registerReceiverInternal() 方法,这里会通过 LoadedApk#getReceiverDispatcher() 方法来生成一个 IIntentReceiver 对象,这个对象非常重要,它是一个 binderServer,用来接收 AMS 发送过来的广播消息。然后通过 ActivityManager#getService() 方法来获取 AMS 在客户端的 binderClient,然后通过 registerReceiverWithFeature() 方法来通知 AMS

我们再来看看 LoadedApk#getReceiverDispatcher() 方法的实现:

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
            Context context, Handler handler,
            Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();
        }
    }

上面的代码比较简单,应用中的所有的 BroadcastReceiver 都会被储存在 mReceivers 中,其中也包含了接收 AMS 广播的 binderServer 对象,也就是 IIntentReceiverIIntentReceiver 的实现类是 ReceiverDispatcher

我们再看看 ReceiverDispatcher 的构造函数:

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                Handler activityThread, Instrumentation instrumentation,
                boolean registered) {
            if (activityThread == null) {
                throw new NullPointerException("Handler must not be null");
            }
            // 构建 binder 的 server 的实现
            mIIntentReceiver = new InnerReceiver(this, !registered);
            // 这个 receiver 对象就是我们传入的 BroadcastReceiver。  
            mReceiver = receiver;
            mContext = context;
            mActivityThread = activityThread;
            mInstrumentation = instrumentation;
            mRegistered = registered;
            mLocation = new IntentReceiverLeaked(null);
            mLocation.fillInStackTrace();
        }

我们再看看 InnerReceiver 的构造函数的实现:

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

朴实无华的构造函数,只是用弱引用来持有 ReceiverDispatcher 实例,这里先提前说明下,有广播来的时候会通过 binder 调用 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) {
                    // 调用 ReceiverDispatcher#performReceive() 方法
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        // 通知 AMS 广播处理完成
                        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) {
            // 将广播的各种参数用 Args 对象封装    
            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);
                }
            }
            // 然后获取执行的线程(默认是主线程),来执行 Args#getRunnable() 方法生成的任务。
            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);
                }
            }
        }

我们继续追踪 Args#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);
        // 调用我们的 BroadcastReceiver#onReceiver() 方法
        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);
};

上面其他的代码都不用太关心,主要是会调用我们传入的 BroadcastReceiver#onReceive() 回调方法,这后续的处理我们就非常熟悉了。

system_server 进程

在前面我们讲到了应用进程注册 BroadcastReceiver 时,会通过 binder 调用 AMS#registerReceiverWithFeature() 方法,我们来看看它的实现:


    public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,
            String permission, int userId, int flags) {
        // ...
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                // 将 receiver (这个就是应用进程传递过来的 binder,主要用于将广播通知给应用进程) 封装到 ReceiverList
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    final int totalReceiversForApp = rl.app.receivers.size();
                    if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                        throw new IllegalStateException("Too many receivers, total of "
                                + totalReceiversForApp + ", registered for pid: "
                                + rl.pid + ", callerPackage: " + callerPackage);
                    }
                    将 ReceiverList 添加到 App 中
                    rl.app.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                // 将 ReceiverList 保存到 mRegisteredReceivers 成员变量中
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            }
           
           // ...
           
           // 将 IntentFilter 和 ReceiverList 封装到 BroadcastFilter 对象中。
           BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                // 将 BroadcastFilter 对象添加到 mReceiverResolver 成员变量中
                mReceiverResolver.addFilter(bf);
            }
        
        // ...
    }

我上面的代码中删掉了很多我们不关注的代码。简单来说上面的代码就是将 receiver (这个就是应用进程传递过来的 binder,主要用于将广播通知给应用进程) 封装到 ReceiverList 对象,并把它添加到 mRegisteredReceivers 成员变量中。将上面的 ReceiverList 对象和 IntentFilter 封装到 BroadcastFilter 对象,并把它添加到 mReceiverResolver 成员变量中。

发送广播

我们不考虑发送有序广播哈。

应用进程

我们发送广播是调用 Conrtext#sendBroadcast() 方法,它最终会到 ContextImpl#sendBroadcast() 方法中去。

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntentWithFeature(
                    mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                    null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
                    false, getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

开门见山,直接通过 binder 调用 AMS#broadcastIntentWithFeature() 方法。

system_server 进程

我们来看看 AMS#broadcastIntentWithFeature() 方法的实现:

    public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
        enforceNotIsolatedCaller("broadcastIntent");
        synchronized(this) {
            intent = verifyBroadcastLocked(intent);

            final ProcessRecord callerApp = getRecordForAppLocked(caller);
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();

            final long origId = Binder.clearCallingIdentity();
            try {
                return broadcastIntentLocked(callerApp,
                        callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermissions, appOp, bOptions, serialized, sticky,
                        callingPid, callingUid, callingUid, callingPid, userId);
            } finally {
                Binder.restoreCallingIdentity(origId);
            }
        }
    }

继续调用 broadcastIntentLocked() 方法:

    @GuardedBy("this")
    final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
            @Nullable String callerFeatureId, 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 realCallingUid,
            int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
            @Nullable int[] broadcastWhitelist) {
        
        // ...
        
        if (intent.getComponent() == null) {
            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                // ...
            } else {
                // 从 mReceiverResolver 去查询当前 intent 对应的 BroadcastFilter(其中包含订阅时的 Receiver)
                registeredReceivers = mReceiverResolver.queryIntent(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);
            }
            // 获取 BroadcastQueue 实例
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 将重要的广播信息封装成 BroadcastRecord 对象,也包含重要的 registeredReceivers 列表
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                    callerFeatureId, 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) {
                // 将 BroadcastRecord 添加到并行广播队列中
                queue.enqueueParallelBroadcastLocked(r);
                // 触发 BroadcastQueue 任务
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }
        
        // ...   
    }

我删除掉了很多其他的代码,感兴趣的同学可以自己去找来看。从 mReceiverResolver 去查询当前 intent 对应的 BroadcastFilter,(其中包含订阅时的 Receiver,在上面讲订阅广播的时候讲到了)查询到的 BroadcastFilter 列表存放在本地变量 registeredReceivers 中。然后将很多的重要变量封装在 BroadcastRecord 对象中,也包括上面的 registeredReceivers,然后将 BroadcastRecord 通过 BroadcastQueue#enqueueParallelBroadcastLocked() 方法添加到并行广播队列中,然后通过 BroadcastQueue#scheduleBroadcastsLocked() 方法来触发 BroadcastQueue 中的任务。

我们来看看 BroadcastQueue#enqueueParallelBroadcastLocked() 方法的实现:

public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

朴实无华的代码,直接将 BroadcastRecord 添加到 mParallelBroadcasts 成员变量列表中。

继续看看 scheduleBroadcastsLocked() 是如何触发任务的:

    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;
    }

直接通过 Handler 来触发,对应的是 BROADCAST_INTENT_MSGMessage

我们再来看看 Handler 是怎么处理这个消息的:

        @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;
            }
        }

收到 BROADCAST_INTENT_MSG 消息后,会调用 processNextBroadcast() 方法。

    final void processNextBroadcast(boolean fromMsg) {
        synchronized (mService) {
            processNextBroadcastLocked(fromMsg, false);
        }
    }
    
    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

        // ...

        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)) {
                // ...
            }

            final int N = r.receivers.size();
            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                    + mQueueName + "] " + r);
            // 遍历 BroadcastRecoder 中对应的 BroadcastFilter        
            for (int i=0; i<N; i++) {
                Object target = r.receivers.get(i);
                // ...
                // 将广播通知给 BroadcastFilter 中的 Receiver
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }
            addBroadcastToHistoryLocked(r);
            // ...
        }
        
        // ...
    }

遍历并行的 BroadcastRecord 列表,然后遍历 BroadcastRecoder 中的 BroadcastFilter 列表(其中就包含我们订阅广播时的 receiver),然后通过 deliverToRegisteredReceiverLocked() 方法来下发广播至 Receiver

    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
           // ...
                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);
                }
                
          // ...      
    
    }

然后继续调用 performReceiveLocked() 方法。

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser)
            throws RemoteException {
        // Send the intent to the receiver asynchronously using one-way binder calls.
        if (app != null) {
            if (app.thread != null) {
                // If we have an app thread, do the call through that so it is
                // correctly ordered with other one-way calls.
                try {
                    // 通过 binder 通知客户端,最后会触发对应的 Broadcast#onReceive() 方法回调
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                // DeadObjectException when the process isn't actually dead.
                //} catch (DeadObjectException ex) {
                // Failed to call into the process.  It's dying so just let it die and move on.
                //    throw ex;
                } catch (RemoteException ex) {
                    // 通过 binder 通知应用进程出现错误
                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
                    synchronized (mService) {
                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                + " (pid " + app.pid + "). Crashing it.");
                        // 将广播错误的信息,通知给应用进程        
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    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);
        }
    }

在上面的方法已经能够看到我们的崩溃信息了,首先通过 thread#scheduleRegisteredReceiver() 方法向应用进程发送广播消息,如果工作正常我们注册的 BroadcastReceiver#onReceive() 方法就会触发。如果这个过程出现了异常,就会向应用进程再发送 can't deliver broadcast 异常,也就是我们最开始看到的崩溃信息。
binder 的通信过程中有两种大的情况会触发 RemoteException

  1. 远端 binder Server 本身的实现方法报错。
  2. 通信本身中断导致报错。

我们看到源码中的注释描述这种情况是:

Failed to call into the process. It's either dying or wedged. Kill it gently.

也就是当前进程正在结束或者被卡住了。

最后

本篇文章简单介绍了广播接收器 can't deliver broadcast 异常的简单处理方式,然后还简单看了一下 Broadcast 的工作方式,希望这些内容能够对你有帮助。