Broadcast 分析 --- 之二
来源:互联网 发布:mac电磁阀说明书 编辑:程序博客网 时间:2024/05/21 19:50
3,发送广播
对应不同的广播,发送方法如下:
public void sendBroadcast(Intent intent, String receiverPermission)public void sendOrderedBroadcast(Intent intent, String receiverPermission)public void sendStickyBroadcast(Intent intent)
ContextImpl的sendBroadcast调用流程图如下,
sendBroadcast方法如下,
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, null, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } }当应用apk发起一个广播时,最后都会通过跨进程调用到AMS的broadcastIntent方法,只是有些标志(是否是顺序广播)不一样而已。
broadcastIntent方法如下,
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, 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, resultExtras, requiredPermissions, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; }}broadcastIntentLocked方法又臭又长,其他的就不多说了,看主要的,
private final int broadcastIntentLocked(){ List receivers = null; // 记录静态广播 List<BroadcastFilter> registeredReceivers = null; // 记录动态广播 // 根据intent 获取匹配的静态广播 receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); // 根据intent 获取匹配的动态广播 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId);if (!ordered && NR > 0) { final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, 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, requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); // 发送静态广播 } }}由于广播分为动态广播和静态广播,所以在该函数中,分别定义了2个list来查询并保存匹配的静态和动态广播,最后分别插入广播队列进行处理。
3.1 查询
3.1.1静态广播的匹配查询
collectReceiverComponents方法如下,
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { List<ResolveInfo> receivers = null; try { HashSet<ComponentName> singleUserReceivers = null; boolean scannedFirstReceivers = false; for (int user : users) { // Skip users that have Shell restrictions if (callingUid == Process.SHELL_UID && getUserManagerLocked().hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, user)) { continue; } List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user); if (user != UserHandle.USER_OWNER && newReceivers != null) { ••• for (int i=0; i<newReceivers.size(); i++) { ResolveInfo ri = newReceivers.get(i); if ((ri.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { ComponentName cn = new ComponentName( ri.activityInfo.packageName, ri.activityInfo.name); if (singleUserReceivers == null) { singleUserReceivers = new HashSet<ComponentName>(); } if (!singleUserReceivers.contains(cn)) { singleUserReceivers.add(cn); receivers.add(ri); } } else { receivers.add(ri); } } } } } catch (RemoteException ex) { // pm is in same process, this will never happen. } return receivers; }
AppGlobals.getPackageManager()方法最后会得到PMS,直接看queryIntentReceivers方法,
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; } // reader 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; } }
一般广播都是动态广播,而有序广播两种状态都有,有序广播保存receivers 序列中。首先查询符合条件的静态广播
receivers =collectReceiverComponents(intent,
AppGlobals.getPackageManager().queryIntentReceivers(intent
然后将receivers 和registeredReceivers根据数据的大小(优先级)合并到receivers中,最后插入队列并发起实际的广播调度。
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
结构图如下:
3.1.2动态广播的匹配查询
查询到符合条件的动态广播之后,根据BroadcastFilter创建一个BroadcastRecord节点,插入BroadcastQueue内的并行处理队列,
最后发起实际的广播调度。
结构图如下:
3.2 一般广播执行流程
3.2.1流程图
3.2.1 关键代码解析
一般广播里面的所有广播同时全部执行,最后调用onReceive函数,通过finishReceiver反馈结果。在processNextBroadcast函数中,
可以看到同时调用,
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); . . . . . . deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } . . . . . .}
3.3 有序广播
3.3.1流程图
3.3.1 关键代码分析
在processNextBroadcast函数中,首先判断该app是否为空,说明该进程还没有起来,那就先调用processCurBroadcastLocked启动app,
最后都会调用processCurBroadcastLocked执行,调用onReceive处理广播。
因为是有序广播,是一个一个安装顺序执行,在反馈的结果BroadcastReceive中,会根据相关信息调用processNextBroadcast函数接着
执行下一个广播。
广播完成之后和AMS还有一个交互,其实有序广播就比一般广播多了一个重复的过程,相当于多条广播逐条执行。
- Broadcast 分析 --- 之二
- Broadcast 分析 --- 之二
- ANR源码分析之Broadcast Timeout
- Spark源码阅读笔记之Broadcast(二)
- Android编程权威指南学习之broadcast intent(二)
- Spark大师之路:广播变量(Broadcast)源码分析
- Android BroadCast (二)
- Broadcast Receiver(二)
- Broadcast使用分析
- Broadcast使用分析
- Android4.2 broadcast 分析
- Spark Broadcast源码分析
- Android Broadcast 特点分析
- Spark Broadcast源码分析
- BroadCast 研究分析
- Spark Broadcast内幕分析
- android 之broadcast receiver
- android之Broadcast
- C++笔试基础题目(一) 类
- json串的处理成为下拉格式
- 欧拉常数(调和级数求和) Harmonic Number
- hdu6105-多校6&&博弈&图&思维-Gameia
- velocity语法
- Broadcast 分析 --- 之二
- PAT 1022. Digital Library (30) map及迭代器用法以及用getline读入空格
- 简单封装一个上传插件——支持拖拽和预览
- MySQL的学习
- HOJ 2662 Pieces Assignment
- 数据库范式
- 过滤驱动的概念
- HDU5542(树状数组优化DP)
- 关于作用域和域解析