Android 广播内部机制详解(三)

4 广播的处理

广播的处理都会调用BroadcastQueue下的scheduleBroadcastsLocked(),接下我们来看看这个函数

4.1 scheduleBroadcastsLocked

文件:BroadcastQueue.java

    public void scheduleBroadcastsLocked() {
        if (mBroadcastsScheduled) {
            return;
        }
        // 见4.1.1
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

mBroadcastsScheduled这个boolean的意思是如果当前真好有一个BROADCAST_INTENT_MSG在执行,那么mBroadcastsScheduled为true,否则为false

4.1.1 BroadcastHandler

文件:BroadcastQueue.java

private final class BroadcastHandler extends Handler {
        ......

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    // 见4.2
                    processNextBroadcast(true);
                } break;

                ......

            }
        }
    }

最重要的就是processNextBroadcast,广播处理会多次调用它

4.2 processNextBroadcast

文件:BroadcastQueue.java
这个函数有500多行,我们分开来讲

4.2.1 非串行广播的处理

            // 如果是从BroadcastHandler中调用来的,则fromMsg为true,mBroadcastsScheduled为false
            if (fromMsg) {
                mBroadcastsScheduled = false;
            }

            // 首先,立即发送所有的非串行广播
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0); // 每次都从一个开始
                r.dispatchTime = SystemClock.uptimeMillis();  // 分发时间
                r.dispatchClockTime = System.currentTimeMillis();  // 分发时间
                final int N = r.receivers.size();

                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    // 将广播发给BroadcastRecord所有的Receiver,见4.3
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                }
                addBroadcastToHistoryLocked(r); //将广播添加历史统计
            }

这部分主要是对非串行广播进行发送,通过两层循环来发送所有的Receiver,接下来看看串行发送的广播

4.2.2 串行广播的处理

            if (mPendingBroadcast != null) {

                boolean isDead;
                synchronized (mService.mPidsSelfLocked) {
                    // 拿到正在处理广播的进程,并判断它是否死亡
                    ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
                    isDead = proc == null || proc.crashing;
                }
                if (!isDead) {
                    // 如果处理广播的进程保持活跃状态,则继续等待
                    return;
                } else {
                    mPendingBroadcast.state = BroadcastRecord.IDLE;
                    mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
                    mPendingBroadcast = null;
                }
            }

判断处理广播的进程是否保持活跃状态,如果是,则继续等待其完成

            boolean looped = false;

            do {
                if (mOrderedBroadcasts.size() == 0) {
                    // 所有串行广播执行完毕,则执行GC操作
                    mService.scheduleAppGcsLocked();
                    if (looped) {
                        mService.updateOomAdjLocked();
                    }
                    return;
                }
                // 拿串行广播中的第一个
                r = mOrderedBroadcasts.get(0);
                boolean forceReceive = false;

                // 该ReceiverList中所有接收者的数量
                int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
                // AMS已经注册启动完成,并且不是该r第一次进这个循环了
                if (mService.mProcessesReady && r.dispatchTime > 0) {
                    long now = SystemClock.uptimeMillis()
                    // 出现超时
                    if ((numReceivers > 0) &&
                            (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                        broadcastTimeoutLocked(false); // 强制结束这个广播
                        forceReceive = true;
                        r.state = BroadcastRecord.IDLE;
                    }
                }
                if (r.state != BroadcastRecord.IDLE) {
                    return;
                }

每次都会取mOrderedBroadcasts中的第一个元素,然后判断是否超时,如果超时,则强制结束这个广播,并且这个BroadcastRecord剩下的广播接收器也将收不到广播。超时的依据是:2*mTimeoutPeriod*numReceivers,其中mTimeoutPeriod为(前台广播为10s,后台广播为60s),numReceivers为接收器的数量;接着如果BroadcastRecord的state不等于BroadcastRecord.IDLE,就返回

                // 要么是广播已经向所有的receiver发送完毕,要么是被强制停止
                if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {
                    if (r.resultTo != null) {
                        try {
                            // 处理广播消息,调用onReceive(),见4.3.1
                            performReceiveLocked(r.callerApp, r.resultTo,
                                new Intent(r.intent), r.resultCode,
                                r.resultData, r.resultExtras, false, false, r.userId);
                            r.resultTo = null;
                        } catch (RemoteException e) {
                            r.resultTo = null;
                        }
                    }

                    // 取消BROADCAST_TIMEOUT_MSG消息,见4.2.3
                    cancelBroadcastTimeoutLocked();

                    addBroadcastToHistoryLocked(r);
                    if (r.intent.getComponent() == null && r.intent.getPackage() == null
                            && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                        mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                                r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
                    }
                    mOrderedBroadcasts.remove(0);
                    r = null;
                    looped = true;
                    continue;
                }
            } while (r == null);

当Broadcasts中所有的receiver都收到了广播或者被强制结束了广播,都会调用performReceiveLocked;另外如果是取到BroadcastRecord第一次进来这个循环,将之前出来,因为不满足while (r == null)

            // 获取下一个需要处理的Receiver的序号
            int recIdx = r.nextReceiver++;
            // 这个BroadcastRecord开始处理这个Receiver的时间
            r.receiverTime = SystemClock.uptimeMillis();
            // 如果是BroadcastRecord中第一个Receiver
            if (recIdx == 0) {
                r.dispatchTime = r.receiverTime;
                r.dispatchClockTime = System.currentTimeMillis();
            }
            if (! mPendingBroadcastTimeoutMessage) {
                long timeoutTime = r.receiverTime + mTimeoutPeriod;
                // 见4.2.4
                setBroadcastTimeoutLocked(timeoutTime);
            }
  • 获取下一个要处理的Receiver

  • 获取当前处理这个Receiver的时间,用于处理ANR问题,如果是当前处理的是第一个Receiver,你们dispatchTime时间和receiverTime相等,用于处理整个BroadcastRecord的超时问题

  • mPendingBroadcastTimeoutMessage的初始值是false,然后设置针对该Receiver的超时处理,超时就会造成ANR;超时的时间为10s(前台广播)或者60s(后台广播)

            final BroadcastOptions brOptions = r.options;
            final Object nextReceiver = r.receivers.get(recIdx);
            // 如果是动态注册的有序广播
            if (nextReceiver instanceof BroadcastFilter) {
                BroadcastFilter filter = (BroadcastFilter)nextReceiver;
                // 发送该动态注册的有序广播,见4.3
                deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
                if (r.receiver == null || !r.ordered) {
                    r.state = BroadcastRecord.IDLE;
                    scheduleBroadcastsLocked();
                } else {
                    if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                        scheduleTempWhitelistLocked(filter.owningUid,
                                brOptions.getTemporaryAppWhitelistDuration(), r);
                    }
                }
                return;
            }

