本文基于Androd8.0。
广播发送有很多个函数,此处以最简单的sendBroadcast为例分析:
sendBroadcast实际是调用的ContextImpl的sendBroadcast:
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
其中ActivityManger.getService():
/**
* @hide
*/
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton IActivityManagerSingleton =
new Singleton() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
经过Binder驱动,最后会调用到ActivityManagerService.broadcastIntent。
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();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
真正做事情的是ActivityManagerService.broadcastIntentLocked:
int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
....
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// If we have not finished booting, don't allow this to launch new processes.
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
....
// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
final String action = intent.getAction();
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID:
case SYSTEM_UID:
case PHONE_UID:
case BLUETOOTH_UID:
case NFC_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
//非system app发送protected broadcast,抛出异常
if (!isCallerSystem) {
if (isProtectedBroadcast) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (...) {
....
}
}
if (action != null) {
if (getBackgroundLaunchBroadcasts().contains(action)) {
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
switch(action) {
//处理Package等相关的广播
....
}
}
第一阶段处理一些特殊的广播。
接下来看第二阶段:
// Add to the sticky list if requested.
if (sticky) {
//检查是否有发送粘性广播的权限
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid) != PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: broadcastIntent() requesting a sticky
broadcast from pid="+ callingPid + ", uid=" + callingUid
+ " requires " + android.Manifest.permission.BROADCAST_STICKY;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (requiredPermissions != null && requiredPermissions.length > 0) {
Slog.w(TAG, "Can't broadcast sticky intent " + intent
+ " and enforce permissions " + Arrays.toString(requiredPermissions));
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
//粘性广播指定发送的组件
if (intent.getComponent() != null) {
throw new SecurityException("Sticky broadcasts can't target a specific
component");
}
//如果广播不是发送给所有人的,则要查看是否和发送给所有人的广播冲突
// We use userId directly here, since the "all" target is maintained
// as a separate set of sticky broadcasts.
if (userId != UserHandle.USER_ALL) {
// But first, if this is not a broadcast to all users, then
// make sure it doesn't conflict with an existing broadcast to
// all users.
ArrayMap> stickies =
mStickyBroadcasts.get(UserHandle.USER_ALL);
if (stickies != null) {
ArrayList list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i> 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));
}
} //end of if(sticky)
...
// Figure out who all will receive this broadcast.
List receivers = null;//保存匹配该Intent的所有广播接收者,包括静态和动态
List registeredReceivers = null;//保存符合该Intent的动态receiver
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {
//如果没有FLAG_RECEIVER_REGISTERED_ONLY flag,则查询PKMS,
//获得那些在AndroidManifest.xml中声明的广播接收者,即静态广播接收者,并保存到receivers
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) { //没有指定接收的对象
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
List registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
//从mReceiver查找符合intent的动态广播接收者
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
/*
判断该广播是否设置了REPLACE_PENDING标签,如果设置了该标签,并且之前的Intent还没有被处理,
则可以使用新的的Intent替换旧的Intent。目的是为了减少不必要的广播发送。
*/
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
//先处理动态注册的接收中者
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
//此次发送的广播为非有序广播,且符合该intent的动态receiver个数不为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, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
//根据FLAG确定是加入到前台广播队列还是后台广播队列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
//只需创建一个BrodacstRecord,一个BroadcastRecord对象可包括所有的接收者
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
//如果没有被替换,则保存到mParallelBroadcasts中
queue.enqueueParallelBroadcastLocked(r);
//调度一次广播发送
queue.scheduleBroadcastsLocked();
}
//至此,动态注册的广播接收者已经处理完毕,设置registeredReceivers为null
registeredReceivers = null;
NR = 0;
}
第二阶段的工作有两项:
// Merge into one list.
int ir = 0;
if (receivers != null) {
String skipPackages[] = null;
//处理PACKAGE_ADDED、PACKAGE_RESTARTED、PACKAGE_DATA_CLEARED的intent,系统不希望有些应用
//一安装就启动。
//这类程序的工作原理是:在改程序内部监听PACKAGE_ADDED广播,如果系统没有防备,则PKMS安装完程序
//后所发送的PACKAGE_ADDED消息将触发该应用的启动
......
//处理ACTION_EXTERNAL_APPLICATIONS_AVAILBLE广播
......
//将动态注册的接收者registeredReceiver的元素合并到receivers中去
//处理完毕后,所有的接收者(无论是动态还是静态)都存储到receivers中了
int NT = receivers != null ? receivers.size() : 0;
int it = 0;
ResolveInfo curt = null;
BroadcastFilter curr = null;
while (it < NT && ir < NR) {
if (curt == null) {
curt = (ResolveInfo)receivers.get(it);
}
if (curr == null) {
curr = registeredReceivers.get(ir);
}
if (curr.getPriority() >= curt.priority) {
// Insert this broadcast record into the final list.
receivers.add(it, curr);
ir++;
curr = null;
it++;
NT++;
} else {
// Skip to the next ResolveInfo in the final list.
it++;
curt = null;
}
}
}
while (ir < NR) {
if (receivers == null) {
receivers = new ArrayList();
}
receivers.add(registeredReceivers.get(ir));
ir++;
}
...
if ((receivers != null && receivers.size() > 0) || resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
//创建一个BroadcastRecord对象,它的receivers中包括所有的接收者
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, callerInstantApp,
resolvedType, requiredPermissions, appOp, brOptions, receivers,
resultTo, resultCode,resultData, resultExtras, ordered, sticky,
false, userId);
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);
try {
oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
oldRecord.intent,
Activity.RESULT_CANCELED, null, null,
false, false, oldRecord.userId);
} catch (RemoteException e) {
Slog.w(TAG, "Failure ["+ queue.mQueueName + "] sending broadcast result of
"+ intent, e);
}
}
} else {
//如果没被替换,将该条广播记录到mOrderedBroadcasts中
queue.enqueueOrderedBroadcastLocked(r);
//调度AMS进行广播发送工作
queue.scheduleBroadcastsLocked();
}
} else {
// There was nobody interested in the broadcast, but we still want to record
// that it happened.
if (intent.getComponent() == null && intent.getPackage() == null
&& (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
}
}
return ActivityManager.BROADCAST_SUCCESS;
} //end of broadcastIntentLocked()
由以上分析可得,AMS将动态receiver和静态receiver都合并到了receivers中了。如果本次广播不是ordered,那么表明动态注册者已经在第二阶段中被处理了。因此在合并时,将不会有动态receiver被加到receivers中。最终所创建的广播记录存在mOrderedBroadcasts中,也即,不管是否为串行发送,静态receiver接收到的广播记录都保存在mOrderedBroadcasts中。
为何不将它们保存到mParallelBroadcasts中呢?
结合code发现,mParallelBroadcasts中的BroadcastRecord所包含的都是动态注册的广播接收者信息,这是因为动态接收者所在的进程是已经存在的,而静态广播接收者就不能保证它已经和一个进程绑定在一起了。如果静态注册的广播接收者所在进程还未启动,则AMS还需要进行创建应用进程,初始化Android运行环境等一系列操作。
且后面,mParallelBroadcasts中的成员是在一个循环中被逐条处理的,如果将静态广播接收者也保存到mParallelBroadcasts中,会有什么后果呢?假设这些静态接收者所在的进程全部未创建和启动,那么AMS将在循环中创建多个进程!系统压力一下就上去了。所以,静态接收者对应的广播记录都被放到了mOrderedBroadcasts中,AMS在处理这类广播信息时,一个进程一个进程地处理,只有处理完一个接收者才继续下一个接收者。这样的好处是避免了惊群效应的出现,坏处是延时较长。