[Android]BroadcastQueue如何分发广播(四)

  • AndroidBroadcastQueue如何分发广播四
    • scheduleBroadcastsLocked
    • processingNextBroadcast
      • 1 平行广播的分发
        • 11 deliverToRegisteredReceiverLocked
        • 12 performReceiveLocked
        • frameworksbasecorejavaandroidappLoadedApkjava
      • 2 串行广播的分发
        • 21 整个流程概述
        • 22 alive进程分发流程
        • 23 进程不存在

1. scheduleBroadcastsLocked()

判断当前是否正在处理广播,true ,则返回等待;发送空消息processNextBroadcast

public void scheduleBroadcastsLocked() {    if (mBroadcastsScheduled) {            return;    }    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));    mBroadcastsScheduled = true;}private final class BroadcastHandler extends 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");            processNextBroadcast(true);        } break;        ...        }    }    }

2. processingNextBroadcast()

我们在前文已经说过,==所有的静态receiver都是串行处理的==,而动态receiver则会按照发广播时指定的方式,==进行“并行”或“串行”处理

动态receiver处理
    发送的普通广播,则会按并行方式分发,

    若sendOrderedXXX,则以串行的方式分发;
    能够并行处理的广播,其对应的若干receiver一定都已经存在了,不会牵扯到启动新进程的操作,所以可以在一个while循环中,一次性全部deliver,分给对应的进程即可。
静态注册的Receiver
    而有序广播,则需要一个一个地处理,其滚动处理的手段是发送事件,也就是说,在一个receiver处理完毕后,会利用广播队列(BroadcastQueue)的mHandler,发送一个BROADCAST_INTENT_MSG事件,从而执行下一次的processNextBroadcast()。

2.1 平行广播的分发

处理Queue中的并行部分,仅需要遍例mParallelBroadcasts中的每一个BroadcastRecord以及其中的receivers列表.对于平行广播而言receivers每个节点都是BroadcastFilter,只需要将广播分发下去即可:

    // First, deliver any non-serialized broadcasts right away.    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            Object target = r.receivers.get(i);            // BroadcastFiler            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);        }        addBroadcastToHistoryLocked(r);     }

2.1.1 deliverToRegisteredReceiverLocked()

