一 概述
BroadcastReceiver 作为 Android 的四大组件之一,也是出场比较频繁的,今天我们就来看看 BroadcastReceiver 是如何工作的。因为 BroadcastReceiver 分为两个部分,一个是广播发送者,一个是广播接受者,所以本文也会分为两个部分介绍,首先是广播接受者。
二 BroadcastReceiver 简介
首先简单回顾一下 BroadcastReceiver 的两种使用方式,分别是静态注册和动态注册。如下,就是 google 官方提供给我们的 BroadcastReceiver 使用示例。
静态注册
<receiver android:name=".MyBroadcastReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.INPUT_METHOD_CHANGED" />
</intent-filter>
</receiver>
动态注册
BroadcastReceiver br = new MyBroadcastReceiver();
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
this.registerReceiver(br, filter);
广播类的定义
public class MyBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "MyBroadcastReceiver";
@Override
public void onReceive(Context context, Intent intent) {
final PendingResult pendingResult = goAsync();
Task asyncTask = new Task(pendingResult, intent);
asyncTask.execute();
}
private static class Task extends AsyncTask<String, Integer, String> {
private final PendingResult pendingResult;
private final Intent intent;
private Task(PendingResult pendingResult, Intent intent) {
this.pendingResult = pendingResult;
this.intent = intent;
}
@Override
protected String doInBackground(String... strings) {
StringBuilder sb = new StringBuilder();
sb.append("Action: " + intent.getAction() + "\n");
sb.append("URI: " + intent.toUri(Intent.URI_INTENT_SCHEME).toString() + "\n");
String log = sb.toString();
Log.d(TAG, log);
return log;
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
// Must call finish() so the BroadcastReceiver can be recycled.
pendingResult.finish();
}
}
}
发送广播
android 提供了三种发送广播的方式
- sendOrderedBroadcast(Intent, String)
- sendBroadcast(Intent)
- LocalBroadcastManager.sendBroadcast
如下,就是其中一种发送广播的代码示例。
Intent intent = new Intent();
intent.setAction("com.example.broadcast.MY_NOTIFICATION");
intent.putExtra("data","Notice me senpai!");
sendBroadcast(intent);
// 带权限的广播
sendBroadcast(new Intent("com.example.NOTIFY"),
Manifest.permission.SEND_SMS);
// 接收方需要注册以下权限
<uses-permission android:name="android.permission.SEND_SMS"/>
关于广播的使用,这里就介绍这么多,不进行扩展了,这些都属于基础内容,我们接下来看看广播具体的工作原理。
广播因为涉及到发送端和注册端,所以我们需要从两个端进行分析,首先我们分析注册端。
三 动态注册
广播的注册分为两种,静态注册和动态注册,静态注册是由 PMS 完成的,动态注册则是由我们应用自己完成的,所以我们先看动态注册。
动态注册也是从 Context 出发,分别经过以下调用
- ContextWrapper.java -> registerReceiver
- ContextImpl.java -> registerReceiver
- ContextImpl.java -> registerReceiverInternal
3.1 registerReceiver
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
int flags) {
return registerReceiver(receiver, filter, null, null, flags);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext(), 0);
}
3.2 registerReceiverInternal
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
// 第一部分就是创建了一个 IIntentReceiver 对象
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
// 第二部分就是调用 AMS 的 registerReceiverWithFeature
try {
... // 省略代码
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
// TODO: determine at registration time if caller is
// protecting themselves with signature permission
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
getAttributionSource());
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里分为两个部分
第一部分 首先是通过 PackageInfo 获取一个 IIntentReceiver,因为广播一般都设计到了跨进程的传递,所以需要将我们传入的 BroadcastReceiver 封装成一个 IIntentReceiver,用来跨进程传递。
第二部分 然后就和其他的四大组件一样,在 registerReceiverInternal 中调用 AMS 的 registerReceiverWithFeature。到此就通过 Binder 调用到了 AMS 所在的系统进程了。
3.3 IIntentReceiver
在 AMS 中,通过调用 mPackageInfo.getReceiverDispatcher 获得了一个 IIntentReceiver,这个 mPackageInfo 是 LoadedApk。
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
// 首先是从复用的 map 中取
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
// 如果没有复用的,就新建一个 ReceiverDispatcher
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
3.4 ReceiverDispatcher 的构造函数
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
// 返回的 mIIntentReceiver 其实就是 ReceiverDispatcher 的内部类 InnerReceiver
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}
所有这里最后拿到的 rd.getIIntentReceiver 其实就是 ReceiverDispatcher 的内部类 InnerReceiver。关于 ReceiverDispatcher 的介绍就先到这里,更详细的介绍见 [10 ReceiverDispatcher]。
四 LoadedApk
4.1 getReceiverDispatcher
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
Context context, Handler handler,
Instrumentation instrumentation, boolean registered) {
synchronized (mReceivers) {
LoadedApk.ReceiverDispatcher rd = null;
ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
// 首先是从一个 map 的集合里取
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
// 如果集合里没有,就构造一个 ReceiverDispatcher
if (rd == null) {
rd = new ReceiverDispatcher(r, context, handler,
instrumentation, registered);
if (registered) {
// 然后再存到 map 集合
if (map == null) {
map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
mReceivers.put(context, map);
}
map.put(r, rd);
}
} else {
rd.validate(context, handler);
}
rd.mForgotten = false;
return rd.getIIntentReceiver();
}
}
4.2 ReceiverDispatcher
ReceiverDispatcher 是 LoadedApk 中的一个内部类。
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
if (intent == null) {
Log.wtf(TAG, "Null intent received");
rd = null;
} else {
rd = mDispatcher.get();
}
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
+ " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
ReceiverDispatcher 中有一个 InnerReceiver 的静态内部类,看来它就是实现 IIntentReceiver.Stub 的类,这个就是用来进行跨进程通信的。再来看一看 AMS 中是如何注册广播的。
五 ActivityManagerService
5.1 registerReceiverWithFeature
public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
String callerFeatureId, String receiverId, IIntentReceiver receiver,
IntentFilter filter, String permission, int userId, int flags) {
... // 省略代码
synchronized (this) {
IApplicationThread thread;
if (callerApp != null && ((thread = callerApp.getThread()) == null
|| thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
// mRegisteredReceivers 是一个 map,首先是从这个 map 中取
// 看看是否有能够复用的 ReceiverList
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
// 如果没有,就用传递进来的 receiver 构造出一个 ReceiverList
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
// 这里会有一个广播数量的判断,超出最大数量就会报错
// MAX_RECEIVERS_ALLOWED_PER_APP 的值是1000
if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
throw new IllegalStateException("Too many receivers, total of "
+ totalReceiversForApp + ", registered for pid: "
+ rl.pid + ", callerPackage: " + callerPackage);
}
rl.app.mReceivers.addReceiver(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
... // 省略代码
}
// 构造出一个广播过滤器,它是 IntentFilter 的子类。
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
+ ", callerPackage is " + callerPackage);
} else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);
}
// 如果有粘性广播,就把它加到粘性广播的队列里
if (allSticky != null) {
ArrayList receivers = new ArrayList();
receivers.add(bf);
final int stickyCount = allSticky.size();
for (int i = 0; i < stickyCount; i++) {
Intent intent = allSticky.get(i);
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, null,
null, null, -1, -1, false, null, null, null, OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1, false, null,
false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
到这里,动态广播的注册流程就算告一段落了,接下来我们看看静态注册是如何完成的。
静态注册
静态注册是由系统的 PMS 完成的,系统会在安装 Apk 的时候解析 Apk 的清单文件,然后调用到 PackageParser 的 parseBaseApplication 中。
5.2 parseBaseApplication
[frameworks/base/core/java/android/content/pm/PackageParser.java]
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
... // 省略代码
if (tagName.equals("receiver")) {
Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
hasReceiverOrder |= (a.order != 0);
owner.receivers.add(a);
}
}
首先是将 receiver 解析成一个 Activity,这里的 Activity 并不是我们四大组件之一的 Activity,而是系统中对这四大组件的封装。
然后,将解析处理的 Activity 添加到 owner 的 receivers 集合中。这里的 owner 是 Package,receivers 是一个泛型是 Activity 的广播接受者集合。
[frameworks/base/core/java/android/content/pm/PackageParser.java]
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
@UnsupportedAppUsage
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
@UnsupportedAppUsage
public final ArrayList<Service> services = new ArrayList<Service>(0);
到这,静态注册就完成了。
六 广播的发送
广播的发送有几种类型,首先我们从最常用的 sendBroadcast 开始。
6.1 sendBroadcast
广播的发送也是从 Context 开始,经过以下调用
- ContextWrapper.java -> sendBroadcast
- ContextImpl.java -> sendBroadcast
- ActivityManagerService.java -> broadcastIntentWithFeature
6.2 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) {
synchronized(this) {
// 首先是校验传入的 intent 是否正确,如果不正确就抛出异常
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLOSP(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
try {
// 然后调用 broadcastIntentLocked 真正执行广播发送
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);
}
}
}
6.3 broadcastIntentLocked
broadcastIntentLocked 这个函数在 Android 12 中非常长,大约有 800 行,所以这里我将这个函数分为几个部分来进行解析。
下面,我将 broadcastIntentLocked 分为以下几个部分进行说明
6.3.1 设置广播 flag
intent = new Intent(intent);
final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
// FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS 表示此广播无法使用静态注册的方式接收
// 这样做是为了防止一些 app 使用静态注册广播的方式拉起自己,实现保活
if (callerInstantApp) {
intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}
if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
broadcastAllowList = new int[]{};
}
// 已经停止的应用也不会接收到广播,防止不断拉起
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// 如果我们尚未完成引导,请不要允许启动新进程
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
// 添加标志,此广播只能动态接收
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
// 获取userId
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "broadcast", callerPackage);
// 确保正在接收此广播的用户或其 parent 正在运行。如果没有,我们将跳过它。
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())) {
// 为关闭广播、升级步骤设置例外。
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
在设置广播 flag 这个阶段,主要给广播添加了如下几个 flag
- FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS -> 此广播是否对 Instant App 可见
- FLAG_EXCLUDE_STOPPED_PACKAGES ->此广播只有活着的应用才能接收
- FLAG_RECEIVER_REGISTERED_ONLY -> 此广播只能通过动态注册接收
Instant App 是谷歌提供的一种免安装应用,有兴趣可以自行了解,这里就不多扩展了。
6.3.2 验证系统权限
final String action = intent.getAction();
BroadcastOptions brOptions = null;
// bOptions 不为空时会检查以下权限,从 AMS 来的 bOptions 都是 null
if (bOptions != null) {
brOptions = new BroadcastOptions(bOptions);
if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
// 检查权限,要求应用有下面三个权限
// CHANGE_DEVICE_IDLE_TEMP_WHITELIST -> 设备的临时白名单
// START_ACTIVITIES_FROM_BACKGROUND -> 后台启动 Activity
// START_FOREGROUND_SERVICES_FROM_BACKGROUND -> 允许配套应用从后台启动前台服务
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) {
throw new SecurityException(msg);
}
}
if (brOptions.isDontSendToRestrictedApps()
&& !isUidActiveLOSP(callingUid)
&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
return ActivityManager.START_CANCELED;
}
if (brOptions.allowsBackgroundActivityStarts()) {
// 检查权限,查应用是否可以后台启动
if (checkComponentPermission(
android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
realCallingPid, realCallingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException(msg);
} else {
allowBackgroundActivityStarts = true;
backgroundActivityStartsToken = null;
}
}
}
// 验证受保护的广播仅由系统代码发送,并且系统代码仅发送受保护的。
final boolean isProtectedBroadcast;
try {
isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
return ActivityManager.BROADCAST_SUCCESS;
}
6.3.3 判断系统广播
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);
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
// 兼容性处理
if (callerPackage == null) {
String msg = "Permission Denial: not allowed to send broadcast "
+ action + " from unknown caller.";
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
// 它们足以发送到显式组件。。。验证它是否被发送到呼叫应用程序。
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 {
// Limit broadcast to their own package.
intent.setPackage(callerPackage);
}
}
}
6.3.4 处理广播的 action
取出 action 进行处理,action 是在[6.3.2] 中获得的。
boolean timeoutExempt = false;
if (action != null) {
if (getBackgroundLaunchBroadcasts().contains(action)) {
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
switch (action) {
case Intent.ACTION_UID_REMOVED: //uid移除
case Intent.ACTION_PACKAGE_REMOVED: //package移除
case Intent.ACTION_PACKAGE_CHANGED: //package改变
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:// applications不可用
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: // applications可用
case Intent.ACTION_PACKAGES_SUSPENDED: // package暂停
case Intent.ACTION_PACKAGES_UNSUSPENDED: // package恢复
// 权限判断
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
callingPid, callingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
// 移除应用是否可以发送广播
throw new SecurityException(msg);
}
... // 省略代码
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
final int uid = getUidFromIntent(intent);
if (uid != -1) {
final UidRecord uidRec = mProcessList.getUidRecordLOSP(uid);
if (uidRec != null) {
uidRec.updateHasInternetPermission();
}
}
}
}
这里涉及到的 action 多达几十种,代码有几百行,这里就不展开了。
6.3.5 处理粘性广播
关于粘性广播这里简单说一下,粘性广播是一种持久性的广播,只要不主动移除,就一种存在内存中。谷歌现在已经不推荐使用粘性广播了,发送粘性广播的函数 sendStickyBroadcast 也被标记为 Deprecated。
当然,本着学习的原则,这里我们还是了解一下粘性广播的原理。
// 如果是粘性广播
if (sticky) {
// 首先检查权限
if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
callingPid, callingUid)
!= PackageManager.PERMISSION_GRANTED) {
...
throw new SecurityException(msg);
}
if (requiredPermissions != null && requiredPermissions.length > 0) {
return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
}
if (intent.getComponent() != null) {
throw new SecurityException(
"Sticky broadcasts can't target a specific component");
}
// 如果不是针对所有用户的广播,那么久要保证它不与其他用户产生冲突
if (userId != UserHandle.USER_ALL) {
// 从粘性广播中,取出针对所有用户的广播,判断是否存在冲突
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
UserHandle.USER_ALL);
if (stickies != null) {
ArrayList<Intent> list = stickies.get(intent.getAction());
if (list != null) {
int N = list.size();
int i;
for (i=0; i<N; i++) {
if (intent.filterEquals(list.get(i))) {
throw new IllegalArgumentException(
"Sticky broadcast " + intent + " for user "
+ userId + " conflicts with existing global broadcast");
}
}
}
}
}
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
if (stickies == null) {
stickies = new ArrayMap<>();
mStickyBroadcasts.put(userId, stickies);
}
ArrayList<Intent> 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++) {
// 替换已经存在的 intent
if (intent.filterEquals(list.get(i))) {
list.set(i, new Intent(intent));
break;
}
}
// 将 intent 添加到粘性广播的 list 中
if (i >= stickiesCount) {
list.add(new Intent(intent));
}
}
6.3.6 获取广播接受者
终于到处理广播接受者的地方了。
... // 省略代码
// 查找静态注册的广播
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(
intent, resolvedType, callingUid, users, broadcastAllowList);
}
//找出所以需要接收此广播的广播接受者
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
for (int i = 0; i < users.length; i++) {
if (mUserController.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
在查找广播接受者的过程中,会先判断发送的广播是否有 FLAG_RECEIVER_REGISTERED_ONLY 标志,此标志表示该广播只能被动态注册者接收,只有没有该标志的广播,才会去取静态注册的广播。
然后,通过 mReceiverResolver 解析 Intent,获取广播接受者,获得的对象 registeredReceivers 是一个 BroadcastFilter 的集合。
collectReceiverComponents
我们稍微看一下 静态广播的查找逻辑,之前我们已经说了,静态广播是由 PMS 解析的。
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
int callingUid, int[] users, int[] broadcastAllowList) {
... // 省略代码
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
.queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
}
首先,通过 AppGlobals.getPackageManager 获得 PMS 的 Binder 对象,然后调用 PMS 的 queryIntentReceivers。
queryIntentReceivers
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
String resolvedType, int flags, int userId) {
return new ParceledListSlice<>(
queryIntentReceiversInternal(intent, resolvedType, flags, userId,
false /*allowDynamicSplits*/));
}
queryIntentReceiversInternal
private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
ComponentName comp = intent.getComponent();
if (comp != null) {
final List<ResolveInfo> list = new ArrayList<>(1);
final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
... // 省略代码
if (!blockResolution) {
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
list.add(ri);
}
}
getReceiverInfo
6.3.7 处理并行广播
// 是否用新的Intent 替换旧的 Intent
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
if (registeredReceivers != null && broadcastAllowList != null) {
// if a uid whitelist was provided, remove anything in the application space that wasn't
// in it.
for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
if (owningAppId >= Process.FIRST_APPLICATION_UID
&& Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
registeredReceivers.remove(i);
}
}
}
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// 如果我们没有序列化此广播,请分别发送已注册的接收器,这样它们就不会等待组件启动。
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, registeredReceivers);
}
// 获取广播接受者的队列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
allowBackgroundActivityStarts, backgroundActivityStartsToken,
timeoutExempt);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// 注意:我们假设resultTo对于非有序广播为空。
if (!replaced) {
// 将 BroadcastRecord 添加到并行广播
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
6.3.8 合并广播
// Merge into one list.
int ir = 0;
if (receivers != null) {
// PACKAGE_ADDED的特殊情况:不允许添加的包观看此广播。这防止了他们在安装后立即将其用作后门来运行。
// 也许在未来,我们希望为应用程序提供一个特殊的安装广播或类似服务,但我们想故意做出这个决定。
String skipPackages[] = null;
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.
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 (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, receivers);
}
6.3.9 处理串行广播
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, excludedPermissions, appOp, brOptions,
receivers, resultTo, resultCode, resultData, resultExtras,
ordered, sticky, false, userId, allowBackgroundActivityStarts,
backgroundActivityStartsToken, timeoutExempt);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);
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 {
// 处理串行广播
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
} else {
// 没有人对广播感兴趣,但我们仍然想记录下这件事的发生
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;
6.3.10 小结
以上,就是所有发送广播的过程了,这里我们总结一下。
- 动态注册是先于静态注册处理的(也就是动态广播优先级更高)
- 对于部分系统广播,只可以通过动态注册的方式接收
- 静态注册是可以拉起应用的(现在系统会限制条件)
- 并行广播会先处理,然后再是串行广播(无序先于有序)
接下来我们再来看看具体的广播处理过程。
七 BroadcastQueue 处理并行广播
接下来,我们再看看并行广播的处理流程。首先从我们在 [6.3.7] 中看到的 BroadcastQueue 开始。
7.1 enqueueParallelBroadcastLocked
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
mParallelBroadcasts.add(r);
enqueueBroadcastHelper(r);
}
mParallelBroadcasts 是 BroadcastQueue 中的一个 ArrayList,保存的是马上要处理的广播列表。然后我们再看 [6.3.7] 中,处理并行广播的第二个函数 scheduleBroadcastsLocked。
7.2 scheduleBroadcastsLocked
public void scheduleBroadcastsLocked() {
if (mBroadcastsScheduled) {
return;
}
// 发送处理广播的消息
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
7.3 handleMessage
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
// 处理下一条广播
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
broadcastTimeoutLocked(true);
}
} break;
}
}
}
八 处理串行广播
然后我们再看看串行广播的处理流程。首先从我们在 [6.3.9] 中看到的 BroadcastQueue 开始。
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
8.1 enqueueOrderedBroadcastLocked
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
mDispatcher.enqueueOrderedBroadcastLocked(r);
enqueueBroadcastHelper(r);
}
在这个函数中,将广播添加进了 mDispatcher 中。,这个 mDispatcher 其实就是 BroadcastDispatcher。
8.2 scheduleBroadcastsLocked
public void scheduleBroadcastsLocked() {
if (mBroadcastsScheduled) {
return;
}
// 发送处理广播的消息 BROADCAST_INTENT_MSG
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
所以不论是串行广播,还是并行广播,最后都会通过消息机制,执行到 processNextBroadcast 中。
九 处理广播的逻辑
9.1 processNextBroadcast
private void processNextBroadcast(boolean fromMsg) {
synchronized (mService) {
processNextBroadcastLocked(fromMsg, false);
}
}
9.2 processNextBroadcastLocked
既然处理广播的逻辑都在一个函数里,所以这个函数肯定会分别对串行广播和并行广播做不同的处理。
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
mService.updateCpuStats();
if (fromMsg) {
mBroadcastsScheduled = false;
}
// 1. mParallelBroadcasts 是并行广播的集合
// 所以首先处理的并行广播
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
// 2. 调用处理并行广播的函数
deliverToRegisteredReceiverLocked(r,
(BroadcastFilter) target, false, i);
}
//3. 将处理完的并行广播添加到历史记录中
addBroadcastToHistoryLocked(r);
}
// 4. 等待处理的广播,之前在 Service 中也有类似的 mPendingService
// 等进程启动后处理,如果进程以及被杀,就会丢弃此 mPendingService
if (mPendingBroadcast != null) {
boolean isDead;
if (mPendingBroadcast.curApp.getPid() > 0) {
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(
mPendingBroadcast.curApp.getPid());
isDead = proc == null || proc.mErrorState.isCrashing();
}
} else {
final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get(
mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
isDead = proc == null || !proc.isPendingStart();
}
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
// 5. 处理串行广播(有序广播),注意,这里是一个循环
do {
// 6. 从 mDispatcher 中获取需要处理的串行广播
final long now = SystemClock.uptimeMillis();
r = mDispatcher.getNextBroadcastLocked(now);
// 在循环的开始,会判断广播是否处理完毕
if (r == null) {
// r 为空,表示串行广播处理完毕,直接返回
... // 省略代码
return;
}
boolean forceReceive = false;
//
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
// 8. 判断广播处理的时间
// 在处理有序广播时,不仅单个广播会超时,多个广播合起来的时间
// 超过制定时间也会超时,触发 ANR
if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
// 如果广播处理超时,就强制关闭
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
return;
}
// Is the current broadcast is done for any reason?
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// Send the final result if requested
if (r.resultTo != null) {
boolean sendResult = true;
// if this was part of a split/deferral complex, update the refcount and only
// send the completion when we clear all of them
if (r.splitToken != 0) {
int newCount = mSplitRefcounts.get(r.splitToken) - 1;
if (newCount == 0) {
// done! clear out this record's bookkeeping and deliver
mSplitRefcounts.delete(r.splitToken);
} else {
// still have some split broadcast records in flight; update refcount
// and hold off on the callback
sendResult = false;
mSplitRefcounts.put(r.splitToken, newCount);
}
}
if (sendResult) {
if (r.callerApp != null) {
mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
r.callerApp);
}
try {
// 9. 处理串行广播
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
}
}
}
// 10. 一个广播处理完毕,取消超时消息
cancelBroadcastTimeoutLocked();
// 11. 把处理过的广播添加到历史中
addBroadcastToHistoryLocked(r);
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
mDispatcher.retireBroadcastLocked(r);
r = null;
looped = true;
continue;
}
// 检查下一个接收者是否在延迟策略下,并进行相应处理。 如果当前的广播已经是延缓交付的一部分 追踪的一部分,我们知道它现在一定是可以按原样交付的,不需要重新延期。
if (!r.deferred) {
final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
if (mDispatcher.isDeferringLocked(receiverUid)) {
// 如果这是广播中唯一的(剩余的)接收器,"分割 "就没有意义了--只需将其原封不动地推迟,并将其作为当前活动的外发广播退役。当前活动的外发广播。
BroadcastRecord defer;
if (r.nextReceiver + 1 == numReceivers) {
defer = r;
mDispatcher.retireBroadcastLocked(r);
} else {
//
defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
// Track completion refcount as well if relevant
if (r.resultTo != null) {
int token = r.splitToken;
if (token == 0) {
// first split of this record; refcount for 'r' and 'deferred'
r.splitToken = defer.splitToken = nextSplitTokenLocked();
mSplitRefcounts.put(r.splitToken, 2);
} else {
// new split from an already-refcounted situation; increment count
final int curCount = mSplitRefcounts.get(token);
mSplitRefcounts.put(token, curCount + 1);
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG_BROADCAST, "New split count for token " + token
+ " is " + (curCount + 1));
}
}
}
}
mDispatcher.addDeferredBroadcast(receiverUid, defer);
r = null;
looped = true;
continue;
}
}
} while (r == null);
// 获得下一个广播接收者的id
int recIdx = r.nextReceiver++;
// 记录接收器开始的时间,必要时出现 ANR 的话就杀死它。
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
}
if (! mPendingBroadcastTimeoutMessage) {
// 设置超时时间,当前时间 + TIMEOUT(10秒)
long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
setBroadcastTimeoutLocked(timeoutTime);
}
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
if (nextReceiver instanceof BroadcastFilter) {
// 如果下一个是动态注册的广播接收者
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
if (r.receiver == null || !r.ordered) {
// 如果接收者已经处理完,就继续处理下一个
r.state = BroadcastRecord.IDLE;
scheduleBroadcastsLocked();
} else {
if (filter.receiverList != null) {
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
}
}
return;
}
// 困难情况:需要实例化接收器,可能是 启动它的应用进程来承载它。
// 权限判断
ResolveInfo info =
(ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
... // 省略代码,大量权限判断
// Broadcast is being executed, its package can't be stopped.
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.curComponent.getPackageName(), false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.curComponent.getPackageName() + ": " + e);
}
// 如果广播所在的进程正在运行,就会在这里处理并返回
if (app != null && app.getThread() != null && !app.isKilled()) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
maybeAddAllowBackgroundActivityStartsToken(app, r);
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// 没有返回,说明进程没有运行,先启动进程
r.curApp = mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
new HostingRecord("broadcast", r.curComponent), isActivityCapable
? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
(r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
if (r.curApp == null) {
// 这个接收者的进程启动失败,所以处理下一个广播
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ receiverUid + " for broadcast "
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
}
9.3 deliverToRegisteredReceiverLocked
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
... // 省略代码,大量的权限判断
try {
if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) {
// 如果 app 处于备份状态,就跳过有序广播
if (ordered) {
skipReceiverLocked(r);
}
} else {
r.receiverTime = SystemClock.uptimeMillis();
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
// 调用处理广播的逻辑
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
// parallel broadcasts are fire-and-forget, not bookended by a call to
// finishReceiverLocked(), so we manage their activity-start token here
if (filter.receiverList.app != null
&& r.allowBackgroundActivityStarts && !r.ordered) {
postActivityStartTokenRemoval(filter.receiverList.app, r);
}
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
// Clean up ProcessRecord state related to this broadcast attempt
if (filter.receiverList.app != null) {
filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
if (ordered) {
filter.receiverList.app.mReceivers.removeCurReceiver(r);
// Something wrong, its oom adj could be downgraded, but not in a hurry.
mService.enqueueOomAdjTargetLocked(r.curApp);
}
}
// And BroadcastRecord state related to ordered delivery, if appropriate
if (ordered) {
r.receiver = null;
r.curFilter = null;
filter.receiverList.curBroadcast = null;
}
}
}
9.4 performReceiveLocked
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser)
throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
final IApplicationThread thread = app.getThread();
if (thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser,
app.mState.getReportedProcState());
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.getPid() + "). Crashing it.");
app.scheduleCrashLocked("can't deliver broadcast");
}
throw ex;
}
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
接下来经过一下调用逻辑,就又到了我们熟悉的 ReceiverDispatcher 了。
- ActivityThread -> scheduleRegisteredReceiver
- IIntentReceiver -> performReceive
10 ReceiverDispatcher
在 ReceiverDispatcher 中,有一个 InnerReceiver,它是 IIntentReceiver.Stub 的子类,所以一开始的跨进程调用,会调用到 InnerReceiver 的 performReceive。
10.1 InnerReceiver.performReceive
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
// 定义一个 rd 对象
final LoadedApk.ReceiverDispatcher rd;
... // 省略代码
if (rd != null) {
// 调用 rd 的 performReceive
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
... // 省略代码
IActivityManager mgr = ActivityManager.getService();
try {
if (extras != null) {
extras.setAllowFds(false);
}
// 调用完成广播
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
10.2 ReceiverDispatcher.performReceive
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
// Args 也是 ReceiverDispatcher 的内部类
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
... // 省略代码
// 调用 Args 的 run
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
// 调用 Args 的 sendFinished
args.sendFinished(mgr);
}
}
}
}
10.3 Args 的 run 函数
final class Args extends BroadcastReceiver.PendingResult {
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
final IActivityManager mgr = ActivityManager.getService();
final Intent intent = mCurIntent;
mCurIntent = null;
mDispatched = true;
mRunCalled = true;
... // 异常处理
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
mContext.getAttributionSource());
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
// 调用广播接收者的 onReceive
receiver.onReceive(mContext, intent);
} catch (Exception e) {
... // 省略代码
}
10.4 sendFinished
public void sendFinished(IActivityManager am) {
synchronized (this) {
if (mFinished) {
throw new IllegalStateException("Broadcast already finished");
}
mFinished = true;
try {
if (mResultExtras != null) {
mResultExtras.setAllowFds(false);
}
if (mOrderedHint) {
// 调用 AMS 的 finishReceiver
am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
mAbortBroadcast, mFlags);
} else {
// This broadcast was sent to a component; it is not ordered,
// but we still need to tell the activity manager we are done.
am.finishReceiver(mToken, 0, null, null, false, mFlags);
}
} catch (RemoteException ex) {
}
}
}
十一 ActivityManagerService
11.1 finishReceiver
public void finishReceiver(IBinder who, int resultCode, String resultData,
Bundle resultExtras, boolean resultAbort, int flags) {
// Refuse possible leaked file descriptors
if (resultExtras != null && resultExtras.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
final long origId = Binder.clearCallingIdentity();
try {
boolean doNext = false;
BroadcastRecord r;
BroadcastQueue queue;
synchronized(this) {
if (isOnFgOffloadQueue(flags)) {
queue = mFgOffloadBroadcastQueue;
} else if (isOnBgOffloadQueue(flags)) {
queue = mBgOffloadBroadcastQueue;
} else {
queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
? mFgBroadcastQueue : mBgBroadcastQueue;
}
r = queue.getMatchingOrderedReceiver(who);
if (r != null) {
doNext = r.queue.finishReceiverLocked(r, resultCode,
resultData, resultExtras, resultAbort, true);
}
if (doNext) {
// 调用 BroadcastQueue 的 processNextBroadcastLocked,分发下一个有序广播
r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
}
trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
十二 总结
到此,广播的发送和接受就都梳理完毕了,最后再来做一个简单的梳理。
广播的注册
- 广播的注册分为两种,静态注册和动态注册。
- 静态注册的逻辑由 PMS 完成
- 动态注册的逻辑在代码中完成
广播的发送和接收
广播的发送方式有三种
- 有序广播
- 无序广播
- 粘性广播(已废弃)
- 发送广播时可以发送有序广播和无序广播
- 无序传播会优先处理
- 有序广播会有时间限制,超时时间就会 ANR(也就是说只有有序广播才会 ANR,无序广播不会 ANR)
- 有序广播 ANR 有两种情况,第一种就是单个广播处理超过了 10 秒(后台 60 秒),另一种是多个广播超过时间 是 2 * mConstants.TIMEOUT * numReceivers(TIMEOUT 前台默认是 10 秒,后台默认是 60 秒)
- 静态广播可以拉起进程(但现在系统限制较严格)
最后用一张图作为总结