[ Android源码分析 ] Android 广播队列中的 mParallelBroadcasts 和 mOrderedBroadcasts

[ Android源码分析 ] Android 广播队列中的 mParallelBroadcasts 和 mOrderedBroadcasts

尊重原创,转载请注明出处!

前言

在前面的博客 [ Android实战 ] 开机时通过广播启动应用,但是很长时间才能接收到,如何解决? 中,我们知道广播发送时,会根据广播类型以及接收器注册的方式,将广播分别加入到 mParallelBroadcasts 和 mOrderedBroadcasts 队列中,并行或串行地进行处理。
但是这个并行处理和串行处理具体是怎么实现的呢?还需要具体分析一下。

广播分发流程

Android 中的广播分为普通广播(sendBroadcast)、有序广播(sendOrderedBroadcast)和粘性广播(sendStickyBroadcast)。

但是无论是哪种广播,最终都是通过封装调用流程走到 AMS 中的 broadcastIntentLocked 方法中,通过 它的 ordered 和 sticky 参数进行区分。参数传递的源码虽然很简单,但是要占用大量篇幅,就不贴代码了,直接给出结论:

普通广播:ordered = false,sticky = false
有序广播:ordered = true,sticky = false
粘性广播:ordered = false,sticky = true

根据 broadcastIntentLocked 中的逻辑,我们暂时以 ordered 作为分类依据,考虑无序广播(包括普通广播和粘性广播)和有序广播,以及对应的静态注册和动态注册的 Receiver,所组成的广播发送流程。

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

final int broadcastIntentLocked(ProcessRecord callerApp,
		String callerPackage, Intent intent, String resolvedType,
		IIntentReceiver resultTo, int resultCode, String resultData,
		Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
		boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
	......
	// 找出接收此广播的所有接收器
	List receivers = null; // 用于记录静态注册receiver
	List<BroadcastFilter> registeredReceivers = null; // 用于记录动态注册receiver
	......

	int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
	// 处理无序广播
	if (!ordered && NR > 0) {
		......
		// 这里会根据是否携带FLAG_RECEIVER_FOREGROUND,选择mFgBroadcastQueue或mBgBroadcastQueue发送广播
		final BroadcastQueue queue = broadcastQueueForIntent(intent);
		BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
				callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
				requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
				resultCode, resultData, resultExtras, ordered, sticky, false, userId);
		if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
		final boolean replaced = replacePending
				&& (queue.replaceParallelBroadcastLocked(r) != null);
		// Note: We assume resultTo is null for non-ordered broadcasts.
		if (!replaced) {
			// 这里是核心代码,将构造的BroadcastRecord加入到mParallelBroadcasts广播队列
			queue.enqueueParallelBroadcastLocked(r);
			// 调用BroadcastQueue.scheduleBroadcastsLocked,从广播队列中取出广播进行并行处理
			queue.scheduleBroadcastsLocked();
		}
		registeredReceivers = null;
		NR = 0;
	}

	// Merge into one list.
	int ir = 0;
	if (receivers != null) {
		// 如果是有序广播,需要结合动态注册和静态注册的receiver,通过比较优先级来调整接收广播的顺序。最终都存放到receivers中进行处理
		......
		int NT = receivers != null ? receivers.size() : 0;
		int it = 0;
		ResolveInfo curt = null; // ResolveInfo是对静态注册receiver的封装
		BroadcastFilter curr = null; // BroadcastFilter是对动态注册receiver的封装
		while (it < NT && ir < NR) {
			if (curt == null) {
				curt = (ResolveInfo)receivers.get(it);
			}
			if (curr == null) {
				curr = registeredReceivers.get(ir);
			}
			
			if (curr.getPriority() >= curt.priority) {
				// Insert this broadcast record into the final list.
				receivers.add(it, curr);
				ir++;
				curr = null;
				it++;
				NT++;
			} else {
				// Skip to the next ResolveInfo in the final list.
				it++;
				curt = null;
			}
		}
	}
	......

	if ((receivers != null && receivers.size() > 0)
			|| resultTo != null) {
		// 根据是否携带FLAG_RECEIVER_FOREGROUND,选择mFgBroadcastQueue或mBgBroadcastQueue发送广播
		BroadcastQueue queue = broadcastQueueForIntent(intent);
		BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
				callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
				requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
				resultData, resultExtras, ordered, sticky, false, userId);

		if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
				+ ": prev had " + queue.mOrderedBroadcasts.size());
		if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
				"Enqueueing broadcast " + r.intent.getAction());

		final BroadcastRecord oldRecord =
				replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
		if (oldRecord != null) {
			// 对替换后的广播进行处理
			......
		} else {
			// 这里是核心代码,将构造的BroadcastRecord加入到mOrderedBroadcasts广播队列
			queue.enqueueOrderedBroadcastLocked(r);
			// 调用BroadcastQueue.scheduleBroadcastsLocked,从广播队列中取出广播进行串行处理
			queue.scheduleBroadcastsLocked();
		}
	} else {
		......
	}

	return ActivityManager.BROADCAST_SUCCESS;
}

