BroadcastReceiver详细分析之串行广播的调度和超时机制

上一篇文章我们主要梳理了广播的动态注册,发送,接收,主要的数据结构以及需要大家严重注意的几点内容,相信大家已经熟悉了。没看过的朋友传送门:BroadcastReceiver详细分析之主要流程

相信聪明的朋友已经发现,上篇基本没怎么介绍串行广播和静态注册器,基本介绍的是普通广播的动态注册器的流程。因此,本篇单独讲解串行广播以及静态注册器的相关调度以及超时机制,毕竟这块知识点还是很多的,值得单开一篇文章。

本篇代码仍然基于原生Android Q

一.有序广播的基本使用

BroadcastReceiver的注册、发送和接收的主要流程和核心数据结构都已经讲解完。本篇主要讲述有序广播的调度和超时,无序广播都是并行发送的,不存在优先级和回调机制,因此也不会存在超时机制。这个好理解吧?还是再提一下吧,无序广播的动态注册器接收在上篇中都是循环直接发送的,属于binder的one way调用,AMS不需要等待它们执行结果。而有序广播需要根据接收器的优先级一个个发送,优先级高的接收器可以拦截广播等等,既然有先来后到,那么咱就只能一个个发了,并且前面的接收器要是处理时间太长怎么办?这不是影响后面的接收器了嘛,因此肯定会有超时机制。OK,废话不多说,我们开始:

下面是有序广播的基本使用方法:

//定义广播
BroadcastReceiver receiver=new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(MainActivity.this,"这是xiaomiapp2",Toast.LENGTH_LONG).show();
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    IntentFilter intentFilter=new IntentFilter("a.b.c");
    registerReceiver(receiver,intentFilter);            //注册广播
 
    ......
    Intent intent=new Intent();                         //发送广播
    intent.setAction("a.b.c");
    sendOrderedBroadcast(intent,null);

平平无奇的代码,不需要过多说。

二.串行广播的调度过程

根据之前介绍,串行广播是将动态注册和静态注册的接收器根据优先级合并在一起,然后统一调度。无序广播都是one way binder call,因此发完就发完了,不存在通知AMS,而有序广播发完是需要通知AMS的,因此需要一个一个的来,让我们回到BroadcastQueue的processNextBroadcastLocked方法:

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

        //......无序动态广播的处理,不再赘述

        // Now take care of the next serialized one...

        

        boolean looped = false;

        do {
            final long now = SystemClock.uptimeMillis();
            //取出有序广播一个BroadcastRecord任务
            r = mDispatcher.getNextBroadcastLocked(now); 

            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;
           
          //......

        // Get the next receiver...
        int recIdx = r.nextReceiver++; //取出该任务中的下一个接收器

        //......

        final BroadcastOptions brOptions = r.options;
        final Object nextReceiver = r.receivers.get(recIdx);

        //有序广播中的动态注册的广播,动态注册的广播是BroadcastFilter实例,静态注册的是ResolveInfo实例
        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方法
            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.
                }
                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;
        
        //......关于广播是否跳过的一系列判断
        
        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(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);
        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;
    }

2.1动态注册接收器的循环

上面动态注册的那部分进入了deliverToRegisteredReceiverLocked方法,我们看看:

    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
        //......
        try {
            if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                    "Delivering to " + filter + " : " + r);
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                // Skip delivery if full backup in progress
                // If it's an ordered broadcast, we need to continue to the next receiver.
                if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                r.receiverTime = SystemClock.uptimeMillis();
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                //进入performReceiveLocked
                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);
                }
            }
            //......

后面类似于上篇无序广播的方法调用链,最终进入args.getRunnable方法:

            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); //回调onReceiver方法
                    } 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();    //调用Pendingresult的finish方法
                    }
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                };
            }
        }

