Android应用程序注册广播接收器(registerReceiver)的过程分析
来自:http://blog.csdn.net/luoshengyang/article/details/6737352
前面我们介绍了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函数来注册广播接收器的:
[java] view plain copy- publicclassMainActivityextendsActivityimplementsOnClickListener{
- ......
- @Override
- publicvoidonResume(){
- super.onResume();
- IntentFiltercounterActionFilter=newIntentFilter(CounterService.BROADCAST_COUNTER_ACTION);
- registerReceiver(counterActionReceiver,counterActionFilter);
- }
- ......
- }
接下来,就开始分析注册过程中的每一个步骤了。
Step 1. ContextWrapper.registerReceiver
这个函数实现在frameworks/base/core/java/android/content/ContextWrapper.java文件中:
[java] view plain copy- publicclassContextWrapperextendsContext{
- ContextmBase;
- ......
- @Override
- publicIntentregisterReceiver(
- BroadcastReceiverreceiver,IntentFilterfilter){
- returnmBase.registerReceiver(receiver,filter);
- }
- ......
- }
Step 2. ContextImpl.registerReceiver
这个函数实现在frameworks/base/core/java/android/app/ContextImpl.java文件中:
[java] view plain copy- classContextImplextendsContext{
- ......
- @Override
- publicIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter){
- returnregisterReceiver(receiver,filter,null,null);
- }
- @Override
- publicIntentregisterReceiver(BroadcastReceiverreceiver,IntentFilterfilter,
- StringbroadcastPermission,Handlerscheduler){
- returnregisterReceiverInternal(receiver,filter,broadcastPermission,
- scheduler,getOuterContext());
- }
- privateIntentregisterReceiverInternal(BroadcastReceiverreceiver,
- IntentFilterfilter,StringbroadcastPermission,
- Handlerscheduler,Contextcontext){
- IIntentReceiverrd=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{
- returnActivityManagerNative.getDefault().registerReceiver(
- mMainThread.getApplicationThread(),
- rd,filter,broadcastPermission);
- }catch(RemoteExceptione){
- returnnull;
- }
- }
- ......
- }
由于条件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文件中:
- publicfinalclassActivityThread{
- ......
- finalHmH=newH();
- privatefinalclassHextendsHandler{
- ......
- publicvoidhandleMessage(Messagemsg){
- ......
- switch(msg.what){
- ......
- }
- ......
- }
- ......
- }
- ......
- finalHandlergetHandler(){
- returnmH;
- }
- ......
- }
再回到上一步的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文件中:
[java] view plain copy- finalclassLoadedApk{
- ......
- publicIIntentReceivergetReceiverDispatcher(BroadcastReceiverr,
- Contextcontext,Handlerhandler,
- Instrumentationinstrumentation,booleanregistered){
- synchronized(mReceivers){
- LoadedApk.ReceiverDispatcherrd=null;
- HashMap<BroadcastReceiver,LoadedApk.ReceiverDispatcher>map=null;
- if(registered){
- map=mReceivers.get(context);
- if(map!=null){
- rd=map.get(r);
- }
- }
- if(rd==null){
- rd=newReceiverDispatcher(r,context,handler,
- instrumentation,registered);
- if(registered){
- if(map==null){
- map=newHashMap<BroadcastReceiver,LoadedApk.ReceiverDispatcher>();
- mReceivers.put(context,map);
- }
- map.put(r,rd);
- }
- }else{
- rd.validate(context,handler);
- }
- returnrd.getIIntentReceiver();
- }
- }
- ......
- staticfinalclassReceiverDispatcher{
- finalstaticclassInnerReceiverextendsIIntentReceiver.Stub{
- finalWeakReference<LoadedApk.ReceiverDispatcher>mDispatcher;
- ......
- InnerReceiver(LoadedApk.ReceiverDispatcherrd,booleanstrong){
- mDispatcher=newWeakReference<LoadedApk.ReceiverDispatcher>(rd);
- ......
- }
- ......
- }
- ......
- finalIIntentReceiver.StubmIIntentReceiver;
- finalHandlermActivityThread;
- ......
- ReceiverDispatcher(BroadcastReceiverreceiver,Contextcontext,
- HandleractivityThread,Instrumentationinstrumentation,
- booleanregistered){
- ......
- mIIntentReceiver=newInnerReceiver(this,!registered);
- mActivityThread=activityThread;
- ......
- }
- ......
- IIntentReceivergetIIntentReceiver(){
- returnmIIntentReceiver;
- }
- }
- ......
- }
在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文件中:
- classActivityManagerProxyimplementsIActivityManager
- {
- ......
- publicIntentregisterReceiver(IApplicationThreadcaller,
- IIntentReceiverreceiver,
- IntentFilterfilter,Stringperm)throwsRemoteException
- {
- Parceldata=Parcel.obtain();
- Parcelreply=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();
- Intentintent=null;
- inthaveIntent=reply.readInt();
- if(haveIntent!=0){
- intent=Intent.CREATOR.createFromParcel(reply);
- }
- reply.recycle();
- data.recycle();
- returnintent;
- }
- ......
- }
Step 6. ActivityManagerService.registerReceiver
这个函数实现在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:
[java] view plain copy- publicfinalclassActivityManagerServiceextendsActivityManagerNative
- implementsWatchdog.Monitor,BatteryStatsImpl.BatteryCallback{
- ......
- publicIntentregisterReceiver(IApplicationThreadcaller,
- IIntentReceiverreceiver,IntentFilterfilter,Stringpermission){
- synchronized(this){
- ProcessRecordcallerApp=null;
- if(caller!=null){
- callerApp=getRecordForAppLocked(caller);
- if(callerApp==null){
- ......
- }
- }
- ListallSticky=null;
- //Lookforanymatchingstickybroadcasts...
- Iteratoractions=filter.actionsIterator();
- if(actions!=null){
- while(actions.hasNext()){
- Stringaction=(String)actions.next();
- allSticky=getStickiesLocked(action,filter,allSticky);
- }
- }else{
- ......
- }
- //Thefirststickyinthelistisreturneddirectlybackto
- //theclient.
- Intentsticky=allSticky!=null?(Intent)allSticky.get(0):null;
- ......
- if(receiver==null){
- returnsticky;
- }
- ReceiverListrl
- =(ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
- if(rl==null){
- rl=newReceiverList(this,callerApp,
- Binder.getCallingPid(),
- Binder.getCallingUid(),receiver);
- if(rl.app!=null){
- rl.app.receivers.add(rl);
- }else{
- ......
- }
- mRegisteredReceivers.put(receiver.asBinder(),rl);
- }
- BroadcastFilterbf=newBroadcastFilter(filter,rl,permission);
- rl.add(bf);
- ......
- mReceiverResolver.addFilter(bf);
- //Enqueuebroadcastsforallexistingstickiesthatmatch
- //thisfilter.
- if(allSticky!=null){
- ......
- }
- returnsticky;
- }
- }
- ......
- }
- ProcessRecordcallerApp=null;
- if(caller!=null){
- callerApp=getRecordForAppLocked(caller);
- if(callerApp==null){
- ......
- }
- }
[java] view plain copy
- ListallSticky=null;
- //Lookforanymatchingstickybroadcasts...
- Iteratoractions=filter.actionsIterator();
- if(actions!=null){
- while(actions.hasNext()){
- Stringaction=(String)actions.next();
- allSticky=getStickiesLocked(action,filter,allSticky);
- }
- }else{
- ......
- }
- //Thefirststickyinthelistisreturneddirectlybackto
- //theclient.
- Intentsticky=allSticky!=null?(Intent)allSticky.get(0):null;
这里,假设我们不使用sendStickyBroadcast来发送CounterService.BROADCAST_COUNTER_ACTION类型的广播,于是,这里得到的allSticky和sticky都为null了。
继续往下看,这里传进来的receiver不为null,于是,继续往下执行:
[java] view plain copy- ReceiverListrl
- =(ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
- if(rl==null){
- rl=newReceiverList(this,callerApp,
- Binder.getCallingPid(),
- Binder.getCallingUid(),receiver);
- if(rl.app!=null){
- rl.app.receivers.add(rl);
- }else{
- ......
- }
- mRegisteredReceivers.put(receiver.asBinder(),rl);
- }
再往下看:
[java] view plain copy- BroadcastFilterbf=newBroadcastFilter(filter,rl,permission);
- rl.add(bf);
- ......
- mReceiverResolver.addFilter(bf);
这样,广播接收器注册的过程就介绍完了,比较简单,但是工作又比较琐碎,主要就是将广播接收器receiver及其要接收的广播类型filter保存在ActivityManagerService中,以便以后能够接收到相应的广播并进行处理,在下一篇文章,我们将详细分析这个过程,敬请关注。
更多相关文章
- android OTG (USB读写,U盘读写)最全使用相关总结
- 用C/C++开发android应用
- android耳机状态的检测
- android画经过多点的曲线
- 解决Android8广播的静态注册接收不到问题
- Android(安卓)串口通讯-------android -serialport-api
- Android进程间通信IPC机制Binder
- Android应用程序消息处理机制(Looper、Handler)分析(4)
- 箭头函数的基础使用