判断当前这个接收器是不是动态注册的,如果是动态注册的,就用deliverToRegisteredReceiverLocked发送,最后return,结束processNextBroadcast这个函数

            ResolveInfo info =
                (ResolveInfo)nextReceiver;
            ComponentName component = new ComponentName(
                    info.activityInfo.applicationInfo.packageName,
                    info.activityInfo.name);

            ......// 主要进行一些权限检查,如果不满足条件skip置为true,跳过这个receiver

            if (skip) {
                r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
                r.receiver = null;
                r.curFilter = null;
                r.state = BroadcastRecord.IDLE;
                scheduleBroadcastsLocked();
                return;
            }

            r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
            r.state = BroadcastRecord.APP_RECEIVE;
            r.curComponent = component;
            r.curReceiver = info.activityInfo;

            if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                scheduleTempWhitelistLocked(receiverUid,
                        brOptions.getTemporaryAppWhitelistDuration(), r);
            }

            // 广播已经开始执行了,这个包不能被停止
            try {
                AppGlobals.getPackageManager().setPackageStoppedState(
                        r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
            } catch (RemoteException e) {
            } catch (IllegalArgumentException e) {
                Slog.w(TAG, "Failed trying to unstop package "
                        + r.curComponent.getPackageName() + ": " + e);
            }

            // 检查目标进程是否已经运行
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(info.activityInfo.packageName,
                            info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
                    //将广播发送给目标进程,见4.2.5
                    processCurBroadcastLocked(r, app);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when sending broadcast to "
                          + r.curComponent, e);
                } catch (RuntimeException e) {
                    logBroadcastReceiverDiscardLocked(r);
                    finishReceiverLocked(r, r.resultCode, r.resultData,
                            r.resultExtras, r.resultAbort, false);
                    scheduleBroadcastsLocked();
                    // 如果启动receiver失败,需要重置state
                    r.state = BroadcastRecord.IDLE;
                    return;
                }
            }

            // 如果目标进程没有启动,则需要将他启动,见4.2.6
            if ((r.curApp=mService.startProcessLocked(targetProcess,
                    info.activityInfo.applicationInfo, true,
                    r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
                    "broadcast", r.curComponent,
                    (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                            == null) {
                // 这个接收器不能使用
                logBroadcastReceiverDiscardLocked(r);
                finishReceiverLocked(r, r.resultCode, r.resultData,
                        r.resultExtras, r.resultAbort, false);
                scheduleBroadcastsLocked();
                r.state = BroadcastRecord.IDLE;
                return;
            }

            mPendingBroadcast = r;
            mPendingBroadcastRecvIndex = recIdx;

处理静态注册下广播的发送,如果进程已经启动,则用processCurBroadcastLocked发送,然后返回,AMS等待广播接收的结果,以便进行下一个receiver发送广播,如果超时,就会触发ANR;
如果没有启动,则AMS调用startProcessLocked来启动接收者进程,启动的时候,将当前这个BroadcastRecord放到mPendingBroadcast中保存,把receiver的序号放到mPendingBroadcastRecvIndex中保存,应用启动完毕后会通知AMS,然后在进行广播发送

4.2.3 cancelBroadcastTimeoutLocked 取消超时

文件:BroadcastQueue.java

    final void cancelBroadcastTimeoutLocked() {
        if (mPendingBroadcastTimeoutMessage) {
            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
            mPendingBroadcastTimeoutMessage = false;
        }
    }

意思就是移除BROADCAST_TIMEOUT_MSG这个消息,不进行超时的处理了

4.2.4 setBroadcastTimeoutLocked 设置超时

    final void setBroadcastTimeoutLocked(long timeoutTime) {
        if (! mPendingBroadcastTimeoutMessage) {
            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
            mHandler.sendMessageAtTime(msg, timeoutTime);
            mPendingBroadcastTimeoutMessage = true;
        }
    }

由mHandler.sendMessageAtTime(msg, timeoutTime)可以看出,如果超时了就会发送消息BROADCAST_TIMEOUT_MSG

4.2.5 processCurBroadcastLocked

文件:BroadcastQueue.java

    private final void processCurBroadcastLocked(BroadcastRecord r,
            ProcessRecord app) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
        if (app.inFullBackup) {
            skipReceiverLocked(r);
            return;
        }

        r.receiver = app.thread.asBinder();
        r.curApp = app;
        app.curReceiver = r;
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        mService.updateLruProcessLocked(app, false, null);
        mService.updateOomAdjLocked();

        // 告诉应用启动receiver.
        r.intent.setComponent(r.curComponent);

        boolean started = false;
        try {
            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
            // 见4.4处理静态广播
            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                    mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                    app.repProcState);
            started = true;
        } finally {
            if (!started) {
                r.receiver = null;
                r.curApp = null;
                app.curReceiver = null;
            }
        }
    }

这里最重要的是scheduleReceiver

4.2.6 启动进程后通知AMS

流程如下:

  • ActivityThread.Main

  • ActivityThread.attach

  • AMS. attachApplication

  • AMS. attachApplicationLocked

到了attachApplicationLocked之后里面一行这样的代码:

didSomething |= sendPendingBroadcastsLocked(app);

我们继续看看sendPendingBroadcastsLocked

    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        for (BroadcastQueue queue : mBroadcastQueues) {
            didSomething |= queue.sendPendingBroadcastsLocked(app);
        }
        return didSomething;
    }

