[原]Android应用程序注册广播接收器(registerReceiver)的过程分析

前面我们介绍了Android系统的广播机制,从本质来说,它是一种消息订阅/发布机制,因此,使用这种消息驱动模型的第一步便是订阅消息;而对Android应用程序来说,订阅消息其实就是注册广播接收器,本文将探讨Android应用程序是如何注册广播接收器以及把广播接收器注册到哪里去的。

在Android的广播机制中,ActivityManagerService扮演着广播中心的角色,负责系统中所有广播的注册和发布操作,因此,Android应用程序注册广播接收器的过程就把是广播接收器注册到ActivityManagerService的过程。Android应用程序是通过调用ContextWrapper类的registerReceiver函数来把广播接收器BroadcastReceiver注册到ActivityManagerService中去的,而ContextWrapper类本身又借助ContextImpl类来注册广播接收器。

在Android应用程序框架中,Activity和Service类都继承了ContextWrapper类,因此,我们可以在Activity或者Service的子类中调用registerReceiver函数来注册广播接收器。Activity、Service、ContextWrapper和ContextImpl这四个类的关系可以参考前面Android系统在新进程中启动自定义服务过程(startService)的原理分析一文中描述的Activity类图。

这篇文章还是继续以实例来进行情景分析,所用到的例子便是上一篇文章Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序了,所以希望读者在继续阅读本文之前,先看看这篇文章;又由于Android应用程序是把广播接器注册到ActivityManagerService中去的,因此,这里又会涉入到Binder进程间通信机制,所以希望读者对Android系统的Binder进程间通信机制有所了解,具体请参考Android进程间通信(IPC)机制Binder简要介绍和学习计划一文。

开始进入主题了,在Android系统中的广播(Broadcast)机制简要介绍和学习计划一文所介绍的例子中,注册广播接收器的操作是MainActivity发起的,我们先来看看注册过程的序列图:


在分析这个序列图之前,我们先来看一下MainActivity是如何调用registerReceiver函数来注册广播接收器的:

public class MainActivity extends Activity implements OnClickListener {  ......@Override   public void onResume() {  super.onResume();  IntentFilter counterActionFilter = new IntentFilter(CounterService.BROADCAST_COUNTER_ACTION);  registerReceiver(counterActionReceiver, counterActionFilter);  } ......}
MainActivity在onResume函数里,通过其父类ContextWrapper的registerReceiver函数注册了一个BroadcastReceiver实例counterActionReceiver,并且通过IntentFilter实例counterActionFilter告诉ActivityManagerService,它要订阅的广播是CounterService.BROADCAST_COUNTER_ACTION类型的,这样,ActivityManagerService在收到CounterService.BROADCAST_COUNTER_ACTION类型的广播时,就会分发给counterActionReceiver实例的onReceive函数。

接下来,就开始分析注册过程中的每一个步骤了。

Step 1. ContextWrapper.registerReceiver

这个函数实现在frameworks/base/core/java/android/content/ContextWrapper.java文件中:

public class ContextWrapper extends Context {Context mBase;......@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return mBase.registerReceiver(receiver, filter);}......}
这里的成员变量mBase是一个ContextImpl实例,想知道为什么,可以回过头去看看 Android应用程序启动过程源代码分析这篇文章>~<。

Step 2. ContextImpl.registerReceiver

这个函数实现在frameworks/base/core/java/android/app/ContextImpl.java文件中:

class ContextImpl extends Context {......@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,String broadcastPermission, Handler scheduler) {return registerReceiverInternal(receiver, filter, broadcastPermission,scheduler, getOuterContext());}private Intent registerReceiverInternal(BroadcastReceiver receiver,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 {......}}try {return ActivityManagerNative.getDefault().registerReceiver(mMainThread.getApplicationThread(),rd, filter, broadcastPermission);} catch (RemoteException e) {return null;}}......}
通过两个函数的中转,最终就进入到ContextImpl.registerReceiverInternal这个函数来了。这里的成员变量mPackageInfo是一个LoadedApk实例,它是用来负责处理广播的接收的,在后面一篇文章讲到广播的发送时(sendBroadcast),会详细描述。参数broadcastPermission和scheduler都为null,而参数context是上面的函数通过调用函数getOuterContext得到的,这里它就是指向MainActivity了,因为MainActivity是继承于Context类的,因此,这里用Context类型来引用。

由于条件mPackageInfo != null和context != null都成立,而且条件scheduler == null也成立,于是就调用mMainThread.getHandler来获得一个Handler了,这个Hanlder是后面用来分发ActivityManagerService发送过的广播用的。这里的成员变量mMainThread是一个ActivityThread实例,在前面Android应用程序启动过程源代码分析这篇文章也描述过了。我们先来看看ActivityThread.getHandler函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。

