
Android四大组件系列8 sendBroadcast流程
发布日期:2021-05-06 20:19:22
浏览次数:18
分类:技术文章
本文共 9227 字,大约阅读时间需要 30 分钟。
一 概述
广播 (Broadcast) 机制用于进程/线程间通信,广播分为广播发送和广播接收两个过程,其中广播接收者 BroadcastReceiver 上篇文章已经介绍过了,本篇文章介绍广播的发送,从广播发送方式可分为三类:
普通广播:通过 Context.sendBroadcast() 发送,并行处理
有序广播:通过 Context.sendOrderedBroadcast() 发送,串行处理 Sticky 广播:通过 Context.sendStickyBroadcast() 发送广播在系统中以 BroadcastRecord 对象来记录, 该对象有几个时间相关的成员变量需要注意。
final class BroadcastRecord extends Binder { final ProcessRecord callerApp;//广播发送者所在进程 final String callerPackage;//广播发送者所在包名 final List receivers;//包括动态注册的BroadcastFilter和静态注册的ResolveInfo final int callingPid;//广播发送者pid final List receivers;//广播接收者 int nextReceiver;//下一个被执行的接收者 IBinder receiver;//当前正在处理的接收者 int anrCount;//广播ANR次数 long enqueueClockTime;//入队列时间,伴随着scheduleBroadcastsLocked long dispatchTime;//分发时间 long dispatchClockTime;//分发时间,伴随着deliverToRegisteredReceiverLocked long receiverTime;//接收时间(首次等于dispatchClockTime) long finishTime;//广播完成时间,位于addBroadcastToHistoryLocked方法内}
我们这一节主要分析广播的注册流程,相关代码路径如下:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaframeworks/base/services/core/java/com/android/server/pm/PackageManagerService.javaframeworks/base/services/core/java/com/android/server/pm/ComponentResolver.javaframeworks/base/services/core/java/com/android/server/am/BroadcastQueue.javaframeworks/base/services/core/java/com/android/server/am/BroadcastRecord.javaframeworks/base/core/java/android/app/ContextImpl.java
二 sendBroadcast流程
2.1 ContextImpl.sendBroadcast
frameworks/base/core/java/android/app/ContextImpl.java
@Overridepublic void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); intent.prepareToLeaveProcess(this); ActivityManager.getService().broadcastIntent( mMainThread.getApplicationThread(), intent, ......);}
2.2 ActivityManagerService.broadcastIntent
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, 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(); try { return broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, ......); } finally { Binder.restoreCallingIdentity(origId); } }}
2.3 ActivityManagerService.broadcastIntentLocked
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, ......) { return broadcastIntentLocked(callerApp, callerPackage, ......);}
具体实现细节看下面代码:
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, ......) { intent = new Intent(intent); //1.根据各种限制设置intent的flags: 比如Instant App不能使用//FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS, 广播不会发送到杀死的进程//系统还没启动不允许启动新进程//2.检查接收广播的userId是否正在运行//3.权限和限制检查: 如CHANGE_DEVICE_IDLE_TEMP_WHITELIST权限// START_ACTIVITIES_FROM_BACKGROUND权限, OP_RUN_ANY_IN_BACKGROUND操作权限//4.非系统用户不允许发送ProtectedBroadcast, 系统用户指//(ROOT_UID/SYSTEM_UID/PHONE_UID/BLUETOOTH_UID//NFC_UID/SE_UID/NETWORK_STACK_UID) ...... userId = mUserController.handleIncomingUser(callingPid, ......); boolean timeoutExempt = false; final String action = intent.getAction(); if (action != null) { // 如果action所属Intent需要发送给未启动的或后台的进程 // 则Intent添加flags为FLAG_RECEIVER_INCLUDE_BACKGROUND if (getBackgroundLaunchBroadcasts().contains(action)) { intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); } //包管理器发出的和包移除相关的action的处理,如 //ACTION_UID_REMOVED/ACTION_PACKAGE_REMOVED //ACTION_PACKAGE_CHANGED/... ... } // sticky广播处理,常规的sendBroadcast发送的都是非sticky广播,走不到这里 if (sticky) { //权限和条件检查包括: Manifest.permission.BROADCAST_STICKY权限检查//requiredPermissions和Component为空检查, mStickyBroadcasts重复广播检查 ...... // 将发送的广播Intent替换或插入到mStickyBroadcasts队列中相应位置 ArrayMap> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<>(); mStickyBroadcasts.put(userId, stickies); } ArrayList list = stickies.get(intent.getAction()); if (list == null) { list = new ArrayList<>(); stickies.put(intent.getAction(), list); } final int stickiesCount = list.size(); int i; for (i = 0; i < stickiesCount; i++) { if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= stickiesCount) { list.add(new Intent(intent)); } } // 设置广播的目标用户数组users int[] users; if (userId == UserHandle.USER_ALL) { // 所有启动用户 users = mUserController.getStartedUserArray(); } else { // 特定用户 users = new int[] { userId}; } // Figure out who all will receive this broadcast. // 收集receivers列表组件信息. List receivers = null; if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } // 通过IntentResolver收集已注册的Receiver列表registeredReceivers List registeredReceivers = null; if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { for (int i = 0; i < users.length; i++) { // 过滤Shell限制的用户 ...... List registeredReceiversForUser = mReceiverResolver.queryIntent(intent, ......); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } else if (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else { registeredReceivers = mReceiverResolver.queryIntent(intent, ......); } } final boolean replacePending = (intent.getFlags()& Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; // 整体逻辑: 将新发送的无序广播入队列 int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { // If we are not serializing this broadcast, then send the // registered receivers separately so they don't wait for the // components to be launched. if (isCallerSystem) { checkBroadcastFromSystem(intent, callerApp, ......); } final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, ......); final boolean replaced = replacePending && (queue.replaceParallelBroadcastLocked(r) != null); if (!replaced) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } // Merge into one list receivers. // 1.receivers中移除如下action对应的广播: ACTION_PACKAGE_ADDED //ACTION_PACKAGE_RESTARTED/ACTION_PACKAGE_DATA_CLEARED //ACTION_EXTERNAL_APPLICATIONS_AVAILABLE // 2.将registeredReceivers列表合并到receivers列表 ... if (isCallerSystem) { checkBroadcastFromSystem(intent, callerApp, ......); } // 将新发送的有序广播入队列 if ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, ......); final BroadcastRecord oldRecord = replacePending ? queue.replaceOrderedBroadcastLocked(r) : null; if (oldRecord != null) { // Replaced, fire the result-to receiver. if (oldRecord.resultTo != null) { final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent); oldQueue.performReceiveLocked(oldRecord.callerApp, ......); } } else { queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } else { // 该广播没有广播接收器, 说明是隐式广播, 记录一下即可 if (intent.getComponent() == null && intent.getPackage() == null && (intent.getFlags() &Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { addBroadcastStatLocked(intent.getAction(), ......); } } return ActivityManager.BROADCAST_SUCCESS;}
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年03月10日 19时36分47秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
bzoj3439: Kpm的MC密码(四种做法)
2019-03-03
Nginx出现500 Internal Server Error 错误
2019-03-03
pytorch loss = loss_func(output, label) 报错
2019-03-03
51nod 1526 分配笔名
2019-03-03
MySQL中drop、truncate和delete的区别?
2019-03-03
Mysql索引底层B+树的实现原理以及Innodb和Myisam引擎存储的区别
2019-03-03
09-01 Java语言基础(package、import)
2019-03-03
11-01 Java语言基础(Scanner类)
2019-03-03
12-04 Java语言基础(Arrays类)
2019-03-03
Accessing Excel Spreadsheets via C++
2019-03-04
excel上传核心
2019-03-04
json.parse细节
2019-03-04
redis
2019-03-04
c# GDI绘制简单的艺术字
2019-03-04
js,小程序共用java后端进行数据传输
2019-03-04
ReID基础 | ReID工程中的一些小trick
2019-03-04
LINQ之Single,SingleOrDefault
2019-03-04
OpenCV6边缘检测[Canny算法]
2019-03-04
Hadoop_Scala操作Hbase
2019-03-04
Scala_1.控制台打印,变量定义,函数定义
2019-03-04