主要是这行didSomething |= queue.sendPendingBroadcastsLocked(app),我们继续追

    public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        final BroadcastRecord br = mPendingBroadcast;
        if (br != null && br.curApp.pid == app.pid) {
            if (br.curApp != app) {
                return false;
            }
            try {
                mPendingBroadcast = null;
                // 发送广播,见4.2.5
                processCurBroadcastLocked(br, app);
                didSomething = true;
            } catch (Exception 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取出正在等待的BroadcastRecord,然后将mPendingBroadcast置为null,接着用processCurBroadcastLocked发送广播

4.3 deliverToRegisteredReceiverLocked 用来发送所有动态注册的广播

文件:BroadcastQueue.java

    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
            BroadcastFilter filter, boolean ordered, int index) {
        boolean skip = false;
        if (filter.requiredPermission != null) {
            int perm = mService.checkComponentPermission(filter.requiredPermission,
                    r.callingPid, r.callingUid, -1, true);
            // 如果接收者没有权限,skip为true
            if (perm != PackageManager.PERMISSION_GRANTED) {
                skip = true;
            }
            ......
        }

        ...... //中间这很长一大串代码都是用来检查权限,如果不符合要求skip会置为true

        if (skip) {
            // 将状态改为DELIVERY_SKIPPED
            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
            return;
        }

        // 复查一下权限
        if (Build.PERMISSIONS_REVIEW_REQUIRED) {
            if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
                    filter.owningUserId)) {
                r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
                return;
            }
        }

        r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;

        // 如果是有序的动态广播
        if (ordered) {
            r.receiver = filter.receiverList.receiver.asBinder();
            r.curFilter = filter;
            filter.receiverList.curBroadcast = r;
            r.state = BroadcastRecord.CALL_IN_RECEIVE;
            if (filter.receiverList.app != null) {
                r.curApp = filter.receiverList.app;
                filter.receiverList.app.curReceiver = r;
                mService.updateOomAdjLocked(r.curApp);
            }
        }
        try {
            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                if (ordered) {
                    skipReceiverLocked(r);
                }
            } else {
                // 发送动态注册的广播,见4.3.1
                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                        new Intent(r.intent), r.resultCode, r.resultData,
                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
            }
            if (ordered) {
                r.state = BroadcastRecord.CALL_DONE_RECEIVE;
            }
        } 
        ......
    }
  • 进来时首先检查权限,不满足的将skip设置为true,并将对应的receiver的状态设置为DELIVERY_DELIVERED

  • 如果是有序的动态广播,以一种同步的方式发送广播,并且在BroadcastRecord中保存receiver,curFilter和state,其中state为CALL_IN_RECEIVE

  • 通过performReceiveLocked发送动态注册的广播

  • 如果有序的动态广播,state改为CALL_DONE_RECEIVE

