在 Android 里面有各种各样的广播,比如电池的使用状态,电话的接收和短信的接收都会产生一个广播,应用程序开发者也可以监听这些广播并做出程序逻辑的处理;

今天我们就来分析下广播的运行机制
PackageManagerService.scanDirLI就是用于扫描目录的方法:
- private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
 - String[] files = dir.list();
 - if (files == null) {
 - return;
 - }
 - int i;
 - for (i=0; i
 - File file = new File(dir, files[i]);
 - if (!isPackageFilename(files[i])) {
 - continue;
 - }
 - PackageParser.Package pkg = scanPackageLI(file,
 - flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
 - if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
 - mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
 - file.delete();
 - }
 - }
 - }
 - private static final boolean isPackageFilename(String name) {
 - return name != null && name.endsWith(".apk");
 - }
 
- scanPackageLI(PackageParser.Package pkg,int parseFlags, int scanMode, long currentTime, UserHandle user):
 - private PackageParser.Package scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime, UserHandle user) {
 - ...
 - final PackageParser.Package pkg = pp.parsePackage(scanFile,scanPath, mMetrics, parseFlags);
 - ...
 - PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user);
 - ...
 - }
 
在这个scanPackageLIl里面会解析Package并且将AndroidManifest.xml中注册的BroadcastReceiver保存下来:
- ...
 - N = pkg.receivers.size();
 - r = null;
 - for (i=0; i
 - PackageParser.Activity a = pkg.receivers.get(i);
 - a.info.processName = fixProcessName(pkg.applicationInfo.processName,
 - a.info.processName, pkg.applicationInfo.uid);
 - mReceivers.addActivity(a, "receiver");
 - ...
 - }
 - ...
 
而我们可以使用PackageManagerService.queryIntentReceivers方法查询intent对应的静态广播
- public List
 queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { - if (!sUserManager.exists(userId)) return Collections.emptyList();
 - ComponentName comp = intent.getComponent();
 - if (comp == null) {
 - if (intent.getSelector() != null) {
 - intent = intent.getSelector();
 - comp = intent.getComponent();
 - }
 - }
 - if (comp != null) {
 - List
 list = new ArrayList (1); - ActivityInfo ai = getReceiverInfo(comp, flags, userId);
 - if (ai != null) {
 - ResolveInfo ri = new ResolveInfo();
 - ri.activityInfo = ai;
 - list.add(ri);
 - }
 - return list;
 - }
 - synchronized (mPackages) {
 - String pkgName = intent.getPackage();
 - if (pkgName == null) {
 - return mReceivers.queryIntent(intent, resolvedType, flags, userId);
 - }
 - final PackageParser.Package pkg = mPackages.get(pkgName);
 - if (pkg != null) {
 - return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
 - userId);
 - }
 - return null;
 - }
 - }
 
我们调用Context.registerReceiver最后会调到ActivityManagerService.registerReceiver:
- public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
 - ...
 - ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
 - ...
 - BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId);
 - ...
 - mReceiverResolver.addFilter(bf);
 - ...
 - }
 
所以通过mReceiverResolver.queryIntent就能获得intent对应的动态广播了;
ContextImpl.sendBroadcast中会调用ActivityManagerNative.getDefault().broadcastIntent()
- public void sendBroadcast(Intent intent) {
 - warnIfCallingFromSystemProcess();
 - String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
 - try {
 - intent.prepareToLeaveProcess();
 - ActivityManagerNative.getDefault().broadcastIntent(
 - mMainThread.getApplicationThread(), intent, resolvedType, null,
 - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false,getUserId());
 - } catch (RemoteException e) {
 - }
 - }
 
实际是调用ActivityManagerService.broadcastIntent:
- public final int broadcastIntent(IApplicationThread caller,
 - Intent intent, String resolvedType, IIntentReceiver resultTo,
 - int resultCode, String resultData, Bundle map,
 - String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) {
 - enforceNotIsolatedCaller("broadcastIntent");
 - synchronized(this) {
 - intent = verifyBroadcastLocked(intent);
 - final ProcessRecord callerApp = getRecordForAppLocked(caller);
 - final int callingPid = Binder.getCallingPid();
 - final int callingUid = Binder.getCallingUid();
 - final long origId = Binder.clearCallingIdentity();
 - int res = broadcastIntentLocked(callerApp,
 - callerApp != null ? callerApp.info.packageName : null,
 - intent, resolvedType, resultTo,
 - resultCode, resultData, map, requiredPermission, appOp, serialized, sticky,
 - callingPid, callingUid, userId);
 - Binder.restoreCallingIdentity(origId);
 - return res;
 - }
 - }
 
