[Android]BroadcastQueue如何分发广播(四)
[Android]BroadcastQueue如何分发广播(四)
- AndroidBroadcastQueue如何分发广播四
- scheduleBroadcastsLocked
- processingNextBroadcast
- 1 平行广播的分发
- 11 deliverToRegisteredReceiverLocked
- 12 performReceiveLocked
- frameworksbasecorejavaandroidappLoadedApkjava
- 2 串行广播的分发
- 21 整个流程概述
- 22 alive进程分发流程
- 23 进程不存在
- 1 平行广播的分发
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整体总结)
更多相关文章
- 通过广播检测sdcard插拔操作
- Android锁屏及监听锁屏事件
- Android(安卓)之通知Notification应用
- [Android] Service和广播联合更新UI
- Android中获取电池电量
- android 接收锁屏广播
- 在android中获取系统后台运行的进程
- Android程序——退出程序的时候杀死所有进程的一个方法
- android 根据pid 获取进程名