4.3.1 performReceiveLocked

文件:BroadcastQueue.java

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
        // 进程已经启动的情况,用binder异步机制向receiver发送数据
        if (app != null) {
            if (app.thread != null) {
                try {
                    // 见4.3.2
                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                } catch (RemoteException ex) {
                    synchronized (mService) {
                        app.scheduleCrash("can't deliver broadcast");
                    }
                    throw ex;
                }
            } else {
                // 应用已经死亡,Receiver不存在
                throw new RemoteException("app.thread must not be null");
            }
        } else {
            // 调用进程为null时,则走这个分支
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

这里分为两种情况:

  • 调用进程和app.thread都不为null,这时通过binder方式向注册进程发起调用,其中Binder调用里会加上IBinder.FLAG_ONEWAY标记
    调用流程为:

  • 调用进程为null,这时执行receiver.performReceive(intent, resultCode, data, extras, ordered,sticky, sendingUser);

其中app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.repProcState)的调用流程为:

  • ApplicationThreadNative.ApplicationThreadProxy. scheduleRegisteredReceiver(system_server进程)

  • Binder驱动(Binder驱动进程,ONEWAY)

  • ApplicationThreadNative. scheduleRegisteredReceiver(应用进程,Binder线程向主线程发送消息)

  • Binder驱动返回 (Binder驱动进程)

  • ActivityThread. scheduleRegisteredReceiver(应用进程,处理消息)

4.3.2 scheduleRegisteredReceiver

        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);
            // 见4.3.3
            receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                    sticky, sendingUser);
        }

4.3.3 performReceive

这是LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive

            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;

                ......

                if (rd != null) {
                    // 见4.3.4
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } 

                ......

            }

4.3.4 ReceiverDispatcher.performReceive

文件:LoadedApk.java

        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            // 见4.3.5
            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中,post到主线程中执行,见4.3.5
            if (intent == null || !mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    // 告诉AMS,广播处理完毕,动态的有序广播会走这里见4.3.6
                    args.sendFinished(mgr);
                }
            }
        }

4.3.5 Args

final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }

            public void run() {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;

                final IActivityManager mgr = ActivityManagerNative.getDefault();
                final Intent intent = mCurIntent;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
                }

                mCurIntent = null;
                mDispatched = true;
                if (receiver == null || intent == null || mForgotten) {
                    if (mRegistered && ordered) {
                        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.onReceive()
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && ordered) {
                        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) {
                    // 见4.3.6
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
        }

这里主要调用的是receiver.onReceive(mContext, intent),至此非串行的动态注册的广播已经接收完毕,值得一提的是下面那个finish()函数,作用是结束这个广播,并将结果发送给下一个广播

4.3.6 sendFinished

文件:BroadcastReceiver.java

        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) {
                        // 见4.3.7
                        am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                                mAbortBroadcast, mFlags);
                    } else {
                        // 什么都不干,目的是告诉ActivityManager,这个广播我处理我完了
                        am.finishReceiver(mToken, 0, null, null, false, mFlags);
                    }
                } catch (RemoteException ex) {
                }
            }
        }

通过前面的分析,我们知道,动态广播如果是无序,在执行finish的时候,因为mType等于TYPE_REGISTERED,ordered为false,所以什么都不执行;只有有序的动态广播最终调用sendFinished,走mOrderedHint为true的那条线路,这里面mAbortBroadcast值得注意,如果为true,级别高的接收器收到广播后,级别低的就收不到广播了,好了,我们来看看finishReceiver,看这里函数你能知道动态的广播为什么可以循环起来