调用ActivityManagerService.broadcastIntentLocked,而broadcastIntentLocked中的关键代码如下:
- broadcastIntentLocked
 - // 静态广播
 - List receivers = null;
 - // 动态广播
 - List
 registeredReceivers = null; - if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
 - == 0) {
 - // 查询静态广播
 - receivers = collectReceiverComponents(intent, resolvedType, users);
 - }
 - if (intent.getComponent() == null) {
 - // 查询动态广播
 - registeredReceivers = mReceiverResolver.queryIntent(intent,
 - resolvedType, false, userId);
 - }
 - final boolean replacePending =
 - (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
 - int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
 - if (!ordered && NR > 0) {
 - final BroadcastQueue queue = broadcastQueueForIntent(intent);
 - BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
 - callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
 - appOp, registeredReceivers, resultTo, resultCode, resultData, map,
 - ordered, sticky, false, userId);
 - final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
 - if (!replaced) {
 - // 发送动态广播
 - queue.enqueueParallelBroadcastLocked(r);
 - queue.scheduleBroadcastsLocked();
 - }
 - registeredReceivers = null;
 - NR = 0;
 - }
 - ...
 - if ((receivers != null && receivers.size() > 0)
 - || resultTo != null) {
 - BroadcastQueue queue = broadcastQueueForIntent(intent);
 - BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
 - callerPackage, callingPid, callingUid, resolvedType,
 - requiredPermission, appOp, receivers, resultTo, resultCode,
 - resultData, map, ordered, sticky, false, userId);
 - boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
 - if (!replaced) {
 - // 发送静态广播
 - queue.enqueueOrderedBroadcastLocked(r);
 - queue.scheduleBroadcastsLocked();
 - }
 - }
 
- private List
 collectReceiverComponents(Intent intent, String resolvedType, - int[] users) {
 - ...
 - List
 newReceivers = AppGlobals.getPackageManager() - .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
 - ...
 
- BroadcastQueue queue = broadcastQueueForIntent(intent);
 - BroadcastRecord r = new BroadcastRecord(queue, intent, null,
 - null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
 - null, null, false, true, true, -1);
 - queue.enqueueParallelBroadcastLocked(r);
 - queue.scheduleBroadcastsLocked();
 - enqueueParallelBroadcastLocked方法用于并发执行广播的发送.它很简单,就是将BroadcastRecord放到了mParallelBroadcasts中:
 - public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
 - mParallelBroadcasts.add(r);
 - }
 
scheduleBroadcastsLocked方法同样很简单,就是向mHandler发送了个BROADCAST_INTENT_MSG消息:
- public void scheduleBroadcastsLocked() {
 - if (mBroadcastsScheduled) {
 - return;
 - }
 - mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
 - mBroadcastsScheduled = true;
 - }
 
mHandler在接收到BROADCAST_INTENT_MSG消息的时候会做些什么:
- final Handler mHandler = new Handler() {
 - public void handleMessage(Message msg) {
 - switch (msg.what) {
 - case BROADCAST_INTENT_MSG: {
 - processNextBroadcast(true);
 - } break;
 - case BROADCAST_TIMEOUT_MSG: {
 - synchronized (mService) {
 - broadcastTimeoutLocked(true);
 - }
 - } break;
 - }
 - }
 - };
 
processNextBroadcast方法用于从队列中获取广播消息并发送给BroadcastReceiver,它内部有两个分支,并行处理和串行处理;
动态注册的非有序广播等就是使用并行处理:
- final void processNextBroadcast(boolean fromMsg) {
 - synchronized(mService) {
 - BroadcastRecord r;
 - mService.updateCpuStats();
 - 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
 - Object target = r.receivers.get(i);
 - // 发送消息给Receiver
 - deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
 - }
 - addBroadcastToHistoryLocked(r);
 - }
 - ...
 - }
 - ...
 - }
 - private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
 - BroadcastFilter filter, boolean ordered) {
 - ...
 - // 获取BroadcastReceiver的Binder
 - r.receiver = filter.receiverList.receiver.asBinder();
 - ...
 - // 使用Binder机制将消息传递给BroadcastReceiver
 - performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
 - new Intent(r.intent), r.resultCode, r.resultData,
 - r.resultExtras, r.ordered, r.initialSticky, r.userId);
 - ...
 - }
 - void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
 - Intent intent, int resultCode, String data, Bundle extras,
 - boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
 - ......
 - //通过Binder将消息处理传到应用进程,应用进程内部再使用Handler机制,将消息处理放到主线程中
 - app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
 - data, extras, ordered, sticky, sendingUser, app.repProcState);
 - ......
 - }
 - }
 
有序广播和静态广播等,会通过enqueueOrderedBroadcastLocked传给BroadcastQueue:
- public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
 - mOrderedBroadcasts.add(r);
 - }
 
然后在processNextBroadcast里面会对mOrderedBroadcasts进行特殊处理;
广播队列传送广播给Receiver的原理其实就是将BroadcastReceiver和消息都放到BroadcastRecord里面,然后通过Handler机制遍历BroadcastQueue里面的BroadcastRecord,将消息发送给BroadcastReceiver;
从实现原理上看,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。具体实现流程要点粗略概括如下:
学如逆水行舟,不进则退。心似平原跑马,易放难收;
本文转载自微信公众号「Android开发编程」
Copyright © 2009-2022 www.wtcwzsj.com 青羊区广皓图文设计工作室(个体工商户) 版权所有 蜀ICP备19037934号