基于Android 7.0源码,分析Android广播机制的注册过程。
简单地说,Android广播机制的主要工作是为了实现一处发生事情,多处得到通知的效果,这种通知工作常常要牵涉跨进程通讯,实现广播的功能时,需要一方注册广播接收器,另外一方需要发送广播。由于注册广播接收器和发送广播的过程比较长,这里分成两篇文章讲解,本篇主要说说注册广播接收器的过程。
注册广播接收器可以通过两种方式————静态注册、动态注册。
静态注册时,是通过在AndroidManifest.xml中配置
<receiver android:name="com.example.my_broadcast.MyBroadcastReceiver" >
<intent-filter>
<action android:name="com.android.broadcasttest.NEW_LIFEFROM" />
intent-filter>
receiver>
配置了以上信息之后,只要是com.android.broadcasttest.NEW_LIFEFROM这个地址的广播,MyBroadcastReceiver都能够接收的到。
注意,这种方式的注册是常驻型的,也就是说当应用进程不存在时,如果有该粘性广播信息传来,MyBroadcastReceiver所在的应用进程会先被系统拉起,随后自动运行。
另外,还有如下intent-filter
<intent-filter . . . >
<category android:name="android.Intent.Category.DEFAULT" />
<category android:name="android.Intent.Category.BROWSABLE" />
intent-filter>
<intent-filter . . . >
<data android:type="video/mpeg" android:scheme="http" . . . />
<data android:type="audio/mpeg" android:scheme="http" . . . />
intent-filter>
它们的信息会在系统启动时,由PackageManagerService解析并记录下来。以后,当AMS调用PKMS的接口来查询“和intent匹配的组件”时,PKMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。
静态注册的具体过程需要比较熟悉包管理的代码,这里暂时略去,后面详细看过PackageManagerService的代码后,在回来补上。
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service使用registerReceiver注册广播接收器:
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler)
IntentFileter类成员:
private int mPriority;
private final ArrayList mActions;
private ArrayList mCategories = null;
private ArrayList mDataSchemes = null;
private ArrayList mDataSchemeSpecificParts = null;
private ArrayList mDataAuthorities = null;
private ArrayList mDataPaths = null;
private ArrayList mDataTypes = null;
注意,动态注册方式与静态注册相反,不是常驻型的,也就是说广播接收器的生命周期会跟随程序的生命周期。
我们以两个参数的registerReceiver接口为例,来分析一下动态注册的具体流程。
registerReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,而ContextWrapper的具体实现者又是ContextImpl。
[===>frameworks\base\core\java\android\app\ContextImpl.java]
@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());
}
传入的receiver参数一般是用户自定义并继承自BroadcastReceiver类。
[===>frameworks\base\core\java\android\app\ContextImpl.java]
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();
}
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 {
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();
}
}
从以上的代码可以看出,动态注册的BroadcastReceiver和ReceiverDispatcher存在着一一对应的关系。
广播最终是通过AMS递送出去,AMS利用binder机制,将语义传递给各个应用进程,应用进程再辗转调用到receiver的onReceive()中以完成这次广播。而IIntentReceiver类型的rd对象正是承担“语义传递工作“的binder实体。
ReceiverDispatcher类就可以看成是这类binder实体的管理者或者是承载者。
static final class ReceiverDispatcher {
final static class InnerReceiver extends IIntentReceiver.Stub {
final WeakReference mDispatcher;
final LoadedApk.ReceiverDispatcher mStrongRef;
InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
mDispatcher = new WeakReference(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 (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
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();
}
}
}
}
final IIntentReceiver.Stub mIIntentReceiver; //注意,它就是传到外面的rd
final BroadcastReceiver mReceiver;
final Context mContext;
final Handler mActivityThread;
final Instrumentation mInstrumentation;
ReceiverDispatcher(BroadcastReceiver receiver, Context context,
Handler activityThread, Instrumentation instrumentation,
boolean registered) {
mIIntentReceiver = new InnerReceiver(this, !registered);
mReceiver = receiver;
mContext = context;
mActivityThread = activityThread;
mInstrumentation = instrumentation;
}
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)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
args.sendFinished(mgr);
}
}
}
}
这里以一张简单的不规范类图来说明。
另外,一个应用可以动态注册多个BroadcastReceiver,即应用和BroadcastReceiver是一个一对多的关系,反映这种关系的代码位于LoadedApk中,在LoadedApk中有一个成员变量mReceivers。应用进程里是使用LoadedApk来指代一个apk的,进程里有多少个apk,就有多少个LoadedApk。
private final ArrayMap> mReceivers
= new ArrayMap>();
该表的key项是Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子ArrayMap”。这是个“表中表”的形式。言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“子ArrayMap”的key值为BroadcastReceiver,value项为ReceiverDispatcher,即反映了动态BroadcastReceiver和ReceiverDispatcher是一一对应。
在ContextImpl.registerReceiverInternal的最后,会调用:
final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
通过Binder机制会最终调用到ActivityManagerService.registerReceiver中。
[===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
final HashMap mRegisteredReceivers = new HashMap<>();
final IntentResolver mReceiverResolver
= new IntentResolver() {
...
};//发送广播时,获取动态注册广播接收器时使用
final SparseArray>> mStickyBroadcasts =
new SparseArray>>();
public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
ArrayList stickyIntents = null;
ProcessRecord callerApp = null;
int callingUid;
int callingPid;
synchronized(this) {
// Collect stickies of users
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
for (int id : userIds) {
ArrayMap> stickies = mStickyBroadcasts.get(id);
if (stickies != null) {
ArrayList intents = stickies.get(action);
if (intents != null) {
if (stickyIntents == null) {
stickyIntents = new ArrayList();
}
stickyIntents.addAll(intents);
}
}
}
}
}
ArrayList 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);
if (filter.match(resolver, intent, true, TAG) >= 0) {
if (allSticky == null) {
allSticky = new ArrayList();
}
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 (receiver == null) {
return 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);
rl.add(bf);
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);
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();
}
}
return sticky;
}
}
}
我们知道,对于同一个BroadcastReceiver对象,是可以注册多个IntentFilter的,这些IntentFilter信息会存放到AMS的mRegisteredReceivers表中。
在AMS端,可以通过以下代码访问相应的汇总表:
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
其中的receiver参数为IIntentReceiver类型,正对应着ReceiverDispatcher中那个binder实体成员变量mIIntentReceiver。换句话说就是,每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。
final class ReceiverList extends ArrayList<BroadcastFilter>
implements IBinder.DeathRecipient {
...
}
final class BroadcastFilter extends IntentFilter {
// Back-pointer to the list this filter is in.
final ReceiverList receiverList;
...
}
ReceiverList继承自ArrayList,BroadcastFilter继承自IntentFilter,那么ReceiverList可以看成是IntentFilter数组列表。
上面代码的大致工作主要是以下四个:
- 根据userId和intentfiler过滤后,得到相应的粘性广播列表;
- 根据userId、IIntentReceiver等信息创建ReceiverList,存放到AMS.mRegisteredReceivers中,key值为IIntentReceiver;
- 创建BroadcastFilter,将它分别添加到ReceiverList中,同时添加到AMS.mReceiverResolver中,mReceiverResolver在发送广播时获取动态注册广播接收器时使用;
- 最后,发送相应的粘性广播;
结合LoadedApk和ActivityManagerService的代码和上面的小图,可以最后得到一张总体的图,如下: