前言
相信大家在应用开发中都用过Broadcast,单纯从使用的角度来说,是非常容易的,但对于系统开发工程师来说,需要了解广播运行的机制,那还是有必要去阅读它的源码。
关于Broadcast的代码也是非常非常多的,我这里将分成几个部分来讲,分别是:
广播的类型、广播的注册、广播的发送、广播的处理、广播总结和建议。
传送门:
Android 广播内部机制详解(二)
Android 广播内部机制详解(三)
1. 广播的类型
广播分为:
普通广播:通过Context.sendBroadcast()发送
有序广播:通过Context.sendOrderedBroadcast()发送
粘性广播:通过Context.sendStickyBroadcast()发送
2. 广播的注册
众所周知,注册有两种方法,分别为动态注册和静态注册,这里我们先来说说动态注册。
2.1 动态注册
动态注册调用的是context中的registerReceiver,这个方法在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) {
//见2.1.1
return registerReceiverInternal(receiver, getUserId(),
filter, broadcastPermission, scheduler, getOuterContext());
}
@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
return registerReceiverInternal(receiver, user.getIdentifier(),
filter, broadcastPermission, scheduler, getOuterContext());
}
大家可以看到这些注册的方法最终都调用了registerReceiverInternal,接下来,我们再来看看registerReceiverInternal
2.1.1 registerReceiverInternal
java文件:ContextImpl.java
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context) {
IIntentReceiver rd = null;
if (receiver != null) {
//mPackageInfo的类型为Loade
if (mPackageInfo != null && context != null) {
//没有设置scheduler的话,就使用主线程的Handler
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
//见2.1.2
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.1.4
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();
}
}
一般情况下,mPackageInfo和context不为null,scheduler用的主线程的Handler,接着会调用rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);
2.1.2 getReceiverDispatcher
java文件:LoadedApk.java
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);
}
}
//第一次注册肯定会走这里,rd == null
if (rd == null) {
//见2.1.3
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();
}
}
这里先解释一下mReceivers,mReceivers一张存储了所有所有receiver的哈希表,在这里通过context和对应的receiver可以得到对应的ReceiverDispatcher,进而返回IIntentReceiver。
大家都知道,其实广播的发送其实靠AMS来传递的,AMS通过匹配注册的信息然后然后将广播发给对应的进程,对应进程的Receiver再调用它的onReceive(),这利用的是binder机制,上文中的rd对象(IIntentReceiver rd)就是binder实体,并用ReceiveDispatcher这个类来管理它,接下来我们来看看ReceiveDispatcher
2.1.3 ReceiverDispatcher
文件:LoadedApk.java
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 {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
//它就是上面的rd
final IIntentReceiver.Stub mIIntentReceiver;
//持有对应的BroacastReceiver,和BroacastReceiver一一对应
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
final boolean mRegistered;
final IntentReceiverLeaked mLocation;
RuntimeException mUnregisterLocation;
boolean mForgotten;
.........
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();
}
..........
}
BroadcastReceiver和ReceiverDispatcher是一一对应的,AMS通过对应的mIIntentReceiver(ReceiverDispatcher类里)来响应对应广播的onReceiver。
2.1.4 registerReceiver
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
看这代码我们可以知道registerReceiver的实现肯定是在AMS里面,我们在去AMS里面看看:
java文件:ActivityManagerService.java
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
......
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
ArrayList<String> noAction = new ArrayList<String>(1);
noAction.add(null);
actions = noAction.iterator();
}
// 收集所有与注册用户userId相关所有的已经广播过的粘性广播,并将它放到stickyIntents里面
// 这里仅仅只是先做一层关于action的筛选
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>();
}
stickyIntents.addAll(intents);
}
}
}
}
}
// 通过IntentFilter.match方法对上面筛选出来的stickyIntents进行一次精准的筛选
ArrayList<Intent> allSticky = null;
if (stickyIntents != null) {
final ContentResolver resolver = mContext.getContentResolver();
// Look for any matching sticky broadcasts...
for (int i = 0, N = stickyIntents.size(); i < N; i++) {
Intent intent = stickyIntents.get(i);
//将匹配成功的粘性广播的intent放入allSticky中
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList<Intent>();
}
allSticky.add(intent);
}
}
}
// The first sticky in the list is returned directly back to the client.
Intent sticky = allSticky != null ? allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
if (receiver == null) {
return sticky;
}
synchronized (this) {
if (callerApp != null && (callerApp.thread == null
|| callerApp.thread.asBinder() != caller.asBinder())) {
// 如果调用进程已经死了,返回null
return 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;
}
//存储了当前系统中所与receiver注册的所有的filter
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
......
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
permission, callingUid, userId);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadcast");
}
// 存储了当前系统中所有的BraodcastFilter
mReceiverResolver.addFilter(bf);
// Enqueue broadcasts for all existing stickies that match
// this filter.
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, null, null, AppOpsManager.OP_NONE, null, receivers,
null, 0, null, null, false, true, true, -1);
//将BroadcastRecord加到BroadcastQueue.ParallelBroadcasts中
queue.enqueueParallelBroadcastLocked(r);
//发送广播,如果当前还有广播正在处理发送,这次推动不会执行
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
这部分代码比较长,重点的地方我在代码中都有注释,我这里再总结一下:
将发送过的粘性广播和注册的filter的action进行匹配,匹配成功的放到stickyIntents,然后再进行一个精准的筛选,包括type、scheme、data等,匹配成功放到allSticky,接着如果传入的receiver为null,返回sticky(如果allSticky不为null,则返回allSticky的第一个,否则返回)
调用进程如果为已经死了,则返回null;返回对应receiver.asBinder()(也就是ReceiverDispatcher)的ReceiverList
根据当前的IntentFilter创建BroadcastFilter对象,创建完毕之后,将BroadcastFilter对象对象放入mReceiverResolver中
发送筛选出来的sticky广播
2.2 静态注册
广播的静态注册是通过在AdroidManifest.xml中声明receiver来实现的,用法非常简单。这些信息会在系统启动的时候,由PKMS解析并记录下来,并对外提供接口,比如:AMS就可以用过queryIntentReceivers()函数来察看有多少receiver对目标action感兴趣