Android四大组件——BroadCastReceiver的工
BroadCastReceiver的工作过程分为包含两方面的内容:
- 注册
- 发送和接收
使用BroadcastReceiver很简单,只需要继承BroadcastReceiver并重写它的onReceive方法即可。
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//TODO something
}
}
为了使BroadcastReceiver工作,就需要对它进程注册。注册BroadCastReceiver分为在AndroidManifest.xml静态注册和代码中动态注册。
静态注册示例:
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="com.sososeen.09.demo.my.receiver"/>
</intent-filter>
</receiver>
动态注册也很简单:
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.sososeen.09.demo.my.receiver");
registerReceiver(new MyReceiver(), intentFilter);
不过动态注册别忘了反注册,否则会造成内存泄漏。
发送广播示例如下,通过给Intent设置action,对应的广播接收者的onReveive就会被回调了。
Intent intent = new Intent();
intent.setAction("com.sososeen.09.demo.my.receiver");
sendBroadcast(intent);
注册广播和发送广播中间过程是怎么进行的,我们今天就来分析一下。由于静态注册牵涉到在应用安装时有系统自动完成注册,确切的说是通过PackageManagerService完成注册,相对比较复杂。今天先来分析一下动态注册的BroadCastReceiver的工作过程。
在本文的分析中,ActivityManagerService简称AMS。
动态注册BroadCastReceiver
注册广播接收者是通过ContextWrapper来进行的,但是类似启动Service,真正干事的还是ContextImpl,我们直接来看它的方法。2个参数的registerReceiver方法,会调用4个参数的registerReceiver方法,然后会调用registerReceiverInternal方法。
# android.app.ContextImpl
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
在registerReceiverInternal方法中主要干了两件事:
-
mPackageInfo指的是LoadedApk对象,通过调用LoadedApk的getReceiverDispatcher方法把BroadcastReceiver包装为ReceiverDispatcher.InnerReceiver对象,这是因为BroadcastReceiver是不具有跨进程通信能力的,想要最终调用到BroadcastReceiver的onReceive方法,必须有一个Binder对象用来进行IPC,在这里就是ReceiverDispatcher.InnerReceiver对象。InnerReceiver对象持有ReceiverDispatcher对象的引用。当AMS端调用InnerReceiver的接收广播的方法,InnerReceiver对象会找到对应的ReceiverDispatcher进而找到BroadcastReceiver对象并调用其onReceive方法。这个过程我们后面再分析。这种方式与bind方式启动Service的中包装ServiceConnection是类似的,有兴趣的可以看一下Android四大组件——Service的工作过程分析。
-
ActivityManagerNative.getDefault()获取的是AMS在本地的代理,该代理通过IPC过程调用AMS的registerReceiver方法。
# android.app.ContextImpl
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
// 1 创建ReceiverDispatcher.InnerReceiver对象
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 IPC过程调用AMS的registerReceiver方法
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
我们先来看一下LoadedApk的getReceiverDispatcher方法,就是创建一个ReceiverDispatcher对象并将其保存起来,在ReceiverDispatcher的构造方法中创建InnerReceiver对象,ReceiverDispatcher对象中保存了BroadcastReceiver和InnerReceiver对象。
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;
if (registered) {
map = mReceivers.get(context);
if (map != null) {
rd = map.get(r);
}
}
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();
}
}
我们来看一下AMS的registerReceiver方法,该方法很长,我们选取一些关键的地方。
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
enforceNotIsolatedCaller("registerReceiver");
ArrayList<Intent> stickyIntents = null;
ProcessRecord callerApp = null;
...
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);
rl.add(bf);
...
mReceiverResolver.addFilter(bf);
...
}
}
在上面的方法中
mRegisteredReceivers 是一个HashMap对象,用于追踪客户端BroadcastReceiver对应的ReceiverDispatcher.InnerReceiver对象。ReceiverList是一个ArrayList集合,用于存放BroadcastFilter,BroadcastFilter用于包装IntentFilter。我们需要知道一点,同一个BroadcastReceiver是可以对应多个IntentFilter的,只要匹配一个就能够接收消息。
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
说明: BroadcastFilter中封装了ReceiverList对象,而ReceiverList对象中包含了客户端BroadcastReceiver对应的IIntentReceiver对象(实际上就是ReceiverDispatcher.InnerReceiver对象),将来在发送广播的阶段,通过Intent找到所有匹配到的动态注册的BroadcastFilter集合。
到此,BroadcastReceiver的动态注册过程就完毕了。
广播的发送和接收过程
广播的发送分为普通广播、有序广播和粘性广播。有序广播是按照广播接收者的优先级,从高优先级到低优先级依次接收,而且在高优先级的广播接收者中是可以打断广播,造成低优先级的广播接收不到。而粘性广播表示想要当发送广播的时候,BroadcastReceiver还没有创建,当BroadcastReceiver创建后,它的onReveive方法会被立即调用。
在这里我们分析一下普通广播的发送和接收流程。
调用Context的方法发送广播,实际上还是会调用ContextImpl的方法,来一下ContextImpl的sendBroadcast方法
@Override
public void sendBroadcast(Intent intent) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
try {
intent.prepareToLeaveProcess(this);
ActivityManagerNative.getDefault().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();
}
}
从这个过程中看,通过一个IPC过程调用到AMS的broadcastIntent方法,在该方法又调用了AMS的broadcastIntentLocked方法。
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle bOptions,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);
final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, bOptions, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}
broadcastIntentLocked方法非常长,我们尽量选取一些关键的地方来分析,在方法的开始会有如下代码:
intent = new Intent(intent);
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
表示会重新创建一个Intent对象用于包裹传递过来的的Intent对象,并且为Intent添加了一个flag,Intent.FLAG_EXCLUDE_STOPPED_PACKAGES,表示默认情况下广播不会发送给已经停止运行的App,这也是为了方式一些App想要利用广播来启动进程。
从Android3.1开始,添加了两个标记
// 表示不包含已经停止的应用,如果广播设置这个标记,就不会发送给已经停止的应用
public static final int FLAG_EXCLUDE_STOPPED_PACKAGES = 0x00000010;
// 表示包含已经停止的应用,如果广播设置这个标记,就会发送给已经停止的应用
public static final int FLAG_INCLUDE_STOPPED_PACKAGES = 0x00000020;
从Android 3.1开始,默认情况下都是添加一个FLAG_EXCLUDE_STOPPED_PACKAGES标记,表示不会发送给停止的应用,如果确实需要的话,需要给广播显式的设置FLAG_INCLUDE_STOPPED_PACKAGES标记。
在broadcastIntentLocked内部,会根据IntentFilter查找出匹配的BroadcastReceiver,经过一系列条件的筛选和过滤,将满足条件的接收者放在BroadcastQueue中,接下来BroadcastQueue就会将广播发送出去。注意在这个过程中会先把找出来的动态注册的广播发出去,然后再把静态注册的广播发出去。因此,动态注册的广播优先级是高于静态注册的广播的。而且,如果BroadcastReceiver同时注册了静态广播和动态广播,其onReceive方法会被调用两次。
if ((receivers != null && receivers.size() > 0)
|| resultTo != null) {
BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
callerPackage, callingPid, callingUid, resolvedType,
requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
resultData, resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
+ ": prev had " + queue.mOrderedBroadcasts.size());
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Enqueueing broadcast " + r.intent.getAction());
boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
if (!replaced) {
queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
BroadcastQueue发送广播的实现如下,通过Handler发送一个BROADCAST_INTENT_MSG类型的消息,Handler收到消息之后会调用BroadcastQueue的processNextBroadcast方法。
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
if (mBroadcastsScheduled) {
return;
}
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
BroadcastQueue的processNextBroadcast方法很长,我们选取发送普通广播的部分来看,可以看到无序广播存放在mParallelBroadcasts集合中,通过遍历这个集合来发送广播给BroadcastReceiver。具体的发送过程是deliverToRegisteredReceiverLocked方法。
final void processNextBroadcast(boolean fromMsg) {
...
// First, deliver any non-serialized broadcasts right away.
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i<N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering non-ordered on [" + mQueueName + "] to registered "
+ target + ": " + r);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
}
addBroadcastToHistoryLocked(r);
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
+ mQueueName + "] " + r);
}
再来看一下BroadcastQueue的deliverToRegisteredReceiverLocked方法,该方法负责将一个特定的广播发送给特定的接收者,具体的发送过程是调用了performReceiveLocked方法。
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
来看一下performReceiveLocked方法,app.thread指的就是ApplicationThread在本地的代理对象,app.thread != null 条件满足,会通过IPC过程调用ApplicationThread的scheduleRegisteredReceiver方法。
# com.android.server.am.BroadcastQueue
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.repProcState);
...
} catch (RemoteException 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);
}
}
在ApplicationThread的scheduleRegisteredReceiver方法中调用了receiver的performReceive方法,而这个receiver我们知道,实际上就是ReceiverDispatcher.InnerReceiver对象。
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);
}
来看一下ReceiverDispatcher.InnerReceiver对象的performReceive方法,在该方法中首先获取InnerReceiver持有的ReceiverDispatcher对象,如果ReceiverDispatcher对象不为空的话就会调用它的performReceive方法。
# android.app.LoadedApk.ReceiverDispatcher.InnerReceiver
@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 (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
...
}
}
在ReceiverDispatcher的performReceive方法中,会封装一个Args对象,Args是ReceiverDispatcher的非静态内部类,因此持有ReceiverDispatcher的引用,可以访问ReceiverDispatcher的参数和方法,并且它实现了Runnable接口。mActivityThread是一个Handler,通过post方法,把调用切换到主线程中来,Args的run方法会被执行。
# android.app.LoadedApk.ReceiverDispatcher
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) {
Log.wtf(TAG, "Null intent received");
} else {
...
}
if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
Args的run方法如下,最后会调用BroadcastReceiver的onReceive方法。
# android.app.LoadedApk.ReceiverDispatcher.Args
public void run() {
final BroadcastReceiver receiver = mReceiver;
...
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
...
}
到此,广播的发送和接收过程也分析完毕了。
总结
-
注册广播的时候是把BroadcastReceiver封装到ReceiverDispatcher中,并且把与此对应的ReceiverDispatcher.InnerReceiver作为一个Binder对象传递到AMS端,AMS端会通过一个Map集合来存放ReceiverDispatcher.InnerReceiver对象和对应的IntentFilter包装类。
-
发送广播的时候,通过一个IPC过程调用到AMS端,AMS端会找到匹配的广播接收者并添加到BroadcastQueue中,在BroadcastQueue中进程处理之后通过一个IPC过程调用到ApplicationThread的scheduleRegisteredReceiver方法,然后会调用ReceiverDispatcher.InnerReceiver的方法,再经过ReceiverDispatcher、以及它的内部类Args,最终调用到BroadcastReceiver的onReveive方法。
-
动态注册的广播优先级是高于静态注册的广播的。而且,如果BroadcastReceiver同时注册了静态广播和动态广播,其onReceive方法会被调用两次。
-
从过程中也可以看到,AMS端如果想要与客户端打交道的话都是通过ApplicationThread。