上述的finish方法,无序广播也会走到,具体的分叉就在finish方法里面啦:

        public final void finish() {
            if (mType == TYPE_COMPONENT) {
                final IActivityManager mgr = ActivityManager.getService();
                if (QueuedWork.hasPendingWork()) {
                    // If this is a broadcast component, we need to make sure any
                    // queued work is complete before telling AM we are done, so
                    // we don't have our process killed before that.  We now know
                    // there is pending work; put another piece of work at the end
                    // of the list to finish the broadcast, so we don't block this
                    // thread (which may be the main thread) to have it finished.
                    //
                    // Note that we don't need to use QueuedWork.addFinisher() with the
                    // runnable, since we know the AM is waiting for us until the
                    // executor gets to it.
                    QueuedWork.queue(new Runnable() {
                        @Override public void run() {
                            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                    "Finishing broadcast after work to component " + mToken);
                            sendFinished(mgr);
                        }
                    }, false);
                } else {
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to component " + mToken);
                    sendFinished(mgr);
                }
            } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing broadcast to " + mToken);
                final IActivityManager mgr = ActivityManager.getService();
                sendFinished(mgr);  //这里会进入sendFinished方法
            }
        }

上述代码段的mOrderedHint决定了无序广播不会走到里面的sendFinish方法,这就是所谓的分叉口啦,我们继续:

        public void sendFinished(IActivityManager am) {
            synchronized (this) {
                if (mFinished) {
                    throw new IllegalStateException("Broadcast already finished");
                }
                mFinished = true;

                try {
                    if (mResultExtras != null) {
                        mResultExtras.setAllowFds(false);
                    }
                    if (mOrderedHint) { //有序广播值为true
                        //通知AMS广播接收完成
                        am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                                mAbortBroadcast, mFlags);
                    } else {
                        // This broadcast was sent to a component; it is not ordered,
                        // but we still need to tell the activity manager we are done.
                        am.finishReceiver(mToken, 0, null, null, false, mFlags);
                    }
                } catch (RemoteException ex) {
                }
            }
        }

接着又是一次binder call,咱们来到AMS:

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

                //根据Ibinder对象,这里也就是IIntentReceiver查出BroadcastRecord
                r = queue.getMatchingOrderedReceiver(who);
                if (r != null) { //判断是否进行下一次分发
                    doNext = r.queue.finishReceiverLocked(r, resultCode,
                        resultData, resultExtras, resultAbort, true);
                }
                if (doNext) { //如果需要继续分发,则继续调用processNextBroadcastLocked
                    r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
                }
                // updateOomAdjLocked() will be done here
                trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
            }

        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

后面又进入到熟悉的processNextBroadcastLocked方法了,会执行下一个receiver的发送,不再赘述咯

2.2 静态注册接收器的循环

根据第二节的代码,静态接收器会执行到processCurBroadcastLocked方法:

    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);
            //同样调用IApplicationThread接口进入APP进程
            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);
            }
        }
    }

同样调用IApplicationThread接口进入APP进程,查看ApplicationThread的scheduleReceiver方法:

        public final void scheduleReceiver(Intent intent, ActivityInfo info,
                CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                boolean sync, int sendingUser, int processState) {
            updateProcessState(processState, false);
            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                    sync, false, mAppThread.asBinder(), sendingUser);
            r.info = info;
            r.compatInfo = compatInfo;
            sendMessage(H.RECEIVER, r);   //进入sendMessage方法
        }

进入sendMessage方法:

    private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) {
            Slog.v(TAG,
                    "SCHEDULE " + what + " " + mH.codeToString(what) + ": " + arg1 + " / " + obj);
        }
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);  //熟悉的主线程Handler
    }

进入主线程的handleMessage方法:

        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case EXIT_APPLICATION:
                    if (mInitialApplication != null) {
                        mInitialApplication.onTerminate();
                    }
                    Looper.myLooper().quit();
                    break;
                case RECEIVER:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
                    handleReceiver((ReceiverData)msg.obj); //what=RECEIVER,执行
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                
    }

进入handleReceiver方法:

    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); //设置pendingResult
            receiver.onReceive(context.getReceiverRestrictedContext(), //回调onReceiver方法
                    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(); //ReceiverData继承于PendingResult,因此后面仍然是调用PendingResult的finish方法
        }
    }

到这里就和动态注册接收器的finish方法一样啦,不再赘述咯

2.3 静态注册接收器进程的启动

