一:广播的概念
广播作为Android四大组件之一,是Android进程间通信或者进程内通信的一种方式。
二:广播的种类
广播一般分为标准广播、有序广播和粘性广播。
PS:粘性广播 API 存在许多与安全性相关的缺点,因此它在 Android 5.0(API 级别 21)中已废弃。所以下文不对粘性广播做分析。
2.1 标准广播
2.1.1 概念
标准广播是最常用的广播类型,它是无序的,一旦广播发送,接收端不分先后顺序接收到广播,该类型广播不可被拦截。
2.1.2 标准广播发送流程

2.1.2.1 ContextImpl.sendBroadcast
我们发广播最常用的是调用contxt.sendBroadcast(intent)发送一个标准广播,context是Context对象,最终实现类是ContextImpl
public void sendBroadcast(Intent intent) {
...
try {
//做一些离开进程的准备工作
intent.prepareToLeaveProcess(this);
//跨进程调用AMS的broadcastIntentWithFeature函数继续发送广播流程
ActivityManager.getService().broadcastIntentWithFeature(
mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
null, AppOpsManager.OP_NONE, null, false, false, getUserId());
}
}
2.1.2.2 ActivityManagerService.broadcastIntentWithFeature
做一些权限检查,调用broadcastIntentLockedTraced继续发送广播流程
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, String[] excludedPermissions,
String[] excludedPackages, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
//检测是否属于被隔离的对象
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
...
//确保只有系统可以发送alarm类型的广播;如果是交互类型的广播,则必须有android.Manifest.permission.BROADCAST_OPTION_INTERACTIVE权限
enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);
try {
//调用broadcastIntentLocked继续发送广播流程
return broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid,
callingPid, userId, BackgroundStartPrivileges.NONE, null, null);
}
}
}
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,
String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered,
boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId) {
return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
resolvedType, null, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid, userId,
BackgroundStartPrivileges.NONE,
null /* broadcastAllowList */, null /* filterExtrasForReceiver */);
}
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid,
int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, excludedPermissions, excludedPackages, appOp,
BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
callingPid, callingUid, realCallingUid, realCallingPid, userId,
backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
BroadcastQueue.traceEnd(cookie);
return res;
}
2.1.2.3 ActivityManagerService.broadcastIntentLockedTraced
此函数代码较多,主要做以下几个事情
1. 判断是否是系统广播,不同的系统广播做不同的处理
2. 粘性广播的处理
3. 发送动态注册的无序广播列表
4. 合并动态注册的有序广播列表和静态注册的广播列表,并发送
final int broadcastIntentLockedTraced(ProcessRecord callerApp, String callerPackage,
@Nullable String callerFeatureId, Intent intent, String resolvedType,
ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions,
String[] excludedPermissions, String[] excludedPackages, int appOp,
BroadcastOptions brOptions, boolean ordered, boolean sticky, int callingPid,
int callingUid, int realCallingUid, int realCallingPid, int userId,
BackgroundStartPrivileges backgroundStartPrivileges,
@Nullable int[] broadcastAllowList,
@Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
// Ensure all internal loopers are registered for idle checks
BroadcastLoopers.addMyLooper();
...
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
// 所有的instant应用,都不能使用FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS这个flag
if (callerInstantApp) {
intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
...
// 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);
}
...
// 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.
// 确保将要接收此广播的用户正在运行
if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
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");
scheduleCanceledResultTo(resultToApp, resultTo, intent, userId,
brOptions, callingUid, callerPackage);
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
final String action = intent.getAction();
if (brOptions != null) {
...
// 不允许发送广播给受限的应用
if (brOptions.isDontSendToRestrictedApps()
&& !isUidActiveLOSP(callingUid)
&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
return ActivityManager.START_CANCELED;
}
// 如果是允许后台活动启动的广播,判断是否有START_ACTIVITIES_FROM_BACKGROUND权限
if (brOptions.allowsBackgroundActivityStarts()) {
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);
throw new SecurityException(msg);
} else {
// We set the token to null since if it wasn't for it we'd allow anyway here
backgroundStartPrivileges = BackgroundStartPrivileges.ALLOW_BAL;
}
}
...
}
// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
// 受保护的广播只能由系统发送且系统也只能发送受保护的广播
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
}
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case ROOT_UID:
case SYSTEM_UID:
case PHONE_UID:
case BLUETOOTH_UID:
case NFC_UID:
case SE_UID:
case NETWORK_STACK_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.isPersistent();
break;
}
// 非系统
if (!isCallerSystem) {
// 受保护广播,直接抛异常
if (isProtectedBroadcast) {
...
throw new SecurityException(msg);
// 如果是更新widget相关广播,则必须显式的指明包名且包名只能是该应用本身
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
...
if (callerPackage == null) {
...
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
if (!intent.getComponent().getPackageName().equals(
callerPackage)) {
...
throw new SecurityException(msg);
}
} else {
// Limit broadcast to their own package.
intent.setPackage(callerPackage);
}
}
}
boolean timeoutExempt = false;
if (action != null) {
// 后台启动广播,必须有FLAG_RECEIVER_INCLUDE_BACKGROUND flag
if (getBackgroundLaunchBroadcasts().contains(action)) {
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
// 处理一些系统广播
switch (action) {
case Intent.ACTION_MEDIA_SCANNER_SCAN_FILE:
...
break;
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
case Intent.ACTION_PACKAGES_SUSPENDED:
case Intent.ACTION_PACKAGES_UNSUSPENDED:
...
break;
case Intent.ACTION_PACKAGE_REPLACED:
{
...
break;
}
case Intent.ACTION_PACKAGE_ADDED:
{
...
break;
}
case Intent.ACTION_PACKAGE_DATA_CLEARED:
{
...
break;
}
case Intent.ACTION_TIMEZONE_CHANGED:
...
break;
case Intent.ACTION_TIME_CHANGED:
...
break;
case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
...
break;
case Proxy.PROXY_CHANGE_ACTION:
...
break;
case android.hardware.Camera.ACTION_NEW_PICTURE:
case android.hardware.Camera.ACTION_NEW_VIDEO:
...
break;
case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
...
break;
case "com.android.launcher.action.INSTALL_SHORTCUT":
...
return ActivityManager.BROADCAST_SUCCESS;
case Intent.ACTION_PRE_BOOT_COMPLETED:
...
break;
case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
...
break;
}
}
// Add to the sticky list if requested.
// 粘性广播,不做分析
if (sticky) {
...
}
...
// 用于存储所有静态注册的广播
List receivers = null;
// 用于存储所有动态注册的广播
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// 通过PMS的queryIntentReceivers函数获取系统所有静态注册此广播的应用列表
receivers = collectReceiverComponents(
intent, resolvedType, callingUid, users, broadcastAllowList);
}
// 如果intent没有指明广播接受者的组件名,说明是发给所有已注册并且需要接收该广播的接收者的
if (intent.getComponent() == null) {
...
// 通过mReceiverResolver获取动态注册广播。mReceiverResolver是在registerReceiver时更新的。
registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
resolvedType, false /*defaultOnly*/, userId);
...
}
...
// 在给定的广播筛选器列表中筛选出non-exported的组件
filterNonExportedComponents(intent, callingUid, callingPid, registeredReceivers,
mPlatformCompat, callerPackage, resolvedType);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
// 当前发送的是无序广播且存在动态注册的广播接收者
if (!ordered && NR > 0 && !mEnableModernQueue) {
// 发送方是系统
if (isCallerSystem) {
// 检查广播是否合规
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
// 寻找符合该intent要求的广播队列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
// 创建BroadcastRecord对象并将当前所有通过动态注册的广播接收者传进去
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
registeredReceivers, resultToApp, resultTo, resultCode, resultData,
resultExtras, ordered, sticky, false, userId,
backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
callerAppProcessState);
// 发送广播
queue.enqueueBroadcastLocked(r);
...
}
// Merge into one list.
int ir = 0;
// 静态注册广播队列不为空
if (receivers != null) {
// A special case for PACKAGE_ADDED: do not allow the package
// being added to see this broadcast. This prevents them from
// using this as a back door to get run as soon as they are
// installed. Maybe in the future we want to have a special install
// broadcast or such for apps, but we'd like to deliberately make
// this decision.
// 需要跳过的广播接收者
String skipPackages[] = null;
// 对于ACTION_PACKAGE_ADDED广播而言,如果是自己被add了,那么这个广播只能别人收到,自己即使注册了这个静态广播也接收不到
if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
|| Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
Uri data = intent.getData();
if (data != null) {
String pkgName = data.getSchemeSpecificPart();
if (pkgName != null) {
skipPackages = new String[] { pkgName };
}
}
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
}
// 如果是需要跳过的广播接收者,则在静态广播队列中移除该接收者
if (skipPackages != null && (skipPackages.length > 0)) {
for (String skipPackage : skipPackages) {
if (skipPackage != null) {
int NT = receivers.size();
for (int it=0; it<NT; it++) {
ResolveInfo curt = (ResolveInfo)receivers.get(it);
if (curt.activityInfo.packageName.equals(skipPackage)) {
receivers.remove(it);
it--;
NT--;
}
}
}
}
}
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.
/

本文聚焦Android广播,它是进程间或进程内通信方式。介绍了广播种类,包括标准广播、有序广播,粘性广播因安全问题已废弃。详细阐述了标准广播和有序广播的概念、优先级设置及发送流程,如标准广播无序不可拦截,有序广播按优先级接收且可修改拦截。
最低0.47元/天 解锁文章
648

被折叠的 条评论
为什么被折叠?