从上面的代码可以得到两个结论:

1、无序广播发送给动态注册的 Receiver,是放到 mParallelBroadcasts(并行广播队列)中等待处理的。

2、无序广播发送给静态注册的 Receiver,以及有序广播发送给静态 / 动态注册的 Receiver,都是放到 mOrderedBroadcasts(串行广播队列)等待处理的。

广播分发主要在 BroadcastQueue 中实现。enqueueParallelBroadcastLockedenqueueOrderedBroadcastLocked 只是把 BroadcastRecord 分别加入到 mParallelBroadcasts 队列和 mOrderedBroadcasts 队列中,真正的分发处理逻辑还是通过 scheduleBroadcastsLocked 发送 message,在 BroadcastHandler 中调用 processNextBroadcast 方法实现。

mParallelBroadcasts 的并行处理实现

processNextBroadcast 的代码中,mParallelBroadcasts 的并行分发处理逻辑很清晰,在一个 while 循环中遍历 mParallelBroadcasts 中所有的广播及其对应的所有 Receiver,通过 deliverToRegisteredReceiverLocked 调用 performReceiveLocked,最终走到 ActivityThread.scheduleRegisteredReceiver 中。

/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
	synchronized(mService) {
		BroadcastRecord r;
		......

		// 首先,直接遍历mParallelBroadcasts,对并行广播(无序广播+动态注册的receiver)进行处理
		while (mParallelBroadcasts.size() > 0) {
			r = mParallelBroadcasts.remove(0);
			......
			final int N = r.receivers.size();
			// 遍历广播的所有receivers,进行分发
			for (int i=0; i<N; i++) {
				Object target = r.receivers.get(i);
				// deliverToRegisteredReceiverLocked -> performReceiveLocked -> ActivityThread.scheduleRegisteredReceiver异步处理广播
				deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
			}
			......
		}
		......
	}
}

注意,scheduleRegisteredReceiver 是 IApplicationThread.aidl 中的方法,是修饰为 oneway 的调用,即异步调用。

所以,总结起来,mParallelBroadcasts 通过一个 while 循环中遍历所有的广播及广播对应的所有 Receiver,并且调用了方法去异步处理广播,确保了 mParallelBroadcasts 的并行分发处理。

mOrderedBroadcasts 的串行处理实现

但是 mOrderedBroadcasts 的串行处理呢,是怎么实现的?

从代码中可以看出,processNextBroadcast 每次被调用,只能分发给 mOrderedBroadcasts 中一个广播的其中一个 Receiver,如果静态注册的应用未启动,还需要等待应用启动后再进行处理。

/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
	synchronized(mService) {
		BroadcastRecord r;
		......
		
		// 这里的do-while只会从mOrderedBroadcasts中取出第一个BroadcastRecord进行后续的处理!
		do {
			......
			r = mOrderedBroadcasts.get(0);
			......
		} while (r == null);

		......
		
		final Object nextReceiver = r.receivers.get(recIdx); // 取出一个Receiver

		// 对动态注册receiver的处理,这里是分发有序广播
		if (nextReceiver instanceof BroadcastFilter) {
			......
			// 通过deliverToRegisteredReceiverLocked调用ActivityThread.scheduleRegisteredReceiver处理广播
			deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
			......
		}

		// 开始对静态注册receiver的处理!!!
		ResolveInfo info = (ResolveInfo)nextReceiver;
		......

		// 如果应用已经启动,则直接分发广播给该应用,并返回
		if (app != null && app.thread != null && !app.killed) {
			try {
				app.addPackage(info.activityInfo.packageName,
						info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
				// 通过processCurBroadcastLocked -> ActivityThread.scheduleReceiver -> receiver.onReceive处理当前广播
				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);
				......
				return;
			}
		}

		......

		// 如果应用未启动,则在这里启动应用进程,广播将在AMS启动完成后被调用处理
		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) {
			Slog.w(TAG, "Unable to launch app "
                    + info.activityInfo.applicationInfo.packageName + "/"
                    + info.activityInfo.applicationInfo.uid + " for broadcast "
                    + r.intent + ": process is bad");
			......
			return;
		}

		// 将BroadcastRecord赋值为mPendingBroadcast,等待应用启动完成后处理
		mPendingBroadcast = r;
		mPendingBroadcastRecvIndex = recIdx;
	}
}