上述几个过程都是APP启动的情况下进程广播接收的,那么在APP未启动的情况下,是怎样的接收过程呢?答案显而易见,AMS会启动APP进程,不过国内手机厂商在这一块把控比较严格,拿小米手机来说,应用安装后默认是关闭自启动权限的,需要打开自启动权限,这样才能启动APP进程。让我们回到BroadcastQueue的processNextBroadcastLocked方法:

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        //......

        // Is this receiver's application already running?
        //这里是APP进程已启动的情况下,上面已经介绍过
        if (app != null && app.thread != null && !app.killed) {
            try {
                app.addPackage(info.activityInfo.packageName,
                        info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
                maybeAddAllowBackgroundActivityStartsToken(app, r);
                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);
        //通过AMS的startProcessLocked启动
        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) {  //为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
            return;
        }

        maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
        mPendingBroadcast = r;               //不为null则把广播任务r赋给mPendingBroadcast
        mPendingBroadcastRecvIndex = recIdx;
    }

看到这里,大家可能觉得APP进程启动成功后也没看到处理广播的操作啊?是的,这个方法到这里就没了,聪明的你肯定想到了,肯定是在进程启动后的某个地方执行了广播,是的,you are so clever。

我们知道,Zygote进程孵化出APP进程后,会执行ActivityThread.main()方法,好的,我们去main方法里面看看:

    public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");

        // Install selective syscall interception
        AndroidOs.install();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();    //创建主线程looper

        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);   //调用thread.attach方法

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

继续,我们去attach方法里面去看看:

    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if (!system) {
            android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                    UserHandle.myUserId());
            RuntimeInit.setApplicationObject(mAppThread.asBinder());
            final IActivityManager mgr = ActivityManager.getService();
            try {
                //这边binder调用了AMS的attachApplication方法
                mgr.attachApplication(mAppThread, startSeq);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
          //......
     }

继续到AMS里面去看看:

    public final void attachApplication(IApplicationThread thread, long startSeq) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            //调用attachApplicationLocked方法
            attachApplicationLocked(thread, callingPid, callingUid, startSeq);
            Binder.restoreCallingIdentity(origId);
        }
    }

继续走着:

    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid, int callingUid, long startSeq) {

        //......

        // Check if a next-broadcast receiver is in this process...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) { //检查是否有待执行的广播
            try {
                //执行sendPendingBroadcastsLocked
                didSomething |= sendPendingBroadcastsLocked(app);
                checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
            } catch (Exception e) {
                // If the app died trying to launch the receiver we declare it 'bad'
                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
                badApp = true;
            }
        }
        //......
}

继续走着:

    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        //这里实际上遍历了所有的广播队列,如前台广播,后台广播等等
        for (BroadcastQueue queue : mBroadcastQueues) { 
            //调用sendPendingBroadcastsLocked
            didSomething |= queue.sendPendingBroadcastsLocked(app);
        }
        return didSomething;
    }

继续:

    public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        final BroadcastRecord br = mPendingBroadcast; //之前的mPendingBroadcast就在这里派上用场啦
        if (br != null && br.curApp.pid > 0 && br.curApp.pid == app.pid) {
            if (br.curApp != app) {
                Slog.e(TAG, "App mismatch when sending pending broadcast to "
                        + app.processName + ", intended target is " + br.curApp.processName);
                return false;
            }
            try {
                mPendingBroadcast = null;
                processCurBroadcastLocked(br, app, false);  //熟悉的函数
                didSomething = true;
            } catch (Exception e) {
                Slog.w(TAG, "Exception in new application when starting receiver "
                        + br.curComponent.flattenToShortString(), e);
                logBroadcastReceiverDiscardLocked(br);
                finishReceiverLocked(br, br.resultCode, br.resultData,
                        br.resultExtras, br.resultAbort, false);
                scheduleBroadcastsLocked();
                // We need to reset the state if we failed to start the receiver.
                br.state = BroadcastRecord.IDLE;
                throw new RuntimeException(e.getMessage());
            }
        }
        return didSomething;
    }

上述代码中,之前的mPendingBroadcast就在这里派上用场啦,后面就是调用processCurBroadcastLocked,跟上面的流程一样啦,不再赘述咯

三.串行广播的超时机制

既然有序广播需要通知AMS我已经接收完毕,那么肯定存在一个计时器来判断某个接收器是否超时,那么超时机制在哪设置的呢?聪明的你肯定又想到了,肯定是在分发有序广播的时候嘛,是的,you are very clever

