简介
本次介绍BroadcastReceiver的工作过程,主要从两方面来讲,一是广播的注册过程,二是广播的发送和接收过程。我们在使用的时候其实都是继承BroadcastReceiver并重写onReceiver方法即可,我们在此方法不能做耗时的工作参考时间为10秒。
广播的注册过程
注册广播有两种方式,一是动态注册通过代码调用registerReceiver方法即可,二是AndroidManifest文件静态注册,一般在安装时由系统自动注册,由PMS(PackageManagerService)来完成注册。现在我们要分析的是动态注册过程,我们先看整个注册过程源码时序图,如图所示:
调用registerReceiver方法后,接着调用registerReceiverInternal方法。在这方法里面做了一些跨进程处理,说明BroadcastReceiver不支持跨进程调用。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//1
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();
}
}
try {
//2
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();
}
}
1)把BroadcastReceiver封装成跨进程可调用的IIntentReceiver类型的rd。IIntentReceiver都是一个Binder接口,方便AMS进程回调。2)开始调用AMS的registerReceiver方法。把registerReceiver方法里代码有些多,分成两块代码来分析。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
ProcessRecord callerApp = null;
synchronized(this) {
if (caller != null) {
//1
callerApp = getRecordForAppLocked(caller);
}
//2
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// Collect stickies of users
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList<Intent> intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList<Intent>();
}
//3
stickyIntents.addAll(intents);
}
}
}
}
}
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
if (instantApp &&
(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
continue;
}
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
//4
allSticky.add(intent);
}
}
}
1 找到广播注册者所在的进程。
2 根据filter得到相应的actions。
3 找到匹配传入参数filter粘性广播的intent。
4 把所有粘性广播的intent都存入allSticky,从这里也可以看出这都保存在AMS中。
我们接着分析此方法的第二块代码,如下所示。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
int flags) {
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// Original caller already died
return null;
}
ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl == null) {
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
if (rl.app != null) {
final int totalReceiversForApp = rl.app.receivers.size();
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);
}
//1
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId, instantApp, visibleToInstantApps);
if (rl.containsFilter(filter)) { } else {
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
//2
mReceiverResolver.addFilter(bf);
}
return sticky;
}
}
1 BroadcastFilter 广播接收者的描述。
2 mReceiverResolver 用来存储广播接收者,当AMS收到广播消息时,从这里面找对应的广播接收者。代码到达这里说明我们广播都注册成功了。
广播的发送和接收过程
当通过send方法来发送广播的时候,AMS查找匹配广播接收者并且把广播发送给他们处理。以下都是发送广播的几种类型
普通广播:依次传递给各个处理器处理。
有序广播:优先级高的处理器先收到消息,可截获消息不让优先级低的处理。
粘性广播:消息发送后都存在系统容器里面,当我注册了接收者都会收到。
现在开始分析广播的发送和接收过程,分析普通广播,首先先看一张源码时序图如图所示:
调用sendBroadcast方法,然后调用AMS的broadcastIntent方法。
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
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, AppOpsManager.OP_NONE,
null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
在broadcastIntent代码中,做了些验证广播的合法性,然后接着调用了broadcastIntentLocked方法,在这方法里面调用了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 realCallingUid,
int realCallingPid, int userId, boolean allowBackgroundActivityStarts) {
intent = new Intent(intent);
...
// By default broadcasts do not go to stopped apps.
//1
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
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,
allowBackgroundActivityStarts, timeoutExempt);
if (!replaced) {
//2
queue.enqueueParallelBroadcastLocked(r);
//3
queue.scheduleBroadcastsLocked();
}
registeredReceivers = null;
NR = 0;
}
return ActivityManager.BROADCAST_SUCCESS;
}
1 默认添加FLAG_EXCLUDE_STOPPED_PACKAGES,防止无意间或者不必要时候调起了已经停止的应用,如果需要启动停止的应用添加FLAG_INCLUDE_STOPPED_PACKAGES标记即可这两种标记可以共存。
2 把BroadcastRecord存入到BroadcastQueue的mParallelBroadcasts数组里面。
3 然后调用BroadcastQueue的scheduleBroadcastsLocked方法。在这方法里面通过Handler发送消息然后processNextBroadcast方法,传递参数是true,接着调用processNextBroadcastLocked方法。
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
BroadcastRecord r;
//1
if (fromMsg) {
mBroadcastsScheduled = false;
}
// First, deliver any non-serialized broadcasts right away.
//2
while (mParallelBroadcasts.size() > 0) {
//3
r = mParallelBroadcasts.remove(0);
final int N = r.receivers.size();
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
//4
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
}
}
这个processNextBroadcastLocked方法有特别多的代码,贴了核心代码出来分析。
1 mBroadcastsScheduled设置成false,对发来BROADCAST_INTENT_MSG消息表示处理。
2 用while循环将mParallelBroadcasts无序的广播发送给广播接收者。
3 取出mParallelBroadcasts存储在此数组的BroadcastRecord类型对象。
4 然后将BroadcastRecord类型的r对象发送给广播接收者。然后我们在调用deliverToRegisteredReceiverLocked方法,如下所示:
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
try {
if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
if (ordered) {
skipReceiverLocked(r);
}
} else {
r.receiverTime = SystemClock.uptimeMillis();
maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
if (r.allowBackgroundActivityStarts && !r.ordered) {
postActivityStartTokenRemoval(filter.receiverList.app, r);
}
}
} catch (RemoteException e) { }
}
上述代码省去无数代码,代码主要是检查广播发送者和广播接收者的权限的。权限检查没问题,接着调用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) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
} catch (RemoteException ex) {
}
} else {
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
检查了应用程序是否在运行,然后调用了ApplicationThread的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);scheduleRegisteredReceiver
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
然后调用了IIntentReceiver Binder接口的performReceive方法。这个类我们应该非常熟悉了,在我们注册广播的时候,就是把BroadcastReceiver封装在IIntentReceiver这个类的。我们可以看下源码:
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
if (activityThread == null) {
throw new NullPointerException("Handler must not be null");
}
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
mRegistered = registered;
mLocation = new IntentReceiverLeaked(null);
mLocation.fillInStackTrace();
}
ReceiverDispatcher持有InnerReceiver类和BroadcastReceiver类对象引用,是这个类扮演了桥梁的角色让他们有了关联关系。接着我们看看InnerReceiver这个类里面的performReceive方法,代码如下:
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference<ReceiverDispatcher> mDispatcher;
final ReceiverDispatcher mStrongRef;
InnerReceiver(ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference<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 ReceiverDispatcher rd;
if (intent == null) {
rd = null;
} else {
rd = mDispatcher.get();
}
if (rd != null) {
//1
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();
}
}
}
}
}
标记1调用了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);
//1
if (intent == null || !mActivityThread.post(args.getRunnable())) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManager.getService();
args.sendFinished(mgr);
}
}
}
1 mActivityThread执行了post方法,其实这个类都是H类继承Handler,H类对我们来说非常熟悉,在分析Activity启动流程通过他往主线程发送消息,这里也看出onReceiver方法在主线程里面。Args类通过getRunnable方法new 出来一个Runnable对象,我们看看这个类具体源码,代码如下:
final class Args extends BroadcastReceiver.PendingResult {
public final Runnable getRunnable() {
return () -> {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
}
};
}
}
BroadcastReceiver类型的receiver对象执行onReceiver方法,这样广播的注册者收到了广播得到了intent。
以上都是普通广播源码所有分析,如有问题及时修改。