4.3.7 finishReceiver

文件:ActivityManagerService.java

    public void finishReceiver(IBinder who, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {

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

            synchronized(this) {
                BroadcastQueue 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.processNextBroadcast(false);
            }
            trimApplications();
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

首先判断是不是是前台广播还是后台广播,如果是后台广播则开始执行下一条广播,值得一提的是resultAbort和mAbortBroadcast上面的一致,最终的影响是这行代码:

if (r.receivers == null || r.nextReceiver >= numReceivers
                        || r.resultAbort || forceReceive) {

4.4 scheduleReceiver处理静态广播

我们还是一步步来看,首先:
文件:ActivityThread.java

        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;
            // 见4.4.1
            sendMessage(H.RECEIVER, r);
        }

4.4.1 H

文件:ActivityThread.java

        public void handleMessage(Message msg) {
            switch (msg.what) {
            ......
                case RECEIVER:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
                    // 见4.4.2
                    handleReceiver((ReceiverData)msg.obj);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
             ......

4.4.2 handleReceiver

文件:ActivityThread.java

    private void handleReceiver(ReceiverData data) {
        unscheduleGcIdler();

        String component = data.intent.getComponent().getClassName();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);

        IActivityManager mgr = ActivityManagerNative.getDefault();

        BroadcastReceiver receiver;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            data.intent.setExtrasClassLoader(cl);
            data.intent.prepareToEnterProcess();
            data.setExtrasClassLoader(cl);
            // 用反射的方式生成BroadcastReceiver
            receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
        } catch (Exception e) {
            data.sendFinished(mgr);
            throw new RuntimeException(
                "Unable to instantiate receiver " + component
                + ": " + e.toString(), e);
        }

        try {
            Application app = packageInfo.makeApplication(false, mInstrumentation);

            ContextImpl context = (ContextImpl)app.getBaseContext();
            sCurrentBroadcastIntent.set(data.intent);
            receiver.setPendingResult(data);
            // 调用目标Receiver的onReceive()
            receiver.onReceive(context.getReceiverRestrictedContext(),
                    data.intent);
        } catch (Exception e) {
            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();
        }
    }

用反射的方法获得类,然后生成BroadcastReceiver,接着调用onReceive()方法

5 总结与建议

5.1 并行广播和串行广播的发送特点

并行发送广播
这是发广播给动态注册接收器时的特点,采用异步的形式,广播之间不会互相干扰

串行发送广播
这是采用串行发送广播的方式,采用的是同步的机制,根据优先级来发送,优先级高的receiver可以停止广播想优先级低的发送;静态注册的Receiver和有序的动态注册的Receiver均采用这个方式

5.2 广播处理的流程图

广播处理流程图
这张图展示了有序和无序广播的处理流程

5.3 广播处理的时序图

广播处理时序图

5.4 建议

  • 判断自己的所需要获取的广播是否能够动态注册获取,因为Google基于优化考虑,比如SCREEN_OFF或SCREEN_OFF已经不能通过静态注册来获取了

  • 不要在onReceiver中进行耗时的操作,如果必须要这样做,可以发送Intent启动一个service来做

  • 如果需要一直对广播保持监听,建议使用静态注册,因为静态注册就算是目标进程不在了也可以重启,而动态注册的Receiver的生命周期会受应用的影响,应用销毁了,Receiver也就收不到广播了

  • 如果只在同一APP内部发送和接收广播,将exported属性设置成false,或者可以使用LocalBroadcastManager类(本地广播)

  • 广播发送和接收建议带上权限

  • 如果在onReceive()中开了一个子线程来执行工作,会碰上onReceive()已经返回,而子线程还没有做完工作的情况,这时候如果AMS结束了进程,这时子线程也会挂掉,但是工作却没有做完,可以利用要PendingResult来规避这个问题,一般finish()方法一般都是PendingResult不等于null的时候调用(参考4.3.6),使用方法如下:

public void onReceive(final Context context, final Intent intent) {
        //得到PendingResult
        final PendingResult result = goAsync();  

        //放到异步线程中执行
        AsyncHandler.post(new Runnable() {  
            @Override  
            public void run() {  
                handleIntent(context, intent);//可进行一些耗时操作  
                result.finish();  
            }  
        });  
    }

一旦调用goAsync(),那么BroadcastReceiver中的PendingResult将为null,这时finish方法得不到执行,AMS就收不到onReceive()执行完的消息,一直要到子线程调用result.finish()才会知道,这个目的只是为了不阻塞主线程,操作还是要在规定时间内完成

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值