很容易想到,既然调用一次 processNextBroadcast 只能处理一个 receiver,那么所谓的串行队列,一定是在处理完当前的 receiver 后,继续调用 processNextBroadcast 处理下一个 receiver。

但是无论是通过 deliverToRegisteredReceiverLocked 调用到 ActivityThread.scheduleRegisteredReceiver,处理动态注册的 receiver;还是通过 processCurBroadcastLocked,调用到 ActivityThread.scheduleReceiver,处理静态注册的 receiver。都是 oneway 的异步调用。

那么,只能是在 ActivityThread.scheduleRegisteredReceiver 和 ActivityThread.scheduleReceiver 的实现中,处理完广播之后,再调用 BroadcastQueue 的 processNextBroadcast 继续处理后续的广播。

以 ActivityThread.scheduleReceiver 为例,它是发送了一个 message,通过 Handler 调用 handleReceiver 进行处理。

private void handleReceiver(ReceiverData data) {
	......
	try {
		......
		// 反射构造BroadcastReceiver的实例
		receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
	} 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 {
		......
		sCurrentBroadcastIntent.set(data.intent);
		// 注意这里调用了setPendingResult,将ReceiverData作为参数传入
		receiver.setPendingResult(data);
		long startTime = CheckTime.getTime();
		// 调用BroadcastReceiver的onReceive方法接收处理广播,这里就到了大家都熟悉的环节
		receiver.onReceive(context.getReceiverRestrictedContext(),
				data.intent);
		if (CheckTime.checkTime(startTime, component + " onReceive")) {
			Slog.w(TAG, component + " running onReceive took long time");
		}
	} 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);
	}

	// 上面将ReceiverData作为参数传入,因此这里不为空,会调用ReceiverData.finish方法进行收尾工作
	if (receiver.getPendingResult() != null) {
		data.finish();
	}

	if (CheckTime.checkTime(data.receiveTime, component + " scheduleReceive", 500)) {
		Slog.w(TAG, "Main thread can not be idle for a long time.");
	}
}

通过 ReceiverData.finish -> ReceiverData.sendFinished -> IActivityManager.finishReceiver 的调用链,走到 AMS 的 finishReceiver 方法中,找到下一个接收广播的 receiver,调用 processNextBroadcast 进行分发处理。

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 = null;

		synchronized(this) {
			BroadcastQueue[] queues = getFgOrBgQueues(flags);
			for (BroadcastQueue queue : queues) {
				r = queue.getMatchingOrderedReceiver(who);
				if (r != null) break;
			}
			if (r != null) {
				// 调用BroadcastQueue.finishReceiverLocked获取下一个receiver,根据广播的状态,返回true
				doNext = r.queue.finishReceiverLocked(r, resultCode,
					resultData, resultExtras, resultAbort, true);
			}
		}

		if (doNext) {
			// 这里调用processNextBroadcast处理下一个广播!
			r.queue.processNextBroadcast(false);
		}
		trimApplications();
	} finally {
		Binder.restoreCallingIdentity(origId);
	}
}

scheduleRegisteredReceiver 的处理相对复杂一点,但也就是多了一层 IIntentReceiver 的封装,最终都是一样调用到 AMS.finishReceiver 中进行相同的处理

通过上面的代码和分析,整个串行广播队列处理的逻辑也就清楚了:

1、发送广播时,调用到 BroadcastQueue.processNextBroadcast,处理 mOrderedBroadcasts 中一个广播的其中一个 Receiver

2、通过ActivityThread回调到 BroadcastReceiver 中的 onReceive 方法,处理应用接收广播的逻辑

3、处理完广播之后,ActivityThread 调用 AMS.finishReceiver,调用 BroadcastQueue.finishReceiverLocked 进行收尾工作,再调用 BroadcastQueue.processNextBroadcast 处理广播的下一个 Receiver

总结

最后再把整个流程梳理一遍:

Android 的 BroadcastQueue 中维护着两个 BroadcastRecord 的队列,分别为 mParallelBroadcasts 和 mOrderedBroadcasts。

mParallelBroadcasts 主要存放的是发送给动态注册 Receiver 的无序(普通 + 粘性)广播,这些广播是异步处理,不需要等待广播的处理结果,发送无序广播时,调用一次 BroadcastQueue.processNextBroadcast 就能将当前的 mParallelBroadcasts 队列清空。

mOrderedBroadcasts 存放的是发送给动态注册 Receiver 的有序广播,以及发送给静态注册 Receiver 的无序和有序广播。发送广播时,调用一次 BroadcastQueue.processNextBroadcast 只能处理 mOrderedBroadcasts 队列中一个广播的其中一个 Receiver,需要等到当前的 Receiver 接收处理完广播后,才会重新调用 processNextBroadcast 处理下一个 Receiver 或下一个广播。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值