分发intent到每个BroadcastFilter
    r.deliver[] 与r.receivers的数量对应,会记录对应receiver的分发状态: Timeout, pending, delivered, skipped;并且这个intent的发送状态都会记录在broadcastRecord中
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,                                                     BroadcastFilter filter,                                                      boolean ordered) {    // 权限检查    . . . . . .    . . . . . .    if (!skip)     {        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();            }        }            . . . . . .            performReceiveLocked(filter.receiverList.app,                                  filter.receiverList.receiver,                                 new Intent(r.intent), r.resultCode,                                 r.resultData, r.resultExtras,                                  r.ordered, r.initialSticky);            if (ordered)             {                r.state = BroadcastRecord.CALL_DONE_RECEIVE;            }        . . . . . .}

检查对应的BroadcastFilter是否有权限处理该intent,否则就将deliver[i] = BroadcastRecord.DELIVERY_SKIPPED

2.1.2 performReceiveLocked

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,        Intent intent, int resultCode, String data, Bundle extras,        boolean ordered, boolean sticky) throws RemoteException {    // Send the intent to the receiver asynchronously using one-way binder calls.    if (app != null && app.thread != null)     {        // If we have an app thread, do the call through that so it is        // correctly ordered with other one-way calls.        // app.thread 调用Reciever APP所在主线程的schedule方法        app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,                data, extras, ordered, sticky);    }     else     {        receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);    }}

终于通过app.thread向用户进程传递语义了。注意scheduleRegisteredReceiver()的receiver参数,它对应的就是前文所说的ReceiverDispatcher的Binder实体——InnerReceiver了;调用到这里则是进入到每个APP的进程中了

frameworks/base/core/java/android/app/ActivityThread.java

// This function exists to make sure all receiver dispatching is// correctly ordered, since these are one-way calls and the binder driver// applies transaction ordering per object for such calls.public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,        int resultCode, String dataStr, Bundle extras, boolean ordered,        boolean sticky) throws RemoteException {    //receiver 的实现类即是ReceiverDispatcher.InnerReceiver    receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky);}

==终于走到ReceiverDispatcher的InnerReceiver了:==

frameworks/base/core/java/android/app/LoadedApk.java

static final class ReceiverDispatcher {    final static class InnerReceiver extends IIntentReceiver.Stub     {        . . . . . .        . . . . . .        public void performReceive(Intent intent, int resultCode,                                   String data, Bundle extras,                                    boolean ordered, boolean sticky)         {            LoadedApk.ReceiverDispatcher rd = mDispatcher.get();            . . . . . .            if (rd != null) {                rd.performReceive(intent, resultCode, data, extras,                                  ordered, sticky);            }             . . . . . .        }    }    . . . . . .    public void performReceive(Intent intent, int resultCode,                               String data, Bundle extras,                                boolean ordered, boolean sticky)     {        . . . . . .        Args args = new Args(intent, resultCode, data, extras, ordered, sticky);        // 此处的ActivityThread则是每个APP的main thread.        // 将此Runnable对象放入主线程队列等待处理        if (!mActivityThread.post(args)) // 请注意这一句!        {            if (mRegistered && ordered)             {                IActivityManager mgr = ActivityManagerNative.getDefault();                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,                        "Finishing sync broadcast to " + mReceiver);                args.sendFinished(mgr);            }        }    }}

轮到Args执行

final class Args extends BroadcastReceiver.PendingResult implements Runnable {    . . . . . .    . . . . . .    public void run()     {        final BroadcastReceiver receiver = mReceiver;        . . . . . .        try {               ClassLoader cl =  mReceiver.getClass().getClassLoader();            intent.setExtrasClassLoader(cl);            intent.prepareToEnterProcess();            setExtrasClassLoader(cl);            receiver.setPendingResult(this);            // 通过反射调用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();        }        . . . . . .    }}

2.2 串行广播的分发

有序广播和静态广播都是以串行的方式分发出去

2.2.1 整个流程概述

 // Now take care of the next serialized one...// If we are waiting for a process to come up to handle the next// broadcast, then do nothing at this point.  Just in case, we// check that the process we're waiting for still exists.//if (mPendingBroadcast != null) {    boolean isDead;    synchronized (mService.mPidsSelfLocked) {        ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);        isDead = proc == null || proc.crashing;    }    if (!isDead) {        // It's still alive, so keep waiting        return;    } else {        mPendingBroadcast.state = BroadcastRecord.IDLE;        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;        mPendingBroadcast = null;    }}do {    // 总是从集合第一个获取    r = mOrderedBroadcasts.get(0);    //超时处理    //最后一个receiver处理完后,重新get(0)    {     cancelBroadcastTimeoutLocked();  // ... and on to the next...  addBroadcastToHistoryLocked(r);  if (r.intent.getComponent() == null && r.intent.getPackage() == null          && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {      // This was an implicit broadcast... let's record it for posterity.      mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,              r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);  }     // 当前Intent已经完全发送结束,移除,进入下一个节点     mOrderedBroadcasts.remove(0);     continue;    }} while (r != null)// Get the next receiver...// 每个intent对应一个Receiver集合,每有一个receiver接收,都会同步其索引int recIdx = r.nextReceiver++; // after nextReceiver = 1, recIdx = 0// Keep track of when this receiver started, and make sure there// is a timeout message pending to kill it if need be.// 开始接收,此时记录接收时间r.receiverTime = SystemClock.uptimeMillis();if (recIdx == 0) {      // 如果recIdx = 0,表示开始分发intent      // 此时记录分发的时间    r.dispatchTime = r.receiverTime;    r.dispatchClockTime = System.currentTimeMillis();}// 处理超时的代码if (! mPendingBroadcastTimeoutMessage) {    long timeoutTime = r.receiverTime + mTimeoutPeriod;    setBroadcastTimeoutLocked(timeoutTime);}final Object nextReceiver = r.receivers.get(recIdx);// 有序广播中的动态接收者,分发流程与普通动态广播的分发流程基本一致if (nextReceiver instanceof BroadcastFilter) {    // Simple case: this is a registered receiver who gets    // a direct call.    BroadcastFilter filter = (BroadcastFilter)nextReceiver;    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);    if (r.receiver == null || !r.ordered) {        // The receiver has already finished, so schedule to        // process the next one.        r.state = BroadcastRecord.IDLE;        scheduleBroadcastsLocked();    } else {        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {            scheduleTempWhitelistLocked(filter.owningUid,                    brOptions.getTemporaryAppWhitelistDuration(), r);        }    }    return;}// 此时才是真正处理静态注册的receiver// 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);...// 这里将有一系统的权限检查,若是不合法则会skip...        String targetProcess = info.activityInfo.processName;ProcessRecord app = mService.getProcessRecordLocked(targetProcess,info.activityInfo.applicationInfo.uid, false);        // 需要skip的receiver,修改状态且重发下一个if (skip) {    r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;    r.receiver = null;    r.curFilter = null;    r.state = BroadcastRecord.IDLE;    scheduleBroadcastsLocked();    return;}// 修改状态,并在BroadcastRecord节点中保存当前的receiverr.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;r.state = BroadcastRecord.APP_RECEIVE;r.curComponent = component;r.curReceiver = info.activityInfo;// 如果广播正在发送的话,这个receiver所在APK是不可被禁用的!!!// Broadcast is being executed, its package can't be stopped.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);}// 若是receiver所在进程已启动if (app != null && app.thread != null) {    try {      app.addPackage(info.activityInfo.packageName,              info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);      // 直接分发给指定进程      processCurBroadcastLocked(r, app);      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.}// receiver所在进程不可用,启动该进程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) {    // Ah, this recipient is unavailable.  Finish it if necessary,    // and mark the broadcast record as ready for the next.    logBroadcastReceiverDiscardLocked(r);    finishReceiverLocked(r, r.resultCode, r.resultData,            r.resultExtras, r.resultAbort, false);    scheduleBroadcastsLocked();    r.state = BroadcastRecord.IDLE;    return;}// 将此节点保存在pendingBroadcast 以便进程启动后即时发送,// 进入到这里,表示该receiver的进程未启动,需要等其启动后再发送mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;

2.2.2 alive进程分发流程

如果进程已经存在,只需要直接发送到该进程即可

private final void processCurBroadcastLocked(BroadcastRecord r,                        ProcessRecord app) throws RemoteException {    . . . . . .    r.receiver = app.thread.asBinder();    r.curApp = app;    app.curReceiver = r;    . . . . . .    . . . . . .        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,              mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),              r.resultCode, r.resultData, r.resultExtras, r.ordered);        . . . . . .        started = true;    . . . . . .}

ActivityThread.java

==当handleReceiver后,通过反射创建出BroadcastReceiver,调用它的onreceiver方法,到此处,BroadcastReceiver就可以收到此广播了==

void scheduleReceiver(Intent intent, ActivityInfo info,                       CompatibilityInfo compatInfo,                                            int resultCode, String data,                       Bundle extras, boolean sync)                       throws RemoteException;case RECEIVER:    ...    handleReceiver((ReceiverData)msg.obj);    ...    break;private void handleReceiver(ReceiverData data) {    . . . . . .    IActivityManager mgr = ActivityManagerNative.getDefault();    BroadcastReceiver receiver;    try {        java.lang.ClassLoader cl = packageInfo.getClassLoader();        data.intent.setExtrasClassLoader(cl);        data.setExtrasClassLoader(cl);        receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();    } catch (Exception e) {        . . . . . .    }    try {        . . . . . .        receiver.setPendingResult(data);        // 反射回调        receiver.onReceive(context.getReceiverRestrictedContext(), data.intent);    } catch (Exception e) {        . . . . . .    } finally {        sCurrentBroadcastIntent.set(null);    }    //     if (receiver.getPendingResult() != null) {        data.finish();    }}
思考
一个节点是对应多个receiver的,那么此时只发给了一个receiver,是如何与其它的receiver连接起来的呢?

2.2.3 进程不存在

如果进程不存在,需要等待receiver所在进程启动后再次触发;启动的过程是异步的,可能很耗时,所以要把BroadcastRecord节点记入mPendingBroadcast。

现在我们回过头来看,在目标进程尚未启动的情况下,是如何完成递送的。刚刚我们已经看到调用startProcessLocked()的句子了,只要不出问题,目标进程成功启动后就会调用AMS的attachApplication()。

有关attachApplication()的详情,请参考其他关于AMS的文档,此处我们只需知道它里面又会调用attachApplicationLocked()函数。

private final boolean attachApplicationLocked(IApplicationThread thread, int pid)...// Check if a next-broadcast receiver is in this process...if (!badApp && isPendingBroadcastProcessLocked(pid)) {    try {        didSomething = sendPendingBroadcastsLocked(app);    } catch (Exception e) {        // If the app died trying to launch the receiver we declare it 'bad'        badApp = true;    }}...
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {    boolean didSomething = false;    final BroadcastRecord br = mPendingBroadcast;    if (br != null && br.curApp.pid == app.pid) {        try {            mPendingBroadcast = null;            processCurBroadcastLocked(br, app);            didSomething = true;        } catch (Exception e) {            . . . . . .        }    }    return didSomething;}

可以看到,既然目标进程已经成功启动了,那么mPendingBroadcast = null了。接着,sendPendingBroadcastsLocked()会调用前文刚刚阐述的processCurBroadcastLocked(),其内再通过app.thread.scheduleReceiver(),将语义发送到用户进程,完成真正的广播递送。这部分在上一小节已有阐述,这里就不多说了。

它们的意思是,如果新启动的进程就是刚刚mPendingBroadcast所记录的进程的话,此时AMS就会执行sendPendingBroadcastsLocked(app)一句。

思考:
串行广播在分发时是有序传递的,那么对于未启动的receiver进程,如果启动慢,或是启动失败,或者是receiver处理超时了,广播队例该如何处理,后续任务?(参考Broadcast整体总结)

更多相关文章

  1. 通过广播检测sdcard插拔操作
  2. Android锁屏及监听锁屏事件
  3. Android(安卓)之通知Notification应用
  4. [Android] Service和广播联合更新UI
  5. Android中获取电池电量
  6. android 接收锁屏广播
  7. 在android中获取系统后台运行的进程
  8. Android程序——退出程序的时候杀死所有进程的一个方法
  9. android 根据pid 获取进程名

随机推荐

  1. Android 的独特shell命令
  2. android google地图定位开发,且可以自由移
  3. Andrid 控件集合大全
  4. Android 安全架构及权限控制机制剖析
  5. Android 技术专题系列之十三 -- 与PC同步
  6. Android视图优化之Merge,ViewStub基本使用
  7. Android SDK 2.2 和ADT插件下载
  8. android 的各种manager
  9. 【Android每日一练】Android项目结构详解
  10. Android中显示在线PDF