【Android】Android Broadcast源码解析

tech2022-11-05  127

Android Broadcast源码解析

一、静态广播的注册

静态广播是通过PackageManagerService在启动的时候扫描已安装的应用去注册的。 在PackageManagerService的构造方法中,会去扫描应用安装目录,顺序是先扫描系统应用安装目录再扫描第三方应用安装目录。 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<files.length; 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"); }

可以看到,它通过File.list方法列出目录下的所有后缀为".apk"的文件传给scanPackageLI去处理。 而scanPackageLI(File scanFile,int parseFlags, int scanMode, long currentTime, UserHandle user)内部会调用它的重载方法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<N; 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"); ... } ...

所以从上面获取静态广播的流程可以看出来:系统应用的广播先于第三方应用的广播注册,而安装在同一个目录下的应用的静态广播的注册顺序是按照File.list列出来的apk的顺序注册的。他们的注册顺序就决定了它们接收广播的顺序。 通过静态广播的注册流程,我们已经将静态广播注册到了PackageManagerService的mReceivers中,而我们可以使用PackageManagerService.queryIntentReceivers方法查询intent对应的静态广播

public List<ResolveInfo> 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<ResolveInfo> list = new ArrayList<ResolveInfo>(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.broadcastIntent中又会调用ActivityManagerService.broadcastIntentLocked,而broadcastIntentLocked中的关键代码如下:

// 静态广播 List receivers = null; // 动态广播 List<BroadcastFilter> 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(); } }

大家应该都有听说过动态广播会优先于静态广播,从上面的代码我们可以看到,这实际是因为安卓的源代码就是按这个顺序写的。 最后我们来看一下ActivityManagerService.collectReceiverComponents方法,实际上静态广播静态就是从PackageManagerService中查询的:

private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int[] users) { ... List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); ...

四、粘性广播的实现原理

ActivityManagerService.broadcastIntentLocked有下面这样一段代码,它将粘性广播存到了mStickyBroadcasts中。

if (sticky) { ... ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<String, ArrayList<Intent>>(); mStickyBroadcasts.put(userId, stickies); } ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null) { list = new ArrayList<Intent>(); stickies.put(intent.getAction(), list); } int N = list.size(); int i; for (i=0; i<N; i++) { if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= N) { list.add(new Intent(intent)); } }

而ManagerService.registerReceiver会获取之前发送的粘性广播,再次发送给刚刚注册的receiver:

... List allSticky = null; // 获取符合的粘性广播 Iterator actions = filter.actionsIterator(); if (actions != null) { while (actions.hasNext()) { String action = (String)actions.next(); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.getUserId(callingUid)); } } else { allSticky = getStickiesLocked(null, filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(null, filter, allSticky, UserHandle.getUserId(callingUid)); } ... //向新注册的receiver发送粘性广播 if (allSticky != null) { ArrayList receivers = new ArrayList(); receivers.add(bf); int N = allSticky.size(); for (int i=0; i<N; i++) { Intent intent = (Intent)allSticky.get(i); 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(); } } ...

getStickiesLocked即从mStickyBroadcasts中查询之前发送过的粘性广播

private final List getStickiesLocked(String action, IntentFilter filter, List cur, int userId) { final ContentResolver resolver = mContext.getContentResolver(); ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { return cur; } final ArrayList<Intent> list = stickies.get(action); if (list == null) { return cur; } int N = list.size(); for (int i=0; i<N; i++) { Intent intent = list.get(i); if (filter.match(resolver, intent, true, TAG) >= 0) { if (cur == null) { cur = new ArrayList<Intent>(); } cur.add(intent); } } return cur; }

五、广播队列

从ActivityManagerService.broadcastIntentLocked中我们可以看到,实际上它不是直接将广播发送到BroadcastReceiver中的。而是将他包装到BroadcastRecord中,再放进BroadcastQueue:

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<N; 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:

所以整个广播的机制可以总结成下面这张图:

最新回复(0)