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

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

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<N; 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节点中保存当前的receiver
r.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整体总结)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值