Android S广播发送流程(广播3)
时间:2022-10-28 02:00:00
Android S广播发送过程
- 1. 广播发送过程
- 2. 广播发送
- 3. 系统处理广播发送
-
- 3.1 AMS接收广播请求
- 3.2 修改增加默认flag可选广播参数分析BroadcastOptions
- 3.4 保护广播isProtectedBroadcast、特定action的处理
- 3.5 处理粘性广播
- 3.6 筛选出静态广播接受者
- 3.7 筛选出动态广播接受者
- 3.8 非oder平行广播的入队和分发
- 3.8 order过滤广播接收者
- 4. 处理广播队列
-
- 4.1 新的广播队列
- 4.2 广播接收者进入队列
- 4.3 广播队列的分发
- 4.4 下一个广播广播的分发
-
- 4.4.1 mParallelBroadcasts平行广播的分发
- 4.4.2 mPendingBroadcast挂广播处理
- 4.4.3 在下一个有序队列中取出广播
- 4.4.4 处理下一个接收者nextReceiver
- 4.4.5 发送给动态注册order注册者
- 4.4.6 静态注册者跳过的逻辑
- 4.4.7 发送给已启动的静态注册人
- 4.4.8 静态注册接收人启动过程
- 4.5 完成广播接收者处理
-
- 4.5.1 广播完成后,始下一个广播的调度
- 4.5.2 广播完成finishReceiverLocked
- 5. 扩展使用广播
1. 广播发送过程
这一次,我们来谈谈广播发送的过程。老规矩先上流程图
2. 广播发送
- 常见的通过ContextImpl.java发送广播的方法有以下几种
=> sendBroadcast/sendBroadcastAsUser :普通广播发送,默认是目前userId,带有“AsUser它是发送给特定的user
=> sendBroadcastMultiplePermissions/sendBroadcastAsUserMultiplePermissions :有多个权限的广播发送
=> sendOrderedBroadcast/sendOrderedBroadcastAsUser :发送order有序的广播(order广播是一个接收完成下一个接收,接收者按顺序接收)
=> sendStickyBroadcast/sendStickyBroadcastAsUser :发送粘性广播,粘性广播是指注册人注册后可立即收到该类型(以前发送的粘性广播)的广播,
接收人的注册不需要在发送人面前
=> sendStickyOrderedBroadcast/sendStickyOrderedBroadcastAsUser :发送粘性和顺序order的广播
都是调用AMS的broadcastIntentWithFeature来发送广播
以下是最简单的,只有一个Intent的广播发送
//ContextImpl.java @Override public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try {
intent.prepareToLeaveProcess(this); //调用AMS的broadcastIntentWithFeature来发送广播 ActivityManager.getService().broadcastIntentWithFeature( mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, null, Activity.RESULT_OK, nll, null, null, null /*excludedPermissions=*/,
AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- 还是以亮屏SCREEN_ON的广播继续讲解其发送流程
其调用方法是sendOrderedBroadcastAsUser(ContextImpl.java)->broadcastIntentWithFeature(ActivityManagerService.java)
//Notifier.java
private final Intent mScreenOnIntent;
//新建一个Intent,它的action是ACTION_SCREEN_ON,
//注意此处增加了
//FLAG_RECEIVER_REGISTERED_ONLY: 只允许动态注册的接收者接受
//FLAG_RECEIVER_FOREGROUND: 前台接收,也就是前台广播(10s超时)的队列
//FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS: 可以被即时app接收
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
//亮屏广播发送完成后才调用的
private final BroadcastReceiver mWakeUpBroadcastDone = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//开始发送广播之前会打印类似“power_screen_broadcast_send: 1”的日志
//这里会在event log中打印类似“power_screen_broadcast_done: [1,125,1]“的日志
//里面包含了发送亮屏广播的时间,此处是“125 ms”
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 1,
SystemClock.uptimeMillis() - mBroadcastStartTime, 1);
sendNextBroadcast();
}
};
private void sendWakeUpBroadcast() {
if (DEBUG) {
Slog.d(TAG, "Sending wake up broadcast.");
}
if (mActivityManagerInternal.isSystemReady()) {
//调用的是ContextImpl的sendOrderedBroadcastAsUser去发送广播
//mScreenOnIntent是发送的亮屏广播
//mHandler是PowerManagerService.java的主线程,用来运行mWakeUpBroadcastDone
//mWakeUpBroadcastDone是亮屏广播发送完成后
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
//ContextImpl.java
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
int initialCode, String initialData, Bundle initialExtras) {
//多带了appOp=OP_NONE、options=null的参数
sendOrderedBroadcastAsUser(intent, user, receiverPermission, AppOpsManager.OP_NONE,
null, resultReceiver, scheduler, initialCode, initialData, initialExtras);
}
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
IIntentReceiver rd = null;
if (resultReceiver != null) {
if (mPackageInfo != null) {
if (scheduler == null) {
//由于传入了scheduler(mHandler),所以这里是不会进来的
scheduler = mMainThread.getHandler();
}
//进入的是这里获取IIntentReceiver rd(通过mPackageInfo、resultReceiver、scheduler构建)
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);
//实际是调用的AMS的broadcastIntentWithFeature方法
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
rd, initialCode, initialData, initialExtras, receiverPermissions,
null /*excludedPermissions=*/, appOp, options, true, false,
user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
3. 系统处理广播发送
3.1 AMS接收广播的请求
系统AMS通过broadcastIntentWithFeature接收广播的请求
//ActivityManagerService.java
//从context过来的都走的这个broadcastIntentWithFeature方法,带特性的发送广播
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
//通过IApplicationThread获取调用者ProcessRecord callerApp
final ProcessRecord callerApp = getRecordForAppLOSP(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
//获取callerApp、callingPid、callingUid用于广播发送参数传入
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, appOp, bOptions, serialized,
sticky, callingPid, callingUid, callingUid, callingPid, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
}
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
//这里再次增加了3个参数allowBackgroundActivityStarts=false,tokenNeededForBackgroundActivityStarts=false
//broadcastAllowList=null
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
excludedPermissions, appOp, bOptions, ordered, sticky, callingPid, callingUid,
realCallingUid, realCallingPid, userId, false /* allowBackgroundActivityStarts */,
null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}
3.2 修改增加默认flag解析可选广播参数BroadcastOptions
- 如默认会增加 FLAG_EXCLUDE_STOPPED_PACKAGES ,不让stop(如通过forcestop会设置)的三方app接收静态广播
- 根据是否粘性广播输出类似的日志:Broadcast (sticky) intent ordered=(true/false) userid=(userId)
- 解析BroadcastOptions brOptions广播可选参数
@GuardedBy("this") final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, @Nullable String callerFeatureId, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid, int realCallingPid, int userId, boolean allowBackgroundActivityStarts, @Nullable IBinder backgroundActivityStartsToken, @Nullable int[] broadcastAllowList) { intent = new Intent(intent); //调用者是否即时app final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid); // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS //如果调用者是即时app,不能添加FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,可以让即时app接收的flag if (callerInstantApp) { intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS); } // broadcastAllowList: 允许接收该广播uid的列表;一般包信息改变的时候才会传入,通过ContextImpl发送广播是不带这个参数的 // broadcastAllowList目前只在PMS的doSendBroadcast发送package相关广播的时候才可能使用到 // PackageManagerService.sendPackageBroadcast/sendMyPackageSuspendedOrUnsuspended->doSendBroadcast-> // ActivityManagerService.LocalService.broadcastIntent if (userId == UserHandle.USER_ALL && broadcastAllowList != null) { Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. " + "Assuming restrictive whitelist."); broadcastAllowList = new int[]{ }; } // By default broadcasts do not go to stopped apps. //默认广播是不发送给stop的应用的,类似于安装后进程从未启动过,或者给强行停止的应用, //是无法通过接收静态注册的广播来启动的(具体在IntentResolver.java的buildResolveList会使用) intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); // If we have not finished booting, don't allow this to launch new processes. //mProcessesReady在systemReady的时候会设置为true //在系统没有启动完成的时候,而且广播发送没有带FLAG_RECEIVER_BOOT_UPGRADE的flag if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { //则默认只能发送到动态注册的接收者中,静态注册的全部无法接收 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } //DEBUG_BROADCAST_LIGHT这个是调试日志的
开关,这里输出是否order有序广播 if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent + " ordered=" + ordered + " userid=" + userId); //如果是非ordered的广播,而且有resultTo则输出warning的信息 //一般情况下orderd的广播才会设置resultTo(发送完成后返回完成的结果到发送者) if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } //多用户判断,如果是callingUid、userId同一个用户组,则直接返回userId userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL, "broadcast", callerPackage); // Make sure that the user who is receiving this broadcast or its parent is running. // If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps. //如果userId不是发送到所有用户USER_ALL(-1),而且当前userId和它的父亲userId都没有在运行 if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) { //如果调用者不是系统或者没有设置FLAG_RECEIVER_BOOT_UPGRADE,而且不是关机广播, //则跳过本次广播发送,不允许stop的userId发送广播,原因是user已经stop了 if ((callingUid != SYSTEM_UID || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { Slog.w(TAG, "Skipping broadcast of " + intent + ": user " + userId + " and its parent (if any) are stopped"); return ActivityManager.BROADCAST_FAILED_USER_STOPPED; } } //获取其意图的action final String action = intent.getAction(); BroadcastOptions brOptions = null; //是否有传入BroadcastOptions的Bundle,开机广播有传入bOptions,亮屏幕广播没有bOptions if (bOptions != null) { //将Bundle转换成BroadcastOptions brOptions brOptions = new BroadcastOptions(bOptions); //如果mTemporaryAppAllowlistDuration的值大于0 if (brOptions.getTemporaryAppAllowlistDuration() > 0) { // See if the caller is allowed to do this. Note we are checking against // the actual real caller (not whoever provided the operation as say a // PendingIntent), because that who is actually supplied the arguments. // 检查一下realCallingPid/realCallingUid是否拥有CHANGE_DEVICE_IDLE_TEMP_WHITELIST(修改临时白名单)、 // START_ACTIVITIES_FROM_BACKGROUND(后台启动activity)、 // START_FOREGROUND_SERVICES_FROM_BACKGROUND(后台启动前台服务)的权限, // 如果一个都没有,则不允许发送该广播,并抛出安全异常 // (在部分情况下callingPid/callingUid调用该发送广播的调用者, // 于realCallingPid/realCallingUid真实调用者不是一样的) if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or " + START_ACTIVITIES_FROM_BACKGROUND + " or " + START_FOREGROUND_SERVICES_FROM_BACKGROUND; Slog.w(TAG, msg); throw new SecurityException(msg); } } //如果带有mDontSendToRestrictedApps不发送给受限制的app // callingUid不在mActiveUids中,而且callingUid/callerPackage后台限制操作 // 则由于“background restrictions”不允许发送广播 if (brOptions.isDontSendToRestrictedApps() && !isUidActiveLOSP(callingUid) && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) { Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage + " has background restrictions"); return ActivityManager.START_CANCELED; } //是否允许mAllowBackgroundActivityStarts后台启动activity if (brOptions.allowsBackgroundActivityStarts()) { // See if the caller is allowed to do this. Note we are checking against // the actual real caller (not whoever provided the operation as say a // PendingIntent), because that who is actually supplied the arguments. //如果没有START_ACTIVITIES_FROM_BACKGROUND则抛出权限异常 if (checkComponentPermission( android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND, realCallingPid, realCallingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND; Slog.w(TAG, msg); thr