目录
- 广播发送与派发整体流程简介
- sendBroadcast时序图
- 源码解析
- 总结
1. 广播发送与派发整体流程简介
从上一节广播的注册,可以知道广播机制是典型的观察者模式,那么通知所有receiver的时机具体是什么时候呢,答案就是在发送广播的时候,广播一发送,此时就应该通知所有已经注册的观察者,也就是已经注册的receiver。整个广播的派发的流程其实就是逐个通知观察者的过程。而这整体的流程主要都在BroadcastQueue中经过调度之后派发给各个注册的receiver,最终回调到APP进程中已注册的receiver的onReceive方法。
注
:本文基于Android 8.1。
2. sendBroadcast时序图
- 上面的流程中,主要涉及到的进程有发送APP的进程,systemserver进程,以及接收广播的进程
- 图中11~18的过程是动态注册的广播的派发(包括有序和无序)
- 图中19~24的过程是静态注册的派发,静态注册的广播默认都以有序广播形式派发
- BroadcastHandler调度线程是用的ActivityManager线程
3. 源码解析
3.1 ContextImpl.sendBroadcast
客户端通过context发送广播,都会调用到ContextImpl.sendBroadcast去实现广播的发送,而且不管是发送有序广播还是无序广播,最终发起binder call的方法都是一致的。
sendBroadcast
@Override
public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, null,
Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
sendOrderedBroadcast
void sendOrderedBroadcast(Intent intent,
String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras, Bundle options) {
warnIfCallingFromSystemProcess();
IIntentReceiver rd = null;
// 相比于发送无序广播,有序广播最重要区别就在
// 有序广播可以有一个resultRceiver,也就是可以指定这个广播的最后一个接收者
// 有序广播是逐个派发的,因此通过最后一个接收者可以知道广播派发完毕了,做一些收尾工作
if (resultReceiver != null) {
if (mPackageInfo != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
resultReceiver, getOuterContext(), scheduler,
mMainThread.getInstrumentation(), false);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
}
}
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
String[] receiverPermissions = receiverPermission == null ? null
: new String[] {receiverPermission};
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntent(
mMainThread.getApplicationThread(), intent, resolvedType, rd,
initialCode, initialData, initialExtras, receiverPermissions, appOp,
options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
上面resultReceiver跟receiver的注册有些类似,这也正是有序广播相对与无序广播多出来的部分,多了最后的InnerReceiver,保证本次发送的所有广播执行结束之后,调用这个广播。
3.2 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;
}
}
参数解析:
caller
:发送方的applicationThread对象
intent
:本次发送的广播所带的intent
resolvedType
:根绝intent schema判断类型
resultTo
:最终接受的receiver
resultCode
:有序广播在一个receiver处理之后可以设置值,这样下一个receiver就可以拿到这个数据
resultData
:作用同上面的code,是string类型的数据
resultExtras
:作用同上面的code,是Bundle类型数据
requiredPermissions
:接收这个广播需要的权限
appOp
:接受这个广播需要的AppopsManager权限
bOptions
:设置在这个广播发送的时候将某个package放入到deviceIdle白名单中,有时长限制
serialized
:是否为有序广播
sticky
:是否为sticky广播
userId
:这个广播将要发送到的user
3.3 ActivityManagerService.broadcastIntentLocked
final 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) {
// Intent支持跨进程传输,保证互不干扰,此处创建新的Intent对象
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
if (callerInstantApp) {
// 如果caller是instant app,则不能使用FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
// 即instant app不能发送给instant app可见的广播
intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
// 默认情况下,广播不会发送给处于stop状态下的package
// 应用在安装后从来没有启动过,或者已经被用户强制停止了,那么这个应用就处于停止状态
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// 如果开机还没有完成,且没有带升级状态可接受的flag,那么添加FLAG_RECEIVER_REGISTERED_ONLY
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
...
// user校验
// 参数中的bOptions会改变deviceidle的临时白名单
// 因此需要查看caller是否有改变deviceidle名单的权限
BroadcastOptions brOptions = null;
if (bOptions != null) {
brOptions = new BroadcastOptions(bOptions);
if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
if (checkComponentPermission(
android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
}
// 确保protectBroadcast广播只能由某些特定的发送者发送
// 主要是root/system/phone/bluetooth/nfc这些uid
// 以及persist应用可以发送
final String action = intent.getAction();
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException 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;
}
if (!isCallerSystem) {
// protectBroadcast只能由系统发送
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 (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
// 对于这些比较特殊的广播,不允许caller为null
if (callerPackage == null) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from unknown caller.";
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
// 如果component不为空,则必须要求所设置的component的package和caller一致
if (!intent.getComponent().getPackageName().equals(
callerPackage)) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " to "
+ intent.getComponent().getPackageName() + " from "
+ callerPackage;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} else {
// 如果component为空则只能发送给自己
intent.setPackage(callerPackage);
}
}
}
if (action != null) {
if (getBackgroundLaunchBroadcasts().contains(action)) {
// 判断允许在后台应用可以接受的广播的action列表中有没有这个action
// 如果有,即允许这个广播被后台应用接收,则添加flag
// 默认的action都是不带这个flag的,所以默认不允许后