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;}
上一篇:Android四大组件系列9 ContentProvider原理
下一篇:Android四大组件系列7 registerReceiver流程

发表评论

最新留言

关注你微信了!
[***.104.42.241]2025年03月10日 19时36分47秒