我们回到BroadcastQueue的分发函数processNextBroadcastLocked里面看看:

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        BroadcastRecord r;

        //......
        if (! mPendingBroadcastTimeoutMessage) { //这里会判断BroadcastHandler里面是否存在超时消息
            //这里会定义超时消息的时间,receiverTime是分发给当前接收器的时间,mConstants.TIMEOUT是超时时间,前台广播10s,后台广播60s
            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) {
            //......
    }

Ok,我们继续查看setBroadcastTimeoutLocked:

    final void setBroadcastTimeoutLocked(long timeoutTime) {
        if (! mPendingBroadcastTimeoutMessage) { //二次校验是否有超时消息
            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
            mHandler.sendMessageAtTime(msg, timeoutTime); //在超时时间到了之后发送消息
            mPendingBroadcastTimeoutMessage = true;      //变量置为true
        }
    }

继续,BroadcastHandler又见面了:

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

继续查看:

    final void broadcastTimeoutLocked(boolean fromMsg) {
        if (fromMsg) {                                 //如果是来自handler的消息
            mPendingBroadcastTimeoutMessage = false; //变量置为false,表示又可以再发超时消息了
        }

        if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {
            return;
        }

        long now = SystemClock.uptimeMillis();
        BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
        if (fromMsg) {
            if (!mService.mProcessesReady) {
                // Only process broadcast timeouts if the system is ready; some early
                // broadcasts do heavy work setting up system facilities
                return;
            }

            // If the broadcast is generally exempt from timeout tracking, we're done
            if (r.timeoutExempt) {
                if (DEBUG_BROADCAST) {
                    Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "
                            + r.intent.getAction());
                }
                return;
            }

           //重点看看这边,这个now肯定是执行到这里的时间,也就是原先设置的超时时间点
            long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
            //这里的r.receiverTime是目前执行的receiver的分发时间点,如果满足,表示上一个接收器没有超时
            if (timeoutTime > now) {
                // We can observe premature timeouts because we do not cancel and reset the
                // broadcast timeout message after each receiver finishes.  Instead, we set up
                // an initial timeout then kick it down the road a little further as needed
                // when it expires.
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                        "Premature timeout ["
                        + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
                        + timeoutTime);
                //既然没有超时,那么就重新设置超时时间点
                setBroadcastTimeoutLocked(timeoutTime);
                return;       //此时对于超时消息的处理就返回了,也就是说本次函数调用不存在超时
            }
        }

        //......

        // Move on to the next receiver.        //如果超时了,就执行下一个接收器
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();

        if (!debugging && anrMessage != null) {   //打印ANR信息
            // Post the ANR to the handler since we do not want to process ANRs while
            // potentially holding our lock.
            mHandler.post(new AppNotResponding(app, anrMessage));
        }
    }

我这里写了一个demo,xiaomiapp2在onReceive()里面执行耗时操作,发生了ANR,而xiaomiapp在超时之后收到了广播,这是超时之后的log:

log很清楚,xiaomiapp2发生了ANR,但是不影响下一个接收器,xiaomiapp继续收到了广播并弹出Toast。

当串行广播接收器全部处理完毕后,取消超时消息:

if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {  //广播分发完毕

//......


                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
                cancelBroadcastTimeoutLocked();  //取消超时消息


//......

    final void cancelBroadcastTimeoutLocked() {
        if (mPendingBroadcastTimeoutMessage) {
            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); //移除超时消息
            mPendingBroadcastTimeoutMessage = false;
        }
    }

不得不说,Android在超时机制这一块还是设计的很巧妙简洁的。

四.总结

串行广播的调度和超时机制也讲完咯,大家看到这里也挺累的,此外,还有一种广播叫粘性广播(sticky),不过Android官方已经不推荐使用了,我也就不说了。大家主要还是关注串行广播的整个循环调度的过程,以及启动进程和超时机制,毕竟平常在排查广播的相关问题时还是需要了解原理的。

有什么不对之处欢迎指出,大家一起学习,一起进步!

发布了10 篇原创文章 · 获赞 89 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/cbzcbzcbzcbz/article/details/104063325