一、概要
BoradcastReceiver在Android中充当的是传递数据和消息的作用。尽管现在有很多框架(比如EventBus、Rxjava等)可以代替它在应用内传递消息和数据,但是不同的是BoradcastReceiver可以跨进新传递数据。所以了解BoradcastReceiver的实现还是比较重要的。这里分析广播机制注意围绕三个方法进行:registerReceiver()、sendBroadcast()和unregisterReceiver()。如果你只是想了解它的使用的话,可以参考下这篇文章Android广播机制总结。
1、涉及主要类
android.app.ContextImpl.java
android.app.Instrumentation.java
android.app.ActivityThread.java
android.app.ActivityManager.java
com.android.server.am.ActivityManagerService.java
android.content.BroadcastReceiver.java
com.android.server.am.BroadcastQueue.java
com.android.server.am.BroadcastRecord.java
android.app.LoadedApk.java
2、流程图
BroadcastReceiver流程.png 3、简要图 BroadcastReceiver运作简单示意图.png
从这里我们可以看出这个广播机制运用的是发布/订阅者模式来设计的。
二、具体流程
1.1、ContextImpl.registerReceiver()
这里最终会调用registerReceiverInternal()方法:
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
//这里先获取ActivityThread.java中的H实例
if (mLoadedApk != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mLoadedApk.getReceiverDispatcher(
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//使用Binder IPC机制和AMS进行通信
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
这里主要就是创建了LoadApk.ReceiverDispatcher的实例,这个实例用于传播广播用的。然后接下来我们看下AMS中的registerReceiver方法:
1.2、ActivityManageService.registerReceiver()
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
// 省略部分代码
// 这里处理Sticky广播
...
synchronized (this) {
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
rl.app.receivers.add(rl);
} else {
try {
receiver.asBinder().linkToDeath(rl, 0);
} catch (RemoteException e) {
return sticky;
}
rl.linkedToDeath = true;
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//添加到Receiver集合中
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
//处理Sticky广播,遍历保存的Sticky广播中有满足注册的received,直接发送
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, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
//将记录着BroadcastRecevied信息的BroadcastRecord加入到BroadcastQueue中
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
这里的主要逻辑是先收集用户发送的sticky广播,根据注册的received设置的IntentFilter去匹配相应的sticky广播。接着把注册的BroadcastFilter加入到mReceiverResolver的集合当中,同时也把记录着BroadcastRecevied信息的BroadcastRecord加入到BroadcastQueue中。最后一步就是如果received注册的IntentFilter有对应的sticky广播时,立即将对应的sticky广播发送给接收器,从这里可以看出sticky广播的机制(即注册时,若有相应的粘性广播相匹配时,会立即收到该广播)。
2.1、ContextImpl.sendBroadcast()
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();
}
}
发送广播时,同样用到的是binder IPC机制与AMS进行通信。接着来看下AMS中的broadcastIntent()方法。
2.2、ActivityManageService.broadcastIntent()
最终会调用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) {
// 省略部分代码(检测权限及处理一些特别的广播)
// 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) {
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<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
//从mReceiverResolve找出相应的接收器
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false /*defaultOnly*/, userId);
}
}
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);
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, callingPid, callingUid, callerInstantApp, resolvedType,
requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
resultCode, resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending
&& (queue.replaceParallelBroadcastLocked(r) != null);
// Note: We assume resultTo is null for non-ordered broadcasts.
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
// Merge into one list.
int ir = 0;
//处理有序广播,广播接收器按照设置的priority进行排序
//省略部分代码
return ActivityManager.BROADCAST_SUCCESS;
}
这个方法比较长,对粘性广播、系统广播、有序广播和正常广播分别进行了处理,最终会匹配相应的注册了的广播接收器。最后执行BroadcastQueue的scheduleBroadcastsLocked()方法,也就是发送广播给接收器。
2.3、BroadcastQueue.scheduleBroadcastsLocked()
最终会执行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) {
if (app.thread != null) {
try {
//调用ActivityThread.scheduleRegisteredReceiver()方法
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
} catch (RemoteException ex) {
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.pid + "). Crashing it.");
app.scheduleCrash("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);
}
}
这里的app.thread其实就是ActivityThread,我们再看ActivityThread. scheduleRegisteredReceiver方法:
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
这里的receiver就是之前在注册广播时获取的(见1.1)LoadApk.ReceiverDispatcher.InnerReceiver(Binder接口 IPC过程)然后再通过LoadApk.ReceiverDispatcher.performReceive()方法通过handle post出一个Runnable:
2.4、LoadApk.ReceiverDispatcher.performReceive()
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
//省略部分代码 ...
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
这里通过ActivityThread.H的handler对象post了一个线程,我们看下这个线程的实现的主要代码:
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
//省略部分代码
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
//省略部分代码
};
}
}
最终是通过ActivityThread.H对象post出一个线程,将 receiver.onReceive(mContext, intent); 方法的调用回到了主线程。
3、ContextImpl.unregisterReceiver()
取消接收器的注册也是通过AMS将receiver移除容器
void removeReceiverLocked(ReceiverList rl) {
mRegisteredReceivers.remove(rl.receiver.asBinder());
for (int i = rl.size() - 1; i >= 0; i--) {
mReceiverResolver.removeFilter(rl.get(i));
}
}
网友评论