Step 3. ActivityThread.getHandler

这个函数实现在frameworks/base/core/java/android/app/ActivityThread.java文件中:

public final class ActivityThread {......final H mH = new H();private final class H extends Handler {......public void handleMessage(Message msg) {......switch (msg.what) {......}......}......}......final Handler getHandler() {return mH;}......}
有了这个Handler之后,就可以分发消息给应用程序处理了。

再回到上一步的ContextImpl.registerReceiverInternal函数中,它通过mPackageInfo.getReceiverDispatcher函数获得一个IIntentReceiver接口对象rd,这是一个Binder对象,接下来会把它传给ActivityManagerService,ActivityManagerService在收到相应的广播时,就是通过这个Binder对象来通知MainActivity来接收的。

我们也是先来看一下mPackageInfo.getReceiverDispatcher函数的实现,然后再回过头来继续分析ContextImpl.registerReceiverInternal函数。

Step 4. LoadedApk.getReceiverDispatcher

这个函数实现在frameworks/base/core/java/android/app/LoadedApk.java文件中:

final class LoadedApk {......public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,Context context, Handler handler,Instrumentation instrumentation, boolean registered) {synchronized (mReceivers) {LoadedApk.ReceiverDispatcher rd = null;HashMap<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 HashMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();mReceivers.put(context, map);}map.put(r, rd);}} else {rd.validate(context, handler);}return rd.getIIntentReceiver();}}......static final class ReceiverDispatcher {final static class InnerReceiver extends IIntentReceiver.Stub {final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;......InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);......}......}......final IIntentReceiver.Stub mIIntentReceiver;final Handler mActivityThread;......ReceiverDispatcher(BroadcastReceiver receiver, Context context,Handler activityThread, Instrumentation instrumentation,boolean registered) {......mIIntentReceiver = new InnerReceiver(this, !registered);mActivityThread = activityThread;......}......IIntentReceiver getIIntentReceiver() {return mIIntentReceiver;}}......}

在LoadedApk.getReceiverDispatcher函数中,首先看一下参数r是不是已经有相应的ReceiverDispatcher存在了,如果有,就直接返回了,否则就新建一个ReceiverDispatcher,并且以r为Key值保在一个HashMap中,而这个HashMap以Context,这里即为MainActivity为Key值保存在LoadedApk的成员变量mReceivers中,这样,只要给定一个Activity和BroadcastReceiver,就可以查看LoadedApk里面是否已经存在相应的广播接收发布器ReceiverDispatcher了。

在新建广播接收发布器ReceiverDispatcher时,会在构造函数里面创建一个InnerReceiver实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver函数来获得,获得后就会把它传给ActivityManagerService,以便接收广播。在ReceiverDispatcher类的构造函数中,还会把传进来的Handle类型的参数activityThread保存下来,以便后面在分发广播的时候使用。

现在,再回到ContextImpl.registerReceiverInternal函数,在获得了IIntentReceiver类型的Binder对象后,就开始要把它注册到ActivityManagerService中去了。

Step 5. ActivityManagerProxy.registerReceiver

这个函数实现在frameworks/base/core/java/android/app/ActivityManagerNative.java文件中:

class ActivityManagerProxy implements IActivityManager{......public Intent registerReceiver(IApplicationThread caller,IIntentReceiver receiver,IntentFilter filter, String perm) throws RemoteException{Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);filter.writeToParcel(data, 0);data.writeString(perm);mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);reply.readException();Intent intent = null;int haveIntent = reply.readInt();if (haveIntent != 0) {intent = Intent.CREATOR.createFromParcel(reply);}reply.recycle();data.recycle();return intent;}......}
这个函数通过Binder驱动程序就进入到ActivityManagerService中的registerReceiver函数中去了。

Step 6. ActivityManagerService.registerReceiver

这个函数实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

public final class ActivityManagerService extends ActivityManagerNativeimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {......public Intent registerReceiver(IApplicationThread caller,IIntentReceiver receiver, IntentFilter filter, String permission) {synchronized(this) {ProcessRecord callerApp = null;if (caller != null) {callerApp = getRecordForAppLocked(caller);if (callerApp == null) {......}}List allSticky = null;// Look for any matching sticky broadcasts...Iterator actions = filter.actionsIterator();if (actions != null) {while (actions.hasNext()) {String action = (String)actions.next();allSticky = getStickiesLocked(action, filter, allSticky);}} else {......}// The first sticky in the list is returned directly back to// the client.Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;......if (receiver == null) {return sticky;}ReceiverList rl= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {rl = new ReceiverList(this, callerApp,Binder.getCallingPid(),Binder.getCallingUid(), receiver);if (rl.app != null) {rl.app.receivers.add(rl);} else {......}mRegisteredReceivers.put(receiver.asBinder(), rl);}BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);rl.add(bf);......mReceiverResolver.addFilter(bf);// Enqueue broadcasts for all existing stickies that match// this filter.if (allSticky != null) {......}return sticky;}}......}
函数首先是获得调用registerReceiver函数的应用程序进程记录块:

    ProcessRecord callerApp = null;    if (caller != null) {callerApp = getRecordForAppLocked(caller);if (callerApp == null) {    ......        }    }
这里得到的便是上一篇文章 Android系统中的广播(Broadcast)机制简要介绍和学习计划里面介绍的应用程序Broadcast的进程记录块了,MainActivity就是在里面启动起来的。

    List allSticky = null;    // Look for any matching sticky broadcasts...    Iterator actions = filter.actionsIterator();    if (actions != null) {while (actions.hasNext()) {String action = (String)actions.next();allSticky = getStickiesLocked(action, filter, allSticky);}    } else {......    }    // The first sticky in the list is returned directly back to    // the client.    Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
这里传进来的filter只有一个action,就是前面描述的CounterService.BROADCAST_COUNTER_ACTION了,这里先通过getStickiesLocked函数查找一下有没有对应的sticky intent列表存在。什么是Sticky Intent呢?我们在最后一次调用sendStickyBroadcast函数来发送某个Action类型的广播时,系统会把代表这个广播的Intent保存下来,这样,后来调用registerReceiver来注册相同Action类型的广播接收器,就会得到这个最后发出的广播。这就是为什么叫做Sticky Intent了,这个最后发出的广播虽然被处理完了,但是仍然被粘住在ActivityManagerService中,以便下一个注册相应Action类型的广播接收器还能继承处理。

这里,假设我们不使用sendStickyBroadcast来发送CounterService.BROADCAST_COUNTER_ACTION类型的广播,于是,这里得到的allSticky和sticky都为null了。

继续往下看,这里传进来的receiver不为null,于是,继续往下执行:

    ReceiverList rl= (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());    if (rl == null) {rl = new ReceiverList(this, callerApp,Binder.getCallingPid(),Binder.getCallingUid(), receiver);if (rl.app != null) {rl.app.receivers.add(rl);} else {......}mRegisteredReceivers.put(receiver.asBinder(), rl);    }
这里其实就是把广播接收器receiver保存一个ReceiverList列表中,这个列表的宿主进程是rl.app,这里就是MainActivity所在的进程了,在ActivityManagerService中,用一个进程记录块来表示这个应用程序进程,它里面有一个列表receivers,专门用来保存这个进程注册的广播接收器。接着,又把这个ReceiverList列表以receiver为Key值保存在ActivityManagerService的成员变量mRegisteredReceivers中,这些都是为了方便在收到广播时,快速找到对应的广播接收器的。

再往下看:

    BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);    rl.add(bf);    ......    mReceiverResolver.addFilter(bf);
上面只是把广播接收器receiver保存起来了,但是还没有把它和filter关联起来,这里就创建一个BroadcastFilter来把广播接收器列表rl和filter关联起来,然后保存在ActivityManagerService中的成员变量mReceiverResolver中去。

这样,广播接收器注册的过程就介绍完了,比较简单,但是工作又比较琐碎,主要就是将广播接收器receiver及其要接收的广播类型filter保存在ActivityManagerService中,以便以后能够接收到相应的广播并进行处理,在下一篇文章,我们将详细分析这个过程,敬请关注。

作者:Luoshengyang 发表于2011-9-2 1:26:33 原文链接 阅读:7141 评论:14 查看评论


更多相关文章

  1. Android(安卓)NDK开发篇(一):新版NDK环境搭建(免Cygwin,超级快)
  2. Android应用程序消息处理机制(Looper、Handler)分析
  3. Android(安卓)应用程序开发基础
  4. Android(安卓)基础总结:(七)BroadcastReceiver详解(上)
  5. Android系统升级全流程
  6. Android输入子系统之启动过程分析
  7. Android中JNI的使用方法
  8. 通过广播Intent控制Android系统自带的音乐播放器
  9. 箭头函数的基础使用

随机推荐

  1. 从SDK的Application Fundamentals开始
  2. android 刷新activity(在本页面刷新)
  3. android布局layout边框颜色
  4. 获取Bitmap和对Bitmap的操作工具类
  5. Android广告轮播
  6. Android(安卓)中保存图片的代码
  7. Android(安卓)带有可滑动效果的用户引导
  8. 点击事件内部类中使用内部类
  9. Android(安卓)UI 常用颜色
  10. Android-Android(安